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