ChangeSet 1.1504.2.10, 2003/12/08 17:08:03-08:00, [EMAIL PROTECTED] [PATCH] USB: Fix khubd synchronization
It improves synchronization with hub_irq() and guarantees that the hub disconnect() routine doesn't exit until the URB's completion routine has finished. drivers/usb/core/hub.c | 22 ++++++++++++++++++---- drivers/usb/core/hub.h | 2 ++ 2 files changed, 20 insertions(+), 4 deletions(-) diff -Nru a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c --- a/drivers/usb/core/hub.c Mon Dec 29 14:25:54 2003 +++ b/drivers/usb/core/hub.c Mon Dec 29 14:25:54 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); @@ -484,6 +494,7 @@ 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) @@ -491,6 +502,7 @@ usb_set_intfdata (intf, NULL); spin_lock_irqsave(&hub_event_lock, flags); + hub->urb_complete = &urb_complete; /* Delete it and then reset it */ list_del_init(&hub->event_list); @@ -507,6 +519,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; } diff -Nru a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h --- a/drivers/usb/core/hub.h Mon Dec 29 14:25:54 2003 +++ b/drivers/usb/core/hub.h Mon Dec 29 14:25:54 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: IBM Linux Tutorials. Become an expert in LINUX or just sharpen your skills. Sign up for IBM's Free Linux Tutorials. Learn everything from the bash shell to sys admin. Click now! http://ads.osdn.com/?ad_id78&alloc_id371&op=click _______________________________________________ [EMAIL PROTECTED] To unsubscribe, use the last form field at: https://lists.sourceforge.net/lists/listinfo/linux-usb-devel