diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/usb/host/uhci-debug.c | 32 | ||||
-rw-r--r-- | drivers/usb/host/uhci-hcd.c | 285 | ||||
-rw-r--r-- | drivers/usb/host/uhci-hcd.h | 49 | ||||
-rw-r--r-- | drivers/usb/host/uhci-hub.c | 2 |
4 files changed, 212 insertions, 156 deletions
diff --git a/drivers/usb/host/uhci-debug.c b/drivers/usb/host/uhci-debug.c index 24c73c5a3435..4538a98b6f9d 100644 --- a/drivers/usb/host/uhci-debug.c +++ b/drivers/usb/host/uhci-debug.c | |||
@@ -237,6 +237,37 @@ static int uhci_show_sc(int port, unsigned short status, char *buf, int len) | |||
237 | return out - buf; | 237 | return out - buf; |
238 | } | 238 | } |
239 | 239 | ||
240 | static int uhci_show_root_hub_state(struct uhci_hcd *uhci, char *buf, int len) | ||
241 | { | ||
242 | char *out = buf; | ||
243 | char *rh_state; | ||
244 | |||
245 | /* Try to make sure there's enough memory */ | ||
246 | if (len < 60) | ||
247 | return 0; | ||
248 | |||
249 | switch (uhci->rh_state) { | ||
250 | case UHCI_RH_RESET: | ||
251 | rh_state = "reset"; break; | ||
252 | case UHCI_RH_SUSPENDED: | ||
253 | rh_state = "suspended"; break; | ||
254 | case UHCI_RH_AUTO_STOPPED: | ||
255 | rh_state = "auto-stopped"; break; | ||
256 | case UHCI_RH_RESUMING: | ||
257 | rh_state = "resuming"; break; | ||
258 | case UHCI_RH_SUSPENDING: | ||
259 | rh_state = "suspending"; break; | ||
260 | case UHCI_RH_RUNNING: | ||
261 | rh_state = "running"; break; | ||
262 | case UHCI_RH_RUNNING_NODEVS: | ||
263 | rh_state = "running, no devs"; break; | ||
264 | default: | ||
265 | rh_state = "?"; break; | ||
266 | } | ||
267 | out += sprintf(out, "Root-hub state: %s\n", rh_state); | ||
268 | return out - buf; | ||
269 | } | ||
270 | |||
240 | static int uhci_show_status(struct uhci_hcd *uhci, char *buf, int len) | 271 | static int uhci_show_status(struct uhci_hcd *uhci, char *buf, int len) |
241 | { | 272 | { |
242 | char *out = buf; | 273 | char *out = buf; |
@@ -408,6 +439,7 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len) | |||
408 | 439 | ||
409 | spin_lock_irqsave(&uhci->lock, flags); | 440 | spin_lock_irqsave(&uhci->lock, flags); |
410 | 441 | ||
442 | out += uhci_show_root_hub_state(uhci, out, len - (out - buf)); | ||
411 | out += sprintf(out, "HC status\n"); | 443 | out += sprintf(out, "HC status\n"); |
412 | out += uhci_show_status(uhci, out, len - (out - buf)); | 444 | out += uhci_show_status(uhci, out, len - (out - buf)); |
413 | 445 | ||
diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index c17bd7ebc021..57b36dcea5d0 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c | |||
@@ -64,7 +64,7 @@ | |||
64 | /* | 64 | /* |
65 | * Version Information | 65 | * Version Information |
66 | */ | 66 | */ |
67 | #define DRIVER_VERSION "v2.2" | 67 | #define DRIVER_VERSION "v2.3" |
68 | #define DRIVER_AUTHOR "Linus 'Frodo Rabbit' Torvalds, Johannes Erdfelt, \ | 68 | #define DRIVER_AUTHOR "Linus 'Frodo Rabbit' Torvalds, Johannes Erdfelt, \ |
69 | Randy Dunlap, Georg Acher, Deti Fliegl, Thomas Sailer, Roman Weissgaerber, \ | 69 | Randy Dunlap, Georg Acher, Deti Fliegl, Thomas Sailer, Roman Weissgaerber, \ |
70 | Alan Stern" | 70 | Alan Stern" |
@@ -109,33 +109,6 @@ static inline void restart_timer(struct uhci_hcd *uhci) | |||
109 | #include "uhci-debug.c" | 109 | #include "uhci-debug.c" |
110 | #include "uhci-q.c" | 110 | #include "uhci-q.c" |
111 | 111 | ||
112 | static int suspend_allowed(struct uhci_hcd *uhci) | ||
113 | { | ||
114 | unsigned long io_addr = uhci->io_addr; | ||
115 | int i; | ||
116 | |||
117 | if (to_pci_dev(uhci_dev(uhci))->vendor != PCI_VENDOR_ID_INTEL) | ||
118 | return 1; | ||
119 | |||
120 | /* Some of Intel's USB controllers have a bug that causes false | ||
121 | * resume indications if any port has an over current condition. | ||
122 | * To prevent problems, we will not allow a global suspend if | ||
123 | * any ports are OC. | ||
124 | * | ||
125 | * Some motherboards using Intel's chipsets (but not using all | ||
126 | * the USB ports) appear to hardwire the over current inputs active | ||
127 | * to disable the USB ports. | ||
128 | */ | ||
129 | |||
130 | /* check for over current condition on any port */ | ||
131 | for (i = 0; i < uhci->rh_numports; i++) { | ||
132 | if (inw(io_addr + USBPORTSC1 + i * 2) & USBPORTSC_OC) | ||
133 | return 0; | ||
134 | } | ||
135 | |||
136 | return 1; | ||
137 | } | ||
138 | |||
139 | static void reset_hc(struct uhci_hcd *uhci) | 112 | static void reset_hc(struct uhci_hcd *uhci) |
140 | { | 113 | { |
141 | unsigned long io_addr = uhci->io_addr; | 114 | unsigned long io_addr = uhci->io_addr; |
@@ -147,7 +120,6 @@ static void reset_hc(struct uhci_hcd *uhci) | |||
147 | outw(0, uhci->io_addr + USBINTR); | 120 | outw(0, uhci->io_addr + USBINTR); |
148 | 121 | ||
149 | /* Global reset for 50ms */ | 122 | /* Global reset for 50ms */ |
150 | uhci->state = UHCI_RESET; | ||
151 | outw(USBCMD_GRESET, io_addr + USBCMD); | 123 | outw(USBCMD_GRESET, io_addr + USBCMD); |
152 | msleep(50); | 124 | msleep(50); |
153 | outw(0, io_addr + USBCMD); | 125 | outw(0, io_addr + USBCMD); |
@@ -156,63 +128,130 @@ static void reset_hc(struct uhci_hcd *uhci) | |||
156 | msleep(10); | 128 | msleep(10); |
157 | uhci->resume_detect = 0; | 129 | uhci->resume_detect = 0; |
158 | uhci->is_stopped = UHCI_IS_STOPPED; | 130 | uhci->is_stopped = UHCI_IS_STOPPED; |
131 | uhci->rh_state = UHCI_RH_RESET; | ||
159 | } | 132 | } |
160 | 133 | ||
161 | static void suspend_hc(struct uhci_hcd *uhci) | 134 | static int resume_detect_interrupts_are_broken(struct uhci_hcd *uhci) |
162 | { | 135 | { |
163 | unsigned long io_addr = uhci->io_addr; | 136 | int port; |
164 | 137 | ||
165 | dev_dbg(uhci_dev(uhci), "%s\n", __FUNCTION__); | 138 | switch (to_pci_dev(uhci_dev(uhci))->vendor) { |
166 | uhci->state = UHCI_SUSPENDED; | 139 | default: |
167 | uhci->resume_detect = 0; | 140 | break; |
168 | outw(USBCMD_EGSM, io_addr + USBCMD); | 141 | |
142 | case PCI_VENDOR_ID_GENESYS: | ||
143 | /* Genesys Logic's GL880S controllers don't generate | ||
144 | * resume-detect interrupts. | ||
145 | */ | ||
146 | return 1; | ||
147 | |||
148 | case PCI_VENDOR_ID_INTEL: | ||
149 | /* Some of Intel's USB controllers have a bug that causes | ||
150 | * resume-detect interrupts if any port has an over-current | ||
151 | * condition. To make matters worse, some motherboards | ||
152 | * hardwire unused USB ports' over-current inputs active! | ||
153 | * To prevent problems, we will not enable resume-detect | ||
154 | * interrupts if any ports are OC. | ||
155 | */ | ||
156 | for (port = 0; port < uhci->rh_numports; ++port) { | ||
157 | if (inw(uhci->io_addr + USBPORTSC1 + port * 2) & | ||
158 | USBPORTSC_OC) | ||
159 | return 1; | ||
160 | } | ||
161 | break; | ||
162 | } | ||
163 | return 0; | ||
164 | } | ||
165 | |||
166 | static void suspend_hc(struct uhci_hcd *uhci, enum uhci_rh_state new_state) | ||
167 | __releases(uhci->lock) | ||
168 | __acquires(uhci->lock) | ||
169 | { | ||
170 | int auto_stop; | ||
171 | int int_enable; | ||
172 | |||
173 | auto_stop = (new_state == UHCI_RH_AUTO_STOPPED); | ||
174 | dev_dbg(uhci_dev(uhci), "%s%s\n", __FUNCTION__, | ||
175 | (auto_stop ? " (auto-stop)" : "")); | ||
176 | |||
177 | /* If we get a suspend request when we're already auto-stopped | ||
178 | * then there's nothing to do. | ||
179 | */ | ||
180 | if (uhci->rh_state == UHCI_RH_AUTO_STOPPED) { | ||
181 | uhci->rh_state = new_state; | ||
182 | return; | ||
183 | } | ||
184 | |||
185 | /* Enable resume-detect interrupts if they work. | ||
186 | * Then enter Global Suspend mode, still configured. | ||
187 | */ | ||
188 | int_enable = (resume_detect_interrupts_are_broken(uhci) ? | ||
189 | 0 : USBINTR_RESUME); | ||
190 | outw(int_enable, uhci->io_addr + USBINTR); | ||
191 | outw(USBCMD_EGSM | USBCMD_CF, uhci->io_addr + USBCMD); | ||
192 | udelay(5); | ||
193 | |||
194 | /* If we're auto-stopping then no devices have been attached | ||
195 | * for a while, so there shouldn't be any active URBs and the | ||
196 | * controller should stop after a few microseconds. Otherwise | ||
197 | * we will give the controller one frame to stop. | ||
198 | */ | ||
199 | if (!auto_stop && !(inw(uhci->io_addr + USBSTS) & USBSTS_HCH)) { | ||
200 | uhci->rh_state = UHCI_RH_SUSPENDING; | ||
201 | spin_unlock_irq(&uhci->lock); | ||
202 | msleep(1); | ||
203 | spin_lock_irq(&uhci->lock); | ||
204 | } | ||
205 | if (!(inw(uhci->io_addr + USBSTS) & USBSTS_HCH)) | ||
206 | dev_warn(uhci_dev(uhci), "Controller not stopped yet!\n"); | ||
169 | 207 | ||
170 | /* FIXME: Wait for the controller to actually stop */ | ||
171 | uhci_get_current_frame_number(uhci); | 208 | uhci_get_current_frame_number(uhci); |
209 | smp_wmb(); | ||
210 | |||
211 | uhci->rh_state = new_state; | ||
172 | uhci->is_stopped = UHCI_IS_STOPPED; | 212 | uhci->is_stopped = UHCI_IS_STOPPED; |
213 | uhci->resume_detect = 0; | ||
173 | 214 | ||
174 | uhci_scan_schedule(uhci, NULL); | 215 | uhci_scan_schedule(uhci, NULL); |
175 | } | 216 | } |
176 | 217 | ||
177 | static void wakeup_hc(struct uhci_hcd *uhci) | 218 | static void wakeup_hc(struct uhci_hcd *uhci) |
219 | __releases(uhci->lock) | ||
220 | __acquires(uhci->lock) | ||
178 | { | 221 | { |
179 | unsigned long io_addr = uhci->io_addr; | 222 | dev_dbg(uhci_dev(uhci), "%s%s\n", __FUNCTION__, |
223 | uhci->rh_state == UHCI_RH_AUTO_STOPPED ? | ||
224 | " (auto-start)" : ""); | ||
180 | 225 | ||
181 | switch (uhci->state) { | 226 | /* If we are auto-stopped then no devices are attached so there's |
182 | case UHCI_SUSPENDED: /* Start the resume */ | 227 | * no need for wakeup signals. Otherwise we send Global Resume |
183 | dev_dbg(uhci_dev(uhci), "%s\n", __FUNCTION__); | 228 | * for 20 ms. |
184 | 229 | */ | |
185 | /* Global resume for >= 20ms */ | 230 | if (uhci->rh_state == UHCI_RH_SUSPENDED) { |
186 | outw(USBCMD_FGR | USBCMD_EGSM, io_addr + USBCMD); | 231 | uhci->rh_state = UHCI_RH_RESUMING; |
187 | uhci->state = UHCI_RESUMING_1; | 232 | outw(USBCMD_FGR | USBCMD_EGSM | USBCMD_CF, |
188 | uhci->state_end = jiffies + msecs_to_jiffies(20); | 233 | uhci->io_addr + USBCMD); |
189 | uhci->is_stopped = 0; | 234 | spin_unlock_irq(&uhci->lock); |
190 | break; | 235 | msleep(20); |
236 | spin_lock_irq(&uhci->lock); | ||
191 | 237 | ||
192 | case UHCI_RESUMING_1: /* End global resume */ | 238 | /* End Global Resume and wait for EOP to be sent */ |
193 | uhci->state = UHCI_RESUMING_2; | 239 | outw(USBCMD_CF, uhci->io_addr + USBCMD); |
194 | outw(0, io_addr + USBCMD); | 240 | udelay(4); |
195 | /* Falls through */ | 241 | if (inw(uhci->io_addr + USBCMD) & USBCMD_FGR) |
196 | 242 | dev_warn(uhci_dev(uhci), "FGR not stopped yet!\n"); | |
197 | case UHCI_RESUMING_2: /* Wait for EOP to be sent */ | 243 | } |
198 | if (inw(io_addr + USBCMD) & USBCMD_FGR) | ||
199 | break; | ||
200 | |||
201 | /* Run for at least 1 second, and | ||
202 | * mark it configured with a 64-byte max packet */ | ||
203 | uhci->state = UHCI_RUNNING_GRACE; | ||
204 | uhci->state_end = jiffies + HZ; | ||
205 | outw(USBCMD_RS | USBCMD_CF | USBCMD_MAXP, | ||
206 | io_addr + USBCMD); | ||
207 | break; | ||
208 | 244 | ||
209 | case UHCI_RUNNING_GRACE: /* Now allowed to suspend */ | 245 | uhci->rh_state = UHCI_RH_RUNNING; |
210 | uhci->state = UHCI_RUNNING; | 246 | uhci->is_stopped = 0; |
211 | break; | 247 | smp_wmb(); |
212 | 248 | ||
213 | default: | 249 | /* Mark it configured and running with a 64-byte max packet. |
214 | break; | 250 | * All interrupts are enabled, even though RD won't do anything. |
215 | } | 251 | */ |
252 | outw(USBCMD_RS | USBCMD_CF | USBCMD_MAXP, uhci->io_addr + USBCMD); | ||
253 | outw(USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC | USBINTR_SP, | ||
254 | uhci->io_addr + USBINTR); | ||
216 | } | 255 | } |
217 | 256 | ||
218 | static int start_hc(struct uhci_hcd *uhci) | 257 | static int start_hc(struct uhci_hcd *uhci) |
@@ -249,49 +288,40 @@ static int start_hc(struct uhci_hcd *uhci) | |||
249 | outl(uhci->fl->dma_handle, io_addr + USBFLBASEADD); | 288 | outl(uhci->fl->dma_handle, io_addr + USBFLBASEADD); |
250 | 289 | ||
251 | /* Run and mark it configured with a 64-byte max packet */ | 290 | /* Run and mark it configured with a 64-byte max packet */ |
252 | uhci->state = UHCI_RUNNING_GRACE; | 291 | uhci->rh_state = UHCI_RH_RUNNING; |
253 | uhci->state_end = jiffies + HZ; | ||
254 | outw(USBCMD_RS | USBCMD_CF | USBCMD_MAXP, io_addr + USBCMD); | 292 | outw(USBCMD_RS | USBCMD_CF | USBCMD_MAXP, io_addr + USBCMD); |
255 | uhci->is_stopped = 0; | 293 | uhci->is_stopped = 0; |
256 | 294 | ||
257 | return 0; | 295 | return 0; |
258 | } | 296 | } |
259 | 297 | ||
260 | static void hc_state_transitions(struct uhci_hcd *uhci) | 298 | static void rh_state_transitions(struct uhci_hcd *uhci) |
261 | { | 299 | { |
262 | switch (uhci->state) { | 300 | switch (uhci->rh_state) { |
263 | case UHCI_RUNNING: | 301 | case UHCI_RH_RUNNING: |
264 | 302 | /* are any devices attached? */ | |
265 | /* global suspend if nothing connected for 1 second */ | 303 | if (!any_ports_active(uhci)) { |
266 | if (!any_ports_active(uhci) && suspend_allowed(uhci)) { | 304 | uhci->rh_state = UHCI_RH_RUNNING_NODEVS; |
267 | uhci->state = UHCI_SUSPENDING_GRACE; | 305 | uhci->auto_stop_time = jiffies + HZ; |
268 | uhci->state_end = jiffies + HZ; | 306 | } |
269 | } | 307 | break; |
270 | break; | 308 | |
271 | 309 | case UHCI_RH_RUNNING_NODEVS: | |
272 | case UHCI_SUSPENDING_GRACE: | 310 | /* auto-stop if nothing connected for 1 second */ |
273 | if (any_ports_active(uhci)) | 311 | if (any_ports_active(uhci)) |
274 | uhci->state = UHCI_RUNNING; | 312 | uhci->rh_state = UHCI_RH_RUNNING; |
275 | else if (time_after_eq(jiffies, uhci->state_end)) | 313 | else if (time_after_eq(jiffies, uhci->auto_stop_time)) |
276 | suspend_hc(uhci); | 314 | suspend_hc(uhci, UHCI_RH_AUTO_STOPPED); |
277 | break; | 315 | break; |
278 | 316 | ||
279 | case UHCI_SUSPENDED: | 317 | case UHCI_RH_AUTO_STOPPED: |
280 | 318 | /* wakeup if requested by a device */ | |
281 | /* wakeup if requested by a device */ | 319 | if (uhci->resume_detect) |
282 | if (uhci->resume_detect) | 320 | wakeup_hc(uhci); |
283 | wakeup_hc(uhci); | 321 | break; |
284 | break; | 322 | |
285 | 323 | default: | |
286 | case UHCI_RESUMING_1: | 324 | break; |
287 | case UHCI_RESUMING_2: | ||
288 | case UHCI_RUNNING_GRACE: | ||
289 | if (time_after_eq(jiffies, uhci->state_end)) | ||
290 | wakeup_hc(uhci); | ||
291 | break; | ||
292 | |||
293 | default: | ||
294 | break; | ||
295 | } | 325 | } |
296 | } | 326 | } |
297 | 327 | ||
@@ -305,8 +335,8 @@ static void stall_callback(unsigned long _uhci) | |||
305 | check_fsbr(uhci); | 335 | check_fsbr(uhci); |
306 | 336 | ||
307 | /* Poll for and perform state transitions */ | 337 | /* Poll for and perform state transitions */ |
308 | hc_state_transitions(uhci); | 338 | rh_state_transitions(uhci); |
309 | if (unlikely(uhci->suspended_ports && uhci->state != UHCI_SUSPENDED)) | 339 | if (unlikely(uhci->suspended_ports)) |
310 | uhci_check_ports(uhci); | 340 | uhci_check_ports(uhci); |
311 | 341 | ||
312 | restart_timer(uhci); | 342 | restart_timer(uhci); |
@@ -336,7 +366,8 @@ static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs) | |||
336 | if (status & USBSTS_HCPE) | 366 | if (status & USBSTS_HCPE) |
337 | dev_err(uhci_dev(uhci), "host controller process " | 367 | dev_err(uhci_dev(uhci), "host controller process " |
338 | "error, something bad happened!\n"); | 368 | "error, something bad happened!\n"); |
339 | if ((status & USBSTS_HCH) && uhci->state > 0) { | 369 | if ((status & USBSTS_HCH) && |
370 | uhci->rh_state >= UHCI_RH_RUNNING) { | ||
340 | dev_err(uhci_dev(uhci), "host controller halted, " | 371 | dev_err(uhci_dev(uhci), "host controller halted, " |
341 | "very bad!\n"); | 372 | "very bad!\n"); |
342 | /* FIXME: Reset the controller, fix the offending TD */ | 373 | /* FIXME: Reset the controller, fix the offending TD */ |
@@ -683,17 +714,7 @@ static int uhci_suspend(struct usb_hcd *hcd, pm_message_t message) | |||
683 | struct uhci_hcd *uhci = hcd_to_uhci(hcd); | 714 | struct uhci_hcd *uhci = hcd_to_uhci(hcd); |
684 | 715 | ||
685 | spin_lock_irq(&uhci->lock); | 716 | spin_lock_irq(&uhci->lock); |
686 | 717 | suspend_hc(uhci, UHCI_RH_SUSPENDED); | |
687 | /* Don't try to suspend broken motherboards, reset instead */ | ||
688 | if (suspend_allowed(uhci)) | ||
689 | suspend_hc(uhci); | ||
690 | else { | ||
691 | spin_unlock_irq(&uhci->lock); | ||
692 | reset_hc(uhci); | ||
693 | spin_lock_irq(&uhci->lock); | ||
694 | uhci_scan_schedule(uhci, NULL); | ||
695 | } | ||
696 | |||
697 | spin_unlock_irq(&uhci->lock); | 718 | spin_unlock_irq(&uhci->lock); |
698 | return 0; | 719 | return 0; |
699 | } | 720 | } |
@@ -701,13 +722,9 @@ static int uhci_suspend(struct usb_hcd *hcd, pm_message_t message) | |||
701 | static int uhci_resume(struct usb_hcd *hcd) | 722 | static int uhci_resume(struct usb_hcd *hcd) |
702 | { | 723 | { |
703 | struct uhci_hcd *uhci = hcd_to_uhci(hcd); | 724 | struct uhci_hcd *uhci = hcd_to_uhci(hcd); |
704 | int rc; | ||
705 | |||
706 | pci_set_master(to_pci_dev(uhci_dev(uhci))); | ||
707 | 725 | ||
708 | spin_lock_irq(&uhci->lock); | 726 | spin_lock_irq(&uhci->lock); |
709 | 727 | if (uhci->rh_state == UHCI_RH_SUSPENDED) { | |
710 | if (uhci->state == UHCI_SUSPENDED) { | ||
711 | 728 | ||
712 | /* | 729 | /* |
713 | * Some systems don't maintain the UHCI register values | 730 | * Some systems don't maintain the UHCI register values |
@@ -721,19 +738,13 @@ static int uhci_resume(struct usb_hcd *hcd) | |||
721 | outl(uhci->fl->dma_handle, uhci->io_addr + USBFLBASEADD); | 738 | outl(uhci->fl->dma_handle, uhci->io_addr + USBFLBASEADD); |
722 | outw(USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC | | 739 | outw(USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC | |
723 | USBINTR_SP, uhci->io_addr + USBINTR); | 740 | USBINTR_SP, uhci->io_addr + USBINTR); |
724 | uhci->resume_detect = 1; | ||
725 | pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP, | 741 | pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP, |
726 | USBLEGSUP_DEFAULT); | 742 | USBLEGSUP_DEFAULT); |
727 | } else { | 743 | wakeup_hc(uhci); |
728 | spin_unlock_irq(&uhci->lock); | ||
729 | reset_hc(uhci); | ||
730 | if ((rc = start_hc(uhci)) != 0) | ||
731 | return rc; | ||
732 | spin_lock_irq(&uhci->lock); | ||
733 | } | 744 | } |
734 | hcd->state = HC_STATE_RUNNING; | ||
735 | |||
736 | spin_unlock_irq(&uhci->lock); | 745 | spin_unlock_irq(&uhci->lock); |
746 | |||
747 | hcd->state = HC_STATE_RUNNING; | ||
737 | return 0; | 748 | return 0; |
738 | } | 749 | } |
739 | #endif | 750 | #endif |
@@ -750,13 +761,15 @@ static void uhci_hcd_endpoint_disable(struct usb_hcd *hcd, | |||
750 | static int uhci_hcd_get_frame_number(struct usb_hcd *hcd) | 761 | static int uhci_hcd_get_frame_number(struct usb_hcd *hcd) |
751 | { | 762 | { |
752 | struct uhci_hcd *uhci = hcd_to_uhci(hcd); | 763 | struct uhci_hcd *uhci = hcd_to_uhci(hcd); |
753 | int frame_number; | ||
754 | unsigned long flags; | 764 | unsigned long flags; |
765 | int is_stopped; | ||
766 | int frame_number; | ||
755 | 767 | ||
756 | /* Minimize latency by avoiding the spinlock */ | 768 | /* Minimize latency by avoiding the spinlock */ |
757 | local_irq_save(flags); | 769 | local_irq_save(flags); |
758 | rmb(); | 770 | is_stopped = uhci->is_stopped; |
759 | frame_number = (uhci->is_stopped ? uhci->frame_number : | 771 | smp_rmb(); |
772 | frame_number = (is_stopped ? uhci->frame_number : | ||
760 | inw(uhci->io_addr + USBFRNUM)); | 773 | inw(uhci->io_addr + USBFRNUM)); |
761 | local_irq_restore(flags); | 774 | local_irq_restore(flags); |
762 | return frame_number; | 775 | return frame_number; |
diff --git a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h index 02255d69e1fe..4bac57c74ec2 100644 --- a/drivers/usb/host/uhci-hcd.h +++ b/drivers/usb/host/uhci-hcd.h | |||
@@ -314,26 +314,29 @@ static inline int __interval_to_skel(int interval) | |||
314 | } | 314 | } |
315 | 315 | ||
316 | /* | 316 | /* |
317 | * Device states for the host controller. | 317 | * States for the root hub. |
318 | * | 318 | * |
319 | * To prevent "bouncing" in the presence of electrical noise, | 319 | * To prevent "bouncing" in the presence of electrical noise, |
320 | * we insist on a 1-second "grace" period, before switching to | 320 | * when there are no devices attached we delay for 1 second in the |
321 | * the RUNNING or SUSPENDED states, during which the state is | 321 | * RUNNING_NODEVS state before switching to the AUTO_STOPPED state. |
322 | * not allowed to change. | 322 | * |
323 | * | 323 | * (Note that the AUTO_STOPPED state won't be necessary once the hub |
324 | * The resume process is divided into substates in order to avoid | 324 | * driver learns to autosuspend.) |
325 | * potentially length delays during the timer handler. | ||
326 | * | ||
327 | * States in which the host controller is halted must have values <= 0. | ||
328 | */ | 325 | */ |
329 | enum uhci_state { | 326 | enum uhci_rh_state { |
330 | UHCI_RESET, | 327 | /* In the next 4 states the HC must be halted */ |
331 | UHCI_RUNNING_GRACE, /* Before RUNNING */ | 328 | UHCI_RH_RESET, |
332 | UHCI_RUNNING, /* The normal state */ | 329 | UHCI_RH_SUSPENDED, |
333 | UHCI_SUSPENDING_GRACE, /* Before SUSPENDED */ | 330 | UHCI_RH_AUTO_STOPPED, |
334 | UHCI_SUSPENDED = -10, /* When no devices are attached */ | 331 | UHCI_RH_RESUMING, |
335 | UHCI_RESUMING_1, | 332 | |
336 | UHCI_RESUMING_2 | 333 | /* In the next state the HC changes from running to halted, so it |
334 | * can legally appear either way */ | ||
335 | UHCI_RH_SUSPENDING, | ||
336 | |||
337 | /* In the next two states it's an error if the HC is halted */ | ||
338 | UHCI_RH_RUNNING, /* The normal state */ | ||
339 | UHCI_RH_RUNNING_NODEVS, /* Running with no devices attached */ | ||
337 | }; | 340 | }; |
338 | 341 | ||
339 | /* | 342 | /* |
@@ -363,8 +366,9 @@ struct uhci_hcd { | |||
363 | int fsbr; /* Full-speed bandwidth reclamation */ | 366 | int fsbr; /* Full-speed bandwidth reclamation */ |
364 | unsigned long fsbrtimeout; /* FSBR delay */ | 367 | unsigned long fsbrtimeout; /* FSBR delay */ |
365 | 368 | ||
366 | enum uhci_state state; /* FIXME: needs a spinlock */ | 369 | enum uhci_rh_state rh_state; |
367 | unsigned long state_end; /* Time of next transition */ | 370 | unsigned long auto_stop_time; /* When to AUTO_STOP */ |
371 | |||
368 | unsigned int frame_number; /* As of last check */ | 372 | unsigned int frame_number; /* As of last check */ |
369 | unsigned int is_stopped; | 373 | unsigned int is_stopped; |
370 | #define UHCI_IS_STOPPED 9999 /* Larger than a frame # */ | 374 | #define UHCI_IS_STOPPED 9999 /* Larger than a frame # */ |
@@ -451,4 +455,11 @@ struct urb_priv { | |||
451 | * #2 urb->lock | 455 | * #2 urb->lock |
452 | */ | 456 | */ |
453 | 457 | ||
458 | |||
459 | /* Some special IDs */ | ||
460 | |||
461 | #define PCI_VENDOR_ID_GENESYS 0x17a0 | ||
462 | #define PCI_DEVICE_ID_GL880S_UHCI 0x8083 | ||
463 | #define PCI_DEVICE_ID_GL880S_EHCI 0x8084 | ||
464 | |||
454 | #endif | 465 | #endif |
diff --git a/drivers/usb/host/uhci-hub.c b/drivers/usb/host/uhci-hub.c index ddb19cbf4b75..fc34fee2ab07 100644 --- a/drivers/usb/host/uhci-hub.c +++ b/drivers/usb/host/uhci-hub.c | |||
@@ -60,7 +60,7 @@ static int uhci_hub_status_data(struct usb_hcd *hcd, char *buf) | |||
60 | test_bit(port, &uhci->port_c_suspend)) | 60 | test_bit(port, &uhci->port_c_suspend)) |
61 | *buf |= (1 << (port + 1)); | 61 | *buf |= (1 << (port + 1)); |
62 | } | 62 | } |
63 | if (*buf && uhci->state == UHCI_SUSPENDED) | 63 | if (*buf && uhci->is_stopped) |
64 | uhci->resume_detect = 1; | 64 | uhci->resume_detect = 1; |
65 | return !!*buf; | 65 | return !!*buf; |
66 | } | 66 | } |