Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 15c5ab60 authored by Daniel Mack's avatar Daniel Mack Committed by Takashi Iwai
Browse files

ALSA: snd-usb-caiaq: Add support for Traktor Kontrol S4



This patch adds support for the new Traktor Kontrol S4 by Native
Instruments. It features a new audio data streaming model, MIDI
in and out ports, a huge number of 174 dimmable LEDs, 96 buttons
and 46 absolute encoder axis, including some rotary encoders.

All features are supported by the driver now.

Did some code refactoring along the way.

Signed-off-by: default avatarDaniel Mack <daniel@caiaq.de>
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 6008fd5a
Loading
Loading
Loading
Loading
+2 −0
Original line number Original line Diff line number Diff line
@@ -65,6 +65,7 @@ config SND_USB_CAIAQ
	    * Native Instruments Guitar Rig Session I/O
	    * Native Instruments Guitar Rig Session I/O
	    * Native Instruments Guitar Rig mobile
	    * Native Instruments Guitar Rig mobile
	    * Native Instruments Traktor Kontrol X1
	    * Native Instruments Traktor Kontrol X1
	    * Native Instruments Traktor Kontrol S4


	   To compile this driver as a module, choose M here: the module
	   To compile this driver as a module, choose M here: the module
	   will be called snd-usb-caiaq.
	   will be called snd-usb-caiaq.
@@ -82,6 +83,7 @@ config SND_USB_CAIAQ_INPUT
	   * Native Instruments Kore Controller
	   * Native Instruments Kore Controller
	   * Native Instruments Kore Controller 2
	   * Native Instruments Kore Controller 2
	   * Native Instruments Audio Kontrol 1
	   * Native Instruments Audio Kontrol 1
	   * Native Instruments Traktor Kontrol S4


config SND_USB_US122L
config SND_USB_US122L
	tristate "Tascam US-122L USB driver"
	tristate "Tascam US-122L USB driver"
+160 −15
Original line number Original line Diff line number Diff line
@@ -111,7 +111,7 @@ static int stream_start(struct snd_usb_caiaqdev *dev)
	memset(dev->sub_capture, 0, sizeof(dev->sub_capture));
	memset(dev->sub_capture, 0, sizeof(dev->sub_capture));
	dev->input_panic = 0;
	dev->input_panic = 0;
	dev->output_panic = 0;
	dev->output_panic = 0;
	dev->first_packet = 1;
	dev->first_packet = 4;
	dev->streaming = 1;
	dev->streaming = 1;
	dev->warned = 0;
	dev->warned = 0;


@@ -201,12 +201,39 @@ static int snd_usb_caiaq_pcm_prepare(struct snd_pcm_substream *substream)
	debug("%s(%p)\n", __func__, substream);
	debug("%s(%p)\n", __func__, substream);


	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
		dev->period_out_count[index] = BYTES_PER_SAMPLE + 1;
		int out_pos;
		dev->audio_out_buf_pos[index] = BYTES_PER_SAMPLE + 1;

		switch (dev->spec.data_alignment) {
		case 0:
		case 2:
			out_pos = BYTES_PER_SAMPLE + 1;
			break;
		case 3:
		default:
			out_pos = 0;
			break;
		}

		dev->period_out_count[index] = out_pos;
		dev->audio_out_buf_pos[index] = out_pos;
	} else {
	} else {
		int in_pos = (dev->spec.data_alignment == 2) ? 0 : 2;
		int in_pos;
		dev->period_in_count[index] = BYTES_PER_SAMPLE + in_pos;

		dev->audio_in_buf_pos[index] = BYTES_PER_SAMPLE + in_pos;
		switch (dev->spec.data_alignment) {
		case 0:
			in_pos = BYTES_PER_SAMPLE + 2;
			break;
		case 2:
			in_pos = BYTES_PER_SAMPLE;
			break;
		case 3:
		default:
			in_pos = 0;
			break;
		}

		dev->period_in_count[index] = in_pos;
		dev->audio_in_buf_pos[index] = in_pos;
	}
	}


	if (dev->streaming)
	if (dev->streaming)
@@ -221,7 +248,7 @@ static int snd_usb_caiaq_pcm_prepare(struct snd_pcm_substream *substream)
	snd_pcm_limit_hw_rates(runtime);
	snd_pcm_limit_hw_rates(runtime);


	bytes_per_sample = BYTES_PER_SAMPLE;
	bytes_per_sample = BYTES_PER_SAMPLE;
	if (dev->spec.data_alignment == 2)
	if (dev->spec.data_alignment >= 2)
		bytes_per_sample++;
		bytes_per_sample++;


	bpp = ((runtime->rate / 8000) + CLOCK_DRIFT_TOLERANCE)
	bpp = ((runtime->rate / 8000) + CLOCK_DRIFT_TOLERANCE)
@@ -253,6 +280,8 @@ static int snd_usb_caiaq_pcm_trigger(struct snd_pcm_substream *sub, int cmd)
{
{
	struct snd_usb_caiaqdev *dev = snd_pcm_substream_chip(sub);
	struct snd_usb_caiaqdev *dev = snd_pcm_substream_chip(sub);


	debug("%s(%p) cmd %d\n", __func__, sub, cmd);

	switch (cmd) {
	switch (cmd) {
	case SNDRV_PCM_TRIGGER_START:
	case SNDRV_PCM_TRIGGER_START:
	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
@@ -402,6 +431,61 @@ static void read_in_urb_mode2(struct snd_usb_caiaqdev *dev,
	}
	}
}
}


static void read_in_urb_mode3(struct snd_usb_caiaqdev *dev,
			      const struct urb *urb,
			      const struct usb_iso_packet_descriptor *iso)
{
	unsigned char *usb_buf = urb->transfer_buffer + iso->offset;
	int stream, i;

	/* paranoia check */
	if (iso->actual_length % (BYTES_PER_SAMPLE_USB * CHANNELS_PER_STREAM))
		return;

	for (i = 0; i < iso->actual_length;) {
		for (stream = 0; stream < dev->n_streams; stream++) {
			struct snd_pcm_substream *sub = dev->sub_capture[stream];
			char *audio_buf = NULL;
			int c, n, sz = 0;

			if (sub && !dev->input_panic) {
				struct snd_pcm_runtime *rt = sub->runtime;
				audio_buf = rt->dma_area;
				sz = frames_to_bytes(rt, rt->buffer_size);
			}

			for (c = 0; c < CHANNELS_PER_STREAM; c++) {
				/* 3 audio data bytes, followed by 1 check byte */
				if (audio_buf) {
					for (n = 0; n < BYTES_PER_SAMPLE; n++) {
						audio_buf[dev->audio_in_buf_pos[stream]++] = usb_buf[i+n];

						if (dev->audio_in_buf_pos[stream] == sz)
							dev->audio_in_buf_pos[stream] = 0;
					}

					dev->period_in_count[stream] += BYTES_PER_SAMPLE;
				}

				i += BYTES_PER_SAMPLE;

				if (usb_buf[i] != ((stream << 1) | c) &&
				    !dev->first_packet) {
					if (!dev->input_panic)
						printk(" EXPECTED: %02x got %02x, c %d, stream %d, i %d\n",
							((stream << 1) | c), usb_buf[i], c, stream, i);
					dev->input_panic = 1;
				}

				i++;
			}
		}
	}

	if (dev->first_packet > 0)
		dev->first_packet--;
}

static void read_in_urb(struct snd_usb_caiaqdev *dev,
static void read_in_urb(struct snd_usb_caiaqdev *dev,
			const struct urb *urb,
			const struct urb *urb,
			const struct usb_iso_packet_descriptor *iso)
			const struct usb_iso_packet_descriptor *iso)
@@ -419,6 +503,9 @@ static void read_in_urb(struct snd_usb_caiaqdev *dev,
	case 2:
	case 2:
		read_in_urb_mode2(dev, urb, iso);
		read_in_urb_mode2(dev, urb, iso);
		break;
		break;
	case 3:
		read_in_urb_mode3(dev, urb, iso);
		break;
	}
	}


	if ((dev->input_panic || dev->output_panic) && !dev->warned) {
	if ((dev->input_panic || dev->output_panic) && !dev->warned) {
@@ -429,7 +516,7 @@ static void read_in_urb(struct snd_usb_caiaqdev *dev,
	}
	}
}
}


static void fill_out_urb(struct snd_usb_caiaqdev *dev,
static void fill_out_urb_mode_0(struct snd_usb_caiaqdev *dev,
				struct urb *urb,
				struct urb *urb,
				const struct usb_iso_packet_descriptor *iso)
				const struct usb_iso_packet_descriptor *iso)
{
{
@@ -463,6 +550,64 @@ static void fill_out_urb(struct snd_usb_caiaqdev *dev,
	}
	}
}
}


static void fill_out_urb_mode_3(struct snd_usb_caiaqdev *dev,
				struct urb *urb,
				const struct usb_iso_packet_descriptor *iso)
{
	unsigned char *usb_buf = urb->transfer_buffer + iso->offset;
	int stream, i;

	for (i = 0; i < iso->length;) {
		for (stream = 0; stream < dev->n_streams; stream++) {
			struct snd_pcm_substream *sub = dev->sub_playback[stream];
			char *audio_buf = NULL;
			int c, n, sz = 0;

			if (sub) {
				struct snd_pcm_runtime *rt = sub->runtime;
				audio_buf = rt->dma_area;
				sz = frames_to_bytes(rt, rt->buffer_size);
			}

			for (c = 0; c < CHANNELS_PER_STREAM; c++) {
				for (n = 0; n < BYTES_PER_SAMPLE; n++) {
					if (audio_buf) {
						usb_buf[i+n] = audio_buf[dev->audio_out_buf_pos[stream]++];

						if (dev->audio_out_buf_pos[stream] == sz)
							dev->audio_out_buf_pos[stream] = 0;
					} else {
						usb_buf[i+n] = 0;
					}
				}

				if (audio_buf)
					dev->period_out_count[stream] += BYTES_PER_SAMPLE;

				i += BYTES_PER_SAMPLE;

				/* fill in the check byte pattern */
				usb_buf[i++] = (stream << 1) | c;
			}
		}
	}
}

static inline void fill_out_urb(struct snd_usb_caiaqdev *dev,
				struct urb *urb,
				const struct usb_iso_packet_descriptor *iso)
{
	switch (dev->spec.data_alignment) {
	case 0:
	case 2:
		fill_out_urb_mode_0(dev, urb, iso);
		break;
	case 3:
		fill_out_urb_mode_3(dev, urb, iso);
		break;
	}
}

static void read_completed(struct urb *urb)
static void read_completed(struct urb *urb)
{
{
	struct snd_usb_caiaq_cb_info *info = urb->context;
	struct snd_usb_caiaq_cb_info *info = urb->context;
+203 −5
Original line number Original line Diff line number Diff line
@@ -55,6 +55,10 @@ static int control_info(struct snd_kcontrol *kcontrol,
	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1):
	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1):
		maxval = 127;
		maxval = 127;
		break;
		break;

	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4):
		maxval = 31;
		break;
	}
	}


	if (is_intval) {
	if (is_intval) {
@@ -93,6 +97,7 @@ static int control_put(struct snd_kcontrol *kcontrol,
	struct snd_usb_audio *chip = snd_kcontrol_chip(kcontrol);
	struct snd_usb_audio *chip = snd_kcontrol_chip(kcontrol);
	struct snd_usb_caiaqdev *dev = caiaqdev(chip->card);
	struct snd_usb_caiaqdev *dev = caiaqdev(chip->card);
	int pos = kcontrol->private_value;
	int pos = kcontrol->private_value;
	int v = ucontrol->value.integer.value[0];
	unsigned char cmd = EP1_CMD_WRITE_IO;
	unsigned char cmd = EP1_CMD_WRITE_IO;


	if (dev->chip.usb_id ==
	if (dev->chip.usb_id ==
@@ -100,12 +105,27 @@ static int control_put(struct snd_kcontrol *kcontrol,
		cmd = EP1_CMD_DIMM_LEDS;
		cmd = EP1_CMD_DIMM_LEDS;


	if (pos & CNT_INTVAL) {
	if (pos & CNT_INTVAL) {
		dev->control_state[pos & ~CNT_INTVAL]
		int i = pos & ~CNT_INTVAL;
			= ucontrol->value.integer.value[0];

		dev->control_state[i] = v;

		if (dev->chip.usb_id ==
			USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4)) {
			int actual_len;

			dev->ep8_out_buf[0] = i;
			dev->ep8_out_buf[1] = v;

			usb_bulk_msg(dev->chip.dev,
				     usb_sndbulkpipe(dev->chip.dev, 8),
				     dev->ep8_out_buf, sizeof(dev->ep8_out_buf),
				     &actual_len, 200);
		} else {
			snd_usb_caiaq_send_command(dev, cmd,
			snd_usb_caiaq_send_command(dev, cmd,
					dev->control_state, sizeof(dev->control_state));
					dev->control_state, sizeof(dev->control_state));
		}
	} else {
	} else {
		if (ucontrol->value.integer.value[0])
		if (v)
			dev->control_state[pos / 8] |= 1 << (pos % 8);
			dev->control_state[pos / 8] |= 1 << (pos % 8);
		else
		else
			dev->control_state[pos / 8] &= ~(1 << (pos % 8));
			dev->control_state[pos / 8] &= ~(1 << (pos % 8));
@@ -296,6 +316,179 @@ static struct caiaq_controller kontrolx1_controller[] = {
	{ "LED Deck B: SYNC",		8  | CNT_INTVAL	},
	{ "LED Deck B: SYNC",		8  | CNT_INTVAL	},
};
};


static struct caiaq_controller kontrols4_controller[] = {
	{ "LED: Master: Quant",			10  | CNT_INTVAL },
	{ "LED: Master: Headphone",		11  | CNT_INTVAL },
	{ "LED: Master: Master",		12  | CNT_INTVAL },
	{ "LED: Master: Snap",			14  | CNT_INTVAL },
	{ "LED: Master: Warning",		15  | CNT_INTVAL },
	{ "LED: Master: Master button",		112 | CNT_INTVAL },
	{ "LED: Master: Snap button",		113 | CNT_INTVAL },
	{ "LED: Master: Rec",			118 | CNT_INTVAL },
	{ "LED: Master: Size",			119 | CNT_INTVAL },
	{ "LED: Master: Quant button",		120 | CNT_INTVAL },
	{ "LED: Master: Browser button",	121 | CNT_INTVAL },
	{ "LED: Master: Play button",		126 | CNT_INTVAL },
	{ "LED: Master: Undo button",		127 | CNT_INTVAL },

	{ "LED: Channel A: >",			4   | CNT_INTVAL },
	{ "LED: Channel A: <",			5   | CNT_INTVAL },
	{ "LED: Channel A: Meter 1",		97  | CNT_INTVAL },
	{ "LED: Channel A: Meter 2",		98  | CNT_INTVAL },
	{ "LED: Channel A: Meter 3",		99  | CNT_INTVAL },
	{ "LED: Channel A: Meter 4",		100 | CNT_INTVAL },
	{ "LED: Channel A: Meter 5",		101 | CNT_INTVAL },
	{ "LED: Channel A: Meter 6",		102 | CNT_INTVAL },
	{ "LED: Channel A: Meter clip",		103 | CNT_INTVAL },
	{ "LED: Channel A: Active",		114 | CNT_INTVAL },
	{ "LED: Channel A: Cue",		116 | CNT_INTVAL },
	{ "LED: Channel A: FX1",		149 | CNT_INTVAL },
	{ "LED: Channel A: FX2",		148 | CNT_INTVAL },

	{ "LED: Channel B: >",			2   | CNT_INTVAL },
	{ "LED: Channel B: <",			3   | CNT_INTVAL },
	{ "LED: Channel B: Meter 1",		89  | CNT_INTVAL },
	{ "LED: Channel B: Meter 2",		90  | CNT_INTVAL },
	{ "LED: Channel B: Meter 3",		91  | CNT_INTVAL },
	{ "LED: Channel B: Meter 4",		92  | CNT_INTVAL },
	{ "LED: Channel B: Meter 5",		93  | CNT_INTVAL },
	{ "LED: Channel B: Meter 6",		94  | CNT_INTVAL },
	{ "LED: Channel B: Meter clip",		95  | CNT_INTVAL },
	{ "LED: Channel B: Active",		122 | CNT_INTVAL },
	{ "LED: Channel B: Cue",		125 | CNT_INTVAL },
	{ "LED: Channel B: FX1",		147 | CNT_INTVAL },
	{ "LED: Channel B: FX2",		146 | CNT_INTVAL },

	{ "LED: Channel C: >",			6   | CNT_INTVAL },
	{ "LED: Channel C: <",			7   | CNT_INTVAL },
	{ "LED: Channel C: Meter 1",		105 | CNT_INTVAL },
	{ "LED: Channel C: Meter 2",		106 | CNT_INTVAL },
	{ "LED: Channel C: Meter 3",		107 | CNT_INTVAL },
	{ "LED: Channel C: Meter 4",		108 | CNT_INTVAL },
	{ "LED: Channel C: Meter 5",		109 | CNT_INTVAL },
	{ "LED: Channel C: Meter 6",		110 | CNT_INTVAL },
	{ "LED: Channel C: Meter clip",		111 | CNT_INTVAL },
	{ "LED: Channel C: Active",		115 | CNT_INTVAL },
	{ "LED: Channel C: Cue",		117 | CNT_INTVAL },
	{ "LED: Channel C: FX1",		151 | CNT_INTVAL },
	{ "LED: Channel C: FX2",		150 | CNT_INTVAL },

	{ "LED: Channel D: >",			0   | CNT_INTVAL },
	{ "LED: Channel D: <",			1   | CNT_INTVAL },
	{ "LED: Channel D: Meter 1",		81  | CNT_INTVAL },
	{ "LED: Channel D: Meter 2",		82  | CNT_INTVAL },
	{ "LED: Channel D: Meter 3",		83  | CNT_INTVAL },
	{ "LED: Channel D: Meter 4",		84  | CNT_INTVAL },
	{ "LED: Channel D: Meter 5",		85  | CNT_INTVAL },
	{ "LED: Channel D: Meter 6",		86  | CNT_INTVAL },
	{ "LED: Channel D: Meter clip",		87  | CNT_INTVAL },
	{ "LED: Channel D: Active",		123 | CNT_INTVAL },
	{ "LED: Channel D: Cue",		124 | CNT_INTVAL },
	{ "LED: Channel D: FX1",		145 | CNT_INTVAL },
	{ "LED: Channel D: FX2",		144 | CNT_INTVAL },

	{ "LED: Deck A: 1 (blue)",		22  | CNT_INTVAL },
	{ "LED: Deck A: 1 (green)",		23  | CNT_INTVAL },
	{ "LED: Deck A: 2 (blue)",		20  | CNT_INTVAL },
	{ "LED: Deck A: 2 (green)",		21  | CNT_INTVAL },
	{ "LED: Deck A: 3 (blue)",		18  | CNT_INTVAL },
	{ "LED: Deck A: 3 (green)",		19  | CNT_INTVAL },
	{ "LED: Deck A: 4 (blue)",		16  | CNT_INTVAL },
	{ "LED: Deck A: 4 (green)",		17  | CNT_INTVAL },
	{ "LED: Deck A: Load",			44  | CNT_INTVAL },
	{ "LED: Deck A: Deck C button",		45  | CNT_INTVAL },
	{ "LED: Deck A: In",			47  | CNT_INTVAL },
	{ "LED: Deck A: Out",			46  | CNT_INTVAL },
	{ "LED: Deck A: Shift",			24  | CNT_INTVAL },
	{ "LED: Deck A: Sync",			27  | CNT_INTVAL },
	{ "LED: Deck A: Cue",			26  | CNT_INTVAL },
	{ "LED: Deck A: Play",			25  | CNT_INTVAL },
	{ "LED: Deck A: Tempo up",		33  | CNT_INTVAL },
	{ "LED: Deck A: Tempo down",		32  | CNT_INTVAL },
	{ "LED: Deck A: Master",		34  | CNT_INTVAL },
	{ "LED: Deck A: Keylock",		35  | CNT_INTVAL },
	{ "LED: Deck A: Deck A",		37  | CNT_INTVAL },
	{ "LED: Deck A: Deck C",		36  | CNT_INTVAL },
	{ "LED: Deck A: Samples",		38  | CNT_INTVAL },
	{ "LED: Deck A: On Air",		39  | CNT_INTVAL },
	{ "LED: Deck A: Sample 1",		31  | CNT_INTVAL },
	{ "LED: Deck A: Sample 2",		30  | CNT_INTVAL },
	{ "LED: Deck A: Sample 3",		29  | CNT_INTVAL },
	{ "LED: Deck A: Sample 4",		28  | CNT_INTVAL },
	{ "LED: Deck A: Digit 1 - A",		55  | CNT_INTVAL },
	{ "LED: Deck A: Digit 1 - B",		54  | CNT_INTVAL },
	{ "LED: Deck A: Digit 1 - C",		53  | CNT_INTVAL },
	{ "LED: Deck A: Digit 1 - D",		52  | CNT_INTVAL },
	{ "LED: Deck A: Digit 1 - E",		51  | CNT_INTVAL },
	{ "LED: Deck A: Digit 1 - F",		50  | CNT_INTVAL },
	{ "LED: Deck A: Digit 1 - G",		49  | CNT_INTVAL },
	{ "LED: Deck A: Digit 1 - dot",		48  | CNT_INTVAL },
	{ "LED: Deck A: Digit 2 - A",		63  | CNT_INTVAL },
	{ "LED: Deck A: Digit 2 - B",		62  | CNT_INTVAL },
	{ "LED: Deck A: Digit 2 - C",		61  | CNT_INTVAL },
	{ "LED: Deck A: Digit 2 - D",		60  | CNT_INTVAL },
	{ "LED: Deck A: Digit 2 - E",		59  | CNT_INTVAL },
	{ "LED: Deck A: Digit 2 - F",		58  | CNT_INTVAL },
	{ "LED: Deck A: Digit 2 - G",		57  | CNT_INTVAL },
	{ "LED: Deck A: Digit 2 - dot",		56  | CNT_INTVAL },

	{ "LED: Deck B: 1 (blue)",		78  | CNT_INTVAL },
	{ "LED: Deck B: 1 (green)",		79  | CNT_INTVAL },
	{ "LED: Deck B: 2 (blue)",		76  | CNT_INTVAL },
	{ "LED: Deck B: 2 (green)",		77  | CNT_INTVAL },
	{ "LED: Deck B: 3 (blue)",		74  | CNT_INTVAL },
	{ "LED: Deck B: 3 (green)",		75  | CNT_INTVAL },
	{ "LED: Deck B: 4 (blue)",		72  | CNT_INTVAL },
	{ "LED: Deck B: 4 (green)",		73  | CNT_INTVAL },
	{ "LED: Deck B: Load",			180 | CNT_INTVAL },
	{ "LED: Deck B: Deck D button",		181 | CNT_INTVAL },
	{ "LED: Deck B: In",			183 | CNT_INTVAL },
	{ "LED: Deck B: Out",			182 | CNT_INTVAL },
	{ "LED: Deck B: Shift",			64  | CNT_INTVAL },
	{ "LED: Deck B: Sync",			67  | CNT_INTVAL },
	{ "LED: Deck B: Cue",			66  | CNT_INTVAL },
	{ "LED: Deck B: Play",			65  | CNT_INTVAL },
	{ "LED: Deck B: Tempo up",		185 | CNT_INTVAL },
	{ "LED: Deck B: Tempo down",		184 | CNT_INTVAL },
	{ "LED: Deck B: Master",		186 | CNT_INTVAL },
	{ "LED: Deck B: Keylock",		187 | CNT_INTVAL },
	{ "LED: Deck B: Deck B",		189 | CNT_INTVAL },
	{ "LED: Deck B: Deck D",		188 | CNT_INTVAL },
	{ "LED: Deck B: Samples",		190 | CNT_INTVAL },
	{ "LED: Deck B: On Air",		191 | CNT_INTVAL },
	{ "LED: Deck B: Sample 1",		71  | CNT_INTVAL },
	{ "LED: Deck B: Sample 2",		70  | CNT_INTVAL },
	{ "LED: Deck B: Sample 3",		69  | CNT_INTVAL },
	{ "LED: Deck B: Sample 4",		68  | CNT_INTVAL },
	{ "LED: Deck B: Digit 1 - A",		175 | CNT_INTVAL },
	{ "LED: Deck B: Digit 1 - B",		174 | CNT_INTVAL },
	{ "LED: Deck B: Digit 1 - C",		173 | CNT_INTVAL },
	{ "LED: Deck B: Digit 1 - D",		172 | CNT_INTVAL },
	{ "LED: Deck B: Digit 1 - E",		171 | CNT_INTVAL },
	{ "LED: Deck B: Digit 1 - F",		170 | CNT_INTVAL },
	{ "LED: Deck B: Digit 1 - G",		169 | CNT_INTVAL },
	{ "LED: Deck B: Digit 1 - dot",		168 | CNT_INTVAL },
	{ "LED: Deck B: Digit 2 - A",		167 | CNT_INTVAL },
	{ "LED: Deck B: Digit 2 - B",		166 | CNT_INTVAL },
	{ "LED: Deck B: Digit 2 - C",		165 | CNT_INTVAL },
	{ "LED: Deck B: Digit 2 - D",		164 | CNT_INTVAL },
	{ "LED: Deck B: Digit 2 - E",		163 | CNT_INTVAL },
	{ "LED: Deck B: Digit 2 - F",		162 | CNT_INTVAL },
	{ "LED: Deck B: Digit 2 - G",		161 | CNT_INTVAL },
	{ "LED: Deck B: Digit 2 - dot",		160 | CNT_INTVAL },

	{ "LED: FX1: dry/wet",			153 | CNT_INTVAL },
	{ "LED: FX1: 1",			154 | CNT_INTVAL },
	{ "LED: FX1: 2",			155 | CNT_INTVAL },
	{ "LED: FX1: 3",			156 | CNT_INTVAL },
	{ "LED: FX1: Mode",			157 | CNT_INTVAL },
	{ "LED: FX2: dry/wet",			129 | CNT_INTVAL },
	{ "LED: FX2: 1",			130 | CNT_INTVAL },
	{ "LED: FX2: 2",			131 | CNT_INTVAL },
	{ "LED: FX2: 3",			132 | CNT_INTVAL },
	{ "LED: FX2: Mode",			133 | CNT_INTVAL },
};

static int __devinit add_controls(struct caiaq_controller *c, int num,
static int __devinit add_controls(struct caiaq_controller *c, int num,
				  struct snd_usb_caiaqdev *dev)
				  struct snd_usb_caiaqdev *dev)
{
{
@@ -354,6 +547,11 @@ int __devinit snd_usb_caiaq_control_init(struct snd_usb_caiaqdev *dev)
		ret = add_controls(kontrolx1_controller,
		ret = add_controls(kontrolx1_controller,
			ARRAY_SIZE(kontrolx1_controller), dev);
			ARRAY_SIZE(kontrolx1_controller), dev);
		break;
		break;

	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4):
		ret = add_controls(kontrols4_controller,
			ARRAY_SIZE(kontrols4_controller), dev);
		break;
	}
	}


	return ret;
	return ret;
+7 −1
Original line number Original line Diff line number Diff line
@@ -48,7 +48,8 @@ MODULE_SUPPORTED_DEVICE("{{Native Instruments, RigKontrol2},"
			 "{Native Instruments, Audio 8 DJ},"
			 "{Native Instruments, Audio 8 DJ},"
			 "{Native Instruments, Session I/O},"
			 "{Native Instruments, Session I/O},"
			 "{Native Instruments, GuitarRig mobile}"
			 "{Native Instruments, GuitarRig mobile}"
			 "{Native Instruments, Traktor Kontrol X1}");
			 "{Native Instruments, Traktor Kontrol X1}"
			 "{Native Instruments, Traktor Kontrol S4}");


static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-max */
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-max */
static char* id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* Id for this card */
static char* id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* Id for this card */
@@ -134,6 +135,11 @@ static struct usb_device_id snd_usb_id_table[] = {
		.idVendor =     USB_VID_NATIVEINSTRUMENTS,
		.idVendor =     USB_VID_NATIVEINSTRUMENTS,
		.idProduct =    USB_PID_TRAKTORKONTROLX1
		.idProduct =    USB_PID_TRAKTORKONTROLX1
	},
	},
	{
		.match_flags =  USB_DEVICE_ID_MATCH_DEVICE,
		.idVendor =     USB_VID_NATIVEINSTRUMENTS,
		.idProduct =    USB_PID_TRAKTORKONTROLS4
	},
	{ /* terminator */ }
	{ /* terminator */ }
};
};


+4 −2
Original line number Original line Diff line number Diff line
@@ -16,6 +16,7 @@
#define USB_PID_SESSIONIO		0x1915
#define USB_PID_SESSIONIO		0x1915
#define USB_PID_GUITARRIGMOBILE		0x0d8d
#define USB_PID_GUITARRIGMOBILE		0x0d8d
#define USB_PID_TRAKTORKONTROLX1	0x2305
#define USB_PID_TRAKTORKONTROLX1	0x2305
#define USB_PID_TRAKTORKONTROLS4	0xbaff


#define EP1_BUFSIZE 64
#define EP1_BUFSIZE 64
#define EP4_BUFSIZE 512
#define EP4_BUFSIZE 512
@@ -99,13 +100,14 @@ struct snd_usb_caiaqdev {
	struct snd_pcm_substream *sub_capture[MAX_STREAMS];
	struct snd_pcm_substream *sub_capture[MAX_STREAMS];


	/* Controls */
	/* Controls */
	unsigned char control_state[64];
	unsigned char control_state[256];
	unsigned char ep8_out_buf[2];


	/* Linux input */
	/* Linux input */
#ifdef CONFIG_SND_USB_CAIAQ_INPUT
#ifdef CONFIG_SND_USB_CAIAQ_INPUT
	struct input_dev *input_dev;
	struct input_dev *input_dev;
	char phys[64];			/* physical device path */
	char phys[64];			/* physical device path */
	unsigned short keycode[64];
	unsigned short keycode[128];
	struct urb *ep4_in_urb;
	struct urb *ep4_in_urb;
	unsigned char ep4_in_buf[EP4_BUFSIZE];
	unsigned char ep4_in_buf[EP4_BUFSIZE];
#endif
#endif
Loading