Merge tag 'trace-v4.20' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt...
[sfrench/cifs-2.6.git] / sound / firewire / oxfw / oxfw-spkr.c
1 /*
2  * oxfw-spkr.c - a part of driver for OXFW970/971 based devices
3  *
4  * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
5  * Licensed under the terms of the GNU General Public License, version 2.
6  */
7
8 #include "oxfw.h"
9
10 struct fw_spkr {
11         bool mute;
12         s16 volume[6];
13         s16 volume_min;
14         s16 volume_max;
15
16         unsigned int mixer_channels;
17         u8 mute_fb_id;
18         u8 volume_fb_id;
19 };
20
21 enum control_action { CTL_READ, CTL_WRITE };
22 enum control_attribute {
23         CTL_MIN         = 0x02,
24         CTL_MAX         = 0x03,
25         CTL_CURRENT     = 0x10,
26 };
27
28 static int avc_audio_feature_mute(struct fw_unit *unit, u8 fb_id, bool *value,
29                                   enum control_action action)
30 {
31         u8 *buf;
32         u8 response_ok;
33         int err;
34
35         buf = kmalloc(11, GFP_KERNEL);
36         if (!buf)
37                 return -ENOMEM;
38
39         if (action == CTL_READ) {
40                 buf[0] = 0x01;          /* AV/C, STATUS */
41                 response_ok = 0x0c;     /*       STABLE */
42         } else {
43                 buf[0] = 0x00;          /* AV/C, CONTROL */
44                 response_ok = 0x09;     /*       ACCEPTED */
45         }
46         buf[1] = 0x08;                  /* audio unit 0 */
47         buf[2] = 0xb8;                  /* FUNCTION BLOCK */
48         buf[3] = 0x81;                  /* function block type: feature */
49         buf[4] = fb_id;                 /* function block ID */
50         buf[5] = 0x10;                  /* control attribute: current */
51         buf[6] = 0x02;                  /* selector length */
52         buf[7] = 0x00;                  /* audio channel number */
53         buf[8] = 0x01;                  /* control selector: mute */
54         buf[9] = 0x01;                  /* control data length */
55         if (action == CTL_READ)
56                 buf[10] = 0xff;
57         else
58                 buf[10] = *value ? 0x70 : 0x60;
59
60         err = fcp_avc_transaction(unit, buf, 11, buf, 11, 0x3fe);
61         if (err < 0)
62                 goto error;
63         if (err < 11) {
64                 dev_err(&unit->device, "short FCP response\n");
65                 err = -EIO;
66                 goto error;
67         }
68         if (buf[0] != response_ok) {
69                 dev_err(&unit->device, "mute command failed\n");
70                 err = -EIO;
71                 goto error;
72         }
73         if (action == CTL_READ)
74                 *value = buf[10] == 0x70;
75
76         err = 0;
77
78 error:
79         kfree(buf);
80
81         return err;
82 }
83
84 static int avc_audio_feature_volume(struct fw_unit *unit, u8 fb_id, s16 *value,
85                                     unsigned int channel,
86                                     enum control_attribute attribute,
87                                     enum control_action action)
88 {
89         u8 *buf;
90         u8 response_ok;
91         int err;
92
93         buf = kmalloc(12, GFP_KERNEL);
94         if (!buf)
95                 return -ENOMEM;
96
97         if (action == CTL_READ) {
98                 buf[0] = 0x01;          /* AV/C, STATUS */
99                 response_ok = 0x0c;     /*       STABLE */
100         } else {
101                 buf[0] = 0x00;          /* AV/C, CONTROL */
102                 response_ok = 0x09;     /*       ACCEPTED */
103         }
104         buf[1] = 0x08;                  /* audio unit 0 */
105         buf[2] = 0xb8;                  /* FUNCTION BLOCK */
106         buf[3] = 0x81;                  /* function block type: feature */
107         buf[4] = fb_id;                 /* function block ID */
108         buf[5] = attribute;             /* control attribute */
109         buf[6] = 0x02;                  /* selector length */
110         buf[7] = channel;               /* audio channel number */
111         buf[8] = 0x02;                  /* control selector: volume */
112         buf[9] = 0x02;                  /* control data length */
113         if (action == CTL_READ) {
114                 buf[10] = 0xff;
115                 buf[11] = 0xff;
116         } else {
117                 buf[10] = *value >> 8;
118                 buf[11] = *value;
119         }
120
121         err = fcp_avc_transaction(unit, buf, 12, buf, 12, 0x3fe);
122         if (err < 0)
123                 goto error;
124         if (err < 12) {
125                 dev_err(&unit->device, "short FCP response\n");
126                 err = -EIO;
127                 goto error;
128         }
129         if (buf[0] != response_ok) {
130                 dev_err(&unit->device, "volume command failed\n");
131                 err = -EIO;
132                 goto error;
133         }
134         if (action == CTL_READ)
135                 *value = (buf[10] << 8) | buf[11];
136
137         err = 0;
138
139 error:
140         kfree(buf);
141
142         return err;
143 }
144
145 static int spkr_mute_get(struct snd_kcontrol *control,
146                          struct snd_ctl_elem_value *value)
147 {
148         struct snd_oxfw *oxfw = control->private_data;
149         struct fw_spkr *spkr = oxfw->spec;
150
151         value->value.integer.value[0] = !spkr->mute;
152
153         return 0;
154 }
155
156 static int spkr_mute_put(struct snd_kcontrol *control,
157                          struct snd_ctl_elem_value *value)
158 {
159         struct snd_oxfw *oxfw = control->private_data;
160         struct fw_spkr *spkr = oxfw->spec;
161         bool mute;
162         int err;
163
164         mute = !value->value.integer.value[0];
165
166         if (mute == spkr->mute)
167                 return 0;
168
169         err = avc_audio_feature_mute(oxfw->unit, spkr->mute_fb_id, &mute,
170                                      CTL_WRITE);
171         if (err < 0)
172                 return err;
173         spkr->mute = mute;
174
175         return 1;
176 }
177
178 static int spkr_volume_info(struct snd_kcontrol *control,
179                             struct snd_ctl_elem_info *info)
180 {
181         struct snd_oxfw *oxfw = control->private_data;
182         struct fw_spkr *spkr = oxfw->spec;
183
184         info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
185         info->count = spkr->mixer_channels;
186         info->value.integer.min = spkr->volume_min;
187         info->value.integer.max = spkr->volume_max;
188
189         return 0;
190 }
191
192 static const u8 channel_map[6] = { 0, 1, 4, 5, 2, 3 };
193
194 static int spkr_volume_get(struct snd_kcontrol *control,
195                            struct snd_ctl_elem_value *value)
196 {
197         struct snd_oxfw *oxfw = control->private_data;
198         struct fw_spkr *spkr = oxfw->spec;
199         unsigned int i;
200
201         for (i = 0; i < spkr->mixer_channels; ++i)
202                 value->value.integer.value[channel_map[i]] = spkr->volume[i];
203
204         return 0;
205 }
206
207 static int spkr_volume_put(struct snd_kcontrol *control,
208                            struct snd_ctl_elem_value *value)
209 {
210         struct snd_oxfw *oxfw = control->private_data;
211         struct fw_spkr *spkr = oxfw->spec;
212         unsigned int i, changed_channels;
213         bool equal_values = true;
214         s16 volume;
215         int err;
216
217         for (i = 0; i < spkr->mixer_channels; ++i) {
218                 if (value->value.integer.value[i] < spkr->volume_min ||
219                     value->value.integer.value[i] > spkr->volume_max)
220                         return -EINVAL;
221                 if (value->value.integer.value[i] !=
222                     value->value.integer.value[0])
223                         equal_values = false;
224         }
225
226         changed_channels = 0;
227         for (i = 0; i < spkr->mixer_channels; ++i)
228                 if (value->value.integer.value[channel_map[i]] !=
229                                                         spkr->volume[i])
230                         changed_channels |= 1 << (i + 1);
231
232         if (equal_values && changed_channels != 0)
233                 changed_channels = 1 << 0;
234
235         for (i = 0; i <= spkr->mixer_channels; ++i) {
236                 volume = value->value.integer.value[channel_map[i ? i - 1 : 0]];
237                 if (changed_channels & (1 << i)) {
238                         err = avc_audio_feature_volume(oxfw->unit,
239                                                   spkr->volume_fb_id, &volume,
240                                                   i, CTL_CURRENT, CTL_WRITE);
241                         if (err < 0)
242                                 return err;
243                 }
244                 if (i > 0)
245                         spkr->volume[i - 1] = volume;
246         }
247
248         return changed_channels != 0;
249 }
250
251 int snd_oxfw_add_spkr(struct snd_oxfw *oxfw, bool is_lacie)
252 {
253         static const struct snd_kcontrol_new controls[] = {
254                 {
255                         .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
256                         .name = "PCM Playback Switch",
257                         .info = snd_ctl_boolean_mono_info,
258                         .get = spkr_mute_get,
259                         .put = spkr_mute_put,
260                 },
261                 {
262                         .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
263                         .name = "PCM Playback Volume",
264                         .info = spkr_volume_info,
265                         .get = spkr_volume_get,
266                         .put = spkr_volume_put,
267                 },
268         };
269         struct fw_spkr *spkr;
270         unsigned int i, first_ch;
271         int err;
272
273         spkr = devm_kzalloc(&oxfw->card->card_dev, sizeof(struct fw_spkr),
274                             GFP_KERNEL);
275         if (!spkr)
276                 return -ENOMEM;
277         oxfw->spec = spkr;
278
279         if (is_lacie) {
280                 spkr->mixer_channels = 1;
281                 spkr->mute_fb_id = 0x01;
282                 spkr->volume_fb_id = 0x01;
283         } else {
284                 spkr->mixer_channels = 6;
285                 spkr->mute_fb_id = 0x01;
286                 spkr->volume_fb_id = 0x02;
287         }
288
289         err = avc_audio_feature_volume(oxfw->unit, spkr->volume_fb_id,
290                                        &spkr->volume_min, 0, CTL_MIN, CTL_READ);
291         if (err < 0)
292                 return err;
293         err = avc_audio_feature_volume(oxfw->unit, spkr->volume_fb_id,
294                                        &spkr->volume_max, 0, CTL_MAX, CTL_READ);
295         if (err < 0)
296                 return err;
297
298         err = avc_audio_feature_mute(oxfw->unit, spkr->mute_fb_id, &spkr->mute,
299                                      CTL_READ);
300         if (err < 0)
301                 return err;
302
303         first_ch = spkr->mixer_channels == 1 ? 0 : 1;
304         for (i = 0; i < spkr->mixer_channels; ++i) {
305                 err = avc_audio_feature_volume(oxfw->unit, spkr->volume_fb_id,
306                                                &spkr->volume[i], first_ch + i,
307                                                CTL_CURRENT, CTL_READ);
308                 if (err < 0)
309                         return err;
310         }
311
312         for (i = 0; i < ARRAY_SIZE(controls); ++i) {
313                 err = snd_ctl_add(oxfw->card,
314                                   snd_ctl_new1(&controls[i], oxfw));
315                 if (err < 0)
316                         return err;
317         }
318
319         return 0;
320 }