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,