ChangeSet 1.1757.66.3, 2004/07/14 14:29:19-07:00, stern@rowland.harvard.edu [PATCH] USB: Make hub driver use usb_kill_urb() This is a rerun of as278, updated to match the current source. It changes the hub driver, replacing calls to synchronous usb_unlink_urb() with usb_kill_urb() and removing the machinery formerly needed to synchronize the status URB handler with the rest of the driver. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman drivers/usb/core/hub.c | 40 ++++++++++++---------------------------- drivers/usb/core/hub.h | 2 -- 2 files changed, 12 insertions(+), 30 deletions(-) diff -Nru a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c --- a/drivers/usb/core/hub.c 2004-07-14 16:46:08 -07:00 +++ b/drivers/usb/core/hub.c 2004-07-14 16:46:08 -07:00 @@ -234,18 +234,11 @@ int i; unsigned long bits; - 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 */ @@ -268,20 +261,17 @@ hub->nerrors = 0; /* Something happened, let khubd figure it out */ + spin_lock(&hub_event_lock); if (list_empty(&hub->event_list)) { list_add_tail(&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", status); - if (status == 0) - hub->urb_active = 1; -done: - spin_unlock(&hub_event_lock); } /* USB 2.0 spec Section 11.24.2.3 */ @@ -612,7 +602,6 @@ message = "couldn't submit status urb"; goto fail; } - hub->urb_active = 1; /* Wake up khubd */ wake_up(&khubd_wait); @@ -640,7 +629,6 @@ static void hub_disconnect(struct usb_interface *intf) { struct usb_hub *hub = usb_get_intfdata (intf); - DECLARE_COMPLETION(urb_complete); if (!hub) return; @@ -649,12 +637,16 @@ highspeed_hubs--; usb_set_intfdata (intf, NULL); - spin_lock_irq(&hub_event_lock); - 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); - spin_unlock_irq(&hub_event_lock); /* assuming we used keventd, it must quiesce too */ @@ -663,14 +655,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; @@ -803,7 +787,7 @@ /* Attempt to reset the hub */ if (hub->urb) - usb_unlink_urb(hub->urb); + usb_kill_urb(hub->urb); else return -1; diff -Nru a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h --- a/drivers/usb/core/hub.h 2004-07-14 16:46:08 -07:00 +++ b/drivers/usb/core/hub.h 2004-07-14 16:46:08 -07:00 @@ -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];