diff options
| author | Alan Stern <stern@rowland.harvard.edu> | 2007-02-26 17:16:06 -0500 | 
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@suse.de> | 2007-03-09 19:52:23 -0800 | 
| commit | 88018158d1253ab4868a2f9204cc390c711fd9b9 (patch) | |
| tree | c624f1166911a7ecb4911fb69a2ef53cfaf242e3 /drivers/usb | |
| parent | 97b9eb91dc131a10342da1f604e5bd8b1316abdb (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/usb')
| -rw-r--r-- | drivers/usb/host/uhci-hub.c | 11 | 
1 files changed, 7 insertions, 4 deletions
| diff --git a/drivers/usb/host/uhci-hub.c b/drivers/usb/host/uhci-hub.c index bacc25c53ba3..8e4427aebb14 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[] =  /* status change bits:  nonzero writes will clear */  #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   * us from AUTO_STOPPING.   */ @@ -96,8 +99,8 @@ static void uhci_finish_suspend(struct uhci_hcd *uhci, int port,  	int status;  	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))  			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  		 * we'll poll for completion. */  		for (i = 0; i < 10; ++i) { -			if (!(inw(port_addr) & USBPORTSC_RD)) +			if (!(inw(port_addr) & SUSPEND_BITS))  				break;  			udelay(1);  		} @@ -289,7 +292,7 @@ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,  			wPortStatus |= USB_PORT_STAT_CONNECTION;  		if (status & USBPORTSC_PE) {  			wPortStatus |= USB_PORT_STAT_ENABLE; -			if (status & (USBPORTSC_SUSP | USBPORTSC_RD)) +			if (status & SUSPEND_BITS)  				wPortStatus |= USB_PORT_STAT_SUSPEND;  		}  		if (status & USBPORTSC_OC) | 
