Google
  Web www.spinics.net

Test patch for OHCI RHSC

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]


Meelis and Andrey:

Here's a patch for the two of you to test.  If you don't enable 
CONFIG_PM then it shouldn't make any difference, but if you do then it 
should allow your OHCI controllers to enter a low-power state when no 
devices are attached.  Hopefully it will behave properly even when 
faced with your broken OHCI hardware.

Alan Stern



Index: usb-2.6/drivers/usb/host/ohci-hub.c
===================================================================
--- usb-2.6.orig/drivers/usb/host/ohci-hub.c
+++ usb-2.6/drivers/usb/host/ohci-hub.c
@@ -362,18 +362,23 @@ static int ohci_root_hub_state_changes(s
 		int any_connected)
 {
 	int	poll_rh = 1;
-	int	rhsc;
+	int	rhsc_status, rhsc_enable;
 
-	rhsc = ohci_readl(ohci, &ohci->regs->intrenable) & OHCI_INTR_RHSC;
-	switch (ohci->hc_control & OHCI_CTRL_HCFS) {
+	/* Some broken controllers never turn off RHCS in the interrupt
+	 * status register.  For their sake we won't re-enable RHSC
+	 * interrupts if the interrupt bit is already active.
+	 */
+	rhsc_status = ohci_readl(ohci, &ohci->regs->intrstatus) &
+			OHCI_INTR_RHSC;
+	rhsc_enable = ohci_readl(ohci, &ohci->regs->intrenable) &
+			OHCI_INTR_RHSC;
 
+	switch (ohci->hc_control & OHCI_CTRL_HCFS) {
 	case OHCI_USB_OPER:
-		/* If no status changes are pending, enable status-change
-		 * interrupts.
-		 */
-		if (!rhsc && !changed) {
-			rhsc = OHCI_INTR_RHSC;
-			ohci_writel(ohci, rhsc, &ohci->regs->intrenable);
+		/* If no status changes are pending, enable RHSC interrupts. */
+		if (!rhsc_enable && !rhsc_status && !changed) {
+			rhsc_enable = OHCI_INTR_RHSC;
+			ohci_writel(ohci, rhsc_enable, &ohci->regs->intrenable);
 		}
 
 		/* Keep on polling until we know a device is connected
@@ -383,7 +388,7 @@ static int ohci_root_hub_state_changes(s
 			if (any_connected ||
 					!device_may_wakeup(&ohci_to_hcd(ohci)
 						->self.root_hub->dev)) {
-				if (rhsc)
+				if (rhsc_enable)
 					poll_rh = 0;
 			} else {
 				ohci->autostop = 1;
@@ -396,34 +401,36 @@ static int ohci_root_hub_state_changes(s
 				ohci->autostop = 0;
 				ohci->next_statechange = jiffies +
 						STATECHANGE_DELAY;
-			} else if (rhsc && time_after_eq(jiffies,
+			} else if (time_after_eq(jiffies,
 						ohci->next_statechange)
 					&& !ohci->ed_rm_list
 					&& !(ohci->hc_control &
 						OHCI_SCHED_ENABLES)) {
 				ohci_rh_suspend(ohci, 1);
-				poll_rh = 0;
+				if (rhsc_enable)
+					poll_rh = 0;
 			}
 		}
 		break;
 
-	/* if there is a port change, autostart or ask to be resumed */
 	case OHCI_USB_SUSPEND:
 	case OHCI_USB_RESUME:
+		/* if there is a port change, autostart or ask to be resumed */
 		if (changed) {
 			if (ohci->autostop)
 				ohci_rh_resume(ohci);
 			else
 				usb_hcd_resume_root_hub(ohci_to_hcd(ohci));
 		} else {
-			if (!rhsc && (ohci->autostop ||
+			if (!rhsc_enable && !rhsc_status && (ohci->autostop ||
 					ohci_to_hcd(ohci)->self.root_hub->
-						do_remote_wakeup))
-				ohci_writel(ohci, OHCI_INTR_RHSC,
+						do_remote_wakeup)) {
+				rhsc_enable = OHCI_INTR_RHSC;
+				ohci_writel(ohci, rhsc_enable,
 						&ohci->regs->intrenable);
-
-			/* everything is idle, no need for polling */
-			poll_rh = 0;
+			}
+			if (rhsc_enable)
+				poll_rh = 0;
 		}
 		break;
 	}
@@ -443,12 +450,16 @@ static inline int ohci_rh_resume(struct 
 static int ohci_root_hub_state_changes(struct ohci_hcd *ohci, int changed,
 		int any_connected)
 {
+	int	rhsc_status;
+
 	/* If RHSC is enabled, don't poll */
 	if (ohci_readl(ohci, &ohci->regs->intrenable) & OHCI_INTR_RHSC)
 		return 0;
 
-	/* If no status changes are pending, enable status-change interrupts */
-	if (!changed) {
+	/* If no status changes are pending, enable RHSC interrupts */
+	rhsc_status = ohci_readl(ohci, &ohci->regs->intrstatus) &
+			OHCI_INTR_RHSC;
+	if (!changed && !rhsc_status) {
 		ohci_writel(ohci, OHCI_INTR_RHSC, &ohci->regs->intrenable);
 		return 0;
 	}
@@ -492,13 +503,6 @@ ohci_hub_status_data (struct usb_hcd *hc
 		length++;
 	}
 
-	/* Some broken controllers never turn off RHCS in the interrupt
-	 * status register.  For their sake we won't re-enable RHSC
-	 * interrupts if the flag is already set.
-	 */
-	if (ohci_readl(ohci, &ohci->regs->intrstatus) & OHCI_INTR_RHSC)
-		changed = 1;
-
 	/* look at each port */
 	for (i = 0; i < ohci->num_ports; i++) {
 		u32	status = roothub_portstatus (ohci, i);

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Home]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Photo]     [Yosemite News]    [Yosemite Photos]    [Video Projectors]     [PDAs]     [Free Online Dating]     [Hacking TiVo]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Devices]     [Big List of Linux Books]     [16.7MP]

Add to Google Powered by Linux