David:

Here's my new usb_root_hub_lost_power() routine.  This is actually two 
separate patches pasted together; the first one updates usbcore and the 
second contains the changes for OHCI and UHCI (with a couple of unrelated
modifications thrown in too).

I wasn't sure how to handle this in the EHCI driver.  It looks like the 
driver assumes power was _always_ lost unless it sees a suspended port 
after the resume.  Is that how it's supposed to work?

Does this patch do what you need?

Alan Stern



Index: usb-2.6/drivers/usb/core/hub.c
===================================================================
--- usb-2.6.orig/drivers/usb/core/hub.c
+++ usb-2.6/drivers/usb/core/hub.c
@@ -1469,6 +1469,37 @@ static void hub_port_logical_disconnect(
        kick_khubd(hub);
 }
 
+/**
+ * usb_root_hub_lost_power - called by HCD if the root hub lost Vbus power
+ * @rhdev: struct usb_device for the root hub
+ *
+ * The USB host controller driver calls this function when its root hub
+ * is resumed and hardware or BIOS problems have caused Vbus power to
+ * be interrupted or the controller to be reset.  The routine marks
+ * all the children of the root hub as NOTATTACHED and marks logical
+ * connect-change events on their ports.
+ *
+ * This routine must be called with local interrupts disabled.  Normally
+ * it will be called only from within an HCD's resume routine, at which
+ * time we can be certain the root hub has been registered.
+ */
+void usb_root_hub_lost_power(struct usb_device *rhdev)
+{
+       struct usb_hub *hub = hdev_to_hub(rhdev);
+       int i;
+
+       dev_warn(&rhdev->dev, "root hub lost power during suspend\n");
+       spin_lock(&device_state_lock);
+       for (i = 0; i < rhdev->maxchild; ++i) {
+               if (rhdev->children[i]) {
+                       recursively_mark_NOTATTACHED(rhdev->children[i]);
+                       set_bit(i + 1, hub->change_bits);
+               }
+       }
+       spin_unlock(&device_state_lock);
+}
+EXPORT_SYMBOL_GPL(usb_root_hub_lost_power);
+
 
 #ifdef CONFIG_USB_SUSPEND
 
Index: usb-2.6/drivers/usb/core/hcd.c
===================================================================
--- usb-2.6.orig/drivers/usb/core/hcd.c
+++ usb-2.6/drivers/usb/core/hcd.c
@@ -1463,10 +1463,10 @@ static int hcd_hub_resume (struct usb_bu
  * usb_hcd_resume_root_hub - called by HCD to resume its root hub 
  * @hcd: host controller for this root hub
  *
- * The USB host controller calls this function when its root hub is
- * suspended (with the remote wakeup feature enabled) and a remote
- * wakeup request is received.  It queues a request for khubd to
- * resume the root hub.
+ * The USB host controller driver calls this function when its root hub
+ * is suspended (with the remote wakeup feature enabled) and a remote
+ * wakeup request is received.  It queues a request for khubd to resume
+ * the root hub.
  */
 void usb_hcd_resume_root_hub (struct usb_hcd *hcd)
 {
@@ -1477,14 +1477,15 @@ void usb_hcd_resume_root_hub (struct usb
                usb_resume_root_hub (hcd->self.root_hub);
        spin_unlock_irqrestore (&hcd_root_hub_lock, flags);
 }
+EXPORT_SYMBOL_GPL(usb_hcd_resume_root_hub);
 
 #else
-void usb_hcd_resume_root_hub (struct usb_hcd *hcd)
-{
-}
-#endif
+
+void usb_hcd_resume_root_hub (struct usb_hcd *hcd) {}
 EXPORT_SYMBOL_GPL(usb_hcd_resume_root_hub);
 
+#endif
+
 /*-------------------------------------------------------------------------*/
 
 #ifdef CONFIG_USB_OTG
Index: usb-2.6/drivers/usb/core/hcd.h
===================================================================
--- usb-2.6.orig/drivers/usb/core/hcd.h
+++ usb-2.6/drivers/usb/core/hcd.h
@@ -354,6 +354,7 @@ extern long usb_calc_bus_time (int speed
 extern struct usb_bus *usb_alloc_bus (struct usb_operations *);
 
 extern void usb_hcd_resume_root_hub (struct usb_hcd *hcd);
+extern void usb_root_hub_lost_power (struct usb_device *rhdev);
 
 extern void usb_set_device_state(struct usb_device *udev,
                enum usb_device_state new_state);
Index: usb-2.6/drivers/usb/host/uhci-hcd.c
===================================================================
--- usb-2.6.orig/drivers/usb/host/uhci-hcd.c
+++ usb-2.6/drivers/usb/host/uhci-hcd.c
@@ -775,15 +775,17 @@ static int uhci_suspend(struct usb_hcd *
 
        dev_dbg(uhci_dev(uhci), "%s\n", __FUNCTION__);
 
-       spin_lock_irq(&uhci->lock);
-       if (uhci->hc_inaccessible)      /* Dead or already suspended */
-               goto done;
-
 #ifndef CONFIG_USB_SUSPEND
        /* Otherwise this would never happen */
-       suspend_rh(uhci, UHCI_RH_SUSPENDED);
+       usb_lock_device(hcd->self.root_hub);
+       uhci_rh_suspend(hcd);
+       usb_unlock_device(hcd->self.root_hub);
 #endif
 
+       spin_lock_irq(&uhci->lock);
+       if (uhci->hc_inaccessible)      /* Dead or already suspended */
+               goto done;
+
        if (uhci->rh_state > UHCI_RH_SUSPENDED) {
                dev_warn(uhci_dev(uhci), "Root hub isn't suspended!\n");
                hcd->state = HC_STATE_RUNNING;
@@ -792,7 +794,7 @@ static int uhci_suspend(struct usb_hcd *
        };
 
        /* All PCI host controllers are required to disable IRQ generation
-        * at the source, so we must turn off PIRQ.
+        * at the source when suspending, so we must turn off PIRQ.
         */
        pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP, 0);
        uhci->hc_inaccessible = 1;
@@ -826,17 +828,24 @@ static int uhci_resume(struct usb_hcd *h
        check_and_reset_hc(uhci);
        configure_hc(uhci);
 
-#ifndef CONFIG_USB_SUSPEND
-       /* Otherwise this would never happen */
-       wakeup_rh(uhci);
-#endif
-       if (uhci->rh_state == UHCI_RH_RESET)
+       if (uhci->rh_state == UHCI_RH_RESET) {
+
+               /* Uh oh, something bad happened */
+               usb_root_hub_lost_power(hcd->self.root_hub);
                suspend_rh(uhci, UHCI_RH_SUSPENDED);
+       }
 
        spin_unlock_irq(&uhci->lock);
-
        if (hcd->poll_rh)
                usb_hcd_poll_rh_status(hcd);
+
+#ifndef CONFIG_USB_SUSPEND
+       /* Otherwise this would never happen */
+       usb_lock_device(hcd->self.root_hub);
+       uhci_rh_resume(hcd);
+       usb_unlock_device(hcd->self.root_hub);
+#endif
+
        return 0;
 }
 #endif
Index: usb-2.6/drivers/usb/host/ohci-hcd.c
===================================================================
--- usb-2.6.orig/drivers/usb/host/ohci-hcd.c
+++ usb-2.6/drivers/usb/host/ohci-hcd.c
@@ -775,7 +775,6 @@ static int ohci_restart (struct ohci_hcd
        int temp;
        int i;
        struct urb_priv *priv;
-       struct usb_device *root = ohci_to_hcd(ohci)->self.root_hub;
 
        /* mark any devices gone, so they do nothing till khubd disconnects.
         * recycle any "live" eds/tds (and urbs) right away.
@@ -784,11 +783,7 @@ static int ohci_restart (struct ohci_hcd
         */ 
        spin_lock_irq(&ohci->lock);
        disable (ohci);
-       for (i = 0; i < root->maxchild; i++) {
-               if (root->children [i])
-                       usb_set_device_state (root->children[i],
-                               USB_STATE_NOTATTACHED);
-       }
+       usb_root_hub_lost_power (ohci_to_hcd (ohci)->self.root_hub);
        if (!list_empty (&ohci->pending))
                ohci_dbg(ohci, "abort schedule...\n");
        list_for_each_entry (priv, &ohci->pending, pending) {



-------------------------------------------------------
SF.Net email is sponsored by: Tell us your software development plans!
Take this survey and enter to win a one-year sub to SourceForge.net
Plus IDC's 2005 look-ahead and a copy of this survey
Click here to start!  http://www.idcswdc.com/cgi-bin/survey?id=105hix
_______________________________________________
linux-usb-devel@lists.sourceforge.net
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to