On Wed, 29 Oct 2003, Greg KH wrote:

> Hm, looks like this patch does 3 different things, right?  Care to send
> 3 different patches?  :)

This is the third of three.  It improves synchronization with hub_irq() 
and guarantees that the hub disconnect() routine doesn't exit until the 
URB's completion routine has finished.  This patch can wait until after 
2.6.0-final.

Alan Stern


===== hub.c 1.123 vs edited =====
--- 1.123/drivers/usb/core/hub.c        Mon Sep 22 12:37:50 2003
+++ edited/drivers/usb/core/hub.c       Wed Oct 29 15:51:32 2003
@@ -128,11 +128,18 @@
        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 */
-               return;
+               goto done;
 
        default:                /* presumably an error */
                /* Cause a hub reset after 10 consecutive errors */
@@ -150,18 +157,20 @@
        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)
                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 */
@@ -466,7 +475,8 @@
                message = "couldn't submit status urb";
                goto fail;
        }
-               
+       hub->urb_active = 1;
+
        /* Wake up khubd */
        wake_up(&khubd_wait);
 
@@ -485,11 +495,13 @@
 {
        struct usb_hub *hub = usb_get_intfdata (intf);
        unsigned long flags;
+       DECLARE_COMPLETION(urb_complete);
 
        if (!hub)
                return;
 
        spin_lock_irqsave(&hub_event_lock, flags);
+       hub->urb_complete = &urb_complete;
 
        /* Delete it and then reset it */
        list_del_init(&hub->event_list);
@@ -506,6 +518,8 @@
 
        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;
        }
===== hub.h 1.20 vs edited =====
--- 1.20/drivers/usb/core/hub.h Wed Jun 11 12:16:43 2003
+++ edited/drivers/usb/core/hub.h       Wed Oct 29 15:20:10 2003
@@ -172,6 +172,8 @@
 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];



-------------------------------------------------------
This SF.net email is sponsored by: SF.net Giveback Program.
Does SourceForge.net help you be more productive?  Does it
help you create better code?   SHARE THE LOVE, and help us help
YOU!  Click Here: http://sourceforge.net/donate/
_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to