snd-usb-audio for Radikal Technologies SAC-2K

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Hi,

I'm working on getting the usb part of this very nice control surface to
work with alsa. I sniffed the usb traffic of the windows driver then
browsed the snd-usb-audio source code for clues.

I managed to get it partially working using a modified QUIRK_MIDI_EMAGIC
since the protocols are fairly similar (at least the 0xF5 port switching
part).

Please find attached the patch I came up to.

I have a few problems and dark areas I hope you'll be able to light up a
little :

First, I more or less get the picture of what the code is doing but
there's one part I fiddled with that I don't understand fully. What are
the .out_cables and .in_cables bitmasks doing besides defining the
number of ports ?

Next, the input part seem to work flawlessly on all ports, but I have
what seems to be a buffer overflow on the device when outputting midi
data. Comparing the windows and linux usb traffic, something obvious
shows up : the windows driver seem to be waiting for the device's
acknowledgment after each sent byte before sending the next one while
the snd-usb-audio module sends a bunch of bytes at once that ends up
confusing the device _and_ module. How can I make it behave like the
windows driver ?

I have traffic and error logs available if needed.

Thanks.
- -- 
RaphaÃl Doursenaud
http://raphael.doursenaud.fr
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.16 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iEYEARECAAYFAky+oqQACgkQaZKmNAdXaVUopgCgifnK+eSsCNpR5rx21iUqmXBQ
wJIAoJlt4h7Tp8tYYSbg9ZfLekE1QQfL
=d7vi
-----END PGP SIGNATURE-----
diff -Nurp linux-2.6.36-rc6/sound/usb/midi.c linux-2.6.36-rc6.patched/sound/usb/midi.c
--- linux-2.6.36-rc6/sound/usb/midi.c	2010-09-29 03:01:22.000000000 +0200
+++ linux-2.6.36-rc6.patched/sound/usb/midi.c	2010-10-18 00:16:43.146000091 +0200
@@ -59,7 +59,7 @@
 /*
  * define this to log all USB packets
  */
-/* #define DUMP_PACKETS */
+#define DUMP_PACKETS
 
 /*
  * how long to wait after some USB errors, so that khubd can disconnect() us
@@ -987,6 +987,108 @@ static struct usb_protocol_ops snd_usbmi
 	.finish_out_endpoint = snd_usbmidi_emagic_finish_out,
 };
 
+/*
+ * Radikal USB MIDI protocol: raw MIDI with "F5 xx" port switching and "FF" padded data.
+ */
+
+static void snd_usbmidi_radikal_input(struct snd_usb_midi_in_endpoint* ep,
+				     uint8_t* buffer, int buffer_length)
+{
+	int i;
+
+	/* 0xFF indicates end of valid data */
+	for (i = 0; i < buffer_length; ++i)
+		if (buffer[i] == 0xff) {
+			buffer_length = i;
+			break;
+		}
+
+	/* handle 0xF5 at end of last buffer */
+	if (ep->seen_f5)
+		goto switch_port;
+
+	while (buffer_length > 0) {
+		/* determine size of data until next 0xF5 */
+		for (i = 0; i < buffer_length; ++i)
+			if (buffer[i] == 0xf5)
+				break;
+		snd_usbmidi_input_data(ep, ep->current_port, buffer, i);
+		buffer += i;
+		buffer_length -= i;
+
+		if (buffer_length <= 0)
+			break;
+		ep->seen_f5 = 1;
+		++buffer;
+		--buffer_length;
+
+	switch_port:
+		if (buffer_length <= 0)
+			break;
+		if (buffer[0] < 0x80) {
+			ep->current_port = (buffer[0] - 1) & 15;
+			++buffer;
+			--buffer_length;
+		}
+		ep->seen_f5 = 0;
+	}
+}
+
+static void snd_usbmidi_radikal_output(struct snd_usb_midi_out_endpoint* ep,
+				      struct urb *urb)
+{
+	int port0 = ep->current_port;
+	uint8_t* buf = urb->transfer_buffer;
+	int buf_free = ep->max_transfer;
+	int length, i;
+
+	for (i = 0; i < 0x10; ++i) {
+		/* round-robin, starting at the last current port */
+		int portnum = (port0 + i) & 15;
+		struct usbmidi_out_port* port = &ep->ports[portnum];
+
+		if (!port->active)
+			continue;
+		if (snd_rawmidi_transmit_peek(port->substream, buf, 1) != 1) {
+			port->active = 0;
+			continue;
+		}
+
+		if (portnum != ep->current_port) {
+			if (buf_free < 2)
+				break;
+			ep->current_port = portnum;
+			buf[0] = 0xf5;
+			buf[1] = (portnum + 1) & 15;
+			buf += 2;
+			buf_free -= 2;
+		}
+
+		if (buf_free < 1)
+			break;
+		length = snd_rawmidi_transmit(port->substream, buf, buf_free);
+		if (length > 0) {
+			buf += length;
+			buf_free -= length;
+			if (buf_free < 1)
+				break;
+		}
+	}
+
+	/* pad remaining bytes with 0xFF */
+	while (buf_free < ep->max_transfer && buf_free > 0) {
+		*buf = 0xff;
+		++buf;
+		--buf_free;
+	}
+	urb->transfer_buffer_length = ep->max_transfer - buf_free;
+}
+
+static struct usb_protocol_ops snd_usbmidi_radikal_ops = {
+	.input = snd_usbmidi_radikal_input,
+	.output = snd_usbmidi_radikal_output,
+};
+
 
 static void update_roland_altsetting(struct snd_usb_midi* umidi)
 {
@@ -1533,6 +1635,13 @@ static struct port_info {
 	EXTERNAL_PORT(0x086a, 0x0001, 8, "%s Broadcast"),
 	EXTERNAL_PORT(0x086a, 0x0002, 8, "%s Broadcast"),
 	EXTERNAL_PORT(0x086a, 0x0003, 4, "%s Broadcast"),
+	/* Radikal Technologies */
+	CONTROL_PORT(0x0a35, 0x002a, 0, "%s Control"),
+	EXTERNAL_PORT(0x0a35, 0x002a, 1, "%s MIDI"),
+	CONTROL_PORT(0x0a35, 0x002a, 2, "%s Instrument 3"),
+	CONTROL_PORT(0x0a35, 0x002a, 3, "%s Instrument 4"),
+	CONTROL_PORT(0x0a35, 0x002a, 4, "%s Instrument 5"),
+	CONTROL_PORT(0x0a35, 0x002a, 5, "%s Config"),
 	/* Akai MPD16 */
 	CONTROL_PORT(0x09e8, 0x0062, 0, "%s Control"),
 	PORT_INFO(0x09e8, 0x0062, 1, "%s MIDI", 0,
@@ -2134,6 +2243,12 @@ int snd_usbmidi_create(struct snd_card *
 		memcpy(&endpoints[0], quirk->data,
 		       sizeof(struct snd_usb_midi_endpoint_info));
 		err = snd_usbmidi_detect_endpoints(umidi, &endpoints[0], 1);
+		break;
+	case QUIRK_MIDI_RADIKAL:
+		umidi->usb_protocol_ops = &snd_usbmidi_radikal_ops;
+		memcpy(&endpoints[0], quirk->data,
+		       sizeof(struct snd_usb_midi_endpoint_info));
+		err = snd_usbmidi_detect_endpoints(umidi, &endpoints[0], 1);
 		break;
 	case QUIRK_MIDI_CME:
 		umidi->usb_protocol_ops = &snd_usbmidi_cme_ops;
diff -Nurp linux-2.6.36-rc6/sound/usb/midi.h linux-2.6.36-rc6.patched/sound/usb/midi.h
--- linux-2.6.36-rc6/sound/usb/midi.h	2010-09-29 03:01:22.000000000 +0200
+++ linux-2.6.36-rc6.patched/sound/usb/midi.h	2010-10-17 03:54:25.066000034 +0200
@@ -35,6 +35,9 @@ struct snd_usb_midi_endpoint_info {
 /* for QUIRK_MIDI_EMAGIC, data points to a snd_usb_midi_endpoint_info
  * structure (out_cables and in_cables only) */
 
+/* for QUIRK_MIDI_RADIKAL, data points to a snd_usb_midi_endpoint_info
+ * structure (out_cables and in_cables only) */
+
 /* for QUIRK_MIDI_CME, data is NULL */
 
 /* for QUIRK_MIDI_AKAI, data is NULL */
diff -Nurp linux-2.6.36-rc6/sound/usb/quirks-table.h linux-2.6.36-rc6.patched/sound/usb/quirks-table.h
--- linux-2.6.36-rc6/sound/usb/quirks-table.h	2010-09-29 03:01:22.000000000 +0200
+++ linux-2.6.36-rc6.patched/sound/usb/quirks-table.h	2010-10-17 04:39:49.509000034 +0200
@@ -1972,6 +1972,37 @@ YAMAHA_DEVICE(0x7010, "UB99"),
 		}
 	}
 },
+/* Radikal Technologies devices */
+{
+	USB_DEVICE(0x0a35, 0x002a),
+	.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+		.vendor_name = "Radikal Technologies",
+		.product_name = "SAC-2K",
+		.ifnum = QUIRK_ANY_INTERFACE,
+		.type = QUIRK_COMPOSITE,
+		.data = (const struct snd_usb_audio_quirk[]) {
+			{
+				.ifnum = 0,
+				.type = QUIRK_IGNORE_INTERFACE
+			},
+			{
+				.ifnum = 1,
+				.type = QUIRK_IGNORE_INTERFACE
+			},
+			{
+				.ifnum = 2,
+				.type = QUIRK_MIDI_RADIKAL,
+				.data = & (const struct snd_usb_midi_endpoint_info) {
+					.out_cables = 0x801f,
+					.in_cables  = 0x801f
+				}
+			},
+			{
+				.ifnum = -1
+			}
+		}
+	}
+},
 
 /* AKAI devices */
 {
diff -Nurp linux-2.6.36-rc6/sound/usb/quirks.c linux-2.6.36-rc6.patched/sound/usb/quirks.c
--- linux-2.6.36-rc6/sound/usb/quirks.c	2010-09-29 03:01:22.000000000 +0200
+++ linux-2.6.36-rc6.patched/sound/usb/quirks.c	2010-10-17 03:54:28.202000034 +0200
@@ -289,6 +289,7 @@ int snd_usb_create_quirk(struct snd_usb_
 		[QUIRK_MIDI_NOVATION] = create_any_midi_quirk,
 		[QUIRK_MIDI_FASTLANE] = create_any_midi_quirk,
 		[QUIRK_MIDI_EMAGIC] = create_any_midi_quirk,
+		[QUIRK_MIDI_RADIKAL] = create_any_midi_quirk,
 		[QUIRK_MIDI_CME] = create_any_midi_quirk,
 		[QUIRK_MIDI_AKAI] = create_any_midi_quirk,
 		[QUIRK_AUDIO_STANDARD_INTERFACE] = create_standard_audio_quirk,
diff -Nurp linux-2.6.36-rc6/sound/usb/usbaudio.h linux-2.6.36-rc6.patched/sound/usb/usbaudio.h
--- linux-2.6.36-rc6/sound/usb/usbaudio.h	2010-09-29 03:01:22.000000000 +0200
+++ linux-2.6.36-rc6.patched/sound/usb/usbaudio.h	2010-10-17 03:54:37.210000034 +0200
@@ -72,6 +72,7 @@ enum quirk_type {
 	QUIRK_MIDI_NOVATION,
 	QUIRK_MIDI_FASTLANE,
 	QUIRK_MIDI_EMAGIC,
+	QUIRK_MIDI_RADIKAL,
 	QUIRK_MIDI_CME,
 	QUIRK_MIDI_AKAI,
 	QUIRK_MIDI_US122L,
begin:vcard
fn;quoted-printable:Rapha=C3=ABl Doursenaud
n;quoted-printable:Doursenaud;Rapha=C3=ABl
email;internet:raphael@xxxxxxxxxxxxx
url:http://raphael.doursenaud.fr
version:2.1
end:vcard

_______________________________________________
Alsa-devel mailing list
Alsa-devel@xxxxxxxxxxxxxxxx
http://mailman.alsa-project.org/mailman/listinfo/alsa-devel

[Index of Archives]     [ALSA User]     [Linux Audio Users]     [Kernel Archive]     [Asterisk PBX]     [Photo Sharing]     [Linux Sound]     [Video 4 Linux]     [Gimp]     [Yosemite News]

  Powered by Linux