diff options
Diffstat (limited to 'drivers/usb/host')
-rw-r--r-- | drivers/usb/host/uhci-hcd.c | 62 | ||||
-rw-r--r-- | drivers/usb/host/uhci-hcd.h | 11 | ||||
-rw-r--r-- | drivers/usb/host/uhci-hub.c | 11 | ||||
-rw-r--r-- | drivers/usb/host/uhci-q.c | 2 |
4 files changed, 32 insertions, 54 deletions
diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index 0d5d254..0c02489 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 bf9c5f9..282f40b 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 4eace2b..a71e48a 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 bbb36cd..ea0d168 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); } |