Colin Fletcher wrote: > I'll be very glad to test any clever patches, though...
If you don't want to wait for the public SourceForge CVS ... --- alsa-kernel/usb/usbmidi.c 25 Jul 2005 15:17:40 -0000 1.51 +++ alsa-kernel/usb/usbmidi.c 2 Aug 2005 14:26:52 -0000 1.52 @@ -44,6 +44,7 @@ #include <linux/string.h> #include <linux/init.h> #include <linux/slab.h> +#include <linux/timer.h> #include <linux/usb.h> #include <sound/core.h> #include <sound/minors.h> @@ -56,6 +57,12 @@ */ /* #define DUMP_PACKETS */ +/* + * how long to wait after some USB errors, so that khubd can disconnect() us + * without too many spurious errors + */ +#define ERROR_DELAY_JIFFIES (HZ / 10) + MODULE_AUTHOR("Clemens Ladisch <[EMAIL PROTECTED]>"); MODULE_DESCRIPTION("USB Audio/MIDI helper module"); @@ -100,6 +107,7 @@ snd_rawmidi_t* rmidi; struct usb_protocol_ops* usb_protocol_ops; struct list_head list; + struct timer_list error_timer; struct snd_usb_midi_endpoint { snd_usb_midi_out_endpoint_t *out; @@ -141,7 +149,8 @@ struct usbmidi_in_port { snd_rawmidi_substream_t* substream; } ports[0x10]; - int seen_f5; + u8 seen_f5; + u8 error_resubmit; int current_port; }; @@ -167,14 +176,22 @@ */ static int snd_usbmidi_urb_error(int status) { - if (status == -ENOENT) - return status; /* killed */ - if (status == -EILSEQ || - status == -ECONNRESET || - status == -ETIMEDOUT) - return -ENODEV; /* device removed/shutdown */ - snd_printk(KERN_ERR "urb status %d\n", status); - return 0; /* continue */ + switch (status) { + /* manually unlinked, or device gone */ + case -ENOENT: + case -ECONNRESET: + case -ESHUTDOWN: + case -ENODEV: + return -ENODEV; + /* errors that might occur during unplugging */ + case -EPROTO: /* EHCI */ + case -ETIMEDOUT: /* OHCI */ + case -EILSEQ: /* UHCI */ + return -EIO; + default: + snd_printk(KERN_ERR "urb status %d\n", status); + return 0; /* continue */ + } } /* @@ -218,8 +235,15 @@ ep->umidi->usb_protocol_ops->input(ep, urb->transfer_buffer, urb->actual_length); } else { - if (snd_usbmidi_urb_error(urb->status) < 0) + int err = snd_usbmidi_urb_error(urb->status); + if (err < 0) { + if (err != -ENODEV) { + ep->error_resubmit = 1; + mod_timer(&ep->umidi->error_timer, + jiffies + ERROR_DELAY_JIFFIES); + } return; + } } if (usb_pipe_needs_resubmit(urb->pipe)) { @@ -236,8 +260,13 @@ ep->urb_active = 0; spin_unlock(&ep->buffer_lock); if (urb->status < 0) { - if (snd_usbmidi_urb_error(urb->status) < 0) + int err = snd_usbmidi_urb_error(urb->status); + if (err < 0) { + if (err != -ENODEV) + mod_timer(&ep->umidi->error_timer, + jiffies + ERROR_DELAY_JIFFIES); return; + } } snd_usbmidi_do_output(ep); } @@ -276,6 +305,24 @@ snd_usbmidi_do_output(ep); } +/* called after transfers had been interrupted due to some USB error */ +static void snd_usbmidi_error_timer(unsigned long data) +{ + snd_usb_midi_t *umidi = (snd_usb_midi_t *)data; + int i; + + for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) { + snd_usb_midi_in_endpoint_t *in = umidi->endpoints[i].in; + if (in && in->error_resubmit) { + in->error_resubmit = 0; + in->urb->dev = umidi->chip->dev; + snd_usbmidi_submit_urb(in->urb, GFP_ATOMIC); + } + if (umidi->endpoints[i].out) + snd_usbmidi_do_output(umidi->endpoints[i].out); + } +} + /* helper function to send static data that may not DMA-able */ static int send_bulk_static_data(snd_usb_midi_out_endpoint_t* ep, const void *data, int len) @@ -832,8 +879,6 @@ */ static void snd_usbmidi_out_endpoint_delete(snd_usb_midi_out_endpoint_t* ep) { - if (ep->tasklet.func) - tasklet_kill(&ep->tasklet); if (ep->urb) { kfree(ep->urb->transfer_buffer); usb_free_urb(ep->urb); @@ -918,8 +963,11 @@ int i; umidi = list_entry(p, snd_usb_midi_t, list); + del_timer_sync(&umidi->error_timer); for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) { snd_usb_midi_endpoint_t* ep = &umidi->endpoints[i]; + if (ep->out) + tasklet_kill(&ep->out->tasklet); if (ep->out && ep->out->urb) { usb_kill_urb(ep->out->urb); if (umidi->usb_protocol_ops->finish_out_endpoint) @@ -1480,6 +1528,9 @@ umidi->iface = iface; umidi->quirk = quirk; umidi->usb_protocol_ops = &snd_usbmidi_standard_ops; + init_timer(&umidi->error_timer); + umidi->error_timer.function = snd_usbmidi_error_timer; + umidi->error_timer.data = (unsigned long)umidi; /* detect the endpoint(s) to use */ memset(endpoints, 0, sizeof(endpoints)); ------------------------------------------------------- SF.Net email is sponsored by: Discover Easy Linux Migration Strategies from IBM. Find simple to follow Roadmaps, straightforward articles, informative Webcasts and more! Get everything you need to get up to speed, fast. http://ads.osdn.com/?ad_id=7477&alloc_id=16492&op=click _______________________________________________ linux-usb-devel@lists.sourceforge.net To unsubscribe, use the last form field at: https://lists.sourceforge.net/lists/listinfo/linux-usb-devel