From 61870aed229519e7cd7f1899a19e4e7c8ba915e4 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Thu, 16 Aug 2007 08:44:51 +0200 Subject: [ALSA] usb-audio: fix parsing of SysEx messages from CME keyboards When CME keyboards send a SysEx message (e.g. master volume), the USB packet uses a format different from the standard format. Parsing this packet according to the specification corrupts the SysEx message itself and can cause the following MIDI messages to be misinterpreted, too. This patch adds a workaround for this case. Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela --- sound/usb/usbmidi.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'sound/usb/usbmidi.c') diff --git a/sound/usb/usbmidi.c b/sound/usb/usbmidi.c index 99295f9b769..2bb1834a8c2 100644 --- a/sound/usb/usbmidi.c +++ b/sound/usb/usbmidi.c @@ -406,6 +406,20 @@ static void snd_usbmidi_maudio_broken_running_status_input( } } +/* + * CME protocol: like the standard protocol, but SysEx commands are sent as a + * single USB packet preceded by a 0x0F byte. + */ +static void snd_usbmidi_cme_input(struct snd_usb_midi_in_endpoint *ep, + uint8_t *buffer, int buffer_length) +{ + if (buffer_length < 2 || (buffer[0] & 0x0f) != 0x0f) + snd_usbmidi_standard_input(ep, buffer, buffer_length); + else + snd_usbmidi_input_data(ep, buffer[0] >> 4, + &buffer[1], buffer_length - 1); +} + /* * Adds one USB MIDI packet to the output buffer. */ @@ -572,6 +586,12 @@ static struct usb_protocol_ops snd_usbmidi_maudio_broken_running_status_ops = { .output_packet = snd_usbmidi_output_standard_packet, }; +static struct usb_protocol_ops snd_usbmidi_cme_ops = { + .input = snd_usbmidi_cme_input, + .output = snd_usbmidi_standard_output, + .output_packet = snd_usbmidi_output_standard_packet, +}; + /* * Novation USB MIDI protocol: number of data bytes is in the first byte * (when receiving) (+1!) or in the second byte (when sending); data begins @@ -1690,6 +1710,7 @@ int snd_usb_create_midi_interface(struct snd_usb_audio* chip, err = snd_usbmidi_detect_endpoints(umidi, &endpoints[0], 1); break; case QUIRK_MIDI_CME: + umidi->usb_protocol_ops = &snd_usbmidi_cme_ops; err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints); break; default: -- cgit v1.2.3 From a6a712aeb17ff30206ae1bc827d50497d884602a Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Tue, 21 Aug 2007 08:56:08 +0200 Subject: [ALSA] usb-audio: allow output interrupt transfers for MIDI Allow output interrupt transfers for some MIDI devices that require them. Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela --- sound/usb/usbmidi.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'sound/usb/usbmidi.c') diff --git a/sound/usb/usbmidi.c b/sound/usb/usbmidi.c index 2bb1834a8c2..4bacb50e9ad 100644 --- a/sound/usb/usbmidi.c +++ b/sound/usb/usbmidi.c @@ -983,8 +983,10 @@ static int snd_usbmidi_out_endpoint_create(struct snd_usb_midi* umidi, snd_usbmidi_out_endpoint_delete(ep); return -ENOMEM; } - /* we never use interrupt output pipes */ - pipe = usb_sndbulkpipe(umidi->chip->dev, ep_info->out_ep); + if (ep_info->out_interval) + pipe = usb_sndintpipe(umidi->chip->dev, ep_info->out_ep); + else + pipe = usb_sndbulkpipe(umidi->chip->dev, ep_info->out_ep); if (umidi->chip->usb_id == USB_ID(0x0a92, 0x1020)) /* ESI M4U */ /* FIXME: we need more URBs to get reasonable bandwidth here: */ ep->max_transfer = 4; @@ -996,8 +998,14 @@ static int snd_usbmidi_out_endpoint_create(struct snd_usb_midi* umidi, snd_usbmidi_out_endpoint_delete(ep); return -ENOMEM; } - usb_fill_bulk_urb(ep->urb, umidi->chip->dev, pipe, buffer, - ep->max_transfer, snd_usbmidi_out_urb_complete, ep); + if (ep_info->out_interval) + usb_fill_int_urb(ep->urb, umidi->chip->dev, pipe, buffer, + ep->max_transfer, snd_usbmidi_out_urb_complete, + ep, ep_info->out_interval); + else + usb_fill_bulk_urb(ep->urb, umidi->chip->dev, + pipe, buffer, ep->max_transfer, + snd_usbmidi_out_urb_complete, ep); ep->urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP; spin_lock_init(&ep->buffer_lock); -- cgit v1.2.3 From 56162aabb2fb8b9f4a8266feb7eb4edd9d1a4d49 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Tue, 21 Aug 2007 08:57:34 +0200 Subject: [ALSA] usb-audio: add workaround for ESI MIDI Mate/RomIO II Force low speed USB MIDI devices like the ESI MIDI Mate and RomIO II to use interrupt transfers because the USB core would not be happy about low speed bulk transfers. Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela --- sound/usb/usbmidi.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'sound/usb/usbmidi.c') diff --git a/sound/usb/usbmidi.c b/sound/usb/usbmidi.c index 4bacb50e9ad..6330788c1c2 100644 --- a/sound/usb/usbmidi.c +++ b/sound/usb/usbmidi.c @@ -1351,6 +1351,13 @@ static int snd_usbmidi_get_ms_info(struct snd_usb_midi* umidi, endpoints[epidx].out_ep = ep->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; if ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT) endpoints[epidx].out_interval = ep->bInterval; + else if (snd_usb_get_speed(umidi->chip->dev) == USB_SPEED_LOW) + /* + * Low speed bulk transfers don't exist, so + * force interrupt transfers for devices like + * ESI MIDI Mate that try to use them anyway. + */ + endpoints[epidx].out_interval = 1; endpoints[epidx].out_cables = (1 << ms_ep->bNumEmbMIDIJack) - 1; snd_printdd(KERN_INFO "EP %02X: %d jack(s)\n", ep->bEndpointAddress, ms_ep->bNumEmbMIDIJack); @@ -1364,6 +1371,8 @@ static int snd_usbmidi_get_ms_info(struct snd_usb_midi* umidi, endpoints[epidx].in_ep = ep->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; if ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT) endpoints[epidx].in_interval = ep->bInterval; + else if (snd_usb_get_speed(umidi->chip->dev) == USB_SPEED_LOW) + endpoints[epidx].in_interval = 1; endpoints[epidx].in_cables = (1 << ms_ep->bNumEmbMIDIJack) - 1; snd_printdd(KERN_INFO "EP %02X: %d jack(s)\n", ep->bEndpointAddress, ms_ep->bNumEmbMIDIJack); -- cgit v1.2.3