ALSA: usb/caiaq: Add support for Traktor Kontrol X1

This device does not have audio controllers and backlit buttons only.
Input data is handled over a dedicated USB endpoint.

All functions are supported by the driver now.

Signed-off-by: Daniel Mack <daniel@caiaq.de>
Cc: Dmitry Torokhov <dtor@mail.ru>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
diff --git a/sound/usb/caiaq/control.c b/sound/usb/caiaq/control.c
index 537102b..36ed703 100644
--- a/sound/usb/caiaq/control.c
+++ b/sound/usb/caiaq/control.c
@@ -35,33 +35,41 @@
 	struct snd_usb_caiaqdev *dev = caiaqdev(chip->card);
 	int pos = kcontrol->private_value;
 	int is_intval = pos & CNT_INTVAL;
-	unsigned int id = dev->chip.usb_id;
+	int maxval = 63;
 
 	uinfo->count = 1;
 	pos &= ~CNT_INTVAL;
 
-	if (id == USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO8DJ)
-		&& (pos == 0)) {
-		/* current input mode of A8DJ */
-		uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
-		uinfo->value.integer.min = 0;
-		uinfo->value.integer.max = 2;
-		return 0;
-	}
+	switch (dev->chip.usb_id) {
+	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO8DJ):
+		if (pos == 0) {
+			/* current input mode of A8DJ */
+			uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+			uinfo->value.integer.min = 0;
+			uinfo->value.integer.max = 2;
+			return 0;
+		}
+		break;
 
-	if (id == USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO4DJ)
-		&& (pos == 0)) {
-		/* current input mode of A4DJ */
-		uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
-		uinfo->value.integer.min = 0;
-		uinfo->value.integer.max = 1;
-		return 0;
+	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO4DJ):
+		if (pos == 0) {
+			/* current input mode of A4DJ */
+			uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+			uinfo->value.integer.min = 0;
+			uinfo->value.integer.max = 1;
+			return 0;
+		}
+		break;
+
+	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1):
+		maxval = 127;
+		break;
 	}
 
 	if (is_intval) {
 		uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
 		uinfo->value.integer.min = 0;
-		uinfo->value.integer.max = 64;
+		uinfo->value.integer.max = maxval;
 	} else {
 		uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
 		uinfo->value.integer.min = 0;
@@ -102,9 +110,10 @@
 	struct snd_usb_audio *chip = snd_kcontrol_chip(kcontrol);
 	struct snd_usb_caiaqdev *dev = caiaqdev(chip->card);
 	int pos = kcontrol->private_value;
+	unsigned char cmd = EP1_CMD_WRITE_IO;
 
-	if (dev->chip.usb_id ==
-		USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO4DJ)) {
+	switch (dev->chip.usb_id) {
+	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO4DJ): {
 		/* A4DJ has only one control */
 		/* do not expose hardware input mode 0 */
 		dev->control_state[0] = ucontrol->value.integer.value[0] + 1;
@@ -113,10 +122,15 @@
 		return 1;
 	}
 
+	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1):
+		cmd = EP1_CMD_DIMM_LEDS;
+		break;
+	}
+
 	if (pos & CNT_INTVAL) {
 		dev->control_state[pos & ~CNT_INTVAL]
 			= ucontrol->value.integer.value[0];
-		snd_usb_caiaq_send_command(dev, EP1_CMD_WRITE_IO,
+		snd_usb_caiaq_send_command(dev, cmd,
 				dev->control_state, sizeof(dev->control_state));
 	} else {
 		if (ucontrol->value.integer.value[0])
@@ -124,7 +138,7 @@
 		else
 			dev->control_state[pos / 8] &= ~(1 << (pos % 8));
 
-		snd_usb_caiaq_send_command(dev, EP1_CMD_WRITE_IO,
+		snd_usb_caiaq_send_command(dev, cmd,
 				dev->control_state, sizeof(dev->control_state));
 	}
 
@@ -273,6 +287,43 @@
 	{ "Current input mode",	0 | CNT_INTVAL 	}
 };
 
+static struct caiaq_controller kontrolx1_controller[] = {
+	{ "LED FX A: ON",		7 | CNT_INTVAL	},
+	{ "LED FX A: 1",		6 | CNT_INTVAL	},
+	{ "LED FX A: 2",		5 | CNT_INTVAL	},
+	{ "LED FX A: 3",		4 | CNT_INTVAL	},
+	{ "LED FX B: ON",		3 | CNT_INTVAL	},
+	{ "LED FX B: 1",		2 | CNT_INTVAL	},
+	{ "LED FX B: 2",		1 | CNT_INTVAL	},
+	{ "LED FX B: 3",		0 | CNT_INTVAL	},
+
+	{ "LED Hotcue",			28 | CNT_INTVAL	},
+	{ "LED Shift (white)",		29 | CNT_INTVAL	},
+	{ "LED Shift (green)",		30 | CNT_INTVAL	},
+
+	{ "LED Deck A: FX1",		24 | CNT_INTVAL	},
+	{ "LED Deck A: FX2",		25 | CNT_INTVAL	},
+	{ "LED Deck A: IN",		17 | CNT_INTVAL	},
+	{ "LED Deck A: OUT",		16 | CNT_INTVAL	},
+	{ "LED Deck A: < BEAT",		19 | CNT_INTVAL	},
+	{ "LED Deck A: BEAT >",		18 | CNT_INTVAL	},
+	{ "LED Deck A: CUE/ABS",	21 | CNT_INTVAL	},
+	{ "LED Deck A: CUP/REL",	20 | CNT_INTVAL	},
+	{ "LED Deck A: PLAY",		23 | CNT_INTVAL	},
+	{ "LED Deck A: SYNC",		22 | CNT_INTVAL	},
+
+	{ "LED Deck B: FX1",		26 | CNT_INTVAL	},
+	{ "LED Deck B: FX2",		27 | CNT_INTVAL	},
+	{ "LED Deck B: IN",		15 | CNT_INTVAL	},
+	{ "LED Deck B: OUT",		14 | CNT_INTVAL	},
+	{ "LED Deck B: < BEAT",		13 | CNT_INTVAL	},
+	{ "LED Deck B: BEAT >",		12 | CNT_INTVAL	},
+	{ "LED Deck B: CUE/ABS",	11 | CNT_INTVAL	},
+	{ "LED Deck B: CUP/REL",	10 | CNT_INTVAL	},
+	{ "LED Deck B: PLAY",		9  | CNT_INTVAL	},
+	{ "LED Deck B: SYNC",		8  | CNT_INTVAL	},
+};
+
 static int __devinit add_controls(struct caiaq_controller *c, int num,
 				  struct snd_usb_caiaqdev *dev)
 {
@@ -321,10 +372,16 @@
 		ret = add_controls(a8dj_controller,
 			ARRAY_SIZE(a8dj_controller), dev);
 		break;
+
 	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO4DJ):
 		ret = add_controls(a4dj_controller,
 			ARRAY_SIZE(a4dj_controller), dev);
 		break;
+
+	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1):
+		ret = add_controls(kontrolx1_controller,
+			ARRAY_SIZE(kontrolx1_controller), dev);
+		break;
 	}
 
 	return ret;