This patch demonstrates how usb_kill_urb() can be used to simplify a 
properly written driver.  The gyrations needed to synchronize khubd 
with disconnect() are greatly reduced.

Alan Stern



===== drivers/usb/core/hub.h 1.25 vs edited =====
--- 1.25/drivers/usb/core/hub.h Mon Apr 19 11:29:02 2004
+++ edited/drivers/usb/core/hub.h       Thu May 13 09:43:41 2004
@@ -188,8 +188,6 @@
 struct usb_hub {
        struct usb_interface    *intf;          /* the "real" device */
        struct urb              *urb;           /* for interrupt polling pipe */
-       struct completion       *urb_complete;  /* wait for urb to end */
-       unsigned int            urb_active:1;
 
        /* buffer for urb ... 1 bit each for hub and children, rounded up */
        char                    (*buffer)[(USB_MAXCHILDREN + 1 + 7) / 8];
===== drivers/usb/core/hub.c 1.149 vs edited =====
--- 1.149/drivers/usb/core/hub.c        Sun May  9 13:26:14 2004
+++ edited/drivers/usb/core/hub.c       Thu May 13 09:47:56 2004
@@ -231,18 +231,11 @@
        struct usb_hub *hub = (struct usb_hub *)urb->context;
        int status;
 
-       spin_lock(&hub_event_lock);
-       hub->urb_active = 0;
-       if (hub->urb_complete) {        /* disconnect or rmmod */
-               complete(hub->urb_complete);
-               goto done;
-       }
-
        switch (urb->status) {
        case -ENOENT:           /* synchronous unlink */
        case -ECONNRESET:       /* async unlink */
        case -ESHUTDOWN:        /* hardware going away */
-               goto done;
+               return;
 
        default:                /* presumably an error */
                /* Cause a hub reset after 10 consecutive errors */
@@ -260,20 +253,17 @@
        hub->nerrors = 0;
 
        /* Something happened, let khubd figure it out */
+       spin_lock(&hub_event_lock);
        if (list_empty(&hub->event_list)) {
                list_add(&hub->event_list, &hub_event_list);
                wake_up(&khubd_wait);
        }
+       spin_unlock(&hub_event_lock);
 
 resubmit:
        if ((status = usb_submit_urb (hub->urb, GFP_ATOMIC)) != 0
-                       /* ENODEV means we raced disconnect() */
-                       && status != -ENODEV)
+                       && status != -ENODEV && status != -EPERM)
                dev_err (&hub->intf->dev, "resubmit --> %d\n", urb->status);
-       if (status == 0)
-               hub->urb_active = 1;
-done:
-       spin_unlock(&hub_event_lock);
 }
 
 /* USB 2.0 spec Section 11.24.2.3 */
@@ -604,7 +594,6 @@
                message = "couldn't submit status urb";
                goto fail;
        }
-       hub->urb_active = 1;
 
        /* Wake up khubd */
        wake_up(&khubd_wait);
@@ -632,8 +621,6 @@
 static void hub_disconnect(struct usb_interface *intf)
 {
        struct usb_hub *hub = usb_get_intfdata (intf);
-       DECLARE_COMPLETION(urb_complete);
-       unsigned long flags;
 
        if (!hub)
                return;
@@ -642,14 +629,18 @@
                highspeed_hubs--;
 
        usb_set_intfdata (intf, NULL);
-       spin_lock_irqsave(&hub_event_lock, flags);
-       hub->urb_complete = &urb_complete;
+
+       if (hub->urb) {
+               usb_kill_urb(hub->urb);
+               usb_free_urb(hub->urb);
+               hub->urb = NULL;
+       }
 
        /* Delete it and then reset it */
+       spin_lock_irq(&hub_event_lock);
        list_del_init(&hub->event_list);
        list_del_init(&hub->hub_list);
-
-       spin_unlock_irqrestore(&hub_event_lock, flags);
+       spin_unlock_irq(&hub_event_lock);
 
        down(&hub->khubd_sem); /* Wait for khubd to leave this hub alone. */
        up(&hub->khubd_sem);
@@ -660,14 +651,6 @@
        if (hub->has_indicators || hub->tt.hub)
                flush_scheduled_work ();
 
-       if (hub->urb) {
-               usb_unlink_urb(hub->urb);
-               if (hub->urb_active)
-                       wait_for_completion(&urb_complete);
-               usb_free_urb(hub->urb);
-               hub->urb = NULL;
-       }
-
        if (hub->descriptor) {
                kfree(hub->descriptor);
                hub->descriptor = NULL;
@@ -810,7 +793,7 @@
 
        /* Attempt to reset the hub */
        if (hub->urb)
-               usb_unlink_urb(hub->urb);
+               usb_kill_urb(hub->urb);
        else
                return -1;
 



-------------------------------------------------------
This SF.Net email is sponsored by: SourceForge.net Broadband
Sign-up now for SourceForge Broadband and get the fastest
6.0/768 connection for only $19.95/mo for the first 3 months!
http://ads.osdn.com/?ad_id=2562&alloc_id=6184&op=click
_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to