[alsa-devel] Patches for new audio devices from Native Instruments

Daniel Mack daniel at zonque.org
Sat Feb 12 20:59:11 CET 2011


Hi,

Native Instruments announced a new set of audio hardware recently, and I
have some patches ready to support them. See here for the details on their
website:

http://www.native-instruments.com/en/products/dj/traktor/

As I'm currently travelling and the only elaborated piece of hardware I got
left is my mobile phone, I have to send them along as attachments.

Many thanks to Mark Hills who rebased the patches for me so they should
apply without trouble.

In case of any doubts or questions - I'm reading my mails occasionally :-)

Best regards,
Daniel
-------------- next part --------------
From 66a340bc3f282ff44f805eb796673df74d994b78 Mon Sep 17 00:00:00 2001
From: Daniel Mack <daniel at caiaq.de>
Date: Wed, 1 Sep 2010 16:23:46 +0800
Subject: [PATCH 1/3] snd-usb-caiaq: Add support for Traktor Audio 2

Signed-off-by: Daniel Mack <daniel at caiaq.de>
---
 sound/usb/Kconfig        |    1 +
 sound/usb/caiaq/audio.c  |    1 +
 sound/usb/caiaq/device.c |    6 ++++++
 sound/usb/caiaq/device.h |    1 +
 4 files changed, 9 insertions(+), 0 deletions(-)

diff --git a/sound/usb/Kconfig b/sound/usb/Kconfig
index 0fefdb4..97724d8 100644
--- a/sound/usb/Kconfig
+++ b/sound/usb/Kconfig
@@ -62,6 +62,7 @@ config SND_USB_CAIAQ
 	    * Native Instruments Audio 2 DJ
 	    * Native Instruments Audio 4 DJ
 	    * Native Instruments Audio 8 DJ
+	    * Native Instruments Traktor Audio 2
 	    * Native Instruments Guitar Rig Session I/O
 	    * Native Instruments Guitar Rig mobile
 	    * Native Instruments Traktor Kontrol X1
diff --git a/sound/usb/caiaq/audio.c b/sound/usb/caiaq/audio.c
index 68b9747..e411cd3 100644
--- a/sound/usb/caiaq/audio.c
+++ b/sound/usb/caiaq/audio.c
@@ -805,6 +805,7 @@ int snd_usb_caiaq_audio_init(struct snd_usb_caiaqdev *dev)
 	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO2DJ):
 	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO4DJ):
 	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO8DJ):
+	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORAUDIO2):
 		dev->samplerates |= SNDRV_PCM_RATE_88200;
 		break;
 	}
diff --git a/sound/usb/caiaq/device.c b/sound/usb/caiaq/device.c
index 6480c32..45bc4a2 100644
--- a/sound/usb/caiaq/device.c
+++ b/sound/usb/caiaq/device.c
@@ -46,6 +46,7 @@ MODULE_SUPPORTED_DEVICE("{{Native Instruments, RigKontrol2},"
 			 "{Native Instruments, Audio 2 DJ},"
 			 "{Native Instruments, Audio 4 DJ},"
 			 "{Native Instruments, Audio 8 DJ},"
+			 "{Native Instruments, Traktor Audio 2},"
 			 "{Native Instruments, Session I/O},"
 			 "{Native Instruments, GuitarRig mobile}"
 			 "{Native Instruments, Traktor Kontrol X1}"
@@ -140,6 +141,11 @@ static struct usb_device_id snd_usb_id_table[] = {
 		.idVendor =     USB_VID_NATIVEINSTRUMENTS,
 		.idProduct =    USB_PID_TRAKTORKONTROLS4
 	},
+	{
+		.match_flags =  USB_DEVICE_ID_MATCH_DEVICE,
+		.idVendor =     USB_VID_NATIVEINSTRUMENTS,
+		.idProduct =    USB_PID_TRAKTORAUDIO2
+	},
 	{ /* terminator */ }
 };
 
diff --git a/sound/usb/caiaq/device.h b/sound/usb/caiaq/device.h
index e3d8a3e..b2b3101 100644
--- a/sound/usb/caiaq/device.h
+++ b/sound/usb/caiaq/device.h
@@ -17,6 +17,7 @@
 #define USB_PID_GUITARRIGMOBILE		0x0d8d
 #define USB_PID_TRAKTORKONTROLX1	0x2305
 #define USB_PID_TRAKTORKONTROLS4	0xbaff
+#define USB_PID_TRAKTORAUDIO2		0x041d
 
 #define EP1_BUFSIZE 64
 #define EP4_BUFSIZE 512
-- 
1.7.4

-------------- next part --------------
From 79acde30358f2eb5a02f31336c9d0eed0461b82c Mon Sep 17 00:00:00 2001
From: Daniel Mack <daniel at caiaq.de>
Date: Fri, 11 Feb 2011 11:08:06 +0000
Subject: [PATCH 2/3] 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 at caiaq.de>
---
 sound/usb/mixer_quirks.c |  153 ++++++++++++++++++++++++++++++++++++++++++++++
 sound/usb/quirks-table.h |   14 ++++
 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 782f741..3fe612a 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)
 	return 0;
 }
 
+/* Native Instruments device quirks */
+
+#define _MAKE_NI_CONTROL(bRequest,wIndex) ((bRequest) << 16 | (wIndex))
+
+static int snd_nativeinstruments_control_get(struct snd_kcontrol *kcontrol,
+					     struct snd_ctl_elem_value *ucontrol)
+{
+	struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol);
+	struct usb_device *dev = mixer->chip->dev;
+	u8 bRequest = (kcontrol->private_value >> 16) & 0xff;
+	u16 wIndex = kcontrol->private_value & 0xffff;
+	u8 tmp;
+
+	int ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), bRequest,
+				  USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
+				  0, cpu_to_le16(wIndex),
+				  &tmp, sizeof(tmp), 1000);
+
+	if (ret < 0) {
+		snd_printk(KERN_ERR
+			   "unable to issue vendor read request (ret = %d)", ret);
+		return ret;
+	}
+
+	ucontrol->value.integer.value[0] = tmp;
+
+	return 0;
+}
+
+static int snd_nativeinstruments_control_put(struct snd_kcontrol *kcontrol,
+					     struct snd_ctl_elem_value *ucontrol)
+{
+	struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol);
+	struct usb_device *dev = mixer->chip->dev;
+	u8 bRequest = (kcontrol->private_value >> 16) & 0xff;
+	u16 wIndex = kcontrol->private_value & 0xffff;
+	u16 wValue = ucontrol->value.integer.value[0];
+
+	int ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), bRequest,
+				  USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
+				  cpu_to_le16(wValue), cpu_to_le16(wIndex),
+				  NULL, 0, 1000);
+
+	if (ret < 0) {
+		snd_printk(KERN_ERR
+			   "unable to issue vendor write request (ret = %d)", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static struct snd_kcontrol_new snd_nativeinstruments_ta6_mixers[] = {
+	{
+		.name = "Direct Thru Channel A",
+		.private_value = _MAKE_NI_CONTROL(0x01, 0x03),
+	},
+	{
+		.name = "Direct Thru Channel B",
+		.private_value = _MAKE_NI_CONTROL(0x01, 0x05),
+	},
+	{
+		.name = "Phono Input Channel A",
+		.private_value = _MAKE_NI_CONTROL(0x02, 0x03),
+	},
+	{
+		.name = "Phono Input Channel B",
+		.private_value = _MAKE_NI_CONTROL(0x02, 0x05),
+	},
+};
+
+static struct snd_kcontrol_new snd_nativeinstruments_ta10_mixers[] = {
+	{
+		.name = "Direct Thru Channel A",
+		.private_value = _MAKE_NI_CONTROL(0x01, 0x03),
+	},
+	{
+		.name = "Direct Thru Channel B",
+		.private_value = _MAKE_NI_CONTROL(0x01, 0x05),
+	},
+	{
+		.name = "Direct Thru Channel C",
+		.private_value = _MAKE_NI_CONTROL(0x01, 0x07),
+	},
+	{
+		.name = "Direct Thru Channel D",
+		.private_value = _MAKE_NI_CONTROL(0x01, 0x09),
+	},
+	{
+		.name = "Phono Input Channel A",
+		.private_value = _MAKE_NI_CONTROL(0x02, 0x03),
+	},
+	{
+		.name = "Phono Input Channel B",
+		.private_value = _MAKE_NI_CONTROL(0x02, 0x05),
+	},
+	{
+		.name = "Phono Input Channel C",
+		.private_value = _MAKE_NI_CONTROL(0x02, 0x07),
+	},
+	{
+		.name = "Phono Input Channel D",
+		.private_value = _MAKE_NI_CONTROL(0x02, 0x09),
+	},
+};
+
+static int snd_nativeinstruments_create_mixer(struct usb_mixer_interface *mixer,
+					      const struct snd_kcontrol_new *kc,
+					      unsigned int count)
+{
+	int i, err = 0;
+	struct snd_kcontrol_new template = {
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+		.get = snd_nativeinstruments_control_get,
+		.put = snd_nativeinstruments_control_put,
+		.info = snd_ctl_boolean_mono_info,
+	};
+
+	for (i = 0; i < count; i++) {
+		struct snd_kcontrol *c;
+
+		template.name = kc[i].name;
+		template.private_value = kc[i].private_value;
+
+		c = snd_ctl_new1(&template, mixer);
+		err = snd_ctl_add(mixer->chip->card, c);
+
+		if (err < 0)
+			break;
+	}
+
+	return err;
+}
+
 void snd_emuusb_set_samplerate(struct snd_usb_audio *chip,
 			       unsigned char samplerate_id)
 {
@@ -391,6 +526,24 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer)
 			return err;
 	}
 
+	/* Traktor Audio 6 */
+	if (mixer->chip->usb_id == USB_ID(0x17cc, 0x1011)) {
+		err = snd_nativeinstruments_create_mixer(mixer,
+				snd_nativeinstruments_ta6_mixers,
+				ARRAY_SIZE(snd_nativeinstruments_ta6_mixers));
+		if (err < 0)
+			return err;
+	}
+
+	/* Traktor Audio 10 */
+	if (mixer->chip->usb_id == USB_ID(0x17cc, 0x1021)) {
+		err = snd_nativeinstruments_create_mixer(mixer,
+				snd_nativeinstruments_ta10_mixers,
+				ARRAY_SIZE(snd_nativeinstruments_ta10_mixers));
+		if (err < 0)
+			return err;
+	}
+
 	return 0;
 }
 
diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h
index 3599987..e1e245d 100644
--- a/sound/usb/quirks-table.h
+++ b/sound/usb/quirks-table.h
@@ -2283,6 +2283,20 @@ YAMAHA_DEVICE(0x7010, "UB99"),
 	}
 },
 
+/* Native Instruments MK2 series */
+{
+	/* Traktor Audio 6 */
+	.match_flags = USB_DEVICE_ID_MATCH_DEVICE,
+	.idVendor = 0x17cc,
+	.idProduct = 0x1010,
+},
+{
+	/* Traktor Audio 10 */
+	.match_flags = USB_DEVICE_ID_MATCH_DEVICE,
+	.idVendor = 0x17cc,
+	.idProduct = 0x1020,
+},
+
 /* Miditech devices */
 {
 	USB_DEVICE(0x4752, 0x0011),
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
index cf8bf08..e55bd1c 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)
 }
 
 /*
+ * Some sound cards from Native Instruments are in fact compliant to the USB
+ * audio standard of version 2 and other approved USB standards, even though
+ * they come up as vendor-specific device when first connected.
+ *
+ * However, they can be told to come up with a new set of descriptors
+ * upon their next enumeration, and the interfaces announced by the new
+ * descriptors will then be handled by the kernel's class drivers. As the
+ * product ID will also change, no further checks are required.
+ */
+
+static int snd_usb_nativeinstruments_boot_quirk(struct usb_device *dev)
+{
+	int ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+				  0xaf, USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+				  cpu_to_le16(1), 0, NULL, 0, 1000);
+
+	if (ret < 0)
+		return ret;
+
+	usb_reset_device(dev);
+
+	/* return -EAGAIN, so the creation of an audio interface for this
+	 * temporary device is aborted. The device will reconnect with a
+	 * new product ID */
+	return -EAGAIN;
+}
+
+/*
  * Setup quirks
  */
 #define AUDIOPHILE_SET			0x01 /* if set, parse device_setup */
@@ -510,6 +538,11 @@ int snd_usb_apply_boot_quirk(struct usb_device *dev,
 	if (id == USB_ID(0x133e, 0x0815))
 		return snd_usb_accessmusic_boot_quirk(dev);
 
+	/* Native Instruments Devices */
+	if (id == USB_ID(0x17cc, 0x1010) || /* Traktor Audio 6 */
+		id == USB_ID(0x17cc, 0x1020)) /* Traktor Audio 10 */
+		return snd_usb_nativeinstruments_boot_quirk(dev);
+
 	return 0;
 }
 
-- 
1.7.4

-------------- next part --------------
From 9f6e86427d3d9780789af363b12652871849d500 Mon Sep 17 00:00:00 2001
From: Daniel Mack <daniel at caiaq.de>
Date: Fri, 11 Feb 2011 11:34:12 +0000
Subject: [PATCH 3/3] usb-audio: reconstruct some dispatcher functions to use switch-case

The number of cases has increased so use switch-case rather than
if-statements.

Signed-off-by: Daniel Mack <daniel at caiaq.de>
---
 sound/usb/mixer_quirks.c |   41 ++++++++++++++++++-----------------------
 sound/usb/quirks.c       |   29 +++++++++++++++--------------
 2 files changed, 33 insertions(+), 37 deletions(-)

diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c
index 3fe612a..73dcc82 100644
--- a/sound/usb/mixer_quirks.c
+++ b/sound/usb/mixer_quirks.c
@@ -502,49 +502,44 @@ void snd_emuusb_set_samplerate(struct snd_usb_audio *chip,
 
 int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer)
 {
-	int err;
+	int err = 0;
 	struct snd_info_entry *entry;
 
 	if ((err = snd_usb_soundblaster_remote_init(mixer)) < 0)
 		return err;
 
-	if (mixer->chip->usb_id == USB_ID(0x041e, 0x3020) ||
-	    mixer->chip->usb_id == USB_ID(0x041e, 0x3040) ||
-	    mixer->chip->usb_id == USB_ID(0x041e, 0x3042) ||
-	    mixer->chip->usb_id == USB_ID(0x041e, 0x3048)) {
-		if ((err = snd_audigy2nx_controls_create(mixer)) < 0)
-			return err;
+	switch (mixer->chip->usb_id) {
+	case USB_ID(0x041e, 0x3020):
+	case USB_ID(0x041e, 0x3040):
+	case USB_ID(0x041e, 0x3042):
+	case USB_ID(0x041e, 0x3048):
+		err = snd_audigy2nx_controls_create(mixer);
+		if (err < 0)
+			break;
 		if (!snd_card_proc_new(mixer->chip->card, "audigy2nx", &entry))
 			snd_info_set_text_ops(entry, mixer,
 					      snd_audigy2nx_proc_read);
-	}
+		break;
 
-	if (mixer->chip->usb_id == USB_ID(0x0b05, 0x1739) ||
-	    mixer->chip->usb_id == USB_ID(0x0b05, 0x1743)) {
+	case USB_ID(0x0b05, 0x1739):
+	case USB_ID(0x0b05, 0x1743):
 		err = snd_xonar_u1_controls_create(mixer);
-		if (err < 0)
-			return err;
-	}
+		break;
 
-	/* Traktor Audio 6 */
-	if (mixer->chip->usb_id == USB_ID(0x17cc, 0x1011)) {
+	case USB_ID(0x17cc, 0x1011): /* Traktor Audio 6 */
 		err = snd_nativeinstruments_create_mixer(mixer,
 				snd_nativeinstruments_ta6_mixers,
 				ARRAY_SIZE(snd_nativeinstruments_ta6_mixers));
-		if (err < 0)
-			return err;
-	}
+		break;
 
-	/* Traktor Audio 10 */
-	if (mixer->chip->usb_id == USB_ID(0x17cc, 0x1021)) {
+	case USB_ID(0x17cc, 0x1021): /* Traktor Audio 10 */
 		err = snd_nativeinstruments_create_mixer(mixer,
 				snd_nativeinstruments_ta10_mixers,
 				ARRAY_SIZE(snd_nativeinstruments_ta10_mixers));
-		if (err < 0)
-			return err;
+		break;
 	}
 
-	return 0;
+	return err;
 }
 
 void snd_usb_mixer_rc_memory_change(struct usb_mixer_interface *mixer,
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
index e55bd1c..ca860e6 100644
--- a/sound/usb/quirks.c
+++ b/sound/usb/quirks.c
@@ -517,31 +517,32 @@ int snd_usb_apply_boot_quirk(struct usb_device *dev,
 	u32 id = USB_ID(le16_to_cpu(dev->descriptor.idVendor),
 			le16_to_cpu(dev->descriptor.idProduct));
 
-	/* SB Extigy needs special boot-up sequence */
-	/* if more models come, this will go to the quirk list. */
-	if (id == USB_ID(0x041e, 0x3000))
+	switch (id) {
+	case USB_ID(0x041e, 0x3000):
+		/* SB Extigy needs special boot-up sequence */
+		/* if more models come, this will go to the quirk list. */
 		return snd_usb_extigy_boot_quirk(dev, intf);
 
-	/* SB Audigy 2 NX needs its own boot-up magic, too */
-	if (id == USB_ID(0x041e, 0x3020))
+	case USB_ID(0x041e, 0x3020):
+		/* SB Audigy 2 NX needs its own boot-up magic, too */
 		return snd_usb_audigy2nx_boot_quirk(dev);
 
-	/* C-Media CM106 / Turtle Beach Audio Advantage Roadie */
-	if (id == USB_ID(0x10f5, 0x0200))
+	case USB_ID(0x10f5, 0x0200):
+		/* C-Media CM106 / Turtle Beach Audio Advantage Roadie */
 		return snd_usb_cm106_boot_quirk(dev);
 
-	/* C-Media CM6206 / CM106-Like Sound Device */
-	if (id == USB_ID(0x0d8c, 0x0102))
+	case USB_ID(0x0d8c, 0x0102):
+		/* C-Media CM6206 / CM106-Like Sound Device */
 		return snd_usb_cm6206_boot_quirk(dev);
 
-	/* Access Music VirusTI Desktop */
-	if (id == USB_ID(0x133e, 0x0815))
+	case USB_ID(0x133e, 0x0815):
+		/* Access Music VirusTI Desktop */
 		return snd_usb_accessmusic_boot_quirk(dev);
 
-	/* Native Instruments Devices */
-	if (id == USB_ID(0x17cc, 0x1010) || /* Traktor Audio 6 */
-		id == USB_ID(0x17cc, 0x1020)) /* Traktor Audio 10 */
+	case USB_ID(0x17cc, 0x1010): /* Traktor Audio 6 */
+	case USB_ID(0x17cc, 0x1020): /* Traktor Audio 10 */
 		return snd_usb_nativeinstruments_boot_quirk(dev);
+	}
 
 	return 0;
 }
-- 
1.7.4



More information about the Alsa-devel mailing list