aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/ohci-hub.c
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2006-10-27 10:33:11 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2006-12-01 17:23:27 -0500
commit052ac01aeb84d8427ba8ac3d70991ac01b009b59 (patch)
treeb232d996dab32777156c4d9f661711e8a29aee86 /drivers/usb/host/ohci-hub.c
parentb1878440d46a0dc357ed5c9687c534e20955e940 (diff)
USB: OHCI: disable RHSC inside interrupt handler
This patch (as808b) moves the Root Hub Status Change interrupt-disable code in ohci-hcd back into the interrupt handler proper, to avoid the chance of adverse interactions with mediocre hardware implementations. It also deletes the root-hub status timer from within the interrupt-enable routine. There's no need to poll for status any more once interrupts are re-enabled. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/host/ohci-hub.c')
-rw-r--r--drivers/usb/host/ohci-hub.c24
1 files changed, 8 insertions, 16 deletions
diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c
index 99357b99d133..1e5ed3bb1a93 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 \
@@ -348,7 +352,7 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf)
348{ 352{
349 struct ohci_hcd *ohci = hcd_to_ohci (hcd); 353 struct ohci_hcd *ohci = hcd_to_ohci (hcd);
350 int i, changed = 0, length = 1; 354 int i, changed = 0, length = 1;
351 int any_connected = 0, rhsc_enabled = 1; 355 int any_connected = 0;
352 unsigned long flags; 356 unsigned long flags;
353 357
354 spin_lock_irqsave (&ohci->lock, flags); 358 spin_lock_irqsave (&ohci->lock, flags);
@@ -389,19 +393,6 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf)
389 } 393 }
390 } 394 }
391 395
392 /* NOTE: vendors didn't always make the same implementation
393 * choices for RHSC. Sometimes it triggers on an edge (like
394 * setting and maybe clearing a port status change bit); and
395 * it's level-triggered on other silicon, active until khubd
396 * clears all active port status change bits. If it's still
397 * set (level-triggered) we must disable it and rely on
398 * polling until khubd re-enables it.
399 */
400 if (ohci_readl (ohci, &ohci->regs->intrstatus) & OHCI_INTR_RHSC) {
401 ohci_writel (ohci, OHCI_INTR_RHSC, &ohci->regs->intrdisable);
402 (void) ohci_readl (ohci, &ohci->regs->intrdisable);
403 rhsc_enabled = 0;
404 }
405 hcd->poll_rh = 1; 396 hcd->poll_rh = 1;
406 397
407 /* carry out appropriate state changes */ 398 /* carry out appropriate state changes */
@@ -412,7 +403,8 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf)
412 * and RHSC is enabled */ 403 * and RHSC is enabled */
413 if (!ohci->autostop) { 404 if (!ohci->autostop) {
414 if (any_connected) { 405 if (any_connected) {
415 if (rhsc_enabled) 406 if (ohci_readl(ohci, &ohci->regs->intrenable) &
407 OHCI_INTR_RHSC)
416 hcd->poll_rh = 0; 408 hcd->poll_rh = 0;
417 } else { 409 } else {
418 ohci->autostop = 1; 410 ohci->autostop = 1;