summaryrefslogtreecommitdiffstats
path: root/drivers/usb/host
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/host')
-rw-r--r--drivers/usb/host/uhci-hcd.c62
-rw-r--r--drivers/usb/host/uhci-hcd.h11
-rw-r--r--drivers/usb/host/uhci-hub.c11
-rw-r--r--drivers/usb/host/uhci-q.c2
4 files changed, 32 insertions, 54 deletions
diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c
index 0d5d2545bf07..0c024898cbea 100644
--- a/drivers/usb/host/uhci-hcd.c
+++ b/drivers/usb/host/uhci-hcd.c
@@ -97,14 +97,9 @@ static void uhci_get_current_frame_number(struct uhci_hcd *uhci);
/* to make sure it doesn't hog all of the bandwidth */
#define DEPTH_INTERVAL 5
-static inline void restart_timer(struct uhci_hcd *uhci)
-{
- mod_timer(&uhci->stall_timer, jiffies + msecs_to_jiffies(100));
-}
-
-#include "uhci-hub.c"
#include "uhci-debug.c"
#include "uhci-q.c"
+#include "uhci-hub.c"
/*
* Make sure the controller is completely inactive, unable to
@@ -160,7 +155,6 @@ static void hc_died(struct uhci_hcd *uhci)
{
reset_hc(uhci);
uhci->hc_inaccessible = 1;
- del_timer(&uhci->stall_timer);
}
/*
@@ -287,8 +281,11 @@ __acquires(uhci->lock)
/* Enable resume-detect interrupts if they work.
* Then enter Global Suspend mode, still configured.
*/
- int_enable = (resume_detect_interrupts_are_broken(uhci) ?
- 0 : USBINTR_RESUME);
+ uhci->working_RD = 1;
+ int_enable = USBINTR_RESUME;
+ if (resume_detect_interrupts_are_broken(uhci)) {
+ uhci->working_RD = int_enable = 0;
+ }
outw(int_enable, uhci->io_addr + USBINTR);
outw(USBCMD_EGSM | USBCMD_CF, uhci->io_addr + USBCMD);
mb();
@@ -315,7 +312,6 @@ __acquires(uhci->lock)
uhci->rh_state = new_state;
uhci->is_stopped = UHCI_IS_STOPPED;
- del_timer(&uhci->stall_timer);
uhci_to_hcd(uhci)->poll_rh = !int_enable;
uhci_scan_schedule(uhci, NULL);
@@ -335,7 +331,6 @@ static void start_rh(struct uhci_hcd *uhci)
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)
@@ -374,20 +369,6 @@ __acquires(uhci->lock)
mod_timer(&uhci_to_hcd(uhci)->rh_timer, jiffies);
}
-static void stall_callback(unsigned long _uhci)
-{
- struct uhci_hcd *uhci = (struct uhci_hcd *) _uhci;
- unsigned long flags;
-
- spin_lock_irqsave(&uhci->lock, flags);
- uhci_scan_schedule(uhci, NULL);
- check_fsbr(uhci);
-
- if (!uhci->is_stopped)
- restart_timer(uhci);
- spin_unlock_irqrestore(&uhci->lock, flags);
-}
-
static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs)
{
struct uhci_hcd *uhci = hcd_to_uhci(hcd);
@@ -418,8 +399,10 @@ static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs)
"host controller halted, "
"very bad!\n");
hc_died(uhci);
- spin_unlock_irqrestore(&uhci->lock, flags);
- return IRQ_HANDLED;
+
+ /* Force a callback in case there are
+ * pending unlinks */
+ mod_timer(&hcd->rh_timer, jiffies);
}
spin_unlock_irqrestore(&uhci->lock, flags);
}
@@ -427,10 +410,11 @@ static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs)
if (status & USBSTS_RD)
usb_hcd_poll_rh_status(hcd);
-
- spin_lock_irqsave(&uhci->lock, flags);
- uhci_scan_schedule(uhci, regs);
- spin_unlock_irqrestore(&uhci->lock, flags);
+ else {
+ spin_lock_irqsave(&uhci->lock, flags);
+ uhci_scan_schedule(uhci, regs);
+ spin_unlock_irqrestore(&uhci->lock, flags);
+ }
return IRQ_HANDLED;
}
@@ -595,10 +579,6 @@ static int uhci_start(struct usb_hcd *hcd)
init_waitqueue_head(&uhci->waitqh);
- init_timer(&uhci->stall_timer);
- uhci->stall_timer.function = stall_callback;
- uhci->stall_timer.data = (unsigned long) uhci;
-
uhci->fl = dma_alloc_coherent(uhci_dev(uhci), sizeof(*uhci->fl),
&dma_handle, 0);
if (!uhci->fl) {
@@ -745,11 +725,11 @@ static void uhci_stop(struct usb_hcd *hcd)
struct uhci_hcd *uhci = hcd_to_uhci(hcd);
spin_lock_irq(&uhci->lock);
- reset_hc(uhci);
+ if (!uhci->hc_inaccessible)
+ reset_hc(uhci);
uhci_scan_schedule(uhci, NULL);
spin_unlock_irq(&uhci->lock);
- del_timer_sync(&uhci->stall_timer);
release_uhci(uhci);
}
@@ -811,13 +791,12 @@ static int uhci_suspend(struct usb_hcd *hcd, pm_message_t message)
*/
pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP, 0);
uhci->hc_inaccessible = 1;
+ hcd->poll_rh = 0;
/* FIXME: Enable non-PME# remote wakeup? */
done:
spin_unlock_irq(&uhci->lock);
- if (rc == 0)
- del_timer_sync(&hcd->rh_timer);
return rc;
}
@@ -850,8 +829,11 @@ static int uhci_resume(struct usb_hcd *hcd)
spin_unlock_irq(&uhci->lock);
- if (hcd->poll_rh)
+ if (!uhci->working_RD) {
+ /* Suspended root hub needs to be polled */
+ hcd->poll_rh = 1;
usb_hcd_poll_rh_status(hcd);
+ }
return 0;
}
#endif
diff --git a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h
index bf9c5f9b508b..282f40b75881 100644
--- a/drivers/usb/host/uhci-hcd.h
+++ b/drivers/usb/host/uhci-hcd.h
@@ -345,9 +345,6 @@ enum uhci_rh_state {
/*
* This describes the full uhci information.
- *
- * Note how the "proper" USB information is just
- * a subset of what the full implementation needs.
*/
struct uhci_hcd {
@@ -360,8 +357,6 @@ struct uhci_hcd {
struct dma_pool *qh_pool;
struct dma_pool *td_pool;
- struct usb_bus *bus;
-
struct uhci_td *term_td; /* Terminating TD, see UHCI bug */
struct uhci_qh *skelqh[UHCI_NUM_SKELQH]; /* Skeleton QH's */
@@ -380,6 +375,8 @@ struct uhci_hcd {
unsigned int scan_in_progress:1; /* Schedule scan is running */
unsigned int need_rescan:1; /* Redo the schedule scan */
unsigned int hc_inaccessible:1; /* HC is suspended or dead */
+ unsigned int working_RD:1; /* Suspended root hub doesn't
+ need to be polled */
/* Support for port suspend/resume/reset */
unsigned long port_c_suspend; /* Bit-arrays of ports */
@@ -405,9 +402,7 @@ struct uhci_hcd {
/* List of URB's awaiting completion callback */
struct list_head complete_list; /* P: uhci->lock */
- int rh_numports;
-
- struct timer_list stall_timer;
+ int rh_numports; /* Number of root-hub ports */
wait_queue_head_t waitqh; /* endpoint_disable waiters */
};
diff --git a/drivers/usb/host/uhci-hub.c b/drivers/usb/host/uhci-hub.c
index 4eace2b19ddb..a71e48a66805 100644
--- a/drivers/usb/host/uhci-hub.c
+++ b/drivers/usb/host/uhci-hub.c
@@ -145,15 +145,16 @@ static int uhci_hub_status_data(struct usb_hcd *hcd, char *buf)
{
struct uhci_hcd *uhci = hcd_to_uhci(hcd);
unsigned long flags;
- int status;
+ int status = 0;
spin_lock_irqsave(&uhci->lock, flags);
- if (uhci->hc_inaccessible) {
- status = 0;
- goto done;
- }
+ uhci_scan_schedule(uhci, NULL);
+ if (uhci->hc_inaccessible)
+ goto done;
+ check_fsbr(uhci);
uhci_check_ports(uhci);
+
status = get_hub_status_data(uhci, buf);
switch (uhci->rh_state) {
diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c
index bbb36cd6ed61..ea0d168a8c67 100644
--- a/drivers/usb/host/uhci-q.c
+++ b/drivers/usb/host/uhci-q.c
@@ -33,7 +33,7 @@ static void uhci_free_pending_tds(struct uhci_hcd *uhci);
static inline void uhci_set_next_interrupt(struct uhci_hcd *uhci)
{
if (uhci->is_stopped)
- mod_timer(&uhci->stall_timer, jiffies);
+ mod_timer(&uhci_to_hcd(uhci)->rh_timer, jiffies);
uhci->term_td->status |= cpu_to_le32(TD_CTRL_IOC);
}
OpenPOWER on IntegriCloud