diff options
author | Alan Stern <stern@rowland.harvard.edu> | 2007-05-04 11:52:40 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2007-07-12 19:29:47 -0400 |
commit | 383975d765523a56dc43a6cd6d52e9b376800cf2 (patch) | |
tree | d6ecbfe620d7d5fba372211d7af185e7c44e5097 /drivers/usb/host/ohci-pci.c | |
parent | 0458d5b4c9cc4ca0f62625d0144ddc4b4bc97a3c (diff) |
USB: EHCI, OHCI: handover changes
This patch (as887) changes the way ehci-hcd and ohci-hcd handle a loss
of VBUS power during suspend. In order for the USB-persist facility
to work correctly, it is necessary for low- and full-speed devices
attached to a high-speed port to be handed back to the companion
controller during resume processing.
This entails three changes: adding code to ehci-hcd to perform the
handover, removing code from ohci-hcd to turn off ports during
root-hub reinit, and adding code to ohci-hcd to turn on ports during
PCI controller resume. (Other bus glue resume methods for platforms
supporting high-speed controllers would need a similar change, if any
existed.)
Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/host/ohci-pci.c')
-rw-r--r-- | drivers/usb/host/ohci-pci.c | 41 |
1 files changed, 40 insertions, 1 deletions
diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c index ca62cb583221..15013f4519ad 100644 --- a/drivers/usb/host/ohci-pci.c +++ b/drivers/usb/host/ohci-pci.c | |||
@@ -202,6 +202,42 @@ static int __devinit ohci_pci_start (struct usb_hcd *hcd) | |||
202 | return ret; | 202 | return ret; |
203 | } | 203 | } |
204 | 204 | ||
205 | #if defined(CONFIG_USB_PERSIST) && (defined(CONFIG_USB_EHCI_HCD) || \ | ||
206 | defined(CONFIG_USB_EHCI_HCD_MODULE)) | ||
207 | |||
208 | /* Following a power loss, we must prepare to regain control of the ports | ||
209 | * we used to own. This means turning on the port power before ehci-hcd | ||
210 | * tries to switch ownership. | ||
211 | * | ||
212 | * This isn't a 100% perfect solution. On most systems the OHCI controllers | ||
213 | * lie at lower PCI addresses than the EHCI controller, so they will be | ||
214 | * discovered (and hence resumed) first. But there is no guarantee things | ||
215 | * will always work this way. If the EHCI controller is resumed first and | ||
216 | * the OHCI ports are unpowered, then the handover will fail. | ||
217 | */ | ||
218 | static void prepare_for_handover(struct usb_hcd *hcd) | ||
219 | { | ||
220 | struct ohci_hcd *ohci = hcd_to_ohci(hcd); | ||
221 | int port; | ||
222 | |||
223 | /* Here we "know" root ports should always stay powered */ | ||
224 | ohci_dbg(ohci, "powerup ports\n"); | ||
225 | for (port = 0; port < ohci->num_ports; port++) | ||
226 | ohci_writel(ohci, RH_PS_PPS, | ||
227 | &ohci->regs->roothub.portstatus[port]); | ||
228 | |||
229 | /* Flush those writes */ | ||
230 | ohci_readl(ohci, &ohci->regs->control); | ||
231 | msleep(20); | ||
232 | } | ||
233 | |||
234 | #else | ||
235 | |||
236 | static inline void prepare_for_handover(struct usb_hcd *hcd) | ||
237 | { } | ||
238 | |||
239 | #endif /* CONFIG_USB_PERSIST etc. */ | ||
240 | |||
205 | #ifdef CONFIG_PM | 241 | #ifdef CONFIG_PM |
206 | 242 | ||
207 | static int ohci_pci_suspend (struct usb_hcd *hcd, pm_message_t message) | 243 | static int ohci_pci_suspend (struct usb_hcd *hcd, pm_message_t message) |
@@ -241,7 +277,10 @@ static int ohci_pci_suspend (struct usb_hcd *hcd, pm_message_t message) | |||
241 | static int ohci_pci_resume (struct usb_hcd *hcd) | 277 | static int ohci_pci_resume (struct usb_hcd *hcd) |
242 | { | 278 | { |
243 | set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); | 279 | set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); |
244 | usb_hcd_resume_root_hub(hcd); | 280 | |
281 | /* FIXME: we should try to detect loss of VBUS power here */ | ||
282 | prepare_for_handover(hcd); | ||
283 | |||
245 | return 0; | 284 | return 0; |
246 | } | 285 | } |
247 | 286 | ||