aboutsummaryrefslogtreecommitdiffstats
path: root/sound/usb/mixer_quirks.c
diff options
context:
space:
mode:
authorGlenn Elliott <gelliott@cs.unc.edu>2012-03-04 19:47:13 -0500
committerGlenn Elliott <gelliott@cs.unc.edu>2012-03-04 19:47:13 -0500
commitc71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch)
treeecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /sound/usb/mixer_quirks.c
parentea53c912f8a86a8567697115b6a0d8152beee5c8 (diff)
parent6a00f206debf8a5c8899055726ad127dbeeed098 (diff)
Merge branch 'mpi-master' into wip-k-fmlpwip-k-fmlp
Conflicts: litmus/sched_cedf.c
Diffstat (limited to 'sound/usb/mixer_quirks.c')
-rw-r--r--sound/usb/mixer_quirks.c268
1 files changed, 255 insertions, 13 deletions
diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c
index e7df1e5e3f2e..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
43extern 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 *
@@ -60,6 +62,8 @@ static const struct rc_config {
60 { USB_ID(0x041e, 0x3000), 0, 1, 2, 1, 18, 0x0013 }, /* Extigy */ 62 { USB_ID(0x041e, 0x3000), 0, 1, 2, 1, 18, 0x0013 }, /* Extigy */
61 { USB_ID(0x041e, 0x3020), 2, 1, 6, 6, 18, 0x0013 }, /* Audigy 2 NX */ 63 { USB_ID(0x041e, 0x3020), 2, 1, 6, 6, 18, 0x0013 }, /* Audigy 2 NX */
62 { USB_ID(0x041e, 0x3040), 2, 2, 6, 6, 2, 0x6e91 }, /* Live! 24-bit */ 64 { USB_ID(0x041e, 0x3040), 2, 2, 6, 6, 2, 0x6e91 }, /* Live! 24-bit */
65 { USB_ID(0x041e, 0x3042), 0, 1, 1, 1, 1, 0x000d }, /* Usb X-Fi S51 */
66 { USB_ID(0x041e, 0x30df), 0, 1, 1, 1, 1, 0x000d }, /* Usb X-Fi S51 Pro */
63 { USB_ID(0x041e, 0x3048), 2, 2, 6, 6, 2, 0x6e91 }, /* Toshiba SB0500 */ 67 { USB_ID(0x041e, 0x3048), 2, 2, 6, 6, 2, 0x6e91 }, /* Toshiba SB0500 */
64}; 68};
65 69
@@ -182,7 +186,19 @@ static int snd_audigy2nx_led_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e
182 if (value > 1) 186 if (value > 1)
183 return -EINVAL; 187 return -EINVAL;
184 changed = value != mixer->audigy2nx_leds[index]; 188 changed = value != mixer->audigy2nx_leds[index];
185 err = snd_usb_ctl_msg(mixer->chip->dev, 189 if (mixer->chip->usb_id == USB_ID(0x041e, 0x3042))
190 err = snd_usb_ctl_msg(mixer->chip->dev,
191 usb_sndctrlpipe(mixer->chip->dev, 0), 0x24,
192 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER,
193 !value, 0, NULL, 0, 100);
194 /* USB X-Fi S51 Pro */
195 if (mixer->chip->usb_id == USB_ID(0x041e, 0x30df))
196 err = snd_usb_ctl_msg(mixer->chip->dev,
197 usb_sndctrlpipe(mixer->chip->dev, 0), 0x24,
198 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER,
199 !value, 0, NULL, 0, 100);
200 else
201 err = snd_usb_ctl_msg(mixer->chip->dev,
186 usb_sndctrlpipe(mixer->chip->dev, 0), 0x24, 202 usb_sndctrlpipe(mixer->chip->dev, 0), 0x24,
187 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, 203 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER,
188 value, index + 2, NULL, 0, 100); 204 value, index + 2, NULL, 0, 100);
@@ -224,8 +240,16 @@ static int snd_audigy2nx_controls_create(struct usb_mixer_interface *mixer)
224 int i, err; 240 int i, err;
225 241
226 for (i = 0; i < ARRAY_SIZE(snd_audigy2nx_controls); ++i) { 242 for (i = 0; i < ARRAY_SIZE(snd_audigy2nx_controls); ++i) {
243 /* USB X-Fi S51 doesn't have a CMSS LED */
244 if ((mixer->chip->usb_id == USB_ID(0x041e, 0x3042)) && i == 0)
245 continue;
246 /* USB X-Fi S51 Pro doesn't have one either */
247 if ((mixer->chip->usb_id == USB_ID(0x041e, 0x30df)) && i == 0)
248 continue;
227 if (i > 1 && /* Live24ext has 2 LEDs only */ 249 if (i > 1 && /* Live24ext has 2 LEDs only */
228 (mixer->chip->usb_id == USB_ID(0x041e, 0x3040) || 250 (mixer->chip->usb_id == USB_ID(0x041e, 0x3040) ||
251 mixer->chip->usb_id == USB_ID(0x041e, 0x3042) ||
252 mixer->chip->usb_id == USB_ID(0x041e, 0x30df) ||
229 mixer->chip->usb_id == USB_ID(0x041e, 0x3048))) 253 mixer->chip->usb_id == USB_ID(0x041e, 0x3048)))
230 break; 254 break;
231 err = snd_ctl_add(mixer->chip->card, 255 err = snd_ctl_add(mixer->chip->card,
@@ -335,6 +359,204 @@ static int snd_xonar_u1_controls_create(struct usb_mixer_interface *mixer)
335 return 0; 359 return 0;
336} 360}
337 361
362/* Native Instruments device quirks */
363
364#define _MAKE_NI_CONTROL(bRequest,wIndex) ((bRequest) << 16 | (wIndex))
365
366static int snd_nativeinstruments_control_get(struct snd_kcontrol *kcontrol,
367 struct snd_ctl_elem_value *ucontrol)
368{
369 struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol);
370 struct usb_device *dev = mixer->chip->dev;
371 u8 bRequest = (kcontrol->private_value >> 16) & 0xff;
372 u16 wIndex = kcontrol->private_value & 0xffff;
373 u8 tmp;
374
375 int ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), bRequest,
376 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
377 0, cpu_to_le16(wIndex),
378 &tmp, sizeof(tmp), 1000);
379
380 if (ret < 0) {
381 snd_printk(KERN_ERR
382 "unable to issue vendor read request (ret = %d)", ret);
383 return ret;
384 }
385
386 ucontrol->value.integer.value[0] = tmp;
387
388 return 0;
389}
390
391static int snd_nativeinstruments_control_put(struct snd_kcontrol *kcontrol,
392 struct snd_ctl_elem_value *ucontrol)
393{
394 struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol);
395 struct usb_device *dev = mixer->chip->dev;
396 u8 bRequest = (kcontrol->private_value >> 16) & 0xff;
397 u16 wIndex = kcontrol->private_value & 0xffff;
398 u16 wValue = ucontrol->value.integer.value[0];
399
400 int ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), bRequest,
401 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
402 cpu_to_le16(wValue), cpu_to_le16(wIndex),
403 NULL, 0, 1000);
404
405 if (ret < 0) {
406 snd_printk(KERN_ERR
407 "unable to issue vendor write request (ret = %d)", ret);
408 return ret;
409 }
410
411 return 0;
412}
413
414static struct snd_kcontrol_new snd_nativeinstruments_ta6_mixers[] = {
415 {
416 .name = "Direct Thru Channel A",
417 .private_value = _MAKE_NI_CONTROL(0x01, 0x03),
418 },
419 {
420 .name = "Direct Thru Channel B",
421 .private_value = _MAKE_NI_CONTROL(0x01, 0x05),
422 },
423 {
424 .name = "Phono Input Channel A",
425 .private_value = _MAKE_NI_CONTROL(0x02, 0x03),
426 },
427 {
428 .name = "Phono Input Channel B",
429 .private_value = _MAKE_NI_CONTROL(0x02, 0x05),
430 },
431};
432
433static struct snd_kcontrol_new snd_nativeinstruments_ta10_mixers[] = {
434 {
435 .name = "Direct Thru Channel A",
436 .private_value = _MAKE_NI_CONTROL(0x01, 0x03),
437 },
438 {
439 .name = "Direct Thru Channel B",
440 .private_value = _MAKE_NI_CONTROL(0x01, 0x05),
441 },
442 {
443 .name = "Direct Thru Channel C",
444 .private_value = _MAKE_NI_CONTROL(0x01, 0x07),
445 },
446 {
447 .name = "Direct Thru Channel D",
448 .private_value = _MAKE_NI_CONTROL(0x01, 0x09),
449 },
450 {
451 .name = "Phono Input Channel A",
452 .private_value = _MAKE_NI_CONTROL(0x02, 0x03),
453 },
454 {
455 .name = "Phono Input Channel B",
456 .private_value = _MAKE_NI_CONTROL(0x02, 0x05),
457 },
458 {
459 .name = "Phono Input Channel C",
460 .private_value = _MAKE_NI_CONTROL(0x02, 0x07),
461 },
462 {
463 .name = "Phono Input Channel D",
464 .private_value = _MAKE_NI_CONTROL(0x02, 0x09),
465 },
466};
467
468static int snd_nativeinstruments_create_mixer(struct usb_mixer_interface *mixer,
469 const struct snd_kcontrol_new *kc,
470 unsigned int count)
471{
472 int i, err = 0;
473 struct snd_kcontrol_new template = {
474 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
475 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
476 .get = snd_nativeinstruments_control_get,
477 .put = snd_nativeinstruments_control_put,
478 .info = snd_ctl_boolean_mono_info,
479 };
480
481 for (i = 0; i < count; i++) {
482 struct snd_kcontrol *c;
483
484 template.name = kc[i].name;
485 template.private_value = kc[i].private_value;
486
487 c = snd_ctl_new1(&template, mixer);
488 err = snd_ctl_add(mixer->chip->card, c);
489
490 if (err < 0)
491 break;
492 }
493
494 return err;
495}
496
497/* M-Audio FastTrack Ultra quirks */
498
499/* private_free callback */
500static void usb_mixer_elem_free(struct snd_kcontrol *kctl)
501{
502 kfree(kctl->private_data);
503 kctl->private_data = NULL;
504}
505
506static 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
534static 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
338void snd_emuusb_set_samplerate(struct snd_usb_audio *chip, 560void snd_emuusb_set_samplerate(struct snd_usb_audio *chip,
339 unsigned char samplerate_id) 561 unsigned char samplerate_id)
340{ 562{
@@ -356,30 +578,50 @@ void snd_emuusb_set_samplerate(struct snd_usb_audio *chip,
356 578
357int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer) 579int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer)
358{ 580{
359 int err; 581 int err = 0;
360 struct snd_info_entry *entry; 582 struct snd_info_entry *entry;
361 583
362 if ((err = snd_usb_soundblaster_remote_init(mixer)) < 0) 584 if ((err = snd_usb_soundblaster_remote_init(mixer)) < 0)
363 return err; 585 return err;
364 586
365 if (mixer->chip->usb_id == USB_ID(0x041e, 0x3020) || 587 switch (mixer->chip->usb_id) {
366 mixer->chip->usb_id == USB_ID(0x041e, 0x3040) || 588 case USB_ID(0x041e, 0x3020):
367 mixer->chip->usb_id == USB_ID(0x041e, 0x3048)) { 589 case USB_ID(0x041e, 0x3040):
368 if ((err = snd_audigy2nx_controls_create(mixer)) < 0) 590 case USB_ID(0x041e, 0x3042):
369 return err; 591 case USB_ID(0x041e, 0x30df):
592 case USB_ID(0x041e, 0x3048):
593 err = snd_audigy2nx_controls_create(mixer);
594 if (err < 0)
595 break;
370 if (!snd_card_proc_new(mixer->chip->card, "audigy2nx", &entry)) 596 if (!snd_card_proc_new(mixer->chip->card, "audigy2nx", &entry))
371 snd_info_set_text_ops(entry, mixer, 597 snd_info_set_text_ops(entry, mixer,
372 snd_audigy2nx_proc_read); 598 snd_audigy2nx_proc_read);
373 } 599 break;
374 600
375 if (mixer->chip->usb_id == USB_ID(0x0b05, 0x1739) || 601 case USB_ID(0x0763, 0x2080): /* M-Audio Fast Track Ultra */
376 mixer->chip->usb_id == USB_ID(0x0b05, 0x1743)) { 602 case USB_ID(0x0763, 0x2081): /* M-Audio Fast Track Ultra 8R */
603 err = snd_maudio_ftu_create_mixer(mixer);
604 break;
605
606 case USB_ID(0x0b05, 0x1739):
607 case USB_ID(0x0b05, 0x1743):
377 err = snd_xonar_u1_controls_create(mixer); 608 err = snd_xonar_u1_controls_create(mixer);
378 if (err < 0) 609 break;
379 return err; 610
611 case USB_ID(0x17cc, 0x1011): /* Traktor Audio 6 */
612 err = snd_nativeinstruments_create_mixer(mixer,
613 snd_nativeinstruments_ta6_mixers,
614 ARRAY_SIZE(snd_nativeinstruments_ta6_mixers));
615 break;
616
617 case USB_ID(0x17cc, 0x1021): /* Traktor Audio 10 */
618 err = snd_nativeinstruments_create_mixer(mixer,
619 snd_nativeinstruments_ta10_mixers,
620 ARRAY_SIZE(snd_nativeinstruments_ta10_mixers));
621 break;
380 } 622 }
381 623
382 return 0; 624 return err;
383} 625}
384 626
385void snd_usb_mixer_rc_memory_change(struct usb_mixer_interface *mixer, 627void snd_usb_mixer_rc_memory_change(struct usb_mixer_interface *mixer,