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

[PATCH] USB: UHCI: don't track suspended ports

Someone recently posted a bug report where it turned out that uhci-hcd
was disagreeing with the UHCI controller over whether or not a port was
suspended: The driver thought it wasn't and the hardware thought it was.
This patch (as665) fixes the problem and simplifies the driver by
removing the internal state-tracking completely.  Now the driver just
asks the hardware whether a port is suspended.
Signed-off-by: default avatarAlan Stern <stern@rowland.harvard.edu>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 01e89506
...@@ -115,8 +115,7 @@ static void finish_reset(struct uhci_hcd *uhci) ...@@ -115,8 +115,7 @@ static void finish_reset(struct uhci_hcd *uhci)
for (port = 0; port < uhci->rh_numports; ++port) for (port = 0; port < uhci->rh_numports; ++port)
outw(0, uhci->io_addr + USBPORTSC1 + (port * 2)); outw(0, uhci->io_addr + USBPORTSC1 + (port * 2));
uhci->port_c_suspend = uhci->suspended_ports = uhci->port_c_suspend = uhci->resuming_ports = 0;
uhci->resuming_ports = 0;
uhci->rh_state = UHCI_RH_RESET; uhci->rh_state = UHCI_RH_RESET;
uhci->is_stopped = UHCI_IS_STOPPED; uhci->is_stopped = UHCI_IS_STOPPED;
uhci_to_hcd(uhci)->state = HC_STATE_HALT; uhci_to_hcd(uhci)->state = HC_STATE_HALT;
......
...@@ -415,7 +415,6 @@ struct uhci_hcd { ...@@ -415,7 +415,6 @@ struct uhci_hcd {
/* Support for port suspend/resume/reset */ /* Support for port suspend/resume/reset */
unsigned long port_c_suspend; /* Bit-arrays of ports */ unsigned long port_c_suspend; /* Bit-arrays of ports */
unsigned long suspended_ports;
unsigned long resuming_ports; unsigned long resuming_ports;
unsigned long ports_timeout; /* Time to stop signalling */ unsigned long ports_timeout; /* Time to stop signalling */
......
...@@ -85,10 +85,9 @@ static void uhci_finish_suspend(struct uhci_hcd *uhci, int port, ...@@ -85,10 +85,9 @@ static void uhci_finish_suspend(struct uhci_hcd *uhci, int port,
{ {
int status; int status;
if (test_bit(port, &uhci->suspended_ports)) { if (inw(port_addr) & (USBPORTSC_SUSP | USBPORTSC_RD)) {
CLR_RH_PORTSTAT(USBPORTSC_SUSP | USBPORTSC_RD); CLR_RH_PORTSTAT(USBPORTSC_SUSP | USBPORTSC_RD);
clear_bit(port, &uhci->suspended_ports); if (test_bit(port, &uhci->resuming_ports))
clear_bit(port, &uhci->resuming_ports);
set_bit(port, &uhci->port_c_suspend); set_bit(port, &uhci->port_c_suspend);
/* The controller won't actually turn off the RD bit until /* The controller won't actually turn off the RD bit until
...@@ -97,6 +96,7 @@ static void uhci_finish_suspend(struct uhci_hcd *uhci, int port, ...@@ -97,6 +96,7 @@ static void uhci_finish_suspend(struct uhci_hcd *uhci, int port,
* slightly longer for good luck. */ * slightly longer for good luck. */
udelay(4); udelay(4);
} }
clear_bit(port, &uhci->resuming_ports);
} }
/* Wait for the UHCI controller in HP's iLO2 server management chip. /* Wait for the UHCI controller in HP's iLO2 server management chip.
...@@ -265,8 +265,6 @@ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, ...@@ -265,8 +265,6 @@ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
wPortChange |= USB_PORT_STAT_C_SUSPEND; wPortChange |= USB_PORT_STAT_C_SUSPEND;
lstatus |= 1; lstatus |= 1;
} }
if (test_bit(port, &uhci->suspended_ports))
lstatus |= 2;
if (test_bit(port, &uhci->resuming_ports)) if (test_bit(port, &uhci->resuming_ports))
lstatus |= 4; lstatus |= 4;
...@@ -309,7 +307,6 @@ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, ...@@ -309,7 +307,6 @@ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
switch (wValue) { switch (wValue) {
case USB_PORT_FEAT_SUSPEND: case USB_PORT_FEAT_SUSPEND:
set_bit(port, &uhci->suspended_ports);
SET_RH_PORTSTAT(USBPORTSC_SUSP); SET_RH_PORTSTAT(USBPORTSC_SUSP);
OK(0); OK(0);
case USB_PORT_FEAT_RESET: case USB_PORT_FEAT_RESET:
...@@ -343,8 +340,11 @@ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, ...@@ -343,8 +340,11 @@ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
CLR_RH_PORTSTAT(USBPORTSC_PEC); CLR_RH_PORTSTAT(USBPORTSC_PEC);
OK(0); OK(0);
case USB_PORT_FEAT_SUSPEND: case USB_PORT_FEAT_SUSPEND:
if (test_bit(port, &uhci->suspended_ports) && if (!(inw(port_addr) & USBPORTSC_SUSP)) {
!test_and_set_bit(port,
/* Make certain the port isn't suspended */
uhci_finish_suspend(uhci, port, port_addr);
} else if (!test_and_set_bit(port,
&uhci->resuming_ports)) { &uhci->resuming_ports)) {
SET_RH_PORTSTAT(USBPORTSC_RD); SET_RH_PORTSTAT(USBPORTSC_RD);
......
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