]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/usb/host/ohci-pci.c
Merge master.kernel.org:/pub/scm/linux/kernel/git/jejb/scsi-rc-fixes-2.6
[linux-2.6-omap-h63xx.git] / drivers / usb / host / ohci-pci.c
index 5f22e6590cd12b82141fe2724c21d9acaf15465a..1b09dde068e11085e08830edc0a38f29c733eeab 100644 (file)
@@ -105,13 +105,36 @@ ohci_pci_start (struct usb_hcd *hcd)
 
 static int ohci_pci_suspend (struct usb_hcd *hcd, pm_message_t message)
 {
-       /* root hub was already suspended */
-       return 0;
+       struct ohci_hcd *ohci = hcd_to_ohci (hcd);
+       unsigned long   flags;
+       int             rc = 0;
+
+       /* Root hub was already suspended. Disable irq emission and
+        * mark HW unaccessible, bail out if RH has been resumed. Use
+        * the spinlock to properly synchronize with possible pending
+        * RH suspend or resume activity.
+        *
+        * This is still racy as hcd->state is manipulated outside of
+        * any locks =P But that will be a different fix.
+        */
+       spin_lock_irqsave (&ohci->lock, flags);
+       if (hcd->state != HC_STATE_SUSPENDED) {
+               rc = -EINVAL;
+               goto bail;
+       }
+       ohci_writel(ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable);
+       (void)ohci_readl(ohci, &ohci->regs->intrdisable);
+       clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
+ bail:
+       spin_unlock_irqrestore (&ohci->lock, flags);
+
+       return rc;
 }
 
 
 static int ohci_pci_resume (struct usb_hcd *hcd)
 {
+       set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
        usb_hcd_resume_root_hub(hcd);
        return 0;
 }