~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/sound/usb/6fire/control.c

Version: ~ [ linux-5.12-rc7 ] ~ [ linux-5.11.13 ] ~ [ linux-5.10.29 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.111 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.186 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.230 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.266 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.266 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.18.140 ] ~ [ linux-3.16.85 ] ~ [ linux-3.14.79 ] ~ [ linux-3.12.74 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  * Linux driver for TerraTec DMX 6Fire USB
  3  *
  4  * Mixer control
  5  *
  6  * Author:      Torsten Schenk <torsten.schenk@zoho.com>
  7  * Created:     Jan 01, 2011
  8  * Copyright:   (C) Torsten Schenk
  9  *
 10  * Thanks to:
 11  * - Holger Ruckdeschel: he found out how to control individual channel
 12  *   volumes and introduced mute switch
 13  *
 14  * This program is free software; you can redistribute it and/or modify
 15  * it under the terms of the GNU General Public License as published by
 16  * the Free Software Foundation; either version 2 of the License, or
 17  * (at your option) any later version.
 18  */
 19 
 20 #include <linux/interrupt.h>
 21 #include <sound/control.h>
 22 #include <sound/tlv.h>
 23 
 24 #include "control.h"
 25 #include "comm.h"
 26 #include "chip.h"
 27 
 28 static char *opt_coax_texts[2] = { "Optical", "Coax" };
 29 static char *line_phono_texts[2] = { "Line", "Phono" };
 30 
 31 /*
 32  * data that needs to be sent to device. sets up card internal stuff.
 33  * values dumped from windows driver and filtered by trial'n'error.
 34  */
 35 static const struct {
 36         u8 type;
 37         u8 reg;
 38         u8 value;
 39 }
 40 init_data[] = {
 41         { 0x22, 0x00, 0x00 }, { 0x20, 0x00, 0x08 }, { 0x22, 0x01, 0x01 },
 42         { 0x20, 0x01, 0x08 }, { 0x22, 0x02, 0x00 }, { 0x20, 0x02, 0x08 },
 43         { 0x22, 0x03, 0x00 }, { 0x20, 0x03, 0x08 }, { 0x22, 0x04, 0x00 },
 44         { 0x20, 0x04, 0x08 }, { 0x22, 0x05, 0x01 }, { 0x20, 0x05, 0x08 },
 45         { 0x22, 0x04, 0x01 }, { 0x12, 0x04, 0x00 }, { 0x12, 0x05, 0x00 },
 46         { 0x12, 0x0d, 0x38 }, { 0x12, 0x21, 0x82 }, { 0x12, 0x22, 0x80 },
 47         { 0x12, 0x23, 0x00 }, { 0x12, 0x06, 0x02 }, { 0x12, 0x03, 0x00 },
 48         { 0x12, 0x02, 0x00 }, { 0x22, 0x03, 0x01 },
 49         { 0 } /* TERMINATING ENTRY */
 50 };
 51 
 52 static const int rates_altsetting[] = { 1, 1, 2, 2, 3, 3 };
 53 /* values to write to soundcard register for all samplerates */
 54 static const u16 rates_6fire_vl[] = {0x00, 0x01, 0x00, 0x01, 0x00, 0x01};
 55 static const u16 rates_6fire_vh[] = {0x11, 0x11, 0x10, 0x10, 0x00, 0x00};
 56 
 57 static DECLARE_TLV_DB_MINMAX(tlv_output, -9000, 0);
 58 static DECLARE_TLV_DB_MINMAX(tlv_input, -1500, 1500);
 59 
 60 enum {
 61         DIGITAL_THRU_ONLY_SAMPLERATE = 3
 62 };
 63 
 64 static void usb6fire_control_output_vol_update(struct control_runtime *rt)
 65 {
 66         struct comm_runtime *comm_rt = rt->chip->comm;
 67         int i;
 68 
 69         if (comm_rt)
 70                 for (i = 0; i < 6; i++)
 71                         if (!(rt->ovol_updated & (1 << i))) {
 72                                 comm_rt->write8(comm_rt, 0x12, 0x0f + i,
 73                                         180 - rt->output_vol[i]);
 74                                 rt->ovol_updated |= 1 << i;
 75                         }
 76 }
 77 
 78 static void usb6fire_control_output_mute_update(struct control_runtime *rt)
 79 {
 80         struct comm_runtime *comm_rt = rt->chip->comm;
 81 
 82         if (comm_rt)
 83                 comm_rt->write8(comm_rt, 0x12, 0x0e, ~rt->output_mute);
 84 }
 85 
 86 static void usb6fire_control_input_vol_update(struct control_runtime *rt)
 87 {
 88         struct comm_runtime *comm_rt = rt->chip->comm;
 89         int i;
 90 
 91         if (comm_rt)
 92                 for (i = 0; i < 2; i++)
 93                         if (!(rt->ivol_updated & (1 << i))) {
 94                                 comm_rt->write8(comm_rt, 0x12, 0x1c + i,
 95                                         rt->input_vol[i] & 0x3f);
 96                                 rt->ivol_updated |= 1 << i;
 97                         }
 98 }
 99 
100 static void usb6fire_control_line_phono_update(struct control_runtime *rt)
101 {
102         struct comm_runtime *comm_rt = rt->chip->comm;
103         if (comm_rt) {
104                 comm_rt->write8(comm_rt, 0x22, 0x02, rt->line_phono_switch);
105                 comm_rt->write8(comm_rt, 0x21, 0x02, rt->line_phono_switch);
106         }
107 }
108 
109 static void usb6fire_control_opt_coax_update(struct control_runtime *rt)
110 {
111         struct comm_runtime *comm_rt = rt->chip->comm;
112         if (comm_rt) {
113                 comm_rt->write8(comm_rt, 0x22, 0x00, rt->opt_coax_switch);
114                 comm_rt->write8(comm_rt, 0x21, 0x00, rt->opt_coax_switch);
115         }
116 }
117 
118 static int usb6fire_control_set_rate(struct control_runtime *rt, int rate)
119 {
120         int ret;
121         struct usb_device *device = rt->chip->dev;
122         struct comm_runtime *comm_rt = rt->chip->comm;
123 
124         if (rate < 0 || rate >= CONTROL_N_RATES)
125                 return -EINVAL;
126 
127         ret = usb_set_interface(device, 1, rates_altsetting[rate]);
128         if (ret < 0)
129                 return ret;
130 
131         /* set soundcard clock */
132         ret = comm_rt->write16(comm_rt, 0x02, 0x01, rates_6fire_vl[rate],
133                         rates_6fire_vh[rate]);
134         if (ret < 0)
135                 return ret;
136 
137         return 0;
138 }
139 
140 static int usb6fire_control_set_channels(
141         struct control_runtime *rt, int n_analog_out,
142         int n_analog_in, bool spdif_out, bool spdif_in)
143 {
144         int ret;
145         struct comm_runtime *comm_rt = rt->chip->comm;
146 
147         /* enable analog inputs and outputs
148          * (one bit per stereo-channel) */
149         ret = comm_rt->write16(comm_rt, 0x02, 0x02,
150                         (1 << (n_analog_out / 2)) - 1,
151                         (1 << (n_analog_in / 2)) - 1);
152         if (ret < 0)
153                 return ret;
154 
155         /* disable digital inputs and outputs */
156         /* TODO: use spdif_x to enable/disable digital channels */
157         ret = comm_rt->write16(comm_rt, 0x02, 0x03, 0x00, 0x00);
158         if (ret < 0)
159                 return ret;
160 
161         return 0;
162 }
163 
164 static int usb6fire_control_streaming_update(struct control_runtime *rt)
165 {
166         struct comm_runtime *comm_rt = rt->chip->comm;
167 
168         if (comm_rt) {
169                 if (!rt->usb_streaming && rt->digital_thru_switch)
170                         usb6fire_control_set_rate(rt,
171                                 DIGITAL_THRU_ONLY_SAMPLERATE);
172                 return comm_rt->write16(comm_rt, 0x02, 0x00, 0x00,
173                         (rt->usb_streaming ? 0x01 : 0x00) |
174                         (rt->digital_thru_switch ? 0x08 : 0x00));
175         }
176         return -EINVAL;
177 }
178 
179 static int usb6fire_control_output_vol_info(struct snd_kcontrol *kcontrol,
180                 struct snd_ctl_elem_info *uinfo)
181 {
182         uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
183         uinfo->count = 2;
184         uinfo->value.integer.min = 0;
185         uinfo->value.integer.max = 180;
186         return 0;
187 }
188 
189 static int usb6fire_control_output_vol_put(struct snd_kcontrol *kcontrol,
190                 struct snd_ctl_elem_value *ucontrol)
191 {
192         struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
193         unsigned int ch = kcontrol->private_value;
194         int changed = 0;
195 
196         if (ch > 4) {
197                 snd_printk(KERN_ERR PREFIX "Invalid channel in volume control.");
198                 return -EINVAL;
199         }
200 
201         if (rt->output_vol[ch] != ucontrol->value.integer.value[0]) {
202                 rt->output_vol[ch] = ucontrol->value.integer.value[0];
203                 rt->ovol_updated &= ~(1 << ch);
204                 changed = 1;
205         }
206         if (rt->output_vol[ch + 1] != ucontrol->value.integer.value[1]) {
207                 rt->output_vol[ch + 1] = ucontrol->value.integer.value[1];
208                 rt->ovol_updated &= ~(2 << ch);
209                 changed = 1;
210         }
211 
212         if (changed)
213                 usb6fire_control_output_vol_update(rt);
214 
215         return changed;
216 }
217 
218 static int usb6fire_control_output_vol_get(struct snd_kcontrol *kcontrol,
219                 struct snd_ctl_elem_value *ucontrol)
220 {
221         struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
222         unsigned int ch = kcontrol->private_value;
223 
224         if (ch > 4) {
225                 snd_printk(KERN_ERR PREFIX "Invalid channel in volume control.");
226                 return -EINVAL;
227         }
228 
229         ucontrol->value.integer.value[0] = rt->output_vol[ch];
230         ucontrol->value.integer.value[1] = rt->output_vol[ch + 1];
231         return 0;
232 }
233 
234 static int usb6fire_control_output_mute_put(struct snd_kcontrol *kcontrol,
235         struct snd_ctl_elem_value *ucontrol)
236 {
237         struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
238         unsigned int ch = kcontrol->private_value;
239         u8 old = rt->output_mute;
240         u8 value = 0;
241 
242         if (ch > 4) {
243                 snd_printk(KERN_ERR PREFIX "Invalid channel in volume control.");
244                 return -EINVAL;
245         }
246 
247         rt->output_mute &= ~(3 << ch);
248         if (ucontrol->value.integer.value[0])
249                 value |= 1;
250         if (ucontrol->value.integer.value[1])
251                 value |= 2;
252         rt->output_mute |= value << ch;
253 
254         if (rt->output_mute != old)
255                 usb6fire_control_output_mute_update(rt);
256 
257         return rt->output_mute != old;
258 }
259 
260 static int usb6fire_control_output_mute_get(struct snd_kcontrol *kcontrol,
261         struct snd_ctl_elem_value *ucontrol)
262 {
263         struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
264         unsigned int ch = kcontrol->private_value;
265         u8 value = rt->output_mute >> ch;
266 
267         if (ch > 4) {
268                 snd_printk(KERN_ERR PREFIX "Invalid channel in volume control.");
269                 return -EINVAL;
270         }
271 
272         ucontrol->value.integer.value[0] = 1 & value;
273         value >>= 1;
274         ucontrol->value.integer.value[1] = 1 & value;
275 
276         return 0;
277 }
278 
279 static int usb6fire_control_input_vol_info(struct snd_kcontrol *kcontrol,
280                 struct snd_ctl_elem_info *uinfo)
281 {
282         uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
283         uinfo->count = 2;
284         uinfo->value.integer.min = 0;
285         uinfo->value.integer.max = 30;
286         return 0;
287 }
288 
289 static int usb6fire_control_input_vol_put(struct snd_kcontrol *kcontrol,
290                 struct snd_ctl_elem_value *ucontrol)
291 {
292         struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
293         int changed = 0;
294 
295         if (rt->input_vol[0] != ucontrol->value.integer.value[0]) {
296                 rt->input_vol[0] = ucontrol->value.integer.value[0] - 15;
297                 rt->ivol_updated &= ~(1 << 0);
298                 changed = 1;
299         }
300         if (rt->input_vol[1] != ucontrol->value.integer.value[1]) {
301                 rt->input_vol[1] = ucontrol->value.integer.value[1] - 15;
302                 rt->ivol_updated &= ~(1 << 1);
303                 changed = 1;
304         }
305 
306         if (changed)
307                 usb6fire_control_input_vol_update(rt);
308 
309         return changed;
310 }
311 
312 static int usb6fire_control_input_vol_get(struct snd_kcontrol *kcontrol,
313                 struct snd_ctl_elem_value *ucontrol)
314 {
315         struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
316 
317         ucontrol->value.integer.value[0] = rt->input_vol[0] + 15;
318         ucontrol->value.integer.value[1] = rt->input_vol[1] + 15;
319 
320         return 0;
321 }
322 
323 static int usb6fire_control_line_phono_info(struct snd_kcontrol *kcontrol,
324                 struct snd_ctl_elem_info *uinfo)
325 {
326         uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
327         uinfo->count = 1;
328         uinfo->value.enumerated.items = 2;
329         if (uinfo->value.enumerated.item > 1)
330                 uinfo->value.enumerated.item = 1;
331         strcpy(uinfo->value.enumerated.name,
332                         line_phono_texts[uinfo->value.enumerated.item]);
333         return 0;
334 }
335 
336 static int usb6fire_control_line_phono_put(struct snd_kcontrol *kcontrol,
337                 struct snd_ctl_elem_value *ucontrol)
338 {
339         struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
340         int changed = 0;
341         if (rt->line_phono_switch != ucontrol->value.integer.value[0]) {
342                 rt->line_phono_switch = ucontrol->value.integer.value[0];
343                 usb6fire_control_line_phono_update(rt);
344                 changed = 1;
345         }
346         return changed;
347 }
348 
349 static int usb6fire_control_line_phono_get(struct snd_kcontrol *kcontrol,
350                 struct snd_ctl_elem_value *ucontrol)
351 {
352         struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
353         ucontrol->value.integer.value[0] = rt->line_phono_switch;
354         return 0;
355 }
356 
357 static int usb6fire_control_opt_coax_info(struct snd_kcontrol *kcontrol,
358                 struct snd_ctl_elem_info *uinfo)
359 {
360         uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
361         uinfo->count = 1;
362         uinfo->value.enumerated.items = 2;
363         if (uinfo->value.enumerated.item > 1)
364                 uinfo->value.enumerated.item = 1;
365         strcpy(uinfo->value.enumerated.name,
366                         opt_coax_texts[uinfo->value.enumerated.item]);
367         return 0;
368 }
369 
370 static int usb6fire_control_opt_coax_put(struct snd_kcontrol *kcontrol,
371                 struct snd_ctl_elem_value *ucontrol)
372 {
373         struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
374         int changed = 0;
375 
376         if (rt->opt_coax_switch != ucontrol->value.enumerated.item[0]) {
377                 rt->opt_coax_switch = ucontrol->value.enumerated.item[0];
378                 usb6fire_control_opt_coax_update(rt);
379                 changed = 1;
380         }
381         return changed;
382 }
383 
384 static int usb6fire_control_opt_coax_get(struct snd_kcontrol *kcontrol,
385                 struct snd_ctl_elem_value *ucontrol)
386 {
387         struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
388         ucontrol->value.enumerated.item[0] = rt->opt_coax_switch;
389         return 0;
390 }
391 
392 static int usb6fire_control_digital_thru_put(struct snd_kcontrol *kcontrol,
393                 struct snd_ctl_elem_value *ucontrol)
394 {
395         struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
396         int changed = 0;
397 
398         if (rt->digital_thru_switch != ucontrol->value.integer.value[0]) {
399                 rt->digital_thru_switch = ucontrol->value.integer.value[0];
400                 usb6fire_control_streaming_update(rt);
401                 changed = 1;
402         }
403         return changed;
404 }
405 
406 static int usb6fire_control_digital_thru_get(struct snd_kcontrol *kcontrol,
407                 struct snd_ctl_elem_value *ucontrol)
408 {
409         struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
410         ucontrol->value.integer.value[0] = rt->digital_thru_switch;
411         return 0;
412 }
413 
414 static struct snd_kcontrol_new vol_elements[] = {
415         {
416                 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
417                 .name = "Analog Playback Volume",
418                 .index = 0,
419                 .private_value = 0,
420                 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
421                         SNDRV_CTL_ELEM_ACCESS_TLV_READ,
422                 .info = usb6fire_control_output_vol_info,
423                 .get = usb6fire_control_output_vol_get,
424                 .put = usb6fire_control_output_vol_put,
425                 .tlv = { .p = tlv_output }
426         },
427         {
428                 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
429                 .name = "Analog Playback Volume",
430                 .index = 1,
431                 .private_value = 2,
432                 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
433                         SNDRV_CTL_ELEM_ACCESS_TLV_READ,
434                 .info = usb6fire_control_output_vol_info,
435                 .get = usb6fire_control_output_vol_get,
436                 .put = usb6fire_control_output_vol_put,
437                 .tlv = { .p = tlv_output }
438         },
439         {
440                 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
441                 .name = "Analog Playback Volume",
442                 .index = 2,
443                 .private_value = 4,
444                 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
445                         SNDRV_CTL_ELEM_ACCESS_TLV_READ,
446                 .info = usb6fire_control_output_vol_info,
447                 .get = usb6fire_control_output_vol_get,
448                 .put = usb6fire_control_output_vol_put,
449                 .tlv = { .p = tlv_output }
450         },
451         {}
452 };
453 
454 static struct snd_kcontrol_new mute_elements[] = {
455         {
456                 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
457                 .name = "Analog Playback Switch",
458                 .index = 0,
459                 .private_value = 0,
460                 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
461                 .info = snd_ctl_boolean_stereo_info,
462                 .get = usb6fire_control_output_mute_get,
463                 .put = usb6fire_control_output_mute_put,
464         },
465         {
466                 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
467                 .name = "Analog Playback Switch",
468                 .index = 1,
469                 .private_value = 2,
470                 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
471                 .info = snd_ctl_boolean_stereo_info,
472                 .get = usb6fire_control_output_mute_get,
473                 .put = usb6fire_control_output_mute_put,
474         },
475         {
476                 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
477                 .name = "Analog Playback Switch",
478                 .index = 2,
479                 .private_value = 4,
480                 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
481                 .info = snd_ctl_boolean_stereo_info,
482                 .get = usb6fire_control_output_mute_get,
483                 .put = usb6fire_control_output_mute_put,
484         },
485         {}
486 };
487 
488 static struct snd_kcontrol_new elements[] = {
489         {
490                 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
491                 .name = "Line/Phono Capture Route",
492                 .index = 0,
493                 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
494                 .info = usb6fire_control_line_phono_info,
495                 .get = usb6fire_control_line_phono_get,
496                 .put = usb6fire_control_line_phono_put
497         },
498         {
499                 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
500                 .name = "Opt/Coax Capture Route",
501                 .index = 0,
502                 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
503                 .info = usb6fire_control_opt_coax_info,
504                 .get = usb6fire_control_opt_coax_get,
505                 .put = usb6fire_control_opt_coax_put
506         },
507         {
508                 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
509                 .name = "Digital Thru Playback Route",
510                 .index = 0,
511                 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
512                 .info = snd_ctl_boolean_mono_info,
513                 .get = usb6fire_control_digital_thru_get,
514                 .put = usb6fire_control_digital_thru_put
515         },
516         {
517                 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
518                 .name = "Analog Capture Volume",
519                 .index = 0,
520                 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
521                         SNDRV_CTL_ELEM_ACCESS_TLV_READ,
522                 .info = usb6fire_control_input_vol_info,
523                 .get = usb6fire_control_input_vol_get,
524                 .put = usb6fire_control_input_vol_put,
525                 .tlv = { .p = tlv_input }
526         },
527         {}
528 };
529 
530 static int usb6fire_control_add_virtual(
531         struct control_runtime *rt,
532         struct snd_card *card,
533         char *name,
534         struct snd_kcontrol_new *elems)
535 {
536         int ret;
537         int i;
538         struct snd_kcontrol *vmaster =
539                 snd_ctl_make_virtual_master(name, tlv_output);
540         struct snd_kcontrol *control;
541 
542         if (!vmaster)
543                 return -ENOMEM;
544         ret = snd_ctl_add(card, vmaster);
545         if (ret < 0)
546                 return ret;
547 
548         i = 0;
549         while (elems[i].name) {
550                 control = snd_ctl_new1(&elems[i], rt);
551                 if (!control)
552                         return -ENOMEM;
553                 ret = snd_ctl_add(card, control);
554                 if (ret < 0)
555                         return ret;
556                 ret = snd_ctl_add_slave(vmaster, control);
557                 if (ret < 0)
558                         return ret;
559                 i++;
560         }
561         return 0;
562 }
563 
564 int usb6fire_control_init(struct sfire_chip *chip)
565 {
566         int i;
567         int ret;
568         struct control_runtime *rt = kzalloc(sizeof(struct control_runtime),
569                         GFP_KERNEL);
570         struct comm_runtime *comm_rt = chip->comm;
571 
572         if (!rt)
573                 return -ENOMEM;
574 
575         rt->chip = chip;
576         rt->update_streaming = usb6fire_control_streaming_update;
577         rt->set_rate = usb6fire_control_set_rate;
578         rt->set_channels = usb6fire_control_set_channels;
579 
580         i = 0;
581         while (init_data[i].type) {
582                 comm_rt->write8(comm_rt, init_data[i].type, init_data[i].reg,
583                                 init_data[i].value);
584                 i++;
585         }
586 
587         usb6fire_control_opt_coax_update(rt);
588         usb6fire_control_line_phono_update(rt);
589         usb6fire_control_output_vol_update(rt);
590         usb6fire_control_output_mute_update(rt);
591         usb6fire_control_input_vol_update(rt);
592         usb6fire_control_streaming_update(rt);
593 
594         ret = usb6fire_control_add_virtual(rt, chip->card,
595                 "Master Playback Volume", vol_elements);
596         if (ret) {
597                 snd_printk(KERN_ERR PREFIX "cannot add control.\n");
598                 kfree(rt);
599                 return ret;
600         }
601         ret = usb6fire_control_add_virtual(rt, chip->card,
602                 "Master Playback Switch", mute_elements);
603         if (ret) {
604                 snd_printk(KERN_ERR PREFIX "cannot add control.\n");
605                 kfree(rt);
606                 return ret;
607         }
608 
609         i = 0;
610         while (elements[i].name) {
611                 ret = snd_ctl_add(chip->card, snd_ctl_new1(&elements[i], rt));
612                 if (ret < 0) {
613                         kfree(rt);
614                         snd_printk(KERN_ERR PREFIX "cannot add control.\n");
615                         return ret;
616                 }
617                 i++;
618         }
619 
620         chip->control = rt;
621         return 0;
622 }
623 
624 void usb6fire_control_abort(struct sfire_chip *chip)
625 {}
626 
627 void usb6fire_control_destroy(struct sfire_chip *chip)
628 {
629         kfree(chip->control);
630         chip->control = NULL;
631 }
632 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp