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