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>

authored by

Alan Stern and committed by
Greg Kroah-Hartman
88018158 97b9eb91

+7 -4
+7 -4
drivers/usb/host/uhci-hub.c
··· 33 /* status change bits: nonzero writes will clear */ 34 #define RWC_BITS (USBPORTSC_OCC | USBPORTSC_PEC | USBPORTSC_CSC) 35 36 /* A port that either is connected or has a changed-bit set will prevent 37 * us from AUTO_STOPPING. 38 */ ··· 99 int status; 100 int i; 101 102 - if (inw(port_addr) & (USBPORTSC_SUSP | USBPORTSC_RD)) { 103 - CLR_RH_PORTSTAT(USBPORTSC_SUSP | USBPORTSC_RD); 104 if (test_bit(port, &uhci->resuming_ports)) 105 set_bit(port, &uhci->port_c_suspend); 106 ··· 110 * Experiments show that some controllers take longer, so 111 * we'll poll for completion. */ 112 for (i = 0; i < 10; ++i) { 113 - if (!(inw(port_addr) & USBPORTSC_RD)) 114 break; 115 udelay(1); 116 } ··· 292 wPortStatus |= USB_PORT_STAT_CONNECTION; 293 if (status & USBPORTSC_PE) { 294 wPortStatus |= USB_PORT_STAT_ENABLE; 295 - if (status & (USBPORTSC_SUSP | USBPORTSC_RD)) 296 wPortStatus |= USB_PORT_STAT_SUSPEND; 297 } 298 if (status & USBPORTSC_OC)
··· 33 /* status change bits: nonzero writes will clear */ 34 #define RWC_BITS (USBPORTSC_OCC | USBPORTSC_PEC | USBPORTSC_CSC) 35 36 + /* suspend/resume bits: port suspended or port resuming */ 37 + #define SUSPEND_BITS (USBPORTSC_SUSP | USBPORTSC_RD) 38 + 39 /* A port that either is connected or has a changed-bit set will prevent 40 * us from AUTO_STOPPING. 41 */ ··· 96 int status; 97 int i; 98 99 + if (inw(port_addr) & SUSPEND_BITS) { 100 + CLR_RH_PORTSTAT(SUSPEND_BITS); 101 if (test_bit(port, &uhci->resuming_ports)) 102 set_bit(port, &uhci->port_c_suspend); 103 ··· 107 * Experiments show that some controllers take longer, so 108 * we'll poll for completion. */ 109 for (i = 0; i < 10; ++i) { 110 + if (!(inw(port_addr) & SUSPEND_BITS)) 111 break; 112 udelay(1); 113 } ··· 289 wPortStatus |= USB_PORT_STAT_CONNECTION; 290 if (status & USBPORTSC_PE) { 291 wPortStatus |= USB_PORT_STAT_ENABLE; 292 + if (status & SUSPEND_BITS) 293 wPortStatus |= USB_PORT_STAT_SUSPEND; 294 } 295 if (status & USBPORTSC_OC)