X-Git-Url: https://git.karo-electronics.de/?a=blobdiff_plain;f=sound%2Fusb%2Fusbmidi.c;h=6676a177c99e3342117051a179c4588bdbdd0335;hb=83f7a2c118833d3738b4d162ea3c17d0bd8ffa94;hp=99295f9b76910eb9610243170dab6acdfcd2e971;hpb=0b662c64840fb281e5948ab6f9d60f84817277d0;p=karo-tx-linux.git diff --git a/sound/usb/usbmidi.c b/sound/usb/usbmidi.c index 99295f9b7691..6676a177c99e 100644 --- a/sound/usb/usbmidi.c +++ b/sound/usb/usbmidi.c @@ -35,7 +35,6 @@ * SUCH DAMAGE. */ -#include #include #include #include @@ -105,12 +104,14 @@ struct snd_usb_midi { struct usb_protocol_ops* usb_protocol_ops; struct list_head list; struct timer_list error_timer; + spinlock_t disc_lock; struct snd_usb_midi_endpoint { struct snd_usb_midi_out_endpoint *out; struct snd_usb_midi_in_endpoint *in; } endpoints[MIDI_MAX_ENDPOINTS]; unsigned long input_triggered; + unsigned char disconnected; }; struct snd_usb_midi_out_endpoint { @@ -307,6 +308,11 @@ static void snd_usbmidi_error_timer(unsigned long data) struct snd_usb_midi *umidi = (struct snd_usb_midi *)data; int i; + spin_lock(&umidi->disc_lock); + if (umidi->disconnected) { + spin_unlock(&umidi->disc_lock); + return; + } for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) { struct snd_usb_midi_in_endpoint *in = umidi->endpoints[i].in; if (in && in->error_resubmit) { @@ -317,6 +323,7 @@ static void snd_usbmidi_error_timer(unsigned long data) if (umidi->endpoints[i].out) snd_usbmidi_do_output(umidi->endpoints[i].out); } + spin_unlock(&umidi->disc_lock); } /* helper function to send static data that may not DMA-able */ @@ -406,6 +413,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 +593,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 @@ -963,8 +990,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; @@ -976,8 +1005,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); @@ -1022,7 +1057,14 @@ void snd_usbmidi_disconnect(struct list_head* p) int i; umidi = list_entry(p, struct snd_usb_midi, list); - del_timer_sync(&umidi->error_timer); + /* + * an URB's completion handler may start the timer and + * a timer may submit an URB. To reliably break the cycle + * a flag under lock must be used + */ + spin_lock_irq(&umidi->disc_lock); + umidi->disconnected = 1; + spin_unlock_irq(&umidi->disc_lock); for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) { struct snd_usb_midi_endpoint* ep = &umidi->endpoints[i]; if (ep->out) @@ -1035,6 +1077,7 @@ void snd_usbmidi_disconnect(struct list_head* p) if (ep->in) usb_kill_urb(ep->in->urb); } + del_timer_sync(&umidi->error_timer); } static void snd_usbmidi_rawmidi_free(struct snd_rawmidi *rmidi) @@ -1323,6 +1366,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); @@ -1336,6 +1386,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); @@ -1649,6 +1701,7 @@ int snd_usb_create_midi_interface(struct snd_usb_audio* chip, umidi->quirk = quirk; umidi->usb_protocol_ops = &snd_usbmidi_standard_ops; init_timer(&umidi->error_timer); + spin_lock_init(&umidi->disc_lock); umidi->error_timer.function = snd_usbmidi_error_timer; umidi->error_timer.data = (unsigned long)umidi; @@ -1690,6 +1743,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: