]>
Commit | Line | Data |
---|---|---|
a1cd50fd GKH |
1 | From stable-bounces@linux.kernel.org Mon Feb 26 14:17:37 2007 |
2 | From: Alan Stern <stern@rowland.harvard.edu> | |
3 | Date: Mon, 26 Feb 2007 17:16:06 -0500 (EST) | |
4 | Subject: UHCI: fix port resume problem | |
5 | To: Greg KH <greg@kroah.com>, <stable@kernel.org> | |
6 | Cc: Guilherme Salgado <gsalgado@gmail.com>, USB development list <linux-usb-devel@lists.sourceforge.net> | |
7 | Message-ID: <Pine.LNX.4.44L0.0702261713080.3374-100000@iolanthe.rowland.org> | |
8 | ||
9 | From: Alan Stern <stern@rowland.harvard.edu> | |
10 | ||
11 | This patch (as863) fixes a problem encountered sometimes when resuming | |
12 | a port on a UHCI controller. The hardware may turn off the | |
13 | Resume-Detect bit before turning off the Suspend bit, leading usbcore | |
14 | to think that the port is still suspended and the resume has failed. | |
15 | The patch makes uhci_finish_suspend() wait until both bits are safely | |
16 | off. | |
17 | ||
18 | Signed-off-by: Alan Stern <stern@rowland.harvard.edu> | |
19 | Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> | |
20 | ||
21 | --- | |
22 | drivers/usb/host/uhci-hub.c | 11 +++++++---- | |
23 | 1 file changed, 7 insertions(+), 4 deletions(-) | |
24 | ||
25 | --- linux-2.6.20.1.orig/drivers/usb/host/uhci-hub.c | |
26 | +++ linux-2.6.20.1/drivers/usb/host/uhci-hub.c | |
27 | @@ -33,6 +33,9 @@ static __u8 root_hub_hub_des[] = | |
28 | /* status change bits: nonzero writes will clear */ | |
29 | #define RWC_BITS (USBPORTSC_OCC | USBPORTSC_PEC | USBPORTSC_CSC) | |
30 | ||
31 | +/* suspend/resume bits: port suspended or port resuming */ | |
32 | +#define SUSPEND_BITS (USBPORTSC_SUSP | USBPORTSC_RD) | |
33 | + | |
34 | /* A port that either is connected or has a changed-bit set will prevent | |
35 | * us from AUTO_STOPPING. | |
36 | */ | |
37 | @@ -96,8 +99,8 @@ static void uhci_finish_suspend(struct u | |
38 | int status; | |
39 | int i; | |
40 | ||
41 | - if (inw(port_addr) & (USBPORTSC_SUSP | USBPORTSC_RD)) { | |
42 | - CLR_RH_PORTSTAT(USBPORTSC_SUSP | USBPORTSC_RD); | |
43 | + if (inw(port_addr) & SUSPEND_BITS) { | |
44 | + CLR_RH_PORTSTAT(SUSPEND_BITS); | |
45 | if (test_bit(port, &uhci->resuming_ports)) | |
46 | set_bit(port, &uhci->port_c_suspend); | |
47 | ||
48 | @@ -107,7 +110,7 @@ static void uhci_finish_suspend(struct u | |
49 | * Experiments show that some controllers take longer, so | |
50 | * we'll poll for completion. */ | |
51 | for (i = 0; i < 10; ++i) { | |
52 | - if (!(inw(port_addr) & USBPORTSC_RD)) | |
53 | + if (!(inw(port_addr) & SUSPEND_BITS)) | |
54 | break; | |
55 | udelay(1); | |
56 | } | |
57 | @@ -289,7 +292,7 @@ static int uhci_hub_control(struct usb_h | |
58 | wPortStatus |= USB_PORT_STAT_CONNECTION; | |
59 | if (status & USBPORTSC_PE) { | |
60 | wPortStatus |= USB_PORT_STAT_ENABLE; | |
61 | - if (status & (USBPORTSC_SUSP | USBPORTSC_RD)) | |
62 | + if (status & SUSPEND_BITS) | |
63 | wPortStatus |= USB_PORT_STAT_SUSPEND; | |
64 | } | |
65 | if (status & USBPORTSC_OC) |