diff options
author | Clemens Ladisch <clemens@ladisch.de> | 2007-05-07 03:28:53 -0400 |
---|---|---|
committer | Jaroslav Kysela <perex@suse.cz> | 2007-05-11 10:56:17 -0400 |
commit | d05cc104320210e1c38ff9675c5038cffb2d86dc (patch) | |
tree | 2d2fecd77706207c66e5ae174374a28ec96e8ae1 /sound | |
parent | a91214589e6527b18f52bc0b31253f9dfb4665e6 (diff) |
[ALSA] usb-audio: work around broken M-Audio MidiSport Uno firmware
The firmware of the M-Audio USB Uno MIDI Interface has, at least in
hardware revision 1.25, a bug that garbles its USB output. When it
receives a Note On MIDI message that uses running status, the resulting
USB MIDI packet has a wrong CIN (4 instead of 9) and a wrong length
(2 bytes, the status byte is still missing).
This patch adds a workaround to track the CINs and the MIDI messages of
received USB MIDI packets to detect whether a packet with CIN 4 is a
correct SysEx packet or a buggy running status packet.
Signed-off-by: Clemens Ladisch <clemens@ladisch.de>
Signed-off-by: Jaroslav Kysela <perex@suse.cz>
Diffstat (limited to 'sound')
-rw-r--r-- | sound/usb/usbmidi.c | 52 |
1 files changed, 51 insertions, 1 deletions
diff --git a/sound/usb/usbmidi.c b/sound/usb/usbmidi.c index 24f5a26c5f0c..911f4482b5e1 100644 --- a/sound/usb/usbmidi.c +++ b/sound/usb/usbmidi.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * usbmidi.c - ALSA USB MIDI driver | 2 | * usbmidi.c - ALSA USB MIDI driver |
3 | * | 3 | * |
4 | * Copyright (c) 2002-2005 Clemens Ladisch | 4 | * Copyright (c) 2002-2007 Clemens Ladisch |
5 | * All rights reserved. | 5 | * All rights reserved. |
6 | * | 6 | * |
7 | * Based on the OSS usb-midi driver by NAGANO Daisuke, | 7 | * Based on the OSS usb-midi driver by NAGANO Daisuke, |
@@ -145,6 +145,7 @@ struct snd_usb_midi_in_endpoint { | |||
145 | struct urb* urb; | 145 | struct urb* urb; |
146 | struct usbmidi_in_port { | 146 | struct usbmidi_in_port { |
147 | struct snd_rawmidi_substream *substream; | 147 | struct snd_rawmidi_substream *substream; |
148 | u8 running_status_length; | ||
148 | } ports[0x10]; | 149 | } ports[0x10]; |
149 | u8 seen_f5; | 150 | u8 seen_f5; |
150 | u8 error_resubmit; | 151 | u8 error_resubmit; |
@@ -366,6 +367,46 @@ static void snd_usbmidi_midiman_input(struct snd_usb_midi_in_endpoint* ep, | |||
366 | } | 367 | } |
367 | 368 | ||
368 | /* | 369 | /* |
370 | * Buggy M-Audio device: running status on input results in a packet that has | ||
371 | * the data bytes but not the status byte and that is marked with CIN 4. | ||
372 | */ | ||
373 | static void snd_usbmidi_maudio_broken_running_status_input( | ||
374 | struct snd_usb_midi_in_endpoint* ep, | ||
375 | uint8_t* buffer, int buffer_length) | ||
376 | { | ||
377 | int i; | ||
378 | |||
379 | for (i = 0; i + 3 < buffer_length; i += 4) | ||
380 | if (buffer[i] != 0) { | ||
381 | int cable = buffer[i] >> 4; | ||
382 | u8 cin = buffer[i] & 0x0f; | ||
383 | struct usbmidi_in_port *port = &ep->ports[cable]; | ||
384 | int length; | ||
385 | |||
386 | length = snd_usbmidi_cin_length[cin]; | ||
387 | if (cin == 0xf && buffer[i + 1] >= 0xf8) | ||
388 | ; /* realtime msg: no running status change */ | ||
389 | else if (cin >= 0x8 && cin <= 0xe) | ||
390 | /* channel msg */ | ||
391 | port->running_status_length = length - 1; | ||
392 | else if (cin == 0x4 && | ||
393 | port->running_status_length != 0 && | ||
394 | buffer[i + 1] < 0x80) | ||
395 | /* CIN 4 that is not a SysEx */ | ||
396 | length = port->running_status_length; | ||
397 | else | ||
398 | /* | ||
399 | * All other msgs cannot begin running status. | ||
400 | * (A channel msg sent as two or three CIN 0xF | ||
401 | * packets could in theory, but this device | ||
402 | * doesn't use this format.) | ||
403 | */ | ||
404 | port->running_status_length = 0; | ||
405 | snd_usbmidi_input_data(ep, cable, &buffer[i + 1], length); | ||
406 | } | ||
407 | } | ||
408 | |||
409 | /* | ||
369 | * Adds one USB MIDI packet to the output buffer. | 410 | * Adds one USB MIDI packet to the output buffer. |
370 | */ | 411 | */ |
371 | static void snd_usbmidi_output_standard_packet(struct urb* urb, uint8_t p0, | 412 | static void snd_usbmidi_output_standard_packet(struct urb* urb, uint8_t p0, |
@@ -525,6 +566,12 @@ static struct usb_protocol_ops snd_usbmidi_midiman_ops = { | |||
525 | .output_packet = snd_usbmidi_output_midiman_packet, | 566 | .output_packet = snd_usbmidi_output_midiman_packet, |
526 | }; | 567 | }; |
527 | 568 | ||
569 | static struct usb_protocol_ops snd_usbmidi_maudio_broken_running_status_ops = { | ||
570 | .input = snd_usbmidi_maudio_broken_running_status_input, | ||
571 | .output = snd_usbmidi_standard_output, | ||
572 | .output_packet = snd_usbmidi_output_standard_packet, | ||
573 | }; | ||
574 | |||
528 | /* | 575 | /* |
529 | * Novation USB MIDI protocol: number of data bytes is in the first byte | 576 | * Novation USB MIDI protocol: number of data bytes is in the first byte |
530 | * (when receiving) (+1!) or in the second byte (when sending); data begins | 577 | * (when receiving) (+1!) or in the second byte (when sending); data begins |
@@ -1606,6 +1653,9 @@ int snd_usb_create_midi_interface(struct snd_usb_audio* chip, | |||
1606 | switch (quirk ? quirk->type : QUIRK_MIDI_STANDARD_INTERFACE) { | 1653 | switch (quirk ? quirk->type : QUIRK_MIDI_STANDARD_INTERFACE) { |
1607 | case QUIRK_MIDI_STANDARD_INTERFACE: | 1654 | case QUIRK_MIDI_STANDARD_INTERFACE: |
1608 | err = snd_usbmidi_get_ms_info(umidi, endpoints); | 1655 | err = snd_usbmidi_get_ms_info(umidi, endpoints); |
1656 | if (chip->usb_id == USB_ID(0x0763, 0x0150)) /* M-Audio Uno */ | ||
1657 | umidi->usb_protocol_ops = | ||
1658 | &snd_usbmidi_maudio_broken_running_status_ops; | ||
1609 | break; | 1659 | break; |
1610 | case QUIRK_MIDI_FIXED_ENDPOINT: | 1660 | case QUIRK_MIDI_FIXED_ENDPOINT: |
1611 | memcpy(&endpoints[0], quirk->data, | 1661 | memcpy(&endpoints[0], quirk->data, |