|
@@ -36,18 +36,6 @@
|
|
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
|
|
-/* hcd->hub_irq_enable() */
|
|
|
|
-static void ohci_rhsc_enable (struct usb_hcd *hcd)
|
|
|
|
-{
|
|
|
|
- struct ohci_hcd *ohci = hcd_to_ohci (hcd);
|
|
|
|
-
|
|
|
|
- spin_lock_irq(&ohci->lock);
|
|
|
|
- if (!ohci->autostop)
|
|
|
|
- del_timer(&hcd->rh_timer); /* Prevent next poll */
|
|
|
|
- ohci_writel(ohci, OHCI_INTR_RHSC, &ohci->regs->intrenable);
|
|
|
|
- spin_unlock_irq(&ohci->lock);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
#define OHCI_SCHED_ENABLES \
|
|
#define OHCI_SCHED_ENABLES \
|
|
(OHCI_CTRL_CLE|OHCI_CTRL_BLE|OHCI_CTRL_PLE|OHCI_CTRL_IE)
|
|
(OHCI_CTRL_CLE|OHCI_CTRL_BLE|OHCI_CTRL_PLE|OHCI_CTRL_IE)
|
|
|
|
|
|
@@ -374,18 +362,28 @@ static int ohci_root_hub_state_changes(struct ohci_hcd *ohci, int changed,
|
|
int any_connected)
|
|
int any_connected)
|
|
{
|
|
{
|
|
int poll_rh = 1;
|
|
int poll_rh = 1;
|
|
|
|
+ int rhsc;
|
|
|
|
|
|
|
|
+ rhsc = ohci_readl(ohci, &ohci->regs->intrenable) & OHCI_INTR_RHSC;
|
|
switch (ohci->hc_control & OHCI_CTRL_HCFS) {
|
|
switch (ohci->hc_control & OHCI_CTRL_HCFS) {
|
|
|
|
|
|
case OHCI_USB_OPER:
|
|
case OHCI_USB_OPER:
|
|
- /* keep on polling until we know a device is connected
|
|
|
|
- * and RHSC is enabled */
|
|
|
|
|
|
+ /* If no status changes are pending, enable status-change
|
|
|
|
+ * interrupts.
|
|
|
|
+ */
|
|
|
|
+ if (!rhsc && !changed) {
|
|
|
|
+ rhsc = OHCI_INTR_RHSC;
|
|
|
|
+ ohci_writel(ohci, rhsc, &ohci->regs->intrenable);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* Keep on polling until we know a device is connected
|
|
|
|
+ * and RHSC is enabled, or until we autostop.
|
|
|
|
+ */
|
|
if (!ohci->autostop) {
|
|
if (!ohci->autostop) {
|
|
if (any_connected ||
|
|
if (any_connected ||
|
|
!device_may_wakeup(&ohci_to_hcd(ohci)
|
|
!device_may_wakeup(&ohci_to_hcd(ohci)
|
|
->self.root_hub->dev)) {
|
|
->self.root_hub->dev)) {
|
|
- if (ohci_readl(ohci, &ohci->regs->intrenable) &
|
|
|
|
- OHCI_INTR_RHSC)
|
|
|
|
|
|
+ if (rhsc)
|
|
poll_rh = 0;
|
|
poll_rh = 0;
|
|
} else {
|
|
} else {
|
|
ohci->autostop = 1;
|
|
ohci->autostop = 1;
|
|
@@ -398,12 +396,13 @@ static int ohci_root_hub_state_changes(struct ohci_hcd *ohci, int changed,
|
|
ohci->autostop = 0;
|
|
ohci->autostop = 0;
|
|
ohci->next_statechange = jiffies +
|
|
ohci->next_statechange = jiffies +
|
|
STATECHANGE_DELAY;
|
|
STATECHANGE_DELAY;
|
|
- } else if (time_after_eq(jiffies,
|
|
|
|
|
|
+ } else if (rhsc && time_after_eq(jiffies,
|
|
ohci->next_statechange)
|
|
ohci->next_statechange)
|
|
&& !ohci->ed_rm_list
|
|
&& !ohci->ed_rm_list
|
|
&& !(ohci->hc_control &
|
|
&& !(ohci->hc_control &
|
|
OHCI_SCHED_ENABLES)) {
|
|
OHCI_SCHED_ENABLES)) {
|
|
ohci_rh_suspend(ohci, 1);
|
|
ohci_rh_suspend(ohci, 1);
|
|
|
|
+ poll_rh = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
break;
|
|
@@ -417,6 +416,12 @@ static int ohci_root_hub_state_changes(struct ohci_hcd *ohci, int changed,
|
|
else
|
|
else
|
|
usb_hcd_resume_root_hub(ohci_to_hcd(ohci));
|
|
usb_hcd_resume_root_hub(ohci_to_hcd(ohci));
|
|
} else {
|
|
} else {
|
|
|
|
+ if (!rhsc && (ohci->autostop ||
|
|
|
|
+ ohci_to_hcd(ohci)->self.root_hub->
|
|
|
|
+ do_remote_wakeup))
|
|
|
|
+ ohci_writel(ohci, OHCI_INTR_RHSC,
|
|
|
|
+ &ohci->regs->intrenable);
|
|
|
|
+
|
|
/* everything is idle, no need for polling */
|
|
/* everything is idle, no need for polling */
|
|
poll_rh = 0;
|
|
poll_rh = 0;
|
|
}
|
|
}
|
|
@@ -438,12 +443,16 @@ static inline int ohci_rh_resume(struct ohci_hcd *ohci)
|
|
static int ohci_root_hub_state_changes(struct ohci_hcd *ohci, int changed,
|
|
static int ohci_root_hub_state_changes(struct ohci_hcd *ohci, int changed,
|
|
int any_connected)
|
|
int any_connected)
|
|
{
|
|
{
|
|
- int poll_rh = 1;
|
|
|
|
-
|
|
|
|
- /* keep on polling until RHSC is enabled */
|
|
|
|
|
|
+ /* If RHSC is enabled, don't poll */
|
|
if (ohci_readl(ohci, &ohci->regs->intrenable) & OHCI_INTR_RHSC)
|
|
if (ohci_readl(ohci, &ohci->regs->intrenable) & OHCI_INTR_RHSC)
|
|
- poll_rh = 0;
|
|
|
|
- return poll_rh;
|
|
|
|
|
|
+ return 0;
|
|
|
|
+
|
|
|
|
+ /* If no status changes are pending, enable status-change interrupts */
|
|
|
|
+ if (!changed) {
|
|
|
|
+ ohci_writel(ohci, OHCI_INTR_RHSC, &ohci->regs->intrenable);
|
|
|
|
+ return 0;
|
|
|
|
+ }
|
|
|
|
+ return 1;
|
|
}
|
|
}
|
|
|
|
|
|
#endif /* CONFIG_PM */
|
|
#endif /* CONFIG_PM */
|