Merge with /pub/scm/linux/kernel/git/torvalds/linux-2.6.git
[sfrench/cifs-2.6.git] / drivers / usb / host / ohci-hub.c
index e01e77bc324b190bdaf845a7606bed0b5e338c5f..0bb972b58336c5f01ad1fbe18f99a3dafb640a82 100644 (file)
@@ -53,6 +53,11 @@ static int ohci_bus_suspend (struct usb_hcd *hcd)
 
        spin_lock_irqsave (&ohci->lock, flags);
 
+       if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))) {
+               spin_unlock_irqrestore (&ohci->lock, flags);
+               return -ESHUTDOWN;
+       }
+
        ohci->hc_control = ohci_readl (ohci, &ohci->regs->control);
        switch (ohci->hc_control & OHCI_CTRL_HCFS) {
        case OHCI_USB_RESUME:
@@ -102,7 +107,7 @@ static int ohci_bus_suspend (struct usb_hcd *hcd)
                        &ohci->regs->intrstatus);
 
        /* maybe resume can wake root hub */
-       if (hcd->remote_wakeup)
+       if (device_may_wakeup(&ohci_to_hcd(ohci)->self.root_hub->dev))
                ohci->hc_control |= OHCI_CTRL_RWE;
        else
                ohci->hc_control &= ~OHCI_CTRL_RWE;
@@ -140,11 +145,19 @@ static int ohci_bus_resume (struct usb_hcd *hcd)
        struct ohci_hcd         *ohci = hcd_to_ohci (hcd);
        u32                     temp, enables;
        int                     status = -EINPROGRESS;
+       unsigned long           flags;
 
        if (time_before (jiffies, ohci->next_statechange))
                msleep(5);
 
-       spin_lock_irq (&ohci->lock);
+       spin_lock_irqsave (&ohci->lock, flags);
+
+       if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))) {
+               spin_unlock_irqrestore (&ohci->lock, flags);
+               return -ESHUTDOWN;
+       }
+
+
        ohci->hc_control = ohci_readl (ohci, &ohci->regs->control);
 
        if (ohci->hc_control & (OHCI_CTRL_IR | OHCI_SCHED_ENABLES)) {
@@ -179,7 +192,7 @@ static int ohci_bus_resume (struct usb_hcd *hcd)
                ohci_dbg (ohci, "lost power\n");
                status = -EBUSY;
        }
-       spin_unlock_irq (&ohci->lock);
+       spin_unlock_irqrestore (&ohci->lock, flags);
        if (status == -EBUSY) {
                (void) ohci_init (ohci);
                return ohci_restart (ohci);
@@ -233,9 +246,9 @@ static int ohci_bus_resume (struct usb_hcd *hcd)
        (void) ohci_readl (ohci, &ohci->regs->control);
        msleep (3);
 
-       temp = OHCI_CONTROL_INIT | OHCI_USB_OPER;
-       if (hcd->can_wakeup)
-               temp |= OHCI_CTRL_RWC;
+       temp = ohci->hc_control;
+       temp &= OHCI_CTRL_RWC;
+       temp |= OHCI_CONTROL_INIT | OHCI_USB_OPER;
        ohci->hc_control = temp;
        ohci_writel (ohci, temp, &ohci->regs->control);
        (void) ohci_readl (ohci, &ohci->regs->control);
@@ -289,7 +302,7 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf)
 {
        struct ohci_hcd *ohci = hcd_to_ohci (hcd);
        int             i, changed = 0, length = 1;
-       int             can_suspend = hcd->can_wakeup;
+       int             can_suspend = device_may_wakeup(&hcd->self.root_hub->dev);
        unsigned long   flags;
 
        spin_lock_irqsave (&ohci->lock, flags);
@@ -297,8 +310,8 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf)
        /* handle autosuspended root:  finish resuming before
         * letting khubd or root hub timer see state changes.
         */
-       if ((ohci->hc_control & OHCI_CTRL_HCFS) != OHCI_USB_OPER
-                       || !HC_IS_RUNNING(hcd->state)) {
+       if (unlikely((ohci->hc_control & OHCI_CTRL_HCFS) != OHCI_USB_OPER
+                    || !HC_IS_RUNNING(hcd->state))) {
                can_suspend = 0;
                goto done;
        }
@@ -341,7 +354,7 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf)
                 */
                if (!(status & RH_PS_CCS))
                        continue;
-               if ((status & RH_PS_PSS) && hcd->remote_wakeup)
+               if ((status & RH_PS_PSS) && can_suspend)
                        continue;
                can_suspend = 0;
        }
@@ -359,7 +372,7 @@ done:
                                        & ohci->hc_control)
                                == OHCI_USB_OPER
                        && time_after (jiffies, ohci->next_statechange)
-                       && usb_trylock_device (hcd->self.root_hub)
+                       && usb_trylock_device (hcd->self.root_hub) == 0
                        ) {
                ohci_vdbg (ohci, "autosuspend\n");
                (void) ohci_bus_suspend (hcd);
@@ -508,6 +521,9 @@ static int ohci_hub_control (
        u32             temp;
        int             retval = 0;
 
+       if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)))
+               return -ESHUTDOWN;
+
        switch (typeReq) {
        case ClearHubFeature:
                switch (wValue) {