diff options
Diffstat (limited to 'drivers/usb/host/ohci-hcd.c')
-rw-r--r-- | drivers/usb/host/ohci-hcd.c | 41 |
1 files changed, 32 insertions, 9 deletions
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 94d8cf4b36c1..0684f57c14a0 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c | |||
@@ -101,7 +101,7 @@ | |||
101 | 101 | ||
102 | #include "../core/hcd.h" | 102 | #include "../core/hcd.h" |
103 | 103 | ||
104 | #define DRIVER_VERSION "2005 April 22" | 104 | #define DRIVER_VERSION "2006 August 04" |
105 | #define DRIVER_AUTHOR "Roman Weissgaerber, David Brownell" | 105 | #define DRIVER_AUTHOR "Roman Weissgaerber, David Brownell" |
106 | #define DRIVER_DESC "USB 1.1 'Open' Host Controller (OHCI) Driver" | 106 | #define DRIVER_DESC "USB 1.1 'Open' Host Controller (OHCI) Driver" |
107 | 107 | ||
@@ -110,9 +110,10 @@ | |||
110 | #undef OHCI_VERBOSE_DEBUG /* not always helpful */ | 110 | #undef OHCI_VERBOSE_DEBUG /* not always helpful */ |
111 | 111 | ||
112 | /* For initializing controller (mask in an HCFS mode too) */ | 112 | /* For initializing controller (mask in an HCFS mode too) */ |
113 | #define OHCI_CONTROL_INIT OHCI_CTRL_CBSR | 113 | #define OHCI_CONTROL_INIT OHCI_CTRL_CBSR |
114 | #define OHCI_INTR_INIT \ | 114 | #define OHCI_INTR_INIT \ |
115 | (OHCI_INTR_MIE | OHCI_INTR_UE | OHCI_INTR_RD | OHCI_INTR_WDH) | 115 | (OHCI_INTR_MIE | OHCI_INTR_RHSC | OHCI_INTR_UE \ |
116 | | OHCI_INTR_RD | OHCI_INTR_WDH) | ||
116 | 117 | ||
117 | #ifdef __hppa__ | 118 | #ifdef __hppa__ |
118 | /* On PA-RISC, PDC can leave IR set incorrectly; ignore it there. */ | 119 | /* On PA-RISC, PDC can leave IR set incorrectly; ignore it there. */ |
@@ -128,6 +129,8 @@ | |||
128 | 129 | ||
129 | static const char hcd_name [] = "ohci_hcd"; | 130 | static const char hcd_name [] = "ohci_hcd"; |
130 | 131 | ||
132 | #define STATECHANGE_DELAY msecs_to_jiffies(300) | ||
133 | |||
131 | #include "ohci.h" | 134 | #include "ohci.h" |
132 | 135 | ||
133 | static void ohci_dump (struct ohci_hcd *ohci, int verbose); | 136 | static void ohci_dump (struct ohci_hcd *ohci, int verbose); |
@@ -446,7 +449,6 @@ static int ohci_init (struct ohci_hcd *ohci) | |||
446 | 449 | ||
447 | disable (ohci); | 450 | disable (ohci); |
448 | ohci->regs = hcd->regs; | 451 | ohci->regs = hcd->regs; |
449 | ohci->next_statechange = jiffies; | ||
450 | 452 | ||
451 | /* REVISIT this BIOS handshake is now moved into PCI "quirks", and | 453 | /* REVISIT this BIOS handshake is now moved into PCI "quirks", and |
452 | * was never needed for most non-PCI systems ... remove the code? | 454 | * was never needed for most non-PCI systems ... remove the code? |
@@ -637,10 +639,14 @@ retry: | |||
637 | return -EOVERFLOW; | 639 | return -EOVERFLOW; |
638 | } | 640 | } |
639 | 641 | ||
640 | /* start controller operations */ | 642 | /* use rhsc irqs after khubd is fully initialized */ |
643 | hcd->poll_rh = 1; | ||
644 | hcd->uses_new_polling = 1; | ||
645 | |||
646 | /* start controller operations */ | ||
641 | ohci->hc_control &= OHCI_CTRL_RWC; | 647 | ohci->hc_control &= OHCI_CTRL_RWC; |
642 | ohci->hc_control |= OHCI_CONTROL_INIT | OHCI_USB_OPER; | 648 | ohci->hc_control |= OHCI_CONTROL_INIT | OHCI_USB_OPER; |
643 | ohci_writel (ohci, ohci->hc_control, &ohci->regs->control); | 649 | ohci_writel (ohci, ohci->hc_control, &ohci->regs->control); |
644 | hcd->state = HC_STATE_RUNNING; | 650 | hcd->state = HC_STATE_RUNNING; |
645 | 651 | ||
646 | /* wake on ConnectStatusChange, matching external hubs */ | 652 | /* wake on ConnectStatusChange, matching external hubs */ |
@@ -648,7 +654,7 @@ retry: | |||
648 | 654 | ||
649 | /* Choose the interrupts we care about now, others later on demand */ | 655 | /* Choose the interrupts we care about now, others later on demand */ |
650 | mask = OHCI_INTR_INIT; | 656 | mask = OHCI_INTR_INIT; |
651 | ohci_writel (ohci, mask, &ohci->regs->intrstatus); | 657 | ohci_writel (ohci, ~0, &ohci->regs->intrstatus); |
652 | ohci_writel (ohci, mask, &ohci->regs->intrenable); | 658 | ohci_writel (ohci, mask, &ohci->regs->intrenable); |
653 | 659 | ||
654 | /* handle root hub init quirks ... */ | 660 | /* handle root hub init quirks ... */ |
@@ -672,6 +678,7 @@ retry: | |||
672 | // flush those writes | 678 | // flush those writes |
673 | (void) ohci_readl (ohci, &ohci->regs->control); | 679 | (void) ohci_readl (ohci, &ohci->regs->control); |
674 | 680 | ||
681 | ohci->next_statechange = jiffies + STATECHANGE_DELAY; | ||
675 | spin_unlock_irq (&ohci->lock); | 682 | spin_unlock_irq (&ohci->lock); |
676 | 683 | ||
677 | // POTPGT delay is bits 24-31, in 2 ms units. | 684 | // POTPGT delay is bits 24-31, in 2 ms units. |
@@ -709,7 +716,23 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd, struct pt_regs *ptregs) | |||
709 | /* interrupt for some other device? */ | 716 | /* interrupt for some other device? */ |
710 | } else if ((ints &= ohci_readl (ohci, ®s->intrenable)) == 0) { | 717 | } else if ((ints &= ohci_readl (ohci, ®s->intrenable)) == 0) { |
711 | return IRQ_NOTMINE; | 718 | return IRQ_NOTMINE; |
712 | } | 719 | } |
720 | |||
721 | /* NOTE: vendors didn't always make the same implementation | ||
722 | * choices for RHSC. Sometimes it triggers on an edge (like | ||
723 | * setting and maybe clearing a port status change bit); and | ||
724 | * it's level-triggered on other silicon, active until khubd | ||
725 | * clears all active port status change bits. Poll by timer | ||
726 | * til it's fully debounced and the difference won't matter. | ||
727 | */ | ||
728 | if (ints & OHCI_INTR_RHSC) { | ||
729 | ohci_vdbg (ohci, "rhsc\n"); | ||
730 | ohci_writel (ohci, OHCI_INTR_RHSC, ®s->intrdisable); | ||
731 | hcd->poll_rh = 1; | ||
732 | ohci->next_statechange = jiffies + STATECHANGE_DELAY; | ||
733 | ohci_writel (ohci, OHCI_INTR_RHSC, ®s->intrstatus); | ||
734 | usb_hcd_poll_rh_status(hcd); | ||
735 | } | ||
713 | 736 | ||
714 | if (ints & OHCI_INTR_UE) { | 737 | if (ints & OHCI_INTR_UE) { |
715 | disable (ohci); | 738 | disable (ohci); |