diff options
Diffstat (limited to 'drivers/usb/host/ohci-hub.c')
-rw-r--r-- | drivers/usb/host/ohci-hub.c | 172 |
1 files changed, 90 insertions, 82 deletions
diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c index 6995ea36f2e8..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,7 @@ __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, "%swakeup\n", | 177 | ohci_dbg(ohci, "%swakeup root hub\n", |
173 | autostopped ? "auto-" : ""); | 178 | autostopped ? "auto-" : ""); |
174 | break; | 179 | break; |
175 | case OHCI_USB_OPER: | 180 | case OHCI_USB_OPER: |
@@ -181,7 +186,6 @@ __acquires(ohci->lock) | |||
181 | ohci_dbg (ohci, "lost power\n"); | 186 | ohci_dbg (ohci, "lost power\n"); |
182 | status = -EBUSY; | 187 | status = -EBUSY; |
183 | } | 188 | } |
184 | #ifdef CONFIG_PM | ||
185 | if (status == -EBUSY) { | 189 | if (status == -EBUSY) { |
186 | if (!autostopped) { | 190 | if (!autostopped) { |
187 | spin_unlock_irq (&ohci->lock); | 191 | spin_unlock_irq (&ohci->lock); |
@@ -191,25 +195,12 @@ __acquires(ohci->lock) | |||
191 | } | 195 | } |
192 | return status; | 196 | return status; |
193 | } | 197 | } |
194 | #endif | ||
195 | if (status != -EINPROGRESS) | 198 | if (status != -EINPROGRESS) |
196 | return status; | 199 | return status; |
197 | if (autostopped) | 200 | if (autostopped) |
198 | goto skip_resume; | 201 | goto skip_resume; |
199 | spin_unlock_irq (&ohci->lock); | 202 | spin_unlock_irq (&ohci->lock); |
200 | 203 | ||
201 | temp = ohci->num_ports; | ||
202 | while (temp--) { | ||
203 | u32 stat = ohci_readl (ohci, | ||
204 | &ohci->regs->roothub.portstatus [temp]); | ||
205 | |||
206 | /* force global, not selective, resume */ | ||
207 | if (!(stat & RH_PS_PSS)) | ||
208 | continue; | ||
209 | ohci_writel (ohci, RH_PS_POCI, | ||
210 | &ohci->regs->roothub.portstatus [temp]); | ||
211 | } | ||
212 | |||
213 | /* Some controllers (lucent erratum) need extra-long delays */ | 204 | /* Some controllers (lucent erratum) need extra-long delays */ |
214 | 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); |
215 | 206 | ||
@@ -217,6 +208,7 @@ __acquires(ohci->lock) | |||
217 | temp &= OHCI_CTRL_HCFS; | 208 | temp &= OHCI_CTRL_HCFS; |
218 | if (temp != OHCI_USB_RESUME) { | 209 | if (temp != OHCI_USB_RESUME) { |
219 | ohci_err (ohci, "controller won't resume\n"); | 210 | ohci_err (ohci, "controller won't resume\n"); |
211 | spin_lock_irq(&ohci->lock); | ||
220 | return -EBUSY; | 212 | return -EBUSY; |
221 | } | 213 | } |
222 | 214 | ||
@@ -296,8 +288,6 @@ skip_resume: | |||
296 | return 0; | 288 | return 0; |
297 | } | 289 | } |
298 | 290 | ||
299 | #ifdef CONFIG_PM | ||
300 | |||
301 | static int ohci_bus_suspend (struct usb_hcd *hcd) | 291 | static int ohci_bus_suspend (struct usb_hcd *hcd) |
302 | { | 292 | { |
303 | struct ohci_hcd *ohci = hcd_to_ohci (hcd); | 293 | struct ohci_hcd *ohci = hcd_to_ohci (hcd); |
@@ -335,6 +325,83 @@ static int ohci_bus_resume (struct usb_hcd *hcd) | |||
335 | return rc; | 325 | return rc; |
336 | } | 326 | } |
337 | 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 | |||
338 | #endif /* CONFIG_PM */ | 405 | #endif /* CONFIG_PM */ |
339 | 406 | ||
340 | /*-------------------------------------------------------------------------*/ | 407 | /*-------------------------------------------------------------------------*/ |
@@ -346,7 +413,7 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf) | |||
346 | { | 413 | { |
347 | struct ohci_hcd *ohci = hcd_to_ohci (hcd); | 414 | struct ohci_hcd *ohci = hcd_to_ohci (hcd); |
348 | int i, changed = 0, length = 1; | 415 | int i, changed = 0, length = 1; |
349 | int any_connected = 0, rhsc_enabled = 1; | 416 | int any_connected = 0; |
350 | unsigned long flags; | 417 | unsigned long flags; |
351 | 418 | ||
352 | spin_lock_irqsave (&ohci->lock, flags); | 419 | spin_lock_irqsave (&ohci->lock, flags); |
@@ -387,67 +454,8 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf) | |||
387 | } | 454 | } |
388 | } | 455 | } |
389 | 456 | ||
390 | /* NOTE: vendors didn't always make the same implementation | 457 | hcd->poll_rh = ohci_root_hub_state_changes(ohci, changed, |
391 | * choices for RHSC. Sometimes it triggers on an edge (like | 458 | any_connected); |
392 | * setting and maybe clearing a port status change bit); and | ||
393 | * it's level-triggered on other silicon, active until khubd | ||
394 | * clears all active port status change bits. If it's still | ||
395 | * set (level-triggered) we must disable it and rely on | ||
396 | * polling until khubd re-enables it. | ||
397 | */ | ||
398 | if (ohci_readl (ohci, &ohci->regs->intrstatus) & OHCI_INTR_RHSC) { | ||
399 | ohci_writel (ohci, OHCI_INTR_RHSC, &ohci->regs->intrdisable); | ||
400 | (void) ohci_readl (ohci, &ohci->regs->intrdisable); | ||
401 | rhsc_enabled = 0; | ||
402 | } | ||
403 | hcd->poll_rh = 1; | ||
404 | |||
405 | /* carry out appropriate state changes */ | ||
406 | switch (ohci->hc_control & OHCI_CTRL_HCFS) { | ||
407 | |||
408 | case OHCI_USB_OPER: | ||
409 | /* keep on polling until we know a device is connected | ||
410 | * and RHSC is enabled */ | ||
411 | if (!ohci->autostop) { | ||
412 | if (any_connected) { | ||
413 | if (rhsc_enabled) | ||
414 | hcd->poll_rh = 0; | ||
415 | } else { | ||
416 | ohci->autostop = 1; | ||
417 | ohci->next_statechange = jiffies + HZ; | ||
418 | } | ||
419 | |||
420 | /* if no devices have been attached for one second, autostop */ | ||
421 | } else { | ||
422 | if (changed || any_connected) { | ||
423 | ohci->autostop = 0; | ||
424 | ohci->next_statechange = jiffies + | ||
425 | STATECHANGE_DELAY; | ||
426 | } else if (device_may_wakeup(&hcd->self.root_hub->dev) | ||
427 | && time_after_eq(jiffies, | ||
428 | ohci->next_statechange) | ||
429 | && !ohci->ed_rm_list | ||
430 | && !(ohci->hc_control & | ||
431 | OHCI_SCHED_ENABLES)) { | ||
432 | ohci_rh_suspend (ohci, 1); | ||
433 | } | ||
434 | } | ||
435 | break; | ||
436 | |||
437 | /* if there is a port change, autostart or ask to be resumed */ | ||
438 | case OHCI_USB_SUSPEND: | ||
439 | case OHCI_USB_RESUME: | ||
440 | if (changed) { | ||
441 | if (ohci->autostop) | ||
442 | ohci_rh_resume (ohci); | ||
443 | else | ||
444 | usb_hcd_resume_root_hub (hcd); | ||
445 | } else { | ||
446 | /* everything is idle, no need for polling */ | ||
447 | hcd->poll_rh = 0; | ||
448 | } | ||
449 | break; | ||
450 | } | ||
451 | 459 | ||
452 | done: | 460 | done: |
453 | spin_unlock_irqrestore (&ohci->lock, flags); | 461 | spin_unlock_irqrestore (&ohci->lock, flags); |