aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2007-02-26 17:16:06 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2007-03-09 22:52:23 -0500
commit88018158d1253ab4868a2f9204cc390c711fd9b9 (patch)
treec624f1166911a7ecb4911fb69a2ef53cfaf242e3 /drivers
parent97b9eb91dc131a10342da1f604e5bd8b1316abdb (diff)
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>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/usb/host/uhci-hub.c11
1 files changed, 7 insertions, 4 deletions
diff --git a/drivers/usb/host/uhci-hub.c b/drivers/usb/host/uhci-hub.c
index bacc25c53ba..8e4427aebb1 100644
--- a/drivers/usb/host/uhci-hub.c
+++ b/drivers/usb/host/uhci-hub.c
@@ -33,6 +33,9 @@ static __u8 root_hub_hub_des[] =
33/* status change bits: nonzero writes will clear */ 33/* status change bits: nonzero writes will clear */
34#define RWC_BITS (USBPORTSC_OCC | USBPORTSC_PEC | USBPORTSC_CSC) 34#define RWC_BITS (USBPORTSC_OCC | USBPORTSC_PEC | USBPORTSC_CSC)
35 35
36/* suspend/resume bits: port suspended or port resuming */
37#define SUSPEND_BITS (USBPORTSC_SUSP | USBPORTSC_RD)
38
36/* A port that either is connected or has a changed-bit set will prevent 39/* A port that either is connected or has a changed-bit set will prevent
37 * us from AUTO_STOPPING. 40 * us from AUTO_STOPPING.
38 */ 41 */
@@ -96,8 +99,8 @@ static void uhci_finish_suspend(struct uhci_hcd *uhci, int port,
96 int status; 99 int status;
97 int i; 100 int i;
98 101
99 if (inw(port_addr) & (USBPORTSC_SUSP | USBPORTSC_RD)) { 102 if (inw(port_addr) & SUSPEND_BITS) {
100 CLR_RH_PORTSTAT(USBPORTSC_SUSP | USBPORTSC_RD); 103 CLR_RH_PORTSTAT(SUSPEND_BITS);
101 if (test_bit(port, &uhci->resuming_ports)) 104 if (test_bit(port, &uhci->resuming_ports))
102 set_bit(port, &uhci->port_c_suspend); 105 set_bit(port, &uhci->port_c_suspend);
103 106
@@ -107,7 +110,7 @@ static void uhci_finish_suspend(struct uhci_hcd *uhci, int port,
107 * Experiments show that some controllers take longer, so 110 * Experiments show that some controllers take longer, so
108 * we'll poll for completion. */ 111 * we'll poll for completion. */
109 for (i = 0; i < 10; ++i) { 112 for (i = 0; i < 10; ++i) {
110 if (!(inw(port_addr) & USBPORTSC_RD)) 113 if (!(inw(port_addr) & SUSPEND_BITS))
111 break; 114 break;
112 udelay(1); 115 udelay(1);
113 } 116 }
@@ -289,7 +292,7 @@ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
289 wPortStatus |= USB_PORT_STAT_CONNECTION; 292 wPortStatus |= USB_PORT_STAT_CONNECTION;
290 if (status & USBPORTSC_PE) { 293 if (status & USBPORTSC_PE) {
291 wPortStatus |= USB_PORT_STAT_ENABLE; 294 wPortStatus |= USB_PORT_STAT_ENABLE;
292 if (status & (USBPORTSC_SUSP | USBPORTSC_RD)) 295 if (status & SUSPEND_BITS)
293 wPortStatus |= USB_PORT_STAT_SUSPEND; 296 wPortStatus |= USB_PORT_STAT_SUSPEND;
294 } 297 }
295 if (status & USBPORTSC_OC) 298 if (status & USBPORTSC_OC)