Browse Source

UHCI: fix port resume problem

This patch (as863) fixes a problem encountered sometimes when resuming
a port on a UHCI controller.  The hardware may turn off the
Resume-Detect bit before turning off the Suspend bit, leading usbcore
to think that the port is still suspended and the resume has failed.
The patch makes uhci_finish_suspend() wait until both bits are safely
off.

Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Alan Stern 18 years ago
parent
commit
88018158d1
1 changed files with 7 additions and 4 deletions
  1. 7 4
      drivers/usb/host/uhci-hub.c

+ 7 - 4
drivers/usb/host/uhci-hub.c

@@ -33,6 +33,9 @@ static __u8 root_hub_hub_des[] =
 /* status change bits:  nonzero writes will clear */
 /* status change bits:  nonzero writes will clear */
 #define RWC_BITS	(USBPORTSC_OCC | USBPORTSC_PEC | USBPORTSC_CSC)
 #define RWC_BITS	(USBPORTSC_OCC | USBPORTSC_PEC | USBPORTSC_CSC)
 
 
+/* suspend/resume bits: port suspended or port resuming */
+#define SUSPEND_BITS	(USBPORTSC_SUSP | USBPORTSC_RD)
+
 /* A port that either is connected or has a changed-bit set will prevent
 /* A port that either is connected or has a changed-bit set will prevent
  * us from AUTO_STOPPING.
  * us from AUTO_STOPPING.
  */
  */
@@ -96,8 +99,8 @@ static void uhci_finish_suspend(struct uhci_hcd *uhci, int port,
 	int status;
 	int status;
 	int i;
 	int i;
 
 
-	if (inw(port_addr) & (USBPORTSC_SUSP | USBPORTSC_RD)) {
-		CLR_RH_PORTSTAT(USBPORTSC_SUSP | USBPORTSC_RD);
+	if (inw(port_addr) & SUSPEND_BITS) {
+		CLR_RH_PORTSTAT(SUSPEND_BITS);
 		if (test_bit(port, &uhci->resuming_ports))
 		if (test_bit(port, &uhci->resuming_ports))
 			set_bit(port, &uhci->port_c_suspend);
 			set_bit(port, &uhci->port_c_suspend);
 
 
@@ -107,7 +110,7 @@ static void uhci_finish_suspend(struct uhci_hcd *uhci, int port,
 		 * Experiments show that some controllers take longer, so
 		 * Experiments show that some controllers take longer, so
 		 * we'll poll for completion. */
 		 * we'll poll for completion. */
 		for (i = 0; i < 10; ++i) {
 		for (i = 0; i < 10; ++i) {
-			if (!(inw(port_addr) & USBPORTSC_RD))
+			if (!(inw(port_addr) & SUSPEND_BITS))
 				break;
 				break;
 			udelay(1);
 			udelay(1);
 		}
 		}
@@ -289,7 +292,7 @@ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
 			wPortStatus |= USB_PORT_STAT_CONNECTION;
 			wPortStatus |= USB_PORT_STAT_CONNECTION;
 		if (status & USBPORTSC_PE) {
 		if (status & USBPORTSC_PE) {
 			wPortStatus |= USB_PORT_STAT_ENABLE;
 			wPortStatus |= USB_PORT_STAT_ENABLE;
-			if (status & (USBPORTSC_SUSP | USBPORTSC_RD))
+			if (status & SUSPEND_BITS)
 				wPortStatus |= USB_PORT_STAT_SUSPEND;
 				wPortStatus |= USB_PORT_STAT_SUSPEND;
 		}
 		}
 		if (status & USBPORTSC_OC)
 		if (status & USBPORTSC_OC)