aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/usb/host/uhci-hcd.c74
-rw-r--r--drivers/usb/host/uhci-hcd.h5
2 files changed, 61 insertions, 18 deletions
diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c
index d3e0d8aa3980..3a7bfe7a8874 100644
--- a/drivers/usb/host/uhci-hcd.c
+++ b/drivers/usb/host/uhci-hcd.c
@@ -234,7 +234,7 @@ static int resume_detect_interrupts_are_broken(struct uhci_hcd *uhci)
234 return 0; 234 return 0;
235} 235}
236 236
237static int remote_wakeup_is_broken(struct uhci_hcd *uhci) 237static int global_suspend_mode_is_broken(struct uhci_hcd *uhci)
238{ 238{
239 int port; 239 int port;
240 const char *sys_info; 240 const char *sys_info;
@@ -261,27 +261,60 @@ __releases(uhci->lock)
261__acquires(uhci->lock) 261__acquires(uhci->lock)
262{ 262{
263 int auto_stop; 263 int auto_stop;
264 int int_enable, egsm_enable; 264 int int_enable, egsm_enable, wakeup_enable;
265 struct usb_device *rhdev = uhci_to_hcd(uhci)->self.root_hub; 265 struct usb_device *rhdev = uhci_to_hcd(uhci)->self.root_hub;
266 266
267 auto_stop = (new_state == UHCI_RH_AUTO_STOPPED); 267 auto_stop = (new_state == UHCI_RH_AUTO_STOPPED);
268 dev_dbg(&rhdev->dev, "%s%s\n", __func__, 268 dev_dbg(&rhdev->dev, "%s%s\n", __func__,
269 (auto_stop ? " (auto-stop)" : "")); 269 (auto_stop ? " (auto-stop)" : ""));
270 270
271 /* Enable resume-detect interrupts if they work. 271 /* Start off by assuming Resume-Detect interrupts and EGSM work
272 * Then enter Global Suspend mode if _it_ works, still configured. 272 * and that remote wakeups should be enabled.
273 */ 273 */
274 egsm_enable = USBCMD_EGSM; 274 egsm_enable = USBCMD_EGSM;
275 uhci->working_RD = 1; 275 uhci->RD_enable = 1;
276 int_enable = USBINTR_RESUME; 276 int_enable = USBINTR_RESUME;
277 if (remote_wakeup_is_broken(uhci)) 277 wakeup_enable = 1;
278 egsm_enable = 0; 278
279 if (resume_detect_interrupts_are_broken(uhci) || !egsm_enable || 279 /* In auto-stop mode wakeups must always be detected, but
280 * Resume-Detect interrupts may be prohibited. (In the absence
281 * of CONFIG_PM, they are always disallowed.)
282 */
283 if (auto_stop) {
284 if (!device_may_wakeup(&rhdev->dev))
285 int_enable = 0;
286
287 /* In bus-suspend mode wakeups may be disabled, but if they are
288 * allowed then so are Resume-Detect interrupts.
289 */
290 } else {
280#ifdef CONFIG_PM 291#ifdef CONFIG_PM
281 (!auto_stop && !rhdev->do_remote_wakeup) || 292 if (!rhdev->do_remote_wakeup)
293 wakeup_enable = 0;
282#endif 294#endif
283 (auto_stop && !device_may_wakeup(&rhdev->dev))) 295 }
284 uhci->working_RD = int_enable = 0; 296
297 /* EGSM causes the root hub to echo a 'K' signal (resume) out any
298 * port which requests a remote wakeup. According to the USB spec,
299 * every hub is supposed to do this. But if we are ignoring
300 * remote-wakeup requests anyway then there's no point to it.
301 * We also shouldn't enable EGSM if it's broken.
302 */
303 if (!wakeup_enable || global_suspend_mode_is_broken(uhci))
304 egsm_enable = 0;
305
306 /* If we're ignoring wakeup events then there's no reason to
307 * enable Resume-Detect interrupts. We also shouldn't enable
308 * them if they are broken or disallowed.
309 *
310 * This logic may lead us to enabling RD but not EGSM. The UHCI
311 * spec foolishly says that RD works only when EGSM is on, but
312 * there's no harm in enabling it anyway -- perhaps some chips
313 * will implement it!
314 */
315 if (!wakeup_enable || resume_detect_interrupts_are_broken(uhci) ||
316 !int_enable)
317 uhci->RD_enable = int_enable = 0;
285 318
286 outw(int_enable, uhci->io_addr + USBINTR); 319 outw(int_enable, uhci->io_addr + USBINTR);
287 outw(egsm_enable | USBCMD_CF, uhci->io_addr + USBCMD); 320 outw(egsm_enable | USBCMD_CF, uhci->io_addr + USBCMD);
@@ -308,7 +341,11 @@ __acquires(uhci->lock)
308 341
309 uhci->rh_state = new_state; 342 uhci->rh_state = new_state;
310 uhci->is_stopped = UHCI_IS_STOPPED; 343 uhci->is_stopped = UHCI_IS_STOPPED;
311 uhci_to_hcd(uhci)->poll_rh = !int_enable; 344
345 /* If interrupts don't work and remote wakeup is enabled then
346 * the suspended root hub needs to be polled.
347 */
348 uhci_to_hcd(uhci)->poll_rh = (!int_enable && wakeup_enable);
312 349
313 uhci_scan_schedule(uhci); 350 uhci_scan_schedule(uhci);
314 uhci_fsbr_off(uhci); 351 uhci_fsbr_off(uhci);
@@ -344,9 +381,12 @@ __acquires(uhci->lock)
344 * for 20 ms. 381 * for 20 ms.
345 */ 382 */
346 if (uhci->rh_state == UHCI_RH_SUSPENDED) { 383 if (uhci->rh_state == UHCI_RH_SUSPENDED) {
384 unsigned egsm;
385
386 /* Keep EGSM on if it was set before */
387 egsm = inw(uhci->io_addr + USBCMD) & USBCMD_EGSM;
347 uhci->rh_state = UHCI_RH_RESUMING; 388 uhci->rh_state = UHCI_RH_RESUMING;
348 outw(USBCMD_FGR | USBCMD_EGSM | USBCMD_CF, 389 outw(USBCMD_FGR | USBCMD_CF | egsm, uhci->io_addr + USBCMD);
349 uhci->io_addr + USBCMD);
350 spin_unlock_irq(&uhci->lock); 390 spin_unlock_irq(&uhci->lock);
351 msleep(20); 391 msleep(20);
352 spin_lock_irq(&uhci->lock); 392 spin_lock_irq(&uhci->lock);
@@ -801,8 +841,10 @@ static int uhci_pci_resume(struct usb_hcd *hcd)
801 841
802 spin_unlock_irq(&uhci->lock); 842 spin_unlock_irq(&uhci->lock);
803 843
804 if (!uhci->working_RD) { 844 /* If interrupts don't work and remote wakeup is enabled then
805 /* Suspended root hub needs to be polled */ 845 * the suspended root hub needs to be polled.
846 */
847 if (!uhci->RD_enable && hcd->self.root_hub->do_remote_wakeup) {
806 hcd->poll_rh = 1; 848 hcd->poll_rh = 1;
807 usb_hcd_poll_rh_status(hcd); 849 usb_hcd_poll_rh_status(hcd);
808 } 850 }
diff --git a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h
index 340d6ed3e6e9..7d01c5677f92 100644
--- a/drivers/usb/host/uhci-hcd.h
+++ b/drivers/usb/host/uhci-hcd.h
@@ -400,8 +400,9 @@ struct uhci_hcd {
400 unsigned int scan_in_progress:1; /* Schedule scan is running */ 400 unsigned int scan_in_progress:1; /* Schedule scan is running */
401 unsigned int need_rescan:1; /* Redo the schedule scan */ 401 unsigned int need_rescan:1; /* Redo the schedule scan */
402 unsigned int dead:1; /* Controller has died */ 402 unsigned int dead:1; /* Controller has died */
403 unsigned int working_RD:1; /* Suspended root hub doesn't 403 unsigned int RD_enable:1; /* Suspended root hub with
404 need to be polled */ 404 Resume-Detect interrupts
405 enabled */
405 unsigned int is_initialized:1; /* Data structure is usable */ 406 unsigned int is_initialized:1; /* Data structure is usable */
406 unsigned int fsbr_is_on:1; /* FSBR is turned on */ 407 unsigned int fsbr_is_on:1; /* FSBR is turned on */
407 unsigned int fsbr_is_wanted:1; /* Does any URB want FSBR? */ 408 unsigned int fsbr_is_wanted:1; /* Does any URB want FSBR? */