]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
USB: controller resume should check the root hub
authorAlan Stern <stern@rowland.harvard.edu>
Fri, 25 Jun 2010 18:02:24 +0000 (14:02 -0400)
committerGreg Kroah-Hartman <gregkh@suse.de>
Tue, 10 Aug 2010 21:35:37 +0000 (14:35 -0700)
This patch (as1394) adds code to ehci-hcd, ohci-hcd, and uhci-hcd for
automatically resuming the root hub when the controller is resumed, if
the root hub has a wakeup request pending on some port.

During resume from system sleep this doesn't matter, because the root
hubs will naturally be resumed along with every other device in the
system.  However it _will_ matter for runtime PM: If the controller is
suspended and a remote wakeup request is received then the controller
will autoresume, but we need to ensure that the root hub also
autoresumes.  Otherwise the wakeup request would be ignored, the
controller would go back to sleep, and the cycle would repeat a large
number of times (I saw this happen before the patch was written).

Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/usb/host/ehci-hub.c
drivers/usb/host/ohci-hub.c
drivers/usb/host/uhci-hcd.c
drivers/usb/host/uhci-hub.c

index 1292a5b2197ae8d4d1b0955fa736e6f74cb31b78..796ea0c8900f77ce19a03faf9ca6e7852aa2456e 100644 (file)
@@ -166,6 +166,10 @@ static void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci,
                        ehci_writel(ehci, temp | HOSTPC_PHCD, hostpc_reg);
                }
        }
+
+       /* Does the root hub have a port wakeup pending? */
+       if (!suspending && (ehci_readl(ehci, &ehci->regs->status) & STS_PCD))
+               usb_hcd_resume_root_hub(ehci_to_hcd(ehci));
 }
 
 static int ehci_bus_suspend (struct usb_hcd *hcd)
index 4dd39022c38846d4e8529b0686b7c311f18b5a74..cddcda95b57930f40698e3d2752226b85b6fbd4b 100644 (file)
@@ -355,6 +355,11 @@ static void ohci_finish_controller_resume(struct usb_hcd *hcd)
                ohci_readl(ohci, &ohci->regs->intrenable);
                msleep(20);
        }
+
+       /* Does the root hub have a port wakeup pending? */
+       if (ohci_readl(ohci, &ohci->regs->intrstatus) &
+                       (OHCI_INTR_RD | OHCI_INTR_RHSC))
+               usb_hcd_resume_root_hub(hcd);
 }
 
 /* Carry out polling-, autostop-, and autoresume-related state changes */
@@ -364,7 +369,7 @@ static int ohci_root_hub_state_changes(struct ohci_hcd *ohci, int changed,
        int     poll_rh = 1;
        int     rhsc_enable;
 
-       /* Some broken controllers never turn off RHCS in the interrupt
+       /* Some broken controllers never turn off RHSC in the interrupt
         * status register.  For their sake we won't re-enable RHSC
         * interrupts if the interrupt bit is already active.
         */
index a7850f51fdc500a0042b41704388ba29856d2e05..9d4d81248f96dd5eb6f207831e36c424fe54276a 100644 (file)
@@ -862,10 +862,11 @@ static int uhci_pci_resume(struct usb_hcd *hcd, bool hibernated)
        /* If interrupts don't work and remote wakeup is enabled then
         * the suspended root hub needs to be polled.
         */
-       if (!uhci->RD_enable && hcd->self.root_hub->do_remote_wakeup) {
+       if (!uhci->RD_enable && hcd->self.root_hub->do_remote_wakeup)
                set_bit(HCD_FLAG_POLL_RH, &hcd->flags);
-               usb_hcd_poll_rh_status(hcd);
-       }
+
+       /* Does the root hub have a port wakeup pending? */
+       usb_hcd_poll_rh_status(hcd);
        return 0;
 }
 #endif
index f0c58116c0adf27e781928e5ae5cb1b37ed2b098..6d59c0f77f2500a757320a0bc6edfba0d084d1e4 100644 (file)
@@ -200,7 +200,7 @@ static int uhci_hub_status_data(struct usb_hcd *hcd, char *buf)
            case UHCI_RH_SUSPENDING:
            case UHCI_RH_SUSPENDED:
                /* if port change, ask to be resumed */
-               if (status)
+               if (status || uhci->resuming_ports)
                        usb_hcd_resume_root_hub(hcd);
                break;