aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/host/ohci-hub.c51
1 files changed, 32 insertions, 19 deletions
diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c
index a150e85c901a..32bbce9718f0 100644
--- a/drivers/usb/host/ohci-hub.c
+++ b/drivers/usb/host/ohci-hub.c
@@ -359,17 +359,15 @@ static void ohci_finish_controller_resume(struct usb_hcd *hcd)
359 359
360/* Carry out polling-, autostop-, and autoresume-related state changes */ 360/* Carry out polling-, autostop-, and autoresume-related state changes */
361static int ohci_root_hub_state_changes(struct ohci_hcd *ohci, int changed, 361static int ohci_root_hub_state_changes(struct ohci_hcd *ohci, int changed,
362 int any_connected) 362 int any_connected, int rhsc_status)
363{ 363{
364 int poll_rh = 1; 364 int poll_rh = 1;
365 int rhsc_status, rhsc_enable; 365 int rhsc_enable;
366 366
367 /* Some broken controllers never turn off RHCS in the interrupt 367 /* Some broken controllers never turn off RHCS in the interrupt
368 * status register. For their sake we won't re-enable RHSC 368 * status register. For their sake we won't re-enable RHSC
369 * interrupts if the interrupt bit is already active. 369 * interrupts if the interrupt bit is already active.
370 */ 370 */
371 rhsc_status = ohci_readl(ohci, &ohci->regs->intrstatus) &
372 OHCI_INTR_RHSC;
373 rhsc_enable = ohci_readl(ohci, &ohci->regs->intrenable) & 371 rhsc_enable = ohci_readl(ohci, &ohci->regs->intrenable) &
374 OHCI_INTR_RHSC; 372 OHCI_INTR_RHSC;
375 373
@@ -421,14 +419,23 @@ static int ohci_root_hub_state_changes(struct ohci_hcd *ohci, int changed,
421 ohci_rh_resume(ohci); 419 ohci_rh_resume(ohci);
422 else 420 else
423 usb_hcd_resume_root_hub(ohci_to_hcd(ohci)); 421 usb_hcd_resume_root_hub(ohci_to_hcd(ohci));
422
423 /* If remote wakeup is disabled, stop polling */
424 } else if (!ohci->autostop &&
425 !ohci_to_hcd(ohci)->self.root_hub->
426 do_remote_wakeup) {
427 poll_rh = 0;
428
424 } else { 429 } else {
425 if (!rhsc_enable && !rhsc_status && (ohci->autostop || 430 /* If no status changes are pending,
426 ohci_to_hcd(ohci)->self.root_hub-> 431 * enable RHSC interrupts
427 do_remote_wakeup)) { 432 */
433 if (!rhsc_enable && !rhsc_status) {
428 rhsc_enable = OHCI_INTR_RHSC; 434 rhsc_enable = OHCI_INTR_RHSC;
429 ohci_writel(ohci, rhsc_enable, 435 ohci_writel(ohci, rhsc_enable,
430 &ohci->regs->intrenable); 436 &ohci->regs->intrenable);
431 } 437 }
438 /* Keep polling until RHSC is enabled */
432 if (rhsc_enable) 439 if (rhsc_enable)
433 poll_rh = 0; 440 poll_rh = 0;
434 } 441 }
@@ -448,22 +455,22 @@ static inline int ohci_rh_resume(struct ohci_hcd *ohci)
448 * autostop isn't used when CONFIG_PM is turned off. 455 * autostop isn't used when CONFIG_PM is turned off.
449 */ 456 */
450static int ohci_root_hub_state_changes(struct ohci_hcd *ohci, int changed, 457static int ohci_root_hub_state_changes(struct ohci_hcd *ohci, int changed,
451 int any_connected) 458 int any_connected, int rhsc_status)
452{ 459{
453 int rhsc_status;
454
455 /* If RHSC is enabled, don't poll */ 460 /* If RHSC is enabled, don't poll */
456 if (ohci_readl(ohci, &ohci->regs->intrenable) & OHCI_INTR_RHSC) 461 if (ohci_readl(ohci, &ohci->regs->intrenable) & OHCI_INTR_RHSC)
457 return 0; 462 return 0;
458 463
459 /* If no status changes are pending, enable RHSC interrupts */ 464 /* If status changes are pending, continue polling.
460 rhsc_status = ohci_readl(ohci, &ohci->regs->intrstatus) & 465 * Conversely, if no status changes are pending but the RHSC
461 OHCI_INTR_RHSC; 466 * status bit was set, then RHSC may be broken so continue polling.
462 if (!changed && !rhsc_status) { 467 */
463 ohci_writel(ohci, OHCI_INTR_RHSC, &ohci->regs->intrenable); 468 if (changed || rhsc_status)
464 return 0; 469 return 1;
465 } 470
466 return 1; 471 /* It's safe to re-enable RHSC interrupts */
472 ohci_writel(ohci, OHCI_INTR_RHSC, &ohci->regs->intrenable);
473 return 0;
467} 474}
468 475
469#endif /* CONFIG_PM */ 476#endif /* CONFIG_PM */
@@ -478,6 +485,7 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf)
478 struct ohci_hcd *ohci = hcd_to_ohci (hcd); 485 struct ohci_hcd *ohci = hcd_to_ohci (hcd);
479 int i, changed = 0, length = 1; 486 int i, changed = 0, length = 1;
480 int any_connected = 0; 487 int any_connected = 0;
488 int rhsc_status;
481 unsigned long flags; 489 unsigned long flags;
482 490
483 spin_lock_irqsave (&ohci->lock, flags); 491 spin_lock_irqsave (&ohci->lock, flags);
@@ -503,6 +511,11 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf)
503 length++; 511 length++;
504 } 512 }
505 513
514 /* Clear the RHSC status flag before reading the port statuses */
515 ohci_writel(ohci, OHCI_INTR_RHSC, &ohci->regs->intrstatus);
516 rhsc_status = ohci_readl(ohci, &ohci->regs->intrstatus) &
517 OHCI_INTR_RHSC;
518
506 /* look at each port */ 519 /* look at each port */
507 for (i = 0; i < ohci->num_ports; i++) { 520 for (i = 0; i < ohci->num_ports; i++) {
508 u32 status = roothub_portstatus (ohci, i); 521 u32 status = roothub_portstatus (ohci, i);
@@ -521,7 +534,7 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf)
521 } 534 }
522 535
523 hcd->poll_rh = ohci_root_hub_state_changes(ohci, changed, 536 hcd->poll_rh = ohci_root_hub_state_changes(ohci, changed,
524 any_connected); 537 any_connected, rhsc_status);
525 538
526done: 539done:
527 spin_unlock_irqrestore (&ohci->lock, flags); 540 spin_unlock_irqrestore (&ohci->lock, flags);