summary refs log tree commit diff
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 14:23:27 -0800
commit052ac01aeb84d8427ba8ac3d70991ac01b009b59 (patch)
treeb232d996dab32777156c4d9f661711e8a29aee86 /drivers/usb/host/ohci-hub.c
parentb1878440d46a0dc357ed5c9687c534e20955e940 (diff)
downloadlinux-052ac01aeb84d8427ba8ac3d70991ac01b009b59.tar.gz
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)
 {
 	struct ohci_hcd		*ohci = hcd_to_ohci (hcd);
 
-	ohci_writel (ohci, OHCI_INTR_RHSC, &ohci->regs->intrenable);
+	spin_lock_irq(&ohci->lock);
+	if (!ohci->autostop)
+		del_timer(&hcd->rh_timer);	/* Prevent next poll */
+	ohci_writel(ohci, OHCI_INTR_RHSC, &ohci->regs->intrenable);
+	spin_unlock_irq(&ohci->lock);
 }
 
 #define OHCI_SCHED_ENABLES \
@@ -348,7 +352,7 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf)
 {
 	struct ohci_hcd	*ohci = hcd_to_ohci (hcd);
 	int		i, changed = 0, length = 1;
-	int		any_connected = 0, rhsc_enabled = 1;
+	int		any_connected = 0;
 	unsigned long	flags;
 
 	spin_lock_irqsave (&ohci->lock, flags);
@@ -389,19 +393,6 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf)
 		}
 	}
 
-	/* NOTE:  vendors didn't always make the same implementation
-	 * choices for RHSC.  Sometimes it triggers on an edge (like
-	 * setting and maybe clearing a port status change bit); and
-	 * it's level-triggered on other silicon, active until khubd
-	 * clears all active port status change bits.  If it's still
-	 * set (level-triggered) we must disable it and rely on
-	 * polling until khubd re-enables it.
-	 */
-	if (ohci_readl (ohci, &ohci->regs->intrstatus) & OHCI_INTR_RHSC) {
-		ohci_writel (ohci, OHCI_INTR_RHSC, &ohci->regs->intrdisable);
-		(void) ohci_readl (ohci, &ohci->regs->intrdisable);
-		rhsc_enabled = 0;
-	}
 	hcd->poll_rh = 1;
 
 	/* carry out appropriate state changes */
@@ -412,7 +403,8 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf)
 		 * and RHSC is enabled */
 		if (!ohci->autostop) {
 			if (any_connected) {
-				if (rhsc_enabled)
+				if (ohci_readl(ohci, &ohci->regs->intrenable) &
+						OHCI_INTR_RHSC)
 					hcd->poll_rh = 0;
 			} else {
 				ohci->autostop = 1;