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