diff options
Diffstat (limited to 'drivers/usb/host')
-rw-r--r-- | drivers/usb/host/uhci-hcd.c | 70 | ||||
-rw-r--r-- | drivers/usb/host/uhci-hcd.h | 12 | ||||
-rw-r--r-- | drivers/usb/host/uhci-hub.c | 67 | ||||
-rw-r--r-- | drivers/usb/host/uhci-q.c | 3 |
4 files changed, 92 insertions, 60 deletions
diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index 82e608a4bbd0..25a718eb1d0f 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c | |||
@@ -84,6 +84,8 @@ static char *errbuf; | |||
84 | 84 | ||
85 | static kmem_cache_t *uhci_up_cachep; /* urb_priv */ | 85 | static kmem_cache_t *uhci_up_cachep; /* urb_priv */ |
86 | 86 | ||
87 | static void suspend_rh(struct uhci_hcd *uhci, enum uhci_rh_state new_state); | ||
88 | static void wakeup_rh(struct uhci_hcd *uhci); | ||
87 | static void uhci_get_current_frame_number(struct uhci_hcd *uhci); | 89 | static void uhci_get_current_frame_number(struct uhci_hcd *uhci); |
88 | 90 | ||
89 | /* If a transfer is still active after this much time, turn off FSBR */ | 91 | /* 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) | |||
133 | outw(0, uhci->io_addr + USBINTR); | 135 | outw(0, uhci->io_addr + USBINTR); |
134 | outw(0, uhci->io_addr + USBCMD); | 136 | outw(0, uhci->io_addr + USBCMD); |
135 | 137 | ||
136 | uhci->resume_detect = 0; | ||
137 | uhci->port_c_suspend = uhci->suspended_ports = | 138 | uhci->port_c_suspend = uhci->suspended_ports = |
138 | uhci->resuming_ports = 0; | 139 | uhci->resuming_ports = 0; |
139 | uhci->rh_state = UHCI_RH_RESET; | 140 | uhci->rh_state = UHCI_RH_RESET; |
140 | uhci->is_stopped = UHCI_IS_STOPPED; | 141 | uhci->is_stopped = UHCI_IS_STOPPED; |
141 | uhci_to_hcd(uhci)->state = HC_STATE_HALT; | 142 | uhci_to_hcd(uhci)->state = HC_STATE_HALT; |
143 | uhci_to_hcd(uhci)->poll_rh = 0; | ||
142 | } | 144 | } |
143 | 145 | ||
144 | /* | 146 | /* |
@@ -148,6 +150,7 @@ static void hc_died(struct uhci_hcd *uhci) | |||
148 | { | 150 | { |
149 | reset_hc(uhci); | 151 | reset_hc(uhci); |
150 | uhci->hc_inaccessible = 1; | 152 | uhci->hc_inaccessible = 1; |
153 | del_timer(&uhci->stall_timer); | ||
151 | } | 154 | } |
152 | 155 | ||
153 | /* | 156 | /* |
@@ -302,14 +305,14 @@ __acquires(uhci->lock) | |||
302 | 305 | ||
303 | uhci->rh_state = new_state; | 306 | uhci->rh_state = new_state; |
304 | uhci->is_stopped = UHCI_IS_STOPPED; | 307 | uhci->is_stopped = UHCI_IS_STOPPED; |
305 | uhci->resume_detect = 0; | 308 | del_timer(&uhci->stall_timer); |
309 | uhci_to_hcd(uhci)->poll_rh = !int_enable; | ||
306 | 310 | ||
307 | uhci_scan_schedule(uhci, NULL); | 311 | uhci_scan_schedule(uhci, NULL); |
308 | } | 312 | } |
309 | 313 | ||
310 | static void start_rh(struct uhci_hcd *uhci) | 314 | static void start_rh(struct uhci_hcd *uhci) |
311 | { | 315 | { |
312 | uhci->rh_state = UHCI_RH_RUNNING; | ||
313 | uhci->is_stopped = 0; | 316 | uhci->is_stopped = 0; |
314 | smp_wmb(); | 317 | smp_wmb(); |
315 | 318 | ||
@@ -320,6 +323,9 @@ static void start_rh(struct uhci_hcd *uhci) | |||
320 | outw(USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC | USBINTR_SP, | 323 | outw(USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC | USBINTR_SP, |
321 | uhci->io_addr + USBINTR); | 324 | uhci->io_addr + USBINTR); |
322 | mb(); | 325 | mb(); |
326 | uhci->rh_state = UHCI_RH_RUNNING; | ||
327 | uhci_to_hcd(uhci)->poll_rh = 1; | ||
328 | restart_timer(uhci); | ||
323 | } | 329 | } |
324 | 330 | ||
325 | static void wakeup_rh(struct uhci_hcd *uhci) | 331 | static void wakeup_rh(struct uhci_hcd *uhci) |
@@ -353,36 +359,9 @@ __acquires(uhci->lock) | |||
353 | } | 359 | } |
354 | 360 | ||
355 | start_rh(uhci); | 361 | start_rh(uhci); |
356 | } | ||
357 | |||
358 | static void rh_state_transitions(struct uhci_hcd *uhci) | ||
359 | { | ||
360 | switch (uhci->rh_state) { | ||
361 | case UHCI_RH_RUNNING: | ||
362 | /* are any devices attached? */ | ||
363 | if (!any_ports_active(uhci)) { | ||
364 | uhci->rh_state = UHCI_RH_RUNNING_NODEVS; | ||
365 | uhci->auto_stop_time = jiffies + HZ; | ||
366 | } | ||
367 | break; | ||
368 | 362 | ||
369 | case UHCI_RH_RUNNING_NODEVS: | 363 | /* Restart root hub polling */ |
370 | /* auto-stop if nothing connected for 1 second */ | 364 | mod_timer(&uhci_to_hcd(uhci)->rh_timer, jiffies); |
371 | if (any_ports_active(uhci)) | ||
372 | uhci->rh_state = UHCI_RH_RUNNING; | ||
373 | else if (time_after_eq(jiffies, uhci->auto_stop_time)) | ||
374 | suspend_rh(uhci, UHCI_RH_AUTO_STOPPED); | ||
375 | break; | ||
376 | |||
377 | case UHCI_RH_AUTO_STOPPED: | ||
378 | /* wakeup if requested by a device */ | ||
379 | if (uhci->resume_detect) | ||
380 | wakeup_rh(uhci); | ||
381 | break; | ||
382 | |||
383 | default: | ||
384 | break; | ||
385 | } | ||
386 | } | 365 | } |
387 | 366 | ||
388 | static void stall_callback(unsigned long _uhci) | 367 | static void stall_callback(unsigned long _uhci) |
@@ -394,14 +373,8 @@ static void stall_callback(unsigned long _uhci) | |||
394 | uhci_scan_schedule(uhci, NULL); | 373 | uhci_scan_schedule(uhci, NULL); |
395 | check_fsbr(uhci); | 374 | check_fsbr(uhci); |
396 | 375 | ||
397 | /* Poll for and perform state transitions */ | 376 | if (!uhci->is_stopped) |
398 | if (!uhci->hc_inaccessible) { | 377 | restart_timer(uhci); |
399 | rh_state_transitions(uhci); | ||
400 | if (uhci->suspended_ports) | ||
401 | uhci_check_ports(uhci); | ||
402 | } | ||
403 | |||
404 | restart_timer(uhci); | ||
405 | spin_unlock_irqrestore(&uhci->lock, flags); | 378 | spin_unlock_irqrestore(&uhci->lock, flags); |
406 | } | 379 | } |
407 | 380 | ||
@@ -443,7 +416,7 @@ static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs) | |||
443 | } | 416 | } |
444 | 417 | ||
445 | if (status & USBSTS_RD) | 418 | if (status & USBSTS_RD) |
446 | uhci->resume_detect = 1; | 419 | usb_hcd_poll_rh_status(hcd); |
447 | 420 | ||
448 | spin_lock_irqsave(&uhci->lock, flags); | 421 | spin_lock_irqsave(&uhci->lock, flags); |
449 | uhci_scan_schedule(uhci, regs); | 422 | uhci_scan_schedule(uhci, regs); |
@@ -542,6 +515,7 @@ static int uhci_start(struct usb_hcd *hcd) | |||
542 | struct dentry *dentry; | 515 | struct dentry *dentry; |
543 | 516 | ||
544 | io_size = (unsigned) hcd->rsrc_len; | 517 | io_size = (unsigned) hcd->rsrc_len; |
518 | hcd->uses_new_polling = 1; | ||
545 | if (pci_find_capability(to_pci_dev(uhci_dev(uhci)), PCI_CAP_ID_PM)) | 519 | if (pci_find_capability(to_pci_dev(uhci_dev(uhci)), PCI_CAP_ID_PM)) |
546 | hcd->can_wakeup = 1; /* Assume it supports PME# */ | 520 | hcd->can_wakeup = 1; /* Assume it supports PME# */ |
547 | 521 | ||
@@ -714,8 +688,6 @@ static int uhci_start(struct usb_hcd *hcd) | |||
714 | configure_hc(uhci); | 688 | configure_hc(uhci); |
715 | start_rh(uhci); | 689 | start_rh(uhci); |
716 | 690 | ||
717 | restart_timer(uhci); | ||
718 | |||
719 | udev->speed = USB_SPEED_FULL; | 691 | udev->speed = USB_SPEED_FULL; |
720 | 692 | ||
721 | if (usb_hcd_register_root_hub(udev, hcd) != 0) { | 693 | if (usb_hcd_register_root_hub(udev, hcd) != 0) { |
@@ -730,8 +702,8 @@ static int uhci_start(struct usb_hcd *hcd) | |||
730 | * error exits: | 702 | * error exits: |
731 | */ | 703 | */ |
732 | err_start_root_hub: | 704 | err_start_root_hub: |
733 | del_timer_sync(&uhci->stall_timer); | ||
734 | reset_hc(uhci); | 705 | reset_hc(uhci); |
706 | del_timer_sync(&uhci->stall_timer); | ||
735 | 707 | ||
736 | err_alloc_skelqh: | 708 | err_alloc_skelqh: |
737 | for (i = 0; i < UHCI_NUM_SKELQH; i++) | 709 | for (i = 0; i < UHCI_NUM_SKELQH; i++) |
@@ -771,13 +743,12 @@ static void uhci_stop(struct usb_hcd *hcd) | |||
771 | { | 743 | { |
772 | struct uhci_hcd *uhci = hcd_to_uhci(hcd); | 744 | struct uhci_hcd *uhci = hcd_to_uhci(hcd); |
773 | 745 | ||
774 | del_timer_sync(&uhci->stall_timer); | ||
775 | |||
776 | spin_lock_irq(&uhci->lock); | 746 | spin_lock_irq(&uhci->lock); |
777 | reset_hc(uhci); | 747 | reset_hc(uhci); |
778 | uhci_scan_schedule(uhci, NULL); | 748 | uhci_scan_schedule(uhci, NULL); |
779 | spin_unlock_irq(&uhci->lock); | 749 | spin_unlock_irq(&uhci->lock); |
780 | 750 | ||
751 | del_timer_sync(&uhci->stall_timer); | ||
781 | release_uhci(uhci); | 752 | release_uhci(uhci); |
782 | } | 753 | } |
783 | 754 | ||
@@ -844,6 +815,8 @@ static int uhci_suspend(struct usb_hcd *hcd, pm_message_t message) | |||
844 | 815 | ||
845 | done: | 816 | done: |
846 | spin_unlock_irq(&uhci->lock); | 817 | spin_unlock_irq(&uhci->lock); |
818 | if (rc == 0) | ||
819 | del_timer_sync(&hcd->rh_timer); | ||
847 | return rc; | 820 | return rc; |
848 | } | 821 | } |
849 | 822 | ||
@@ -875,6 +848,9 @@ static int uhci_resume(struct usb_hcd *hcd) | |||
875 | suspend_rh(uhci, UHCI_RH_SUSPENDED); | 848 | suspend_rh(uhci, UHCI_RH_SUSPENDED); |
876 | 849 | ||
877 | spin_unlock_irq(&uhci->lock); | 850 | spin_unlock_irq(&uhci->lock); |
851 | |||
852 | if (hcd->poll_rh) | ||
853 | usb_hcd_poll_rh_status(hcd); | ||
878 | return 0; | 854 | return 0; |
879 | } | 855 | } |
880 | #endif | 856 | #endif |
diff --git a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h index 827df5e06800..d7c67b73eb7a 100644 --- a/drivers/usb/host/uhci-hcd.h +++ b/drivers/usb/host/uhci-hcd.h | |||
@@ -327,18 +327,19 @@ static inline int __interval_to_skel(int interval) | |||
327 | * driver learns to autosuspend.) | 327 | * driver learns to autosuspend.) |
328 | */ | 328 | */ |
329 | enum uhci_rh_state { | 329 | enum uhci_rh_state { |
330 | /* In the next 4 states the HC must be halted */ | 330 | /* In the following states the HC must be halted. |
331 | UHCI_RH_RESET, /* These two must come first */ | 331 | * These two must come first */ |
332 | UHCI_RH_RESET, | ||
332 | UHCI_RH_SUSPENDED, | 333 | UHCI_RH_SUSPENDED, |
333 | 334 | ||
334 | UHCI_RH_AUTO_STOPPED, | 335 | UHCI_RH_AUTO_STOPPED, |
335 | UHCI_RH_RESUMING, | 336 | UHCI_RH_RESUMING, |
336 | 337 | ||
337 | /* In the next state the HC changes from running to halted, so it | 338 | /* In this state the HC changes from running to halted, |
338 | * can legally appear either way */ | 339 | * so it can legally appear either way. */ |
339 | UHCI_RH_SUSPENDING, | 340 | UHCI_RH_SUSPENDING, |
340 | 341 | ||
341 | /* In the next two states it's an error if the HC is halted. | 342 | /* In the following states it's an error if the HC is halted. |
342 | * These two must come last */ | 343 | * These two must come last */ |
343 | UHCI_RH_RUNNING, /* The normal state */ | 344 | UHCI_RH_RUNNING, /* The normal state */ |
344 | UHCI_RH_RUNNING_NODEVS, /* Running with no devices attached */ | 345 | UHCI_RH_RUNNING_NODEVS, /* Running with no devices attached */ |
@@ -380,7 +381,6 @@ struct uhci_hcd { | |||
380 | 381 | ||
381 | unsigned int scan_in_progress:1; /* Schedule scan is running */ | 382 | unsigned int scan_in_progress:1; /* Schedule scan is running */ |
382 | unsigned int need_rescan:1; /* Redo the schedule scan */ | 383 | unsigned int need_rescan:1; /* Redo the schedule scan */ |
383 | unsigned int resume_detect:1; /* Need a Global Resume */ | ||
384 | unsigned int hc_inaccessible:1; /* HC is suspended or dead */ | 384 | unsigned int hc_inaccessible:1; /* HC is suspended or dead */ |
385 | 385 | ||
386 | /* Support for port suspend/resume/reset */ | 386 | /* Support for port suspend/resume/reset */ |
diff --git a/drivers/usb/host/uhci-hub.c b/drivers/usb/host/uhci-hub.c index 13652de52203..4eace2b19ddb 100644 --- a/drivers/usb/host/uhci-hub.c +++ b/drivers/usb/host/uhci-hub.c | |||
@@ -49,22 +49,16 @@ static int any_ports_active(struct uhci_hcd *uhci) | |||
49 | return 0; | 49 | return 0; |
50 | } | 50 | } |
51 | 51 | ||
52 | static int uhci_hub_status_data(struct usb_hcd *hcd, char *buf) | 52 | static inline int get_hub_status_data(struct uhci_hcd *uhci, char *buf) |
53 | { | 53 | { |
54 | struct uhci_hcd *uhci = hcd_to_uhci(hcd); | ||
55 | int port; | 54 | int port; |
56 | 55 | ||
57 | if (uhci->hc_inaccessible) | ||
58 | return 0; | ||
59 | |||
60 | *buf = 0; | 56 | *buf = 0; |
61 | for (port = 0; port < uhci->rh_numports; ++port) { | 57 | for (port = 0; port < uhci->rh_numports; ++port) { |
62 | if ((inw(uhci->io_addr + USBPORTSC1 + port * 2) & RWC_BITS) || | 58 | if ((inw(uhci->io_addr + USBPORTSC1 + port * 2) & RWC_BITS) || |
63 | test_bit(port, &uhci->port_c_suspend)) | 59 | test_bit(port, &uhci->port_c_suspend)) |
64 | *buf |= (1 << (port + 1)); | 60 | *buf |= (1 << (port + 1)); |
65 | } | 61 | } |
66 | if (*buf && uhci->is_stopped) | ||
67 | uhci->resume_detect = 1; | ||
68 | return !!*buf; | 62 | return !!*buf; |
69 | } | 63 | } |
70 | 64 | ||
@@ -134,6 +128,11 @@ static void uhci_check_ports(struct uhci_hcd *uhci) | |||
134 | set_bit(port, &uhci->resuming_ports); | 128 | set_bit(port, &uhci->resuming_ports); |
135 | uhci->ports_timeout = jiffies + | 129 | uhci->ports_timeout = jiffies + |
136 | msecs_to_jiffies(20); | 130 | msecs_to_jiffies(20); |
131 | |||
132 | /* Make sure we see the port again | ||
133 | * after the resuming period is over. */ | ||
134 | mod_timer(&uhci_to_hcd(uhci)->rh_timer, | ||
135 | uhci->ports_timeout); | ||
137 | } else if (time_after_eq(jiffies, | 136 | } else if (time_after_eq(jiffies, |
138 | uhci->ports_timeout)) { | 137 | uhci->ports_timeout)) { |
139 | uhci_finish_suspend(uhci, port, port_addr); | 138 | uhci_finish_suspend(uhci, port, port_addr); |
@@ -142,6 +141,60 @@ static void uhci_check_ports(struct uhci_hcd *uhci) | |||
142 | } | 141 | } |
143 | } | 142 | } |
144 | 143 | ||
144 | static int uhci_hub_status_data(struct usb_hcd *hcd, char *buf) | ||
145 | { | ||
146 | struct uhci_hcd *uhci = hcd_to_uhci(hcd); | ||
147 | unsigned long flags; | ||
148 | int status; | ||
149 | |||
150 | spin_lock_irqsave(&uhci->lock, flags); | ||
151 | if (uhci->hc_inaccessible) { | ||
152 | status = 0; | ||
153 | goto done; | ||
154 | } | ||
155 | |||
156 | uhci_check_ports(uhci); | ||
157 | status = get_hub_status_data(uhci, buf); | ||
158 | |||
159 | switch (uhci->rh_state) { | ||
160 | case UHCI_RH_SUSPENDING: | ||
161 | case UHCI_RH_SUSPENDED: | ||
162 | /* if port change, ask to be resumed */ | ||
163 | if (status) | ||
164 | usb_hcd_resume_root_hub(hcd); | ||
165 | break; | ||
166 | |||
167 | case UHCI_RH_AUTO_STOPPED: | ||
168 | /* if port change, auto start */ | ||
169 | if (status) | ||
170 | wakeup_rh(uhci); | ||
171 | break; | ||
172 | |||
173 | case UHCI_RH_RUNNING: | ||
174 | /* are any devices attached? */ | ||
175 | if (!any_ports_active(uhci)) { | ||
176 | uhci->rh_state = UHCI_RH_RUNNING_NODEVS; | ||
177 | uhci->auto_stop_time = jiffies + HZ; | ||
178 | } | ||
179 | break; | ||
180 | |||
181 | case UHCI_RH_RUNNING_NODEVS: | ||
182 | /* auto-stop if nothing connected for 1 second */ | ||
183 | if (any_ports_active(uhci)) | ||
184 | uhci->rh_state = UHCI_RH_RUNNING; | ||
185 | else if (time_after_eq(jiffies, uhci->auto_stop_time)) | ||
186 | suspend_rh(uhci, UHCI_RH_AUTO_STOPPED); | ||
187 | break; | ||
188 | |||
189 | default: | ||
190 | break; | ||
191 | } | ||
192 | |||
193 | done: | ||
194 | spin_unlock_irqrestore(&uhci->lock, flags); | ||
195 | return status; | ||
196 | } | ||
197 | |||
145 | /* size of returned buffer is part of USB spec */ | 198 | /* size of returned buffer is part of USB spec */ |
146 | static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, | 199 | static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, |
147 | u16 wIndex, char *buf, u16 wLength) | 200 | u16 wIndex, char *buf, u16 wLength) |
diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c index f5c75885f7be..77f264851e98 100644 --- a/drivers/usb/host/uhci-q.c +++ b/drivers/usb/host/uhci-q.c | |||
@@ -32,6 +32,8 @@ static void uhci_free_pending_tds(struct uhci_hcd *uhci); | |||
32 | */ | 32 | */ |
33 | static inline void uhci_set_next_interrupt(struct uhci_hcd *uhci) | 33 | static inline void uhci_set_next_interrupt(struct uhci_hcd *uhci) |
34 | { | 34 | { |
35 | if (uhci->is_stopped) | ||
36 | mod_timer(&uhci->stall_timer, jiffies); | ||
35 | uhci->term_td->status |= cpu_to_le32(TD_CTRL_IOC); | 37 | uhci->term_td->status |= cpu_to_le32(TD_CTRL_IOC); |
36 | } | 38 | } |
37 | 39 | ||
@@ -1497,6 +1499,7 @@ static void uhci_scan_schedule(struct uhci_hcd *uhci, struct pt_regs *regs) | |||
1497 | rescan: | 1499 | rescan: |
1498 | uhci->need_rescan = 0; | 1500 | uhci->need_rescan = 0; |
1499 | 1501 | ||
1502 | uhci_clear_next_interrupt(uhci); | ||
1500 | uhci_get_current_frame_number(uhci); | 1503 | uhci_get_current_frame_number(uhci); |
1501 | 1504 | ||
1502 | if (uhci->frame_number + uhci->is_stopped != uhci->qh_remove_age) | 1505 | if (uhci->frame_number + uhci->is_stopped != uhci->qh_remove_age) |