ChangeSet 1.2181.4.40, 2005/03/21 14:58:02-08:00, [EMAIL PROTECTED] [PATCH] USBcore updates
This is the third of five updates to usbcore: Adjust the usb_hc_died routine to eliminate races with root-hub registration/deregistration and have it tell khubd to remove all devices below the root hub. Signed-off-by: Alan Stern <[EMAIL PROTECTED]> Signed-off-by: Greg Kroah-Hartman <[EMAIL PROTECTED]> drivers/usb/core/hcd.c | 32 +++++++++++++++++++++++++++++--- drivers/usb/core/hcd.h | 2 ++ drivers/usb/core/hub.c | 17 ++++++++++++++++- drivers/usb/core/usb.h | 2 ++ 4 files changed, 49 insertions(+), 4 deletions(-) diff -Nru a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c --- a/drivers/usb/core/hcd.c 2005-03-30 13:36:20 -08:00 +++ b/drivers/usb/core/hcd.c 2005-03-30 13:36:20 -08:00 @@ -101,6 +101,9 @@ DECLARE_MUTEX (usb_bus_list_lock); /* exported only for usbfs */ EXPORT_SYMBOL_GPL (usb_bus_list_lock); +/* used for controlling access to virtual root hubs */ +static DEFINE_SPINLOCK(hcd_root_hub_lock); + /* used when updating hcd data */ static DEFINE_SPINLOCK(hcd_data_lock); @@ -874,6 +877,17 @@ usb_dev->dev.bus_id, retval); } up (&usb_bus_list_lock); + + if (retval == 0) { + spin_lock_irq (&hcd_root_hub_lock); + hcd->rh_registered = 1; + spin_unlock_irq (&hcd_root_hub_lock); + + /* Did the HC die before the root hub was registered? */ + if (hcd->state == HC_STATE_HALT) + usb_hc_died (hcd); /* This time clean up */ + } + return retval; } EXPORT_SYMBOL_GPL(usb_hcd_register_root_hub); @@ -1575,12 +1589,21 @@ */ void usb_hc_died (struct usb_hcd *hcd) { + unsigned long flags; + dev_err (hcd->self.controller, "HC died; cleaning up\n"); - /* make khubd clean up old urbs and devices */ - usb_set_device_state(hcd->self.root_hub, USB_STATE_NOTATTACHED); - mod_timer(&hcd->rh_timer, jiffies); + spin_lock_irqsave (&hcd_root_hub_lock, flags); + if (hcd->rh_registered) { + + /* make khubd clean up old urbs and devices */ + usb_set_device_state (hcd->self.root_hub, + USB_STATE_NOTATTACHED); + usb_kick_khubd (hcd->self.root_hub); + } + spin_unlock_irqrestore (&hcd_root_hub_lock, flags); } +EXPORT_SYMBOL_GPL (usb_hc_died); /*-------------------------------------------------------------------------*/ @@ -1737,6 +1760,9 @@ hcd->state = HC_STATE_QUIESCING; dev_dbg(hcd->self.controller, "roothub graceful disconnect\n"); + spin_lock_irq (&hcd_root_hub_lock); + hcd->rh_registered = 0; + spin_unlock_irq (&hcd_root_hub_lock); usb_disconnect(&hcd->self.root_hub); hcd->driver->stop(hcd); diff -Nru a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h --- a/drivers/usb/core/hcd.h 2005-03-30 13:36:20 -08:00 +++ b/drivers/usb/core/hcd.h 2005-03-30 13:36:20 -08:00 @@ -74,6 +74,8 @@ unsigned saw_irq : 1; unsigned can_wakeup:1; /* hw supports wakeup? */ unsigned remote_wakeup:1;/* sw should use wakeup? */ + unsigned rh_registered:1;/* is root hub registered? */ + int irq; /* irq allocated */ void __iomem *regs; /* device memory/io */ u64 rsrc_start; /* memory/io resource start */ diff -Nru a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c --- a/drivers/usb/core/hub.c 2005-03-30 13:36:20 -08:00 +++ b/drivers/usb/core/hub.c 2005-03-30 13:36:20 -08:00 @@ -289,6 +289,11 @@ spin_unlock_irqrestore(&hub_event_lock, flags); } +void usb_kick_khubd(struct usb_device *hdev) +{ + kick_khubd(hdev_to_hub(hdev)); +} + /* completion function, fires on port status changes and various faults */ static void hub_irq(struct urb *urb, struct pt_regs *regs) @@ -2624,7 +2629,17 @@ usb_put_intf(intf); continue; } - if (hub != usb_get_intfdata(intf) || hub->quiescing) + if (hub != usb_get_intfdata(intf)) + goto loop; + + /* If the hub has died, clean up after it */ + if (hdev->state == USB_STATE_NOTATTACHED) { + hub_pre_reset(hub); + goto loop; + } + + /* If this is an inactive or suspended hub, do nothing */ + if (hub->quiescing) goto loop; if (hub->error) { diff -Nru a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h --- a/drivers/usb/core/usb.h 2005-03-30 13:36:20 -08:00 +++ b/drivers/usb/core/usb.h 2005-03-30 13:36:20 -08:00 @@ -18,6 +18,8 @@ extern void usb_lock_all_devices(void); extern void usb_unlock_all_devices(void); +extern void usb_kick_khubd(struct usb_device *dev); + /* for labeling diagnostics */ extern const char *usbcore_name; ------------------------------------------------------- This SF.net email is sponsored by Demarc: A global provider of Threat Management Solutions. Download our HomeAdmin security software for free today! http://www.demarc.com/info/Sentarus/hamr30 _______________________________________________ linux-usb-devel@lists.sourceforge.net To unsubscribe, use the last form field at: https://lists.sourceforge.net/lists/listinfo/linux-usb-devel