aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/usb/host/ohci-hub.c60
1 files changed, 32 insertions, 28 deletions
diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c
index 7ea9a7b31155..a150e85c901a 100644
--- a/drivers/usb/host/ohci-hub.c
+++ b/drivers/usb/host/ohci-hub.c
@@ -362,18 +362,23 @@ static int ohci_root_hub_state_changes(struct ohci_hcd *ohci, int changed,
362 int any_connected) 362 int any_connected)
363{ 363{
364 int poll_rh = 1; 364 int poll_rh = 1;
365 int rhsc; 365 int rhsc_status, rhsc_enable;
366 366
367 rhsc = ohci_readl(ohci, &ohci->regs->intrenable) & OHCI_INTR_RHSC; 367 /* Some broken controllers never turn off RHCS in the interrupt
368 switch (ohci->hc_control & OHCI_CTRL_HCFS) { 368 * status register. For their sake we won't re-enable RHSC
369 * interrupts if the interrupt bit is already active.
370 */
371 rhsc_status = ohci_readl(ohci, &ohci->regs->intrstatus) &
372 OHCI_INTR_RHSC;
373 rhsc_enable = ohci_readl(ohci, &ohci->regs->intrenable) &
374 OHCI_INTR_RHSC;
369 375
376 switch (ohci->hc_control & OHCI_CTRL_HCFS) {
370 case OHCI_USB_OPER: 377 case OHCI_USB_OPER:
371 /* If no status changes are pending, enable status-change 378 /* If no status changes are pending, enable RHSC interrupts. */
372 * interrupts. 379 if (!rhsc_enable && !rhsc_status && !changed) {
373 */ 380 rhsc_enable = OHCI_INTR_RHSC;
374 if (!rhsc && !changed) { 381 ohci_writel(ohci, rhsc_enable, &ohci->regs->intrenable);
375 rhsc = OHCI_INTR_RHSC;
376 ohci_writel(ohci, rhsc, &ohci->regs->intrenable);
377 } 382 }
378 383
379 /* Keep on polling until we know a device is connected 384 /* Keep on polling until we know a device is connected
@@ -383,7 +388,7 @@ static int ohci_root_hub_state_changes(struct ohci_hcd *ohci, int changed,
383 if (any_connected || 388 if (any_connected ||
384 !device_may_wakeup(&ohci_to_hcd(ohci) 389 !device_may_wakeup(&ohci_to_hcd(ohci)
385 ->self.root_hub->dev)) { 390 ->self.root_hub->dev)) {
386 if (rhsc) 391 if (rhsc_enable)
387 poll_rh = 0; 392 poll_rh = 0;
388 } else { 393 } else {
389 ohci->autostop = 1; 394 ohci->autostop = 1;
@@ -396,34 +401,36 @@ static int ohci_root_hub_state_changes(struct ohci_hcd *ohci, int changed,
396 ohci->autostop = 0; 401 ohci->autostop = 0;
397 ohci->next_statechange = jiffies + 402 ohci->next_statechange = jiffies +
398 STATECHANGE_DELAY; 403 STATECHANGE_DELAY;
399 } else if (rhsc && time_after_eq(jiffies, 404 } else if (time_after_eq(jiffies,
400 ohci->next_statechange) 405 ohci->next_statechange)
401 && !ohci->ed_rm_list 406 && !ohci->ed_rm_list
402 && !(ohci->hc_control & 407 && !(ohci->hc_control &
403 OHCI_SCHED_ENABLES)) { 408 OHCI_SCHED_ENABLES)) {
404 ohci_rh_suspend(ohci, 1); 409 ohci_rh_suspend(ohci, 1);
405 poll_rh = 0; 410 if (rhsc_enable)
411 poll_rh = 0;
406 } 412 }
407 } 413 }
408 break; 414 break;
409 415
410 /* if there is a port change, autostart or ask to be resumed */
411 case OHCI_USB_SUSPEND: 416 case OHCI_USB_SUSPEND:
412 case OHCI_USB_RESUME: 417 case OHCI_USB_RESUME:
418 /* if there is a port change, autostart or ask to be resumed */
413 if (changed) { 419 if (changed) {
414 if (ohci->autostop) 420 if (ohci->autostop)
415 ohci_rh_resume(ohci); 421 ohci_rh_resume(ohci);
416 else 422 else
417 usb_hcd_resume_root_hub(ohci_to_hcd(ohci)); 423 usb_hcd_resume_root_hub(ohci_to_hcd(ohci));
418 } else { 424 } else {
419 if (!rhsc && (ohci->autostop || 425 if (!rhsc_enable && !rhsc_status && (ohci->autostop ||
420 ohci_to_hcd(ohci)->self.root_hub-> 426 ohci_to_hcd(ohci)->self.root_hub->
421 do_remote_wakeup)) 427 do_remote_wakeup)) {
422 ohci_writel(ohci, OHCI_INTR_RHSC, 428 rhsc_enable = OHCI_INTR_RHSC;
429 ohci_writel(ohci, rhsc_enable,
423 &ohci->regs->intrenable); 430 &ohci->regs->intrenable);
424 431 }
425 /* everything is idle, no need for polling */ 432 if (rhsc_enable)
426 poll_rh = 0; 433 poll_rh = 0;
427 } 434 }
428 break; 435 break;
429 } 436 }
@@ -443,12 +450,16 @@ static inline int ohci_rh_resume(struct ohci_hcd *ohci)
443static int ohci_root_hub_state_changes(struct ohci_hcd *ohci, int changed, 450static int ohci_root_hub_state_changes(struct ohci_hcd *ohci, int changed,
444 int any_connected) 451 int any_connected)
445{ 452{
453 int rhsc_status;
454
446 /* If RHSC is enabled, don't poll */ 455 /* If RHSC is enabled, don't poll */
447 if (ohci_readl(ohci, &ohci->regs->intrenable) & OHCI_INTR_RHSC) 456 if (ohci_readl(ohci, &ohci->regs->intrenable) & OHCI_INTR_RHSC)
448 return 0; 457 return 0;
449 458
450 /* If no status changes are pending, enable status-change interrupts */ 459 /* If no status changes are pending, enable RHSC interrupts */
451 if (!changed) { 460 rhsc_status = ohci_readl(ohci, &ohci->regs->intrstatus) &
461 OHCI_INTR_RHSC;
462 if (!changed && !rhsc_status) {
452 ohci_writel(ohci, OHCI_INTR_RHSC, &ohci->regs->intrenable); 463 ohci_writel(ohci, OHCI_INTR_RHSC, &ohci->regs->intrenable);
453 return 0; 464 return 0;
454 } 465 }
@@ -492,13 +503,6 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf)
492 length++; 503 length++;
493 } 504 }
494 505
495 /* Some broken controllers never turn off RHCS in the interrupt
496 * status register. For their sake we won't re-enable RHSC
497 * interrupts if the flag is already set.
498 */
499 if (ohci_readl(ohci, &ohci->regs->intrstatus) & OHCI_INTR_RHSC)
500 changed = 1;
501
502 /* look at each port */ 506 /* look at each port */
503 for (i = 0; i < ohci->num_ports; i++) { 507 for (i = 0; i < ohci->num_ports; i++) {
504 u32 status = roothub_portstatus (ohci, i); 508 u32 status = roothub_portstatus (ohci, i);