diff options
Diffstat (limited to 'sound/usb')
-rw-r--r-- | sound/usb/card.c | 17 | ||||
-rw-r--r-- | sound/usb/mixer.c | 32 | ||||
-rw-r--r-- | sound/usb/mixer.h | 14 | ||||
-rw-r--r-- | sound/usb/mixer_quirks.c | 70 | ||||
-rw-r--r-- | sound/usb/quirks-table.h | 4 | ||||
-rw-r--r-- | sound/usb/quirks.c | 18 | ||||
-rw-r--r-- | sound/usb/usbaudio.h | 1 |
7 files changed, 125 insertions, 31 deletions
diff --git a/sound/usb/card.c b/sound/usb/card.c index a90662af2d6b..220c6167dd86 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c | |||
@@ -48,6 +48,7 @@ | |||
48 | #include <linux/usb/audio.h> | 48 | #include <linux/usb/audio.h> |
49 | #include <linux/usb/audio-v2.h> | 49 | #include <linux/usb/audio-v2.h> |
50 | 50 | ||
51 | #include <sound/control.h> | ||
51 | #include <sound/core.h> | 52 | #include <sound/core.h> |
52 | #include <sound/info.h> | 53 | #include <sound/info.h> |
53 | #include <sound/pcm.h> | 54 | #include <sound/pcm.h> |
@@ -492,14 +493,6 @@ static void *snd_usb_audio_probe(struct usb_device *dev, | |||
492 | } | 493 | } |
493 | } | 494 | } |
494 | 495 | ||
495 | chip->txfr_quirk = 0; | ||
496 | err = 1; /* continue */ | ||
497 | if (quirk && quirk->ifnum != QUIRK_NO_INTERFACE) { | ||
498 | /* need some special handlings */ | ||
499 | if ((err = snd_usb_create_quirk(chip, intf, &usb_audio_driver, quirk)) < 0) | ||
500 | goto __error; | ||
501 | } | ||
502 | |||
503 | /* | 496 | /* |
504 | * For devices with more than one control interface, we assume the | 497 | * For devices with more than one control interface, we assume the |
505 | * first contains the audio controls. We might need a more specific | 498 | * first contains the audio controls. We might need a more specific |
@@ -508,6 +501,14 @@ static void *snd_usb_audio_probe(struct usb_device *dev, | |||
508 | if (!chip->ctrl_intf) | 501 | if (!chip->ctrl_intf) |
509 | chip->ctrl_intf = alts; | 502 | chip->ctrl_intf = alts; |
510 | 503 | ||
504 | chip->txfr_quirk = 0; | ||
505 | err = 1; /* continue */ | ||
506 | if (quirk && quirk->ifnum != QUIRK_NO_INTERFACE) { | ||
507 | /* need some special handlings */ | ||
508 | if ((err = snd_usb_create_quirk(chip, intf, &usb_audio_driver, quirk)) < 0) | ||
509 | goto __error; | ||
510 | } | ||
511 | |||
511 | if (err > 0) { | 512 | if (err > 0) { |
512 | /* create normal USB audio interfaces */ | 513 | /* create normal USB audio interfaces */ |
513 | if (snd_usb_create_streams(chip, ifnum) < 0 || | 514 | if (snd_usb_create_streams(chip, ifnum) < 0 || |
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index eab06edcc9b7..c22fa76e363a 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c | |||
@@ -86,16 +86,6 @@ struct mixer_build { | |||
86 | const struct usbmix_selector_map *selector_map; | 86 | const struct usbmix_selector_map *selector_map; |
87 | }; | 87 | }; |
88 | 88 | ||
89 | enum { | ||
90 | USB_MIXER_BOOLEAN, | ||
91 | USB_MIXER_INV_BOOLEAN, | ||
92 | USB_MIXER_S8, | ||
93 | USB_MIXER_U8, | ||
94 | USB_MIXER_S16, | ||
95 | USB_MIXER_U16, | ||
96 | }; | ||
97 | |||
98 | |||
99 | /*E-mu 0202/0404/0204 eXtension Unit(XU) control*/ | 89 | /*E-mu 0202/0404/0204 eXtension Unit(XU) control*/ |
100 | enum { | 90 | enum { |
101 | USB_XU_CLOCK_RATE = 0xe301, | 91 | USB_XU_CLOCK_RATE = 0xe301, |
@@ -535,20 +525,21 @@ static int check_matrix_bitmap(unsigned char *bmap, int ich, int och, int num_ou | |||
535 | * if failed, give up and free the control instance. | 525 | * if failed, give up and free the control instance. |
536 | */ | 526 | */ |
537 | 527 | ||
538 | static int add_control_to_empty(struct mixer_build *state, struct snd_kcontrol *kctl) | 528 | int snd_usb_mixer_add_control(struct usb_mixer_interface *mixer, |
529 | struct snd_kcontrol *kctl) | ||
539 | { | 530 | { |
540 | struct usb_mixer_elem_info *cval = kctl->private_data; | 531 | struct usb_mixer_elem_info *cval = kctl->private_data; |
541 | int err; | 532 | int err; |
542 | 533 | ||
543 | while (snd_ctl_find_id(state->chip->card, &kctl->id)) | 534 | while (snd_ctl_find_id(mixer->chip->card, &kctl->id)) |
544 | kctl->id.index++; | 535 | kctl->id.index++; |
545 | if ((err = snd_ctl_add(state->chip->card, kctl)) < 0) { | 536 | if ((err = snd_ctl_add(mixer->chip->card, kctl)) < 0) { |
546 | snd_printd(KERN_ERR "cannot add control (err = %d)\n", err); | 537 | snd_printd(KERN_ERR "cannot add control (err = %d)\n", err); |
547 | return err; | 538 | return err; |
548 | } | 539 | } |
549 | cval->elem_id = &kctl->id; | 540 | cval->elem_id = &kctl->id; |
550 | cval->next_id_elem = state->mixer->id_elems[cval->id]; | 541 | cval->next_id_elem = mixer->id_elems[cval->id]; |
551 | state->mixer->id_elems[cval->id] = cval; | 542 | mixer->id_elems[cval->id] = cval; |
552 | return 0; | 543 | return 0; |
553 | } | 544 | } |
554 | 545 | ||
@@ -984,6 +975,9 @@ static struct snd_kcontrol_new usb_feature_unit_ctl_ro = { | |||
984 | .put = NULL, | 975 | .put = NULL, |
985 | }; | 976 | }; |
986 | 977 | ||
978 | /* This symbol is exported in order to allow the mixer quirks to | ||
979 | * hook up to the standard feature unit control mechanism */ | ||
980 | struct snd_kcontrol_new *snd_usb_feature_unit_ctl = &usb_feature_unit_ctl; | ||
987 | 981 | ||
988 | /* | 982 | /* |
989 | * build a feature control | 983 | * build a feature control |
@@ -1176,7 +1170,7 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc, | |||
1176 | 1170 | ||
1177 | snd_printdd(KERN_INFO "[%d] FU [%s] ch = %d, val = %d/%d/%d\n", | 1171 | snd_printdd(KERN_INFO "[%d] FU [%s] ch = %d, val = %d/%d/%d\n", |
1178 | cval->id, kctl->id.name, cval->channels, cval->min, cval->max, cval->res); | 1172 | cval->id, kctl->id.name, cval->channels, cval->min, cval->max, cval->res); |
1179 | add_control_to_empty(state, kctl); | 1173 | snd_usb_mixer_add_control(state->mixer, kctl); |
1180 | } | 1174 | } |
1181 | 1175 | ||
1182 | 1176 | ||
@@ -1340,7 +1334,7 @@ static void build_mixer_unit_ctl(struct mixer_build *state, | |||
1340 | 1334 | ||
1341 | snd_printdd(KERN_INFO "[%d] MU [%s] ch = %d, val = %d/%d\n", | 1335 | snd_printdd(KERN_INFO "[%d] MU [%s] ch = %d, val = %d/%d\n", |
1342 | cval->id, kctl->id.name, cval->channels, cval->min, cval->max); | 1336 | cval->id, kctl->id.name, cval->channels, cval->min, cval->max); |
1343 | add_control_to_empty(state, kctl); | 1337 | snd_usb_mixer_add_control(state->mixer, kctl); |
1344 | } | 1338 | } |
1345 | 1339 | ||
1346 | 1340 | ||
@@ -1641,7 +1635,7 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, void *raw | |||
1641 | 1635 | ||
1642 | snd_printdd(KERN_INFO "[%d] PU [%s] ch = %d, val = %d/%d\n", | 1636 | snd_printdd(KERN_INFO "[%d] PU [%s] ch = %d, val = %d/%d\n", |
1643 | cval->id, kctl->id.name, cval->channels, cval->min, cval->max); | 1637 | cval->id, kctl->id.name, cval->channels, cval->min, cval->max); |
1644 | if ((err = add_control_to_empty(state, kctl)) < 0) | 1638 | if ((err = snd_usb_mixer_add_control(state->mixer, kctl)) < 0) |
1645 | return err; | 1639 | return err; |
1646 | } | 1640 | } |
1647 | return 0; | 1641 | return 0; |
@@ -1858,7 +1852,7 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, void | |||
1858 | 1852 | ||
1859 | snd_printdd(KERN_INFO "[%d] SU [%s] items = %d\n", | 1853 | snd_printdd(KERN_INFO "[%d] SU [%s] items = %d\n", |
1860 | cval->id, kctl->id.name, desc->bNrInPins); | 1854 | cval->id, kctl->id.name, desc->bNrInPins); |
1861 | if ((err = add_control_to_empty(state, kctl)) < 0) | 1855 | if ((err = snd_usb_mixer_add_control(state->mixer, kctl)) < 0) |
1862 | return err; | 1856 | return err; |
1863 | 1857 | ||
1864 | return 0; | 1858 | return 0; |
diff --git a/sound/usb/mixer.h b/sound/usb/mixer.h index b4a2c8165e4b..ae1a14dcfe82 100644 --- a/sound/usb/mixer.h +++ b/sound/usb/mixer.h | |||
@@ -24,7 +24,16 @@ struct usb_mixer_interface { | |||
24 | u8 xonar_u1_status; | 24 | u8 xonar_u1_status; |
25 | }; | 25 | }; |
26 | 26 | ||
27 | #define MAX_CHANNELS 10 /* max logical channels */ | 27 | #define MAX_CHANNELS 16 /* max logical channels */ |
28 | |||
29 | enum { | ||
30 | USB_MIXER_BOOLEAN, | ||
31 | USB_MIXER_INV_BOOLEAN, | ||
32 | USB_MIXER_S8, | ||
33 | USB_MIXER_U8, | ||
34 | USB_MIXER_S16, | ||
35 | USB_MIXER_U16, | ||
36 | }; | ||
28 | 37 | ||
29 | struct usb_mixer_elem_info { | 38 | struct usb_mixer_elem_info { |
30 | struct usb_mixer_interface *mixer; | 39 | struct usb_mixer_interface *mixer; |
@@ -55,4 +64,7 @@ int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval, | |||
55 | void snd_usb_mixer_inactivate(struct usb_mixer_interface *mixer); | 64 | void snd_usb_mixer_inactivate(struct usb_mixer_interface *mixer); |
56 | int snd_usb_mixer_activate(struct usb_mixer_interface *mixer); | 65 | int snd_usb_mixer_activate(struct usb_mixer_interface *mixer); |
57 | 66 | ||
67 | int snd_usb_mixer_add_control(struct usb_mixer_interface *mixer, | ||
68 | struct snd_kcontrol *kctl); | ||
69 | |||
58 | #endif /* __USBMIXER_H */ | 70 | #endif /* __USBMIXER_H */ |
diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index 9146cffa6ede..3d0f4873112b 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c | |||
@@ -40,6 +40,8 @@ | |||
40 | #include "mixer_quirks.h" | 40 | #include "mixer_quirks.h" |
41 | #include "helper.h" | 41 | #include "helper.h" |
42 | 42 | ||
43 | extern struct snd_kcontrol_new *snd_usb_feature_unit_ctl; | ||
44 | |||
43 | /* | 45 | /* |
44 | * Sound Blaster remote control configuration | 46 | * Sound Blaster remote control configuration |
45 | * | 47 | * |
@@ -492,6 +494,69 @@ static int snd_nativeinstruments_create_mixer(struct usb_mixer_interface *mixer, | |||
492 | return err; | 494 | return err; |
493 | } | 495 | } |
494 | 496 | ||
497 | /* M-Audio FastTrack Ultra quirks */ | ||
498 | |||
499 | /* private_free callback */ | ||
500 | static void usb_mixer_elem_free(struct snd_kcontrol *kctl) | ||
501 | { | ||
502 | kfree(kctl->private_data); | ||
503 | kctl->private_data = NULL; | ||
504 | } | ||
505 | |||
506 | static int snd_maudio_ftu_create_ctl(struct usb_mixer_interface *mixer, | ||
507 | int in, int out, const char *name) | ||
508 | { | ||
509 | struct usb_mixer_elem_info *cval; | ||
510 | struct snd_kcontrol *kctl; | ||
511 | |||
512 | cval = kzalloc(sizeof(*cval), GFP_KERNEL); | ||
513 | if (!cval) | ||
514 | return -ENOMEM; | ||
515 | |||
516 | cval->id = 5; | ||
517 | cval->mixer = mixer; | ||
518 | cval->val_type = USB_MIXER_S16; | ||
519 | cval->channels = 1; | ||
520 | cval->control = out + 1; | ||
521 | cval->cmask = 1 << in; | ||
522 | |||
523 | kctl = snd_ctl_new1(snd_usb_feature_unit_ctl, cval); | ||
524 | if (!kctl) { | ||
525 | kfree(cval); | ||
526 | return -ENOMEM; | ||
527 | } | ||
528 | |||
529 | snprintf(kctl->id.name, sizeof(kctl->id.name), name); | ||
530 | kctl->private_free = usb_mixer_elem_free; | ||
531 | return snd_usb_mixer_add_control(mixer, kctl); | ||
532 | } | ||
533 | |||
534 | static int snd_maudio_ftu_create_mixer(struct usb_mixer_interface *mixer) | ||
535 | { | ||
536 | char name[64]; | ||
537 | int in, out, err; | ||
538 | |||
539 | for (out = 0; out < 8; out++) { | ||
540 | for (in = 0; in < 8; in++) { | ||
541 | snprintf(name, sizeof(name), | ||
542 | "AIn%d - Out%d Capture Volume", in + 1, out + 1); | ||
543 | err = snd_maudio_ftu_create_ctl(mixer, in, out, name); | ||
544 | if (err < 0) | ||
545 | return err; | ||
546 | } | ||
547 | |||
548 | for (in = 8; in < 16; in++) { | ||
549 | snprintf(name, sizeof(name), | ||
550 | "DIn%d - Out%d Playback Volume", in - 7, out + 1); | ||
551 | err = snd_maudio_ftu_create_ctl(mixer, in, out, name); | ||
552 | if (err < 0) | ||
553 | return err; | ||
554 | } | ||
555 | } | ||
556 | |||
557 | return 0; | ||
558 | } | ||
559 | |||
495 | void snd_emuusb_set_samplerate(struct snd_usb_audio *chip, | 560 | void snd_emuusb_set_samplerate(struct snd_usb_audio *chip, |
496 | unsigned char samplerate_id) | 561 | unsigned char samplerate_id) |
497 | { | 562 | { |
@@ -533,6 +598,11 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer) | |||
533 | snd_audigy2nx_proc_read); | 598 | snd_audigy2nx_proc_read); |
534 | break; | 599 | break; |
535 | 600 | ||
601 | case USB_ID(0x0763, 0x2080): /* M-Audio Fast Track Ultra */ | ||
602 | case USB_ID(0x0763, 0x2081): /* M-Audio Fast Track Ultra 8R */ | ||
603 | err = snd_maudio_ftu_create_mixer(mixer); | ||
604 | break; | ||
605 | |||
536 | case USB_ID(0x0b05, 0x1739): | 606 | case USB_ID(0x0b05, 0x1739): |
537 | case USB_ID(0x0b05, 0x1743): | 607 | case USB_ID(0x0b05, 0x1743): |
538 | err = snd_xonar_u1_controls_create(mixer); | 608 | err = snd_xonar_u1_controls_create(mixer); |
diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h index 78792a8900c3..0b2ae8e1c02d 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h | |||
@@ -1988,7 +1988,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), | |||
1988 | .data = & (const struct snd_usb_audio_quirk[]) { | 1988 | .data = & (const struct snd_usb_audio_quirk[]) { |
1989 | { | 1989 | { |
1990 | .ifnum = 0, | 1990 | .ifnum = 0, |
1991 | .type = QUIRK_IGNORE_INTERFACE | 1991 | .type = QUIRK_AUDIO_STANDARD_MIXER, |
1992 | }, | 1992 | }, |
1993 | { | 1993 | { |
1994 | .ifnum = 1, | 1994 | .ifnum = 1, |
@@ -2055,7 +2055,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), | |||
2055 | .data = & (const struct snd_usb_audio_quirk[]) { | 2055 | .data = & (const struct snd_usb_audio_quirk[]) { |
2056 | { | 2056 | { |
2057 | .ifnum = 0, | 2057 | .ifnum = 0, |
2058 | .type = QUIRK_IGNORE_INTERFACE | 2058 | .type = QUIRK_AUDIO_STANDARD_MIXER, |
2059 | }, | 2059 | }, |
2060 | { | 2060 | { |
2061 | .ifnum = 1, | 2061 | .ifnum = 1, |
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index bd13d7257240..2e969cbb393b 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/usb.h> | 19 | #include <linux/usb.h> |
20 | #include <linux/usb/audio.h> | 20 | #include <linux/usb/audio.h> |
21 | 21 | ||
22 | #include <sound/control.h> | ||
22 | #include <sound/core.h> | 23 | #include <sound/core.h> |
23 | #include <sound/info.h> | 24 | #include <sound/info.h> |
24 | #include <sound/pcm.h> | 25 | #include <sound/pcm.h> |
@@ -263,6 +264,20 @@ static int create_uaxx_quirk(struct snd_usb_audio *chip, | |||
263 | } | 264 | } |
264 | 265 | ||
265 | /* | 266 | /* |
267 | * Create a standard mixer for the specified interface. | ||
268 | */ | ||
269 | static int create_standard_mixer_quirk(struct snd_usb_audio *chip, | ||
270 | struct usb_interface *iface, | ||
271 | struct usb_driver *driver, | ||
272 | const struct snd_usb_audio_quirk *quirk) | ||
273 | { | ||
274 | if (quirk->ifnum < 0) | ||
275 | return 0; | ||
276 | |||
277 | return snd_usb_create_mixer(chip, quirk->ifnum, 0); | ||
278 | } | ||
279 | |||
280 | /* | ||
266 | * audio-interface quirks | 281 | * audio-interface quirks |
267 | * | 282 | * |
268 | * returns zero if no standard audio/MIDI parsing is needed. | 283 | * returns zero if no standard audio/MIDI parsing is needed. |
@@ -294,7 +309,8 @@ int snd_usb_create_quirk(struct snd_usb_audio *chip, | |||
294 | [QUIRK_AUDIO_STANDARD_INTERFACE] = create_standard_audio_quirk, | 309 | [QUIRK_AUDIO_STANDARD_INTERFACE] = create_standard_audio_quirk, |
295 | [QUIRK_AUDIO_FIXED_ENDPOINT] = create_fixed_stream_quirk, | 310 | [QUIRK_AUDIO_FIXED_ENDPOINT] = create_fixed_stream_quirk, |
296 | [QUIRK_AUDIO_EDIROL_UAXX] = create_uaxx_quirk, | 311 | [QUIRK_AUDIO_EDIROL_UAXX] = create_uaxx_quirk, |
297 | [QUIRK_AUDIO_ALIGN_TRANSFER] = create_align_transfer_quirk | 312 | [QUIRK_AUDIO_ALIGN_TRANSFER] = create_align_transfer_quirk, |
313 | [QUIRK_AUDIO_STANDARD_MIXER] = create_standard_mixer_quirk, | ||
298 | }; | 314 | }; |
299 | 315 | ||
300 | if (quirk->type < QUIRK_TYPE_COUNT) { | 316 | if (quirk->type < QUIRK_TYPE_COUNT) { |
diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index 32f2a97f2f14..1e79986b5777 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h | |||
@@ -84,6 +84,7 @@ enum quirk_type { | |||
84 | QUIRK_AUDIO_FIXED_ENDPOINT, | 84 | QUIRK_AUDIO_FIXED_ENDPOINT, |
85 | QUIRK_AUDIO_EDIROL_UAXX, | 85 | QUIRK_AUDIO_EDIROL_UAXX, |
86 | QUIRK_AUDIO_ALIGN_TRANSFER, | 86 | QUIRK_AUDIO_ALIGN_TRANSFER, |
87 | QUIRK_AUDIO_STANDARD_MIXER, | ||
87 | 88 | ||
88 | QUIRK_TYPE_COUNT | 89 | QUIRK_TYPE_COUNT |
89 | }; | 90 | }; |