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
_______________________________________________
[email protected]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel