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>
This commit is contained in:
parent
97b9eb91dc
commit
88018158d1
|
@ -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)) {
|
if (inw(port_addr) & SUSPEND_BITS) {
|
||||||
CLR_RH_PORTSTAT(USBPORTSC_SUSP | USBPORTSC_RD);
|
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)
|
||||||
|
|
Loading…
Reference in New Issue