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