aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/ehci-hub.c
diff options
context:
space:
mode:
authorMatthew Garrett <mjg@redhat.com>2011-01-11 12:26:48 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2011-02-25 14:32:13 -0500
commit294d95f2cbc2aef5346258f216cd9df570e271a5 (patch)
treee999eac991ebb3b4f43753cfe7d922eb0a9f05a4 /drivers/usb/host/ehci-hub.c
parent0fd857ae09c455f0036bf548fb6ec26b3049f5de (diff)
ehci: Check individual port status registers on resume
If a device plug/unplug is detected on an ATI SB700 USB controller in D3, it appears to set the port status register but not the controller status register. As a result we'll fail to detect the plug event. Check the port status register on resume as well in order to catch this case. Signed-off-by: Matthew Garrett <mjg@redhat.com> Cc: stable <stable@kernel.org> [after .39-rc1 is out] Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/host/ehci-hub.c')
-rw-r--r--drivers/usb/host/ehci-hub.c23
1 files changed, 22 insertions, 1 deletions
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index c0b37fedfbc2..ae0140dd9b9b 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -106,6 +106,27 @@ static void ehci_handover_companion_ports(struct ehci_hcd *ehci)
106 ehci->owned_ports = 0; 106 ehci->owned_ports = 0;
107} 107}
108 108
109static int ehci_port_change(struct ehci_hcd *ehci)
110{
111 int i = HCS_N_PORTS(ehci->hcs_params);
112
113 /* First check if the controller indicates a change event */
114
115 if (ehci_readl(ehci, &ehci->regs->status) & STS_PCD)
116 return 1;
117
118 /*
119 * Not all controllers appear to update this while going from D3 to D0,
120 * so check the individual port status registers as well
121 */
122
123 while (i--)
124 if (ehci_readl(ehci, &ehci->regs->port_status[i]) & PORT_CSC)
125 return 1;
126
127 return 0;
128}
129
109static void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci, 130static void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci,
110 bool suspending, bool do_wakeup) 131 bool suspending, bool do_wakeup)
111{ 132{
@@ -173,7 +194,7 @@ static void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci,
173 } 194 }
174 195
175 /* Does the root hub have a port wakeup pending? */ 196 /* Does the root hub have a port wakeup pending? */
176 if (!suspending && (ehci_readl(ehci, &ehci->regs->status) & STS_PCD)) 197 if (!suspending && ehci_port_change(ehci))
177 usb_hcd_resume_root_hub(ehci_to_hcd(ehci)); 198 usb_hcd_resume_root_hub(ehci_to_hcd(ehci));
178 199
179 spin_unlock_irqrestore(&ehci->lock, flags); 200 spin_unlock_irqrestore(&ehci->lock, flags);