USB: HCDs use the do_remote_wakeup flag
authorAlan Stern <stern@rowland.harvard.edu>
Mon, 14 Apr 2008 16:17:10 +0000 (12:17 -0400)
committerGreg Kroah-Hartman <gregkh@suse.de>
Fri, 25 Apr 2008 04:16:53 +0000 (21:16 -0700)
When a USB device is suspended, whether or not it is enabled for
remote wakeup depends on the device_may_wakeup() setting.  The setting
is then saved in the do_remote_wakeup flag.

Later on, however, the device_may_wakeup() value can change because of
user activity.  So when testing whether a suspended device is or
should be enabled for remote wakeup, we should always test
do_remote_wakeup instead of device_may_wakeup().  This patch (as1076)
makes that change for root hubs in several places.

The patch also adjusts uhci-hcd so that when an autostopped controller
is suspended, the remote wakeup setting agrees with the value recorded
in the root hub's do_remote_wakeup flag.

And the patch adjusts ehci-hcd so that wakeup events on selectively
suspended ports (i.e., the bus itself isn't suspended) don't turn on
the PME# wakeup signal.

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

index 2ea333a43d6588676a19cb9b0e9d86dafb2e29e2..edc31e13e95e48b3cb557e8094f5565826964c97 100644 (file)
@@ -932,7 +932,6 @@ static int autosuspend_check(struct usb_device *udev, int reschedule)
         * is disabled.  Also fail if any interfaces require remote wakeup
         * but it isn't available.
         */
-       udev->do_remote_wakeup = device_may_wakeup(&udev->dev);
        if (udev->pm_usage_cnt > 0)
                return -EBUSY;
        if (udev->autosuspend_delay < 0 || udev->autosuspend_disabled)
index 21ac3781f21abe7bc0d628593e6174c122d87c36..536b433d24f778327af3e8ee201acd6160fbc3e9 100644 (file)
@@ -30,6 +30,8 @@
 
 #ifdef CONFIG_PM
 
+#define        PORT_WAKE_BITS  (PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E)
+
 static int ehci_hub_control(
        struct usb_hcd  *hcd,
        u16             typeReq,
@@ -149,10 +151,10 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
                }
 
                /* enable remote wakeup on all ports */
-               if (device_may_wakeup(&hcd->self.root_hub->dev))
-                       t2 |= PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E;
+               if (hcd->self.root_hub->do_remote_wakeup)
+                       t2 |= PORT_WAKE_BITS;
                else
-                       t2 &= ~(PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E);
+                       t2 &= ~PORT_WAKE_BITS;
 
                if (t1 != t2) {
                        ehci_vdbg (ehci, "port %d, %08x -> %08x\n",
@@ -174,7 +176,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
 
        /* allow remote wakeup */
        mask = INTR_MASK;
-       if (!device_may_wakeup(&hcd->self.root_hub->dev))
+       if (!hcd->self.root_hub->do_remote_wakeup)
                mask &= ~STS_PCD;
        ehci_writel(ehci, mask, &ehci->regs->intr_enable);
        ehci_readl(ehci, &ehci->regs->intr_enable);
@@ -232,8 +234,7 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
        i = HCS_N_PORTS (ehci->hcs_params);
        while (i--) {
                temp = ehci_readl(ehci, &ehci->regs->port_status [i]);
-               temp &= ~(PORT_RWC_BITS
-                       | PORT_WKOC_E | PORT_WKDISC_E | PORT_WKCONN_E);
+               temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS);
                if (test_bit(i, &ehci->bus_suspended) &&
                                (temp & PORT_SUSPEND)) {
                        ehci->reset_done [i] = jiffies + msecs_to_jiffies (20);
@@ -534,8 +535,6 @@ ehci_hub_descriptor (
 
 /*-------------------------------------------------------------------------*/
 
-#define        PORT_WAKE_BITS  (PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E)
-
 static int ehci_hub_control (
        struct usb_hcd  *hcd,
        u16             typeReq,
@@ -801,8 +800,6 @@ static int ehci_hub_control (
                        if ((temp & PORT_PE) == 0
                                        || (temp & PORT_RESET) != 0)
                                goto error;
-                       if (device_may_wakeup(&hcd->self.root_hub->dev))
-                               temp |= PORT_WAKE_BITS;
                        ehci_writel(ehci, temp | PORT_SUSPEND, status_reg);
                        break;
                case USB_PORT_FEAT_POWER:
index a0afc78b273e2509aa6223aefc1933222315d1ce..88dad4b5313150e8ca2de9505777269548ba88a9 100644 (file)
@@ -300,7 +300,7 @@ static int ehci_pci_resume(struct usb_hcd *hcd)
        if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF) {
                int     mask = INTR_MASK;
 
-               if (!device_may_wakeup(&hcd->self.root_hub->dev))
+               if (!hcd->self.root_hub->do_remote_wakeup)
                        mask &= ~STS_PCD;
                ehci_writel(ehci, mask, &ehci->regs->intr_enable);
                ehci_readl(ehci, &ehci->regs->intr_enable);
index 66d773c726f65b4d4402a9b38614a719b4ffb1ee..20b9a0d07420d986f7dfc1e2edb9329a175083cc 100644 (file)
@@ -1400,7 +1400,7 @@ static int isp116x_bus_suspend(struct usb_hcd *hcd)
                spin_unlock_irqrestore(&isp116x->lock, flags);
                val &= (~HCCONTROL_HCFS & ~HCCONTROL_RWE);
                val |= HCCONTROL_USB_SUSPEND;
-               if (device_may_wakeup(&hcd->self.root_hub->dev))
+               if (hcd->self.root_hub->do_remote_wakeup)
                        val |= HCCONTROL_RWE;
                /* Wait for usb transfers to finish */
                msleep(2);
index 28d6d775eb5f15726889c142a666154126d17a9c..cf3e1d255639f7a9f0a696c757f34351e1ebd61e 100644 (file)
@@ -103,10 +103,9 @@ __acquires(ohci->lock)
        finish_unlinks (ohci, ohci_frame_no(ohci));
 
        /* maybe resume can wake root hub */
-       if (device_may_wakeup(&ohci_to_hcd(ohci)->self.root_hub->dev) ||
-                       autostop)
+       if (ohci_to_hcd(ohci)->self.root_hub->do_remote_wakeup || autostop) {
                ohci->hc_control |= OHCI_CTRL_RWE;
-       else {
+       else {
                ohci_writel (ohci, OHCI_INTR_RHSC, &ohci->regs->intrdisable);
                ohci->hc_control &= ~OHCI_CTRL_RWE;
        }
index fec9872dd9dc83d5bbc90d0d780c1419b67ec009..f65d5a858733eb6af8c4aa4d805a850dd8ffd67a 100644 (file)
@@ -262,20 +262,12 @@ __acquires(uhci->lock)
 {
        int auto_stop;
        int int_enable, egsm_enable;
+       struct usb_device *rhdev = uhci_to_hcd(uhci)->self.root_hub;
 
        auto_stop = (new_state == UHCI_RH_AUTO_STOPPED);
-       dev_dbg(&uhci_to_hcd(uhci)->self.root_hub->dev,
-                       "%s%s\n", __FUNCTION__,
+       dev_dbg(&rhdev->dev, "%s%s\n", __func__,
                        (auto_stop ? " (auto-stop)" : ""));
 
-       /* If we get a suspend request when we're already auto-stopped
-        * then there's nothing to do.
-        */
-       if (uhci->rh_state == UHCI_RH_AUTO_STOPPED) {
-               uhci->rh_state = new_state;
-               return;
-       }
-
        /* Enable resume-detect interrupts if they work.
         * Then enter Global Suspend mode if _it_ works, still configured.
         */
@@ -285,8 +277,10 @@ __acquires(uhci->lock)
        if (remote_wakeup_is_broken(uhci))
                egsm_enable = 0;
        if (resume_detect_interrupts_are_broken(uhci) || !egsm_enable ||
-                       !device_may_wakeup(
-                               &uhci_to_hcd(uhci)->self.root_hub->dev))
+#ifdef CONFIG_PM
+                       (!auto_stop && !rhdev->do_remote_wakeup) ||
+#endif
+                       (auto_stop && !device_may_wakeup(&rhdev->dev)))
                uhci->working_RD = int_enable = 0;
 
        outw(int_enable, uhci->io_addr + USBINTR);
@@ -308,8 +302,7 @@ __acquires(uhci->lock)
                        return;
        }
        if (!(inw(uhci->io_addr + USBSTS) & USBSTS_HCH))
-               dev_warn(&uhci_to_hcd(uhci)->self.root_hub->dev,
-                       "Controller not stopped yet!\n");
+               dev_warn(uhci_dev(uhci), "Controller not stopped yet!\n");
 
        uhci_get_current_frame_number(uhci);