aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/ohci-hub.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2008-10-17 18:43:52 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2008-10-17 18:43:52 -0400
commit0cfd81031a26717fe14380d18275f8e217571615 (patch)
tree78a84e4cb97e7f45eb77dc0fbd8857a5dd717869 /drivers/usb/host/ohci-hub.c
parentf7ea4a4ba84f382e8eb143e435551de0feee5b4b (diff)
parent802f389a2cc6e2771b8de915ac241456d41eb79e (diff)
Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6: (94 commits) USB: remove err() macro from more usb drivers USB: remove err() macro from usb misc drivers USB: remove err() macro from usb core code USB: remove err() macro from usb class drivers USB: remove use of err() in drivers/usb/serial USB: remove info() macro from usb mtd drivers USB: remove info() macro from usb input drivers USB: remove info() macro from usb network drivers USB: remove info() macro from remaining usb drivers USB: remove info() macro from usb/misc drivers USB: remove info() macro from usb/serial drivers USB: remove warn macro from HID core USB: remove warn() macro from usb drivers USB: remove warn() macro from usb net drivers USB: remove warn() macro from usb media drivers USB: remove warn() macro from usb input drivers usb/fsl_qe_udc: clear data toggle on clear halt request usb/fsl_qe_udc: fix response to get status request fsl_usb2_udc: Fix oops on probe failure. fsl_usb2_udc: Add a wmb before priming endpoint. ...
Diffstat (limited to 'drivers/usb/host/ohci-hub.c')
-rw-r--r--drivers/usb/host/ohci-hub.c87
1 files changed, 52 insertions, 35 deletions
diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c
index 7ea9a7b31155..32bbce9718f0 100644
--- a/drivers/usb/host/ohci-hub.c
+++ b/drivers/usb/host/ohci-hub.c
@@ -359,21 +359,24 @@ static void ohci_finish_controller_resume(struct usb_hcd *hcd)
359 359
360/* Carry out polling-, autostop-, and autoresume-related state changes */ 360/* Carry out polling-, autostop-, and autoresume-related state changes */
361static int ohci_root_hub_state_changes(struct ohci_hcd *ohci, int changed, 361static int ohci_root_hub_state_changes(struct ohci_hcd *ohci, int changed,
362 int any_connected) 362 int any_connected, int rhsc_status)
363{ 363{
364 int poll_rh = 1; 364 int poll_rh = 1;
365 int rhsc; 365 int 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_enable = ohci_readl(ohci, &ohci->regs->intrenable) &
372 OHCI_INTR_RHSC;
369 373
374 switch (ohci->hc_control & OHCI_CTRL_HCFS) {
370 case OHCI_USB_OPER: 375 case OHCI_USB_OPER:
371 /* If no status changes are pending, enable status-change 376 /* If no status changes are pending, enable RHSC interrupts. */
372 * interrupts. 377 if (!rhsc_enable && !rhsc_status && !changed) {
373 */ 378 rhsc_enable = OHCI_INTR_RHSC;
374 if (!rhsc && !changed) { 379 ohci_writel(ohci, rhsc_enable, &ohci->regs->intrenable);
375 rhsc = OHCI_INTR_RHSC;
376 ohci_writel(ohci, rhsc, &ohci->regs->intrenable);
377 } 380 }
378 381
379 /* Keep on polling until we know a device is connected 382 /* Keep on polling until we know a device is connected
@@ -383,7 +386,7 @@ static int ohci_root_hub_state_changes(struct ohci_hcd *ohci, int changed,
383 if (any_connected || 386 if (any_connected ||
384 !device_may_wakeup(&ohci_to_hcd(ohci) 387 !device_may_wakeup(&ohci_to_hcd(ohci)
385 ->self.root_hub->dev)) { 388 ->self.root_hub->dev)) {
386 if (rhsc) 389 if (rhsc_enable)
387 poll_rh = 0; 390 poll_rh = 0;
388 } else { 391 } else {
389 ohci->autostop = 1; 392 ohci->autostop = 1;
@@ -396,34 +399,45 @@ static int ohci_root_hub_state_changes(struct ohci_hcd *ohci, int changed,
396 ohci->autostop = 0; 399 ohci->autostop = 0;
397 ohci->next_statechange = jiffies + 400 ohci->next_statechange = jiffies +
398 STATECHANGE_DELAY; 401 STATECHANGE_DELAY;
399 } else if (rhsc && time_after_eq(jiffies, 402 } else if (time_after_eq(jiffies,
400 ohci->next_statechange) 403 ohci->next_statechange)
401 && !ohci->ed_rm_list 404 && !ohci->ed_rm_list
402 && !(ohci->hc_control & 405 && !(ohci->hc_control &
403 OHCI_SCHED_ENABLES)) { 406 OHCI_SCHED_ENABLES)) {
404 ohci_rh_suspend(ohci, 1); 407 ohci_rh_suspend(ohci, 1);
405 poll_rh = 0; 408 if (rhsc_enable)
409 poll_rh = 0;
406 } 410 }
407 } 411 }
408 break; 412 break;
409 413
410 /* if there is a port change, autostart or ask to be resumed */
411 case OHCI_USB_SUSPEND: 414 case OHCI_USB_SUSPEND:
412 case OHCI_USB_RESUME: 415 case OHCI_USB_RESUME:
416 /* if there is a port change, autostart or ask to be resumed */
413 if (changed) { 417 if (changed) {
414 if (ohci->autostop) 418 if (ohci->autostop)
415 ohci_rh_resume(ohci); 419 ohci_rh_resume(ohci);
416 else 420 else
417 usb_hcd_resume_root_hub(ohci_to_hcd(ohci)); 421 usb_hcd_resume_root_hub(ohci_to_hcd(ohci));
418 } else {
419 if (!rhsc && (ohci->autostop ||
420 ohci_to_hcd(ohci)->self.root_hub->
421 do_remote_wakeup))
422 ohci_writel(ohci, OHCI_INTR_RHSC,
423 &ohci->regs->intrenable);
424 422
425 /* everything is idle, no need for polling */ 423 /* If remote wakeup is disabled, stop polling */
424 } else if (!ohci->autostop &&
425 !ohci_to_hcd(ohci)->self.root_hub->
426 do_remote_wakeup) {
426 poll_rh = 0; 427 poll_rh = 0;
428
429 } else {
430 /* If no status changes are pending,
431 * enable RHSC interrupts
432 */
433 if (!rhsc_enable && !rhsc_status) {
434 rhsc_enable = OHCI_INTR_RHSC;
435 ohci_writel(ohci, rhsc_enable,
436 &ohci->regs->intrenable);
437 }
438 /* Keep polling until RHSC is enabled */
439 if (rhsc_enable)
440 poll_rh = 0;
427 } 441 }
428 break; 442 break;
429 } 443 }
@@ -441,18 +455,22 @@ static inline int ohci_rh_resume(struct ohci_hcd *ohci)
441 * autostop isn't used when CONFIG_PM is turned off. 455 * autostop isn't used when CONFIG_PM is turned off.
442 */ 456 */
443static int ohci_root_hub_state_changes(struct ohci_hcd *ohci, int changed, 457static int ohci_root_hub_state_changes(struct ohci_hcd *ohci, int changed,
444 int any_connected) 458 int any_connected, int rhsc_status)
445{ 459{
446 /* If RHSC is enabled, don't poll */ 460 /* If RHSC is enabled, don't poll */
447 if (ohci_readl(ohci, &ohci->regs->intrenable) & OHCI_INTR_RHSC) 461 if (ohci_readl(ohci, &ohci->regs->intrenable) & OHCI_INTR_RHSC)
448 return 0; 462 return 0;
449 463
450 /* If no status changes are pending, enable status-change interrupts */ 464 /* If status changes are pending, continue polling.
451 if (!changed) { 465 * Conversely, if no status changes are pending but the RHSC
452 ohci_writel(ohci, OHCI_INTR_RHSC, &ohci->regs->intrenable); 466 * status bit was set, then RHSC may be broken so continue polling.
453 return 0; 467 */
454 } 468 if (changed || rhsc_status)
455 return 1; 469 return 1;
470
471 /* It's safe to re-enable RHSC interrupts */
472 ohci_writel(ohci, OHCI_INTR_RHSC, &ohci->regs->intrenable);
473 return 0;
456} 474}
457 475
458#endif /* CONFIG_PM */ 476#endif /* CONFIG_PM */
@@ -467,6 +485,7 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf)
467 struct ohci_hcd *ohci = hcd_to_ohci (hcd); 485 struct ohci_hcd *ohci = hcd_to_ohci (hcd);
468 int i, changed = 0, length = 1; 486 int i, changed = 0, length = 1;
469 int any_connected = 0; 487 int any_connected = 0;
488 int rhsc_status;
470 unsigned long flags; 489 unsigned long flags;
471 490
472 spin_lock_irqsave (&ohci->lock, flags); 491 spin_lock_irqsave (&ohci->lock, flags);
@@ -492,12 +511,10 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf)
492 length++; 511 length++;
493 } 512 }
494 513
495 /* Some broken controllers never turn off RHCS in the interrupt 514 /* Clear the RHSC status flag before reading the port statuses */
496 * status register. For their sake we won't re-enable RHSC 515 ohci_writel(ohci, OHCI_INTR_RHSC, &ohci->regs->intrstatus);
497 * interrupts if the flag is already set. 516 rhsc_status = ohci_readl(ohci, &ohci->regs->intrstatus) &
498 */ 517 OHCI_INTR_RHSC;
499 if (ohci_readl(ohci, &ohci->regs->intrstatus) & OHCI_INTR_RHSC)
500 changed = 1;
501 518
502 /* look at each port */ 519 /* look at each port */
503 for (i = 0; i < ohci->num_ports; i++) { 520 for (i = 0; i < ohci->num_ports; i++) {
@@ -517,7 +534,7 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf)
517 } 534 }
518 535
519 hcd->poll_rh = ohci_root_hub_state_changes(ohci, changed, 536 hcd->poll_rh = ohci_root_hub_state_changes(ohci, changed,
520 any_connected); 537 any_connected, rhsc_status);
521 538
522done: 539done:
523 spin_unlock_irqrestore (&ohci->lock, flags); 540 spin_unlock_irqrestore (&ohci->lock, flags);