diff options
Diffstat (limited to 'drivers/usb/host/ohci-hub.c')
-rw-r--r-- | drivers/usb/host/ohci-hub.c | 172 |
1 files changed, 91 insertions, 81 deletions
diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c index 6f113596af66..2441642cb7b4 100644 --- a/drivers/usb/host/ohci-hub.c +++ b/drivers/usb/host/ohci-hub.c | |||
@@ -41,7 +41,11 @@ static void ohci_rhsc_enable (struct usb_hcd *hcd) | |||
41 | { | 41 | { |
42 | struct ohci_hcd *ohci = hcd_to_ohci (hcd); | 42 | struct ohci_hcd *ohci = hcd_to_ohci (hcd); |
43 | 43 | ||
44 | ohci_writel (ohci, OHCI_INTR_RHSC, &ohci->regs->intrenable); | 44 | spin_lock_irq(&ohci->lock); |
45 | if (!ohci->autostop) | ||
46 | del_timer(&hcd->rh_timer); /* Prevent next poll */ | ||
47 | ohci_writel(ohci, OHCI_INTR_RHSC, &ohci->regs->intrenable); | ||
48 | spin_unlock_irq(&ohci->lock); | ||
45 | } | 49 | } |
46 | 50 | ||
47 | #define OHCI_SCHED_ENABLES \ | 51 | #define OHCI_SCHED_ENABLES \ |
@@ -50,6 +54,9 @@ static void ohci_rhsc_enable (struct usb_hcd *hcd) | |||
50 | static void dl_done_list (struct ohci_hcd *); | 54 | static void dl_done_list (struct ohci_hcd *); |
51 | static void finish_unlinks (struct ohci_hcd *, u16); | 55 | static void finish_unlinks (struct ohci_hcd *, u16); |
52 | 56 | ||
57 | #ifdef CONFIG_PM | ||
58 | static int ohci_restart(struct ohci_hcd *ohci); | ||
59 | |||
53 | static int ohci_rh_suspend (struct ohci_hcd *ohci, int autostop) | 60 | static int ohci_rh_suspend (struct ohci_hcd *ohci, int autostop) |
54 | __releases(ohci->lock) | 61 | __releases(ohci->lock) |
55 | __acquires(ohci->lock) | 62 | __acquires(ohci->lock) |
@@ -132,8 +139,6 @@ static inline struct ed *find_head (struct ed *ed) | |||
132 | return ed; | 139 | return ed; |
133 | } | 140 | } |
134 | 141 | ||
135 | static int ohci_restart (struct ohci_hcd *ohci); | ||
136 | |||
137 | /* caller has locked the root hub */ | 142 | /* caller has locked the root hub */ |
138 | static int ohci_rh_resume (struct ohci_hcd *ohci) | 143 | static int ohci_rh_resume (struct ohci_hcd *ohci) |
139 | __releases(ohci->lock) | 144 | __releases(ohci->lock) |
@@ -169,7 +174,8 @@ __acquires(ohci->lock) | |||
169 | break; | 174 | break; |
170 | case OHCI_USB_RESUME: | 175 | case OHCI_USB_RESUME: |
171 | /* HCFS changes sometime after INTR_RD */ | 176 | /* HCFS changes sometime after INTR_RD */ |
172 | ohci_info (ohci, "wakeup\n"); | 177 | ohci_dbg(ohci, "%swakeup root hub\n", |
178 | autostopped ? "auto-" : ""); | ||
173 | break; | 179 | break; |
174 | case OHCI_USB_OPER: | 180 | case OHCI_USB_OPER: |
175 | /* this can happen after resuming a swsusp snapshot */ | 181 | /* this can happen after resuming a swsusp snapshot */ |
@@ -180,7 +186,6 @@ __acquires(ohci->lock) | |||
180 | ohci_dbg (ohci, "lost power\n"); | 186 | ohci_dbg (ohci, "lost power\n"); |
181 | status = -EBUSY; | 187 | status = -EBUSY; |
182 | } | 188 | } |
183 | #ifdef CONFIG_PM | ||
184 | if (status == -EBUSY) { | 189 | if (status == -EBUSY) { |
185 | if (!autostopped) { | 190 | if (!autostopped) { |
186 | spin_unlock_irq (&ohci->lock); | 191 | spin_unlock_irq (&ohci->lock); |
@@ -190,25 +195,12 @@ __acquires(ohci->lock) | |||
190 | } | 195 | } |
191 | return status; | 196 | return status; |
192 | } | 197 | } |
193 | #endif | ||
194 | if (status != -EINPROGRESS) | 198 | if (status != -EINPROGRESS) |
195 | return status; | 199 | return status; |
196 | if (autostopped) | 200 | if (autostopped) |
197 | goto skip_resume; | 201 | goto skip_resume; |
198 | spin_unlock_irq (&ohci->lock); | 202 | spin_unlock_irq (&ohci->lock); |
199 | 203 | ||
200 | temp = ohci->num_ports; | ||
201 | while (temp--) { | ||
202 | u32 stat = ohci_readl (ohci, | ||
203 | &ohci->regs->roothub.portstatus [temp]); | ||
204 | |||
205 | /* force global, not selective, resume */ | ||
206 | if (!(stat & RH_PS_PSS)) | ||
207 | continue; | ||
208 | ohci_writel (ohci, RH_PS_POCI, | ||
209 | &ohci->regs->roothub.portstatus [temp]); | ||
210 | } | ||
211 | |||
212 | /* Some controllers (lucent erratum) need extra-long delays */ | 204 | /* Some controllers (lucent erratum) need extra-long delays */ |
213 | msleep (20 /* usb 11.5.1.10 */ + 12 /* 32 msec counter */ + 1); | 205 | msleep (20 /* usb 11.5.1.10 */ + 12 /* 32 msec counter */ + 1); |
214 | 206 | ||
@@ -216,6 +208,7 @@ __acquires(ohci->lock) | |||
216 | temp &= OHCI_CTRL_HCFS; | 208 | temp &= OHCI_CTRL_HCFS; |
217 | if (temp != OHCI_USB_RESUME) { | 209 | if (temp != OHCI_USB_RESUME) { |
218 | ohci_err (ohci, "controller won't resume\n"); | 210 | ohci_err (ohci, "controller won't resume\n"); |
211 | spin_lock_irq(&ohci->lock); | ||
219 | return -EBUSY; | 212 | return -EBUSY; |
220 | } | 213 | } |
221 | 214 | ||
@@ -295,8 +288,6 @@ skip_resume: | |||
295 | return 0; | 288 | return 0; |
296 | } | 289 | } |
297 | 290 | ||
298 | #ifdef CONFIG_PM | ||
299 | |||
300 | static int ohci_bus_suspend (struct usb_hcd *hcd) | 291 | static int ohci_bus_suspend (struct usb_hcd *hcd) |
301 | { | 292 | { |
302 | struct ohci_hcd *ohci = hcd_to_ohci (hcd); | 293 | struct ohci_hcd *ohci = hcd_to_ohci (hcd); |
@@ -334,6 +325,83 @@ static int ohci_bus_resume (struct usb_hcd *hcd) | |||
334 | return rc; | 325 | return rc; |
335 | } | 326 | } |
336 | 327 | ||
328 | /* Carry out polling-, autostop-, and autoresume-related state changes */ | ||
329 | static int ohci_root_hub_state_changes(struct ohci_hcd *ohci, int changed, | ||
330 | int any_connected) | ||
331 | { | ||
332 | int poll_rh = 1; | ||
333 | |||
334 | switch (ohci->hc_control & OHCI_CTRL_HCFS) { | ||
335 | |||
336 | case OHCI_USB_OPER: | ||
337 | /* keep on polling until we know a device is connected | ||
338 | * and RHSC is enabled */ | ||
339 | if (!ohci->autostop) { | ||
340 | if (any_connected || | ||
341 | !device_may_wakeup(&ohci_to_hcd(ohci) | ||
342 | ->self.root_hub->dev)) { | ||
343 | if (ohci_readl(ohci, &ohci->regs->intrenable) & | ||
344 | OHCI_INTR_RHSC) | ||
345 | poll_rh = 0; | ||
346 | } else { | ||
347 | ohci->autostop = 1; | ||
348 | ohci->next_statechange = jiffies + HZ; | ||
349 | } | ||
350 | |||
351 | /* if no devices have been attached for one second, autostop */ | ||
352 | } else { | ||
353 | if (changed || any_connected) { | ||
354 | ohci->autostop = 0; | ||
355 | ohci->next_statechange = jiffies + | ||
356 | STATECHANGE_DELAY; | ||
357 | } else if (time_after_eq(jiffies, | ||
358 | ohci->next_statechange) | ||
359 | && !ohci->ed_rm_list | ||
360 | && !(ohci->hc_control & | ||
361 | OHCI_SCHED_ENABLES)) { | ||
362 | ohci_rh_suspend(ohci, 1); | ||
363 | } | ||
364 | } | ||
365 | break; | ||
366 | |||
367 | /* if there is a port change, autostart or ask to be resumed */ | ||
368 | case OHCI_USB_SUSPEND: | ||
369 | case OHCI_USB_RESUME: | ||
370 | if (changed) { | ||
371 | if (ohci->autostop) | ||
372 | ohci_rh_resume(ohci); | ||
373 | else | ||
374 | usb_hcd_resume_root_hub(ohci_to_hcd(ohci)); | ||
375 | } else { | ||
376 | /* everything is idle, no need for polling */ | ||
377 | poll_rh = 0; | ||
378 | } | ||
379 | break; | ||
380 | } | ||
381 | return poll_rh; | ||
382 | } | ||
383 | |||
384 | #else /* CONFIG_PM */ | ||
385 | |||
386 | static inline int ohci_rh_resume(struct ohci_hcd *ohci) | ||
387 | { | ||
388 | return 0; | ||
389 | } | ||
390 | |||
391 | /* Carry out polling-related state changes. | ||
392 | * autostop isn't used when CONFIG_PM is turned off. | ||
393 | */ | ||
394 | static int ohci_root_hub_state_changes(struct ohci_hcd *ohci, int changed, | ||
395 | int any_connected) | ||
396 | { | ||
397 | int poll_rh = 1; | ||
398 | |||
399 | /* keep on polling until RHSC is enabled */ | ||
400 | if (ohci_readl(ohci, &ohci->regs->intrenable) & OHCI_INTR_RHSC) | ||
401 | poll_rh = 0; | ||
402 | return poll_rh; | ||
403 | } | ||
404 | |||
337 | #endif /* CONFIG_PM */ | 405 | #endif /* CONFIG_PM */ |
338 | 406 | ||
339 | /*-------------------------------------------------------------------------*/ | 407 | /*-------------------------------------------------------------------------*/ |
@@ -345,7 +413,7 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf) | |||
345 | { | 413 | { |
346 | struct ohci_hcd *ohci = hcd_to_ohci (hcd); | 414 | struct ohci_hcd *ohci = hcd_to_ohci (hcd); |
347 | int i, changed = 0, length = 1; | 415 | int i, changed = 0, length = 1; |
348 | int any_connected = 0, rhsc_enabled = 1; | 416 | int any_connected = 0; |
349 | unsigned long flags; | 417 | unsigned long flags; |
350 | 418 | ||
351 | spin_lock_irqsave (&ohci->lock, flags); | 419 | spin_lock_irqsave (&ohci->lock, flags); |
@@ -386,66 +454,8 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf) | |||
386 | } | 454 | } |
387 | } | 455 | } |
388 | 456 | ||
389 | /* NOTE: vendors didn't always make the same implementation | 457 | hcd->poll_rh = ohci_root_hub_state_changes(ohci, changed, |
390 | * choices for RHSC. Sometimes it triggers on an edge (like | 458 | any_connected); |
391 | * setting and maybe clearing a port status change bit); and | ||
392 | * it's level-triggered on other silicon, active until khubd | ||
393 | * clears all active port status change bits. If it's still | ||
394 | * set (level-triggered) we must disable it and rely on | ||
395 | * polling until khubd re-enables it. | ||
396 | */ | ||
397 | if (ohci_readl (ohci, &ohci->regs->intrstatus) & OHCI_INTR_RHSC) { | ||
398 | ohci_writel (ohci, OHCI_INTR_RHSC, &ohci->regs->intrdisable); | ||
399 | (void) ohci_readl (ohci, &ohci->regs->intrdisable); | ||
400 | rhsc_enabled = 0; | ||
401 | } | ||
402 | hcd->poll_rh = 1; | ||
403 | |||
404 | /* carry out appropriate state changes */ | ||
405 | switch (ohci->hc_control & OHCI_CTRL_HCFS) { | ||
406 | |||
407 | case OHCI_USB_OPER: | ||
408 | /* keep on polling until we know a device is connected | ||
409 | * and RHSC is enabled */ | ||
410 | if (!ohci->autostop) { | ||
411 | if (any_connected) { | ||
412 | if (rhsc_enabled) | ||
413 | hcd->poll_rh = 0; | ||
414 | } else { | ||
415 | ohci->autostop = 1; | ||
416 | ohci->next_statechange = jiffies + HZ; | ||
417 | } | ||
418 | |||
419 | /* if no devices have been attached for one second, autostop */ | ||
420 | } else { | ||
421 | if (changed || any_connected) { | ||
422 | ohci->autostop = 0; | ||
423 | ohci->next_statechange = jiffies + | ||
424 | STATECHANGE_DELAY; | ||
425 | } else if (time_after_eq (jiffies, | ||
426 | ohci->next_statechange) | ||
427 | && !ohci->ed_rm_list | ||
428 | && !(ohci->hc_control & | ||
429 | OHCI_SCHED_ENABLES)) { | ||
430 | ohci_rh_suspend (ohci, 1); | ||
431 | } | ||
432 | } | ||
433 | break; | ||
434 | |||
435 | /* if there is a port change, autostart or ask to be resumed */ | ||
436 | case OHCI_USB_SUSPEND: | ||
437 | case OHCI_USB_RESUME: | ||
438 | if (changed) { | ||
439 | if (ohci->autostop) | ||
440 | ohci_rh_resume (ohci); | ||
441 | else | ||
442 | usb_hcd_resume_root_hub (hcd); | ||
443 | } else { | ||
444 | /* everything is idle, no need for polling */ | ||
445 | hcd->poll_rh = 0; | ||
446 | } | ||
447 | break; | ||
448 | } | ||
449 | 459 | ||
450 | done: | 460 | done: |
451 | spin_unlock_irqrestore (&ohci->lock, flags); | 461 | spin_unlock_irqrestore (&ohci->lock, flags); |