diff options
Diffstat (limited to 'drivers/usb/host/ohci-pci.c')
-rw-r--r-- | drivers/usb/host/ohci-pci.c | 93 |
1 files changed, 29 insertions, 64 deletions
diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c index eede6be098d..1b09dde068e 100644 --- a/drivers/usb/host/ohci-pci.c +++ b/drivers/usb/host/ohci-pci.c @@ -14,13 +14,6 @@ * This file is licenced under the GPL. */ -#ifdef CONFIG_PPC_PMAC -#include <asm/machdep.h> -#include <asm/pmac_feature.h> -#include <asm/pci-bridge.h> -#include <asm/prom.h> -#endif - #ifndef CONFIG_PCI #error "This file is PCI bus glue. CONFIG_PCI must be defined." #endif @@ -112,66 +105,38 @@ ohci_pci_start (struct usb_hcd *hcd) static int ohci_pci_suspend (struct usb_hcd *hcd, pm_message_t message) { - struct ohci_hcd *ohci = hcd_to_ohci (hcd); - - /* suspend root hub, hoping it keeps power during suspend */ - if (time_before (jiffies, ohci->next_statechange)) - msleep (100); - -#ifdef CONFIG_USB_SUSPEND - (void) usb_suspend_device (hcd->self.root_hub, message); -#else - usb_lock_device (hcd->self.root_hub); - (void) ohci_hub_suspend (hcd); - usb_unlock_device (hcd->self.root_hub); -#endif - - /* let things settle down a bit */ - msleep (100); - -#ifdef CONFIG_PPC_PMAC - if (_machine == _MACH_Pmac) { - struct device_node *of_node; - - /* Disable USB PAD & cell clock */ - of_node = pci_device_to_OF_node (to_pci_dev(hcd->self.controller)); - if (of_node) - pmac_call_feature(PMAC_FTR_USB_ENABLE, of_node, 0, 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; } -#endif /* CONFIG_PPC_PMAC */ - return 0; + 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) { - struct ohci_hcd *ohci = hcd_to_ohci (hcd); - int retval = 0; - -#ifdef CONFIG_PPC_PMAC - if (_machine == _MACH_Pmac) { - struct device_node *of_node; - - /* Re-enable USB PAD & cell clock */ - of_node = pci_device_to_OF_node (to_pci_dev(hcd->self.controller)); - if (of_node) - pmac_call_feature (PMAC_FTR_USB_ENABLE, of_node, 0, 1); - } -#endif /* CONFIG_PPC_PMAC */ - - /* resume root hub */ - if (time_before (jiffies, ohci->next_statechange)) - msleep (100); -#ifdef CONFIG_USB_SUSPEND - /* get extra cleanup even if remote wakeup isn't in use */ - retval = usb_resume_device (hcd->self.root_hub); -#else - usb_lock_device (hcd->self.root_hub); - retval = ohci_hub_resume (hcd); - usb_unlock_device (hcd->self.root_hub); -#endif - - return retval; + set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); + usb_hcd_resume_root_hub(hcd); + return 0; } #endif /* CONFIG_PM */ @@ -218,9 +183,9 @@ static const struct hc_driver ohci_pci_hc_driver = { */ .hub_status_data = ohci_hub_status_data, .hub_control = ohci_hub_control, -#ifdef CONFIG_USB_SUSPEND - .hub_suspend = ohci_hub_suspend, - .hub_resume = ohci_hub_resume, +#ifdef CONFIG_PM + .bus_suspend = ohci_bus_suspend, + .bus_resume = ohci_bus_resume, #endif .start_port_reset = ohci_start_port_reset, }; |