diff options
author | Daniel Mack <daniel@caiaq.de> | 2011-02-11 06:08:06 -0500 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2011-02-14 11:10:57 -0500 |
commit | 54a8c500d5b80c83e0f14cbcfcfd4a84abff8a80 (patch) | |
tree | 2292d77a630dec193a5682e6238d73b7c09a8cd9 | |
parent | df8d81a32fa0309d64726fc62d83cb70adc899e8 (diff) |
ALSA: usb-audio: add support for Native Instruments MK2 devices
The MK2 generation of Native Instruments' sound cards are in fact
compliant to the USB audio standard of version 2 and other approved USB
standards. However, they come up as vendor-specific device when first
connected but can be told to come up with a new set of descriptors
upon their next enumeration. The interfaces announced by the new
descriptors will be handled by the kernel's class drivers. This is done
by issuing a vendor specific device request and sending the device to
reset.
There are also some vendor-specific USB requests for some mixer elements
that can't be exported in a standard compliant way. The driver now
supports them with quirks handling mechanisms.
Signed-off-by: Daniel Mack <daniel@caiaq.de>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
-rw-r--r-- | sound/usb/mixer_quirks.c | 153 | ||||
-rw-r--r-- | sound/usb/quirks-table.h | 14 | ||||
-rw-r--r-- | sound/usb/quirks.c | 33 |
3 files changed, 200 insertions, 0 deletions
diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index 782f741cd00a..3fe612a369a7 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c | |||
@@ -346,6 +346,141 @@ static int snd_xonar_u1_controls_create(struct usb_mixer_interface *mixer) | |||
346 | return 0; | 346 | return 0; |
347 | } | 347 | } |
348 | 348 | ||
349 | /* Native Instruments device quirks */ | ||
350 | |||
351 | #define _MAKE_NI_CONTROL(bRequest,wIndex) ((bRequest) << 16 | (wIndex)) | ||
352 | |||
353 | static int snd_nativeinstruments_control_get(struct snd_kcontrol *kcontrol, | ||
354 | struct snd_ctl_elem_value *ucontrol) | ||
355 | { | ||
356 | struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol); | ||
357 | struct usb_device *dev = mixer->chip->dev; | ||
358 | u8 bRequest = (kcontrol->private_value >> 16) & 0xff; | ||
359 | u16 wIndex = kcontrol->private_value & 0xffff; | ||
360 | u8 tmp; | ||
361 | |||
362 | int ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), bRequest, | ||
363 | USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, | ||
364 | 0, cpu_to_le16(wIndex), | ||
365 | &tmp, sizeof(tmp), 1000); | ||
366 | |||
367 | if (ret < 0) { | ||
368 | snd_printk(KERN_ERR | ||
369 | "unable to issue vendor read request (ret = %d)", ret); | ||
370 | return ret; | ||
371 | } | ||
372 | |||
373 | ucontrol->value.integer.value[0] = tmp; | ||
374 | |||
375 | return 0; | ||
376 | } | ||
377 | |||
378 | static int snd_nativeinstruments_control_put(struct snd_kcontrol *kcontrol, | ||
379 | struct snd_ctl_elem_value *ucontrol) | ||
380 | { | ||
381 | struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol); | ||
382 | struct usb_device *dev = mixer->chip->dev; | ||
383 | u8 bRequest = (kcontrol->private_value >> 16) & 0xff; | ||
384 | u16 wIndex = kcontrol->private_value & 0xffff; | ||
385 | u16 wValue = ucontrol->value.integer.value[0]; | ||
386 | |||
387 | int ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), bRequest, | ||
388 | USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, | ||
389 | cpu_to_le16(wValue), cpu_to_le16(wIndex), | ||
390 | NULL, 0, 1000); | ||
391 | |||
392 | if (ret < 0) { | ||
393 | snd_printk(KERN_ERR | ||
394 | "unable to issue vendor write request (ret = %d)", ret); | ||
395 | return ret; | ||
396 | } | ||
397 | |||
398 | return 0; | ||
399 | } | ||
400 | |||
401 | static struct snd_kcontrol_new snd_nativeinstruments_ta6_mixers[] = { | ||
402 | { | ||
403 | .name = "Direct Thru Channel A", | ||
404 | .private_value = _MAKE_NI_CONTROL(0x01, 0x03), | ||
405 | }, | ||
406 | { | ||
407 | .name = "Direct Thru Channel B", | ||
408 | .private_value = _MAKE_NI_CONTROL(0x01, 0x05), | ||
409 | }, | ||
410 | { | ||
411 | .name = "Phono Input Channel A", | ||
412 | .private_value = _MAKE_NI_CONTROL(0x02, 0x03), | ||
413 | }, | ||
414 | { | ||
415 | .name = "Phono Input Channel B", | ||
416 | .private_value = _MAKE_NI_CONTROL(0x02, 0x05), | ||
417 | }, | ||
418 | }; | ||
419 | |||
420 | static struct snd_kcontrol_new snd_nativeinstruments_ta10_mixers[] = { | ||
421 | { | ||
422 | .name = "Direct Thru Channel A", | ||
423 | .private_value = _MAKE_NI_CONTROL(0x01, 0x03), | ||
424 | }, | ||
425 | { | ||
426 | .name = "Direct Thru Channel B", | ||
427 | .private_value = _MAKE_NI_CONTROL(0x01, 0x05), | ||
428 | }, | ||
429 | { | ||
430 | .name = "Direct Thru Channel C", | ||
431 | .private_value = _MAKE_NI_CONTROL(0x01, 0x07), | ||
432 | }, | ||
433 | { | ||
434 | .name = "Direct Thru Channel D", | ||
435 | .private_value = _MAKE_NI_CONTROL(0x01, 0x09), | ||
436 | }, | ||
437 | { | ||
438 | .name = "Phono Input Channel A", | ||
439 | .private_value = _MAKE_NI_CONTROL(0x02, 0x03), | ||
440 | }, | ||
441 | { | ||
442 | .name = "Phono Input Channel B", | ||
443 | .private_value = _MAKE_NI_CONTROL(0x02, 0x05), | ||
444 | }, | ||
445 | { | ||
446 | .name = "Phono Input Channel C", | ||
447 | .private_value = _MAKE_NI_CONTROL(0x02, 0x07), | ||
448 | }, | ||
449 | { | ||
450 | .name = "Phono Input Channel D", | ||
451 | .private_value = _MAKE_NI_CONTROL(0x02, 0x09), | ||
452 | }, | ||
453 | }; | ||
454 | |||
455 | static int snd_nativeinstruments_create_mixer(struct usb_mixer_interface *mixer, | ||
456 | const struct snd_kcontrol_new *kc, | ||
457 | unsigned int count) | ||
458 | { | ||
459 | int i, err = 0; | ||
460 | struct snd_kcontrol_new template = { | ||
461 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
462 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, | ||
463 | .get = snd_nativeinstruments_control_get, | ||
464 | .put = snd_nativeinstruments_control_put, | ||
465 | .info = snd_ctl_boolean_mono_info, | ||
466 | }; | ||
467 | |||
468 | for (i = 0; i < count; i++) { | ||
469 | struct snd_kcontrol *c; | ||
470 | |||
471 | template.name = kc[i].name; | ||
472 | template.private_value = kc[i].private_value; | ||
473 | |||
474 | c = snd_ctl_new1(&template, mixer); | ||
475 | err = snd_ctl_add(mixer->chip->card, c); | ||
476 | |||
477 | if (err < 0) | ||
478 | break; | ||
479 | } | ||
480 | |||
481 | return err; | ||
482 | } | ||
483 | |||
349 | void snd_emuusb_set_samplerate(struct snd_usb_audio *chip, | 484 | void snd_emuusb_set_samplerate(struct snd_usb_audio *chip, |
350 | unsigned char samplerate_id) | 485 | unsigned char samplerate_id) |
351 | { | 486 | { |
@@ -391,6 +526,24 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer) | |||
391 | return err; | 526 | return err; |
392 | } | 527 | } |
393 | 528 | ||
529 | /* Traktor Audio 6 */ | ||
530 | if (mixer->chip->usb_id == USB_ID(0x17cc, 0x1011)) { | ||
531 | err = snd_nativeinstruments_create_mixer(mixer, | ||
532 | snd_nativeinstruments_ta6_mixers, | ||
533 | ARRAY_SIZE(snd_nativeinstruments_ta6_mixers)); | ||
534 | if (err < 0) | ||
535 | return err; | ||
536 | } | ||
537 | |||
538 | /* Traktor Audio 10 */ | ||
539 | if (mixer->chip->usb_id == USB_ID(0x17cc, 0x1021)) { | ||
540 | err = snd_nativeinstruments_create_mixer(mixer, | ||
541 | snd_nativeinstruments_ta10_mixers, | ||
542 | ARRAY_SIZE(snd_nativeinstruments_ta10_mixers)); | ||
543 | if (err < 0) | ||
544 | return err; | ||
545 | } | ||
546 | |||
394 | return 0; | 547 | return 0; |
395 | } | 548 | } |
396 | 549 | ||
diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h index 35999874d301..e1e245d0e5ec 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h | |||
@@ -2283,6 +2283,20 @@ YAMAHA_DEVICE(0x7010, "UB99"), | |||
2283 | } | 2283 | } |
2284 | }, | 2284 | }, |
2285 | 2285 | ||
2286 | /* Native Instruments MK2 series */ | ||
2287 | { | ||
2288 | /* Traktor Audio 6 */ | ||
2289 | .match_flags = USB_DEVICE_ID_MATCH_DEVICE, | ||
2290 | .idVendor = 0x17cc, | ||
2291 | .idProduct = 0x1010, | ||
2292 | }, | ||
2293 | { | ||
2294 | /* Traktor Audio 10 */ | ||
2295 | .match_flags = USB_DEVICE_ID_MATCH_DEVICE, | ||
2296 | .idVendor = 0x17cc, | ||
2297 | .idProduct = 0x1020, | ||
2298 | }, | ||
2299 | |||
2286 | /* Miditech devices */ | 2300 | /* Miditech devices */ |
2287 | { | 2301 | { |
2288 | USB_DEVICE(0x4752, 0x0011), | 2302 | USB_DEVICE(0x4752, 0x0011), |
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index cf8bf088394b..e55bd1cac77d 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c | |||
@@ -425,6 +425,34 @@ static int snd_usb_accessmusic_boot_quirk(struct usb_device *dev) | |||
425 | } | 425 | } |
426 | 426 | ||
427 | /* | 427 | /* |
428 | * Some sound cards from Native Instruments are in fact compliant to the USB | ||
429 | * audio standard of version 2 and other approved USB standards, even though | ||
430 | * they come up as vendor-specific device when first connected. | ||
431 | * | ||
432 | * However, they can be told to come up with a new set of descriptors | ||
433 | * upon their next enumeration, and the interfaces announced by the new | ||
434 | * descriptors will then be handled by the kernel's class drivers. As the | ||
435 | * product ID will also change, no further checks are required. | ||
436 | */ | ||
437 | |||
438 | static int snd_usb_nativeinstruments_boot_quirk(struct usb_device *dev) | ||
439 | { | ||
440 | int ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), | ||
441 | 0xaf, USB_TYPE_VENDOR | USB_RECIP_DEVICE, | ||
442 | cpu_to_le16(1), 0, NULL, 0, 1000); | ||
443 | |||
444 | if (ret < 0) | ||
445 | return ret; | ||
446 | |||
447 | usb_reset_device(dev); | ||
448 | |||
449 | /* return -EAGAIN, so the creation of an audio interface for this | ||
450 | * temporary device is aborted. The device will reconnect with a | ||
451 | * new product ID */ | ||
452 | return -EAGAIN; | ||
453 | } | ||
454 | |||
455 | /* | ||
428 | * Setup quirks | 456 | * Setup quirks |
429 | */ | 457 | */ |
430 | #define AUDIOPHILE_SET 0x01 /* if set, parse device_setup */ | 458 | #define AUDIOPHILE_SET 0x01 /* if set, parse device_setup */ |
@@ -510,6 +538,11 @@ int snd_usb_apply_boot_quirk(struct usb_device *dev, | |||
510 | if (id == USB_ID(0x133e, 0x0815)) | 538 | if (id == USB_ID(0x133e, 0x0815)) |
511 | return snd_usb_accessmusic_boot_quirk(dev); | 539 | return snd_usb_accessmusic_boot_quirk(dev); |
512 | 540 | ||
541 | /* Native Instruments Devices */ | ||
542 | if (id == USB_ID(0x17cc, 0x1010) || /* Traktor Audio 6 */ | ||
543 | id == USB_ID(0x17cc, 0x1020)) /* Traktor Audio 10 */ | ||
544 | return snd_usb_nativeinstruments_boot_quirk(dev); | ||
545 | |||
513 | return 0; | 546 | return 0; |
514 | } | 547 | } |
515 | 548 | ||