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

Reply via email to