Commit 88018158 authored by Alan Stern's avatar Alan Stern Committed by Greg Kroah-Hartman

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: default avatarAlan Stern <stern@rowland.harvard.edu>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 97b9eb91
...@@ -33,6 +33,9 @@ static __u8 root_hub_hub_des[] = ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment