aboutsummaryrefslogtreecommitdiff
path: root/drivers/usb/host/uhci-hcd.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/host/uhci-hcd.c')
-rw-r--r--drivers/usb/host/uhci-hcd.c70
1 files changed, 23 insertions, 47 deletions
diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c
index 82e608a4bbd..25a718eb1d0 100644
--- a/drivers/usb/host/uhci-hcd.c
+++ b/drivers/usb/host/uhci-hcd.c
@@ -84,6 +84,8 @@ static char *errbuf;
static kmem_cache_t *uhci_up_cachep; /* urb_priv */
+static void suspend_rh(struct uhci_hcd *uhci, enum uhci_rh_state new_state);
+static void wakeup_rh(struct uhci_hcd *uhci);
static void uhci_get_current_frame_number(struct uhci_hcd *uhci);
/* If a transfer is still active after this much time, turn off FSBR */
@@ -133,12 +135,12 @@ static void reset_hc(struct uhci_hcd *uhci)
outw(0, uhci->io_addr + USBINTR);
outw(0, uhci->io_addr + USBCMD);
- uhci->resume_detect = 0;
uhci->port_c_suspend = uhci->suspended_ports =
uhci->resuming_ports = 0;
uhci->rh_state = UHCI_RH_RESET;
uhci->is_stopped = UHCI_IS_STOPPED;
uhci_to_hcd(uhci)->state = HC_STATE_HALT;
+ uhci_to_hcd(uhci)->poll_rh = 0;
}
/*
@@ -148,6 +150,7 @@ static void hc_died(struct uhci_hcd *uhci)
{
reset_hc(uhci);
uhci->hc_inaccessible = 1;
+ del_timer(&uhci->stall_timer);
}
/*
@@ -302,14 +305,14 @@ __acquires(uhci->lock)
uhci->rh_state = new_state;
uhci->is_stopped = UHCI_IS_STOPPED;
- uhci->resume_detect = 0;
+ del_timer(&uhci->stall_timer);
+ uhci_to_hcd(uhci)->poll_rh = !int_enable;
uhci_scan_schedule(uhci, NULL);
}
static void start_rh(struct uhci_hcd *uhci)
{
- uhci->rh_state = UHCI_RH_RUNNING;
uhci->is_stopped = 0;
smp_wmb();
@@ -320,6 +323,9 @@ static void start_rh(struct uhci_hcd *uhci)
outw(USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC | USBINTR_SP,
uhci->io_addr + USBINTR);
mb();
+ uhci->rh_state = UHCI_RH_RUNNING;
+ uhci_to_hcd(uhci)->poll_rh = 1;
+ restart_timer(uhci);
}
static void wakeup_rh(struct uhci_hcd *uhci)
@@ -353,36 +359,9 @@ __acquires(uhci->lock)
}
start_rh(uhci);
-}
-
-static void rh_state_transitions(struct uhci_hcd *uhci)
-{
- switch (uhci->rh_state) {
- case UHCI_RH_RUNNING:
- /* are any devices attached? */
- if (!any_ports_active(uhci)) {
- uhci->rh_state = UHCI_RH_RUNNING_NODEVS;
- uhci->auto_stop_time = jiffies + HZ;
- }
- break;
- case UHCI_RH_RUNNING_NODEVS:
- /* auto-stop if nothing connected for 1 second */
- if (any_ports_active(uhci))
- uhci->rh_state = UHCI_RH_RUNNING;
- else if (time_after_eq(jiffies, uhci->auto_stop_time))
- suspend_rh(uhci, UHCI_RH_AUTO_STOPPED);
- break;
-
- case UHCI_RH_AUTO_STOPPED:
- /* wakeup if requested by a device */
- if (uhci->resume_detect)
- wakeup_rh(uhci);
- break;
-
- default:
- break;
- }
+ /* Restart root hub polling */
+ mod_timer(&uhci_to_hcd(uhci)->rh_timer, jiffies);
}
static void stall_callback(unsigned long _uhci)
@@ -394,14 +373,8 @@ static void stall_callback(unsigned long _uhci)
uhci_scan_schedule(uhci, NULL);
check_fsbr(uhci);
- /* Poll for and perform state transitions */
- if (!uhci->hc_inaccessible) {
- rh_state_transitions(uhci);
- if (uhci->suspended_ports)
- uhci_check_ports(uhci);
- }
-
- restart_timer(uhci);
+ if (!uhci->is_stopped)
+ restart_timer(uhci);
spin_unlock_irqrestore(&uhci->lock, flags);
}
@@ -443,7 +416,7 @@ static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs)
}
if (status & USBSTS_RD)
- uhci->resume_detect = 1;
+ usb_hcd_poll_rh_status(hcd);
spin_lock_irqsave(&uhci->lock, flags);
uhci_scan_schedule(uhci, regs);
@@ -542,6 +515,7 @@ static int uhci_start(struct usb_hcd *hcd)
struct dentry *dentry;
io_size = (unsigned) hcd->rsrc_len;
+ hcd->uses_new_polling = 1;
if (pci_find_capability(to_pci_dev(uhci_dev(uhci)), PCI_CAP_ID_PM))
hcd->can_wakeup = 1; /* Assume it supports PME# */
@@ -714,8 +688,6 @@ static int uhci_start(struct usb_hcd *hcd)
configure_hc(uhci);
start_rh(uhci);
- restart_timer(uhci);
-
udev->speed = USB_SPEED_FULL;
if (usb_hcd_register_root_hub(udev, hcd) != 0) {
@@ -730,8 +702,8 @@ static int uhci_start(struct usb_hcd *hcd)
* error exits:
*/
err_start_root_hub:
- del_timer_sync(&uhci->stall_timer);
reset_hc(uhci);
+ del_timer_sync(&uhci->stall_timer);
err_alloc_skelqh:
for (i = 0; i < UHCI_NUM_SKELQH; i++)
@@ -771,13 +743,12 @@ static void uhci_stop(struct usb_hcd *hcd)
{
struct uhci_hcd *uhci = hcd_to_uhci(hcd);
- del_timer_sync(&uhci->stall_timer);
-
spin_lock_irq(&uhci->lock);
reset_hc(uhci);
uhci_scan_schedule(uhci, NULL);
spin_unlock_irq(&uhci->lock);
-
+
+ del_timer_sync(&uhci->stall_timer);
release_uhci(uhci);
}
@@ -844,6 +815,8 @@ static int uhci_suspend(struct usb_hcd *hcd, pm_message_t message)
done:
spin_unlock_irq(&uhci->lock);
+ if (rc == 0)
+ del_timer_sync(&hcd->rh_timer);
return rc;
}
@@ -875,6 +848,9 @@ static int uhci_resume(struct usb_hcd *hcd)
suspend_rh(uhci, UHCI_RH_SUSPENDED);
spin_unlock_irq(&uhci->lock);
+
+ if (hcd->poll_rh)
+ usb_hcd_poll_rh_status(hcd);
return 0;
}
#endif