diff options
-rw-r--r-- | drivers/usb/host/ohci-hub.c | 133 |
1 files changed, 79 insertions, 54 deletions
diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c index 4c9492779ede..2441642cb7b4 100644 --- a/drivers/usb/host/ohci-hub.c +++ b/drivers/usb/host/ohci-hub.c | |||
@@ -56,7 +56,6 @@ static void finish_unlinks (struct ohci_hcd *, u16); | |||
56 | 56 | ||
57 | #ifdef CONFIG_PM | 57 | #ifdef CONFIG_PM |
58 | static int ohci_restart(struct ohci_hcd *ohci); | 58 | static int ohci_restart(struct ohci_hcd *ohci); |
59 | #endif | ||
60 | 59 | ||
61 | static int ohci_rh_suspend (struct ohci_hcd *ohci, int autostop) | 60 | static int ohci_rh_suspend (struct ohci_hcd *ohci, int autostop) |
62 | __releases(ohci->lock) | 61 | __releases(ohci->lock) |
@@ -187,7 +186,6 @@ __acquires(ohci->lock) | |||
187 | ohci_dbg (ohci, "lost power\n"); | 186 | ohci_dbg (ohci, "lost power\n"); |
188 | status = -EBUSY; | 187 | status = -EBUSY; |
189 | } | 188 | } |
190 | #ifdef CONFIG_PM | ||
191 | if (status == -EBUSY) { | 189 | if (status == -EBUSY) { |
192 | if (!autostopped) { | 190 | if (!autostopped) { |
193 | spin_unlock_irq (&ohci->lock); | 191 | spin_unlock_irq (&ohci->lock); |
@@ -197,7 +195,6 @@ __acquires(ohci->lock) | |||
197 | } | 195 | } |
198 | return status; | 196 | return status; |
199 | } | 197 | } |
200 | #endif | ||
201 | if (status != -EINPROGRESS) | 198 | if (status != -EINPROGRESS) |
202 | return status; | 199 | return status; |
203 | if (autostopped) | 200 | if (autostopped) |
@@ -291,8 +288,6 @@ skip_resume: | |||
291 | return 0; | 288 | return 0; |
292 | } | 289 | } |
293 | 290 | ||
294 | #ifdef CONFIG_PM | ||
295 | |||
296 | static int ohci_bus_suspend (struct usb_hcd *hcd) | 291 | static int ohci_bus_suspend (struct usb_hcd *hcd) |
297 | { | 292 | { |
298 | struct ohci_hcd *ohci = hcd_to_ohci (hcd); | 293 | struct ohci_hcd *ohci = hcd_to_ohci (hcd); |
@@ -330,6 +325,83 @@ static int ohci_bus_resume (struct usb_hcd *hcd) | |||
330 | return rc; | 325 | return rc; |
331 | } | 326 | } |
332 | 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 | |||
333 | #endif /* CONFIG_PM */ | 405 | #endif /* CONFIG_PM */ |
334 | 406 | ||
335 | /*-------------------------------------------------------------------------*/ | 407 | /*-------------------------------------------------------------------------*/ |
@@ -382,55 +454,8 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf) | |||
382 | } | 454 | } |
383 | } | 455 | } |
384 | 456 | ||
385 | hcd->poll_rh = 1; | 457 | hcd->poll_rh = ohci_root_hub_state_changes(ohci, changed, |
386 | 458 | any_connected); | |
387 | /* carry out appropriate state changes */ | ||
388 | switch (ohci->hc_control & OHCI_CTRL_HCFS) { | ||
389 | |||
390 | case OHCI_USB_OPER: | ||
391 | /* keep on polling until we know a device is connected | ||
392 | * and RHSC is enabled */ | ||
393 | if (!ohci->autostop) { | ||
394 | if (any_connected) { | ||
395 | if (ohci_readl(ohci, &ohci->regs->intrenable) & | ||
396 | OHCI_INTR_RHSC) | ||
397 | hcd->poll_rh = 0; | ||
398 | } else { | ||
399 | ohci->autostop = 1; | ||
400 | ohci->next_statechange = jiffies + HZ; | ||
401 | } | ||
402 | |||
403 | /* if no devices have been attached for one second, autostop */ | ||
404 | } else { | ||
405 | if (changed || any_connected) { | ||
406 | ohci->autostop = 0; | ||
407 | ohci->next_statechange = jiffies + | ||
408 | STATECHANGE_DELAY; | ||
409 | } else if (device_may_wakeup(&hcd->self.root_hub->dev) | ||
410 | && time_after_eq(jiffies, | ||
411 | ohci->next_statechange) | ||
412 | && !ohci->ed_rm_list | ||
413 | && !(ohci->hc_control & | ||
414 | OHCI_SCHED_ENABLES)) { | ||
415 | ohci_rh_suspend (ohci, 1); | ||
416 | } | ||
417 | } | ||
418 | break; | ||
419 | |||
420 | /* if there is a port change, autostart or ask to be resumed */ | ||
421 | case OHCI_USB_SUSPEND: | ||
422 | case OHCI_USB_RESUME: | ||
423 | if (changed) { | ||
424 | if (ohci->autostop) | ||
425 | ohci_rh_resume (ohci); | ||
426 | else | ||
427 | usb_hcd_resume_root_hub (hcd); | ||
428 | } else { | ||
429 | /* everything is idle, no need for polling */ | ||
430 | hcd->poll_rh = 0; | ||
431 | } | ||
432 | break; | ||
433 | } | ||
434 | 459 | ||
435 | done: | 460 | done: |
436 | spin_unlock_irqrestore (&ohci->lock, flags); | 461 | spin_unlock_irqrestore (&ohci->lock, flags); |