From: "Raphaël Doursenaud" <rdoursenaud@free.fr>
To: alsa-devel@alsa-project.org
Subject: snd-usb-audio for Radikal Technologies SAC-2K
Date: Wed, 20 Oct 2010 10:04:53 +0200 [thread overview]
Message-ID: <4CBEA2A5.7070902@free.fr> (raw)
[-- Attachment #1: Type: text/plain, Size: 1677 bytes --]
-----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-----
[-- Attachment #2: sac-2K.patch --]
[-- Type: text/plain, Size: 6950 bytes --]
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,
[-- Attachment #3: rdoursenaud.vcf --]
[-- Type: text/x-vcard, Size: 200 bytes --]
begin:vcard
fn;quoted-printable:Rapha=C3=ABl Doursenaud
n;quoted-printable:Doursenaud;Rapha=C3=ABl
email;internet:raphael@doursenaud.fr
url:http://raphael.doursenaud.fr
version:2.1
end:vcard
[-- Attachment #4: Type: text/plain, Size: 160 bytes --]
_______________________________________________
Alsa-devel mailing list
Alsa-devel@alsa-project.org
http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
next reply other threads:[~2010-10-20 8:07 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2010-10-20 8:04 Raphaël Doursenaud [this message]
2010-10-20 9:29 ` snd-usb-audio for Radikal Technologies SAC-2K Clemens Ladisch
2010-10-20 11:10 ` Raphaël Doursenaud
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4CBEA2A5.7070902@free.fr \
--to=rdoursenaud@free.fr \
--cc=alsa-devel@alsa-project.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.