aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2005-04-09 17:27:32 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2005-06-27 17:43:43 -0400
commitc8f4fe4358c5e0a79b4bd47b814d19f1d1d06f21 (patch)
tree0c12fec97ac524e77489d3e8460bd9bb4817c0d5 /drivers/usb/host
parentf5946f8220a866dcdb8edc6abe23c1443e252425 (diff)
[PATCH] USB UHCI: Add root hub states
This patch starts making some serious changes to the UHCI driver. There's a set of private states for the root hub, and the internal routines for suspending and resuming work completely differently, with transitions based on the new states. Now the driver distinguishes between a privately auto-stopped state and a publicly suspended state, and it will properly suspend controllers with broken resume-detect interrupts instead of resetting them. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/host')
-rw-r--r--drivers/usb/host/uhci-debug.c32
-rw-r--r--drivers/usb/host/uhci-hcd.c285
-rw-r--r--drivers/usb/host/uhci-hcd.h49
-rw-r--r--drivers/usb/host/uhci-hub.c2
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
240static 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
240static int uhci_show_status(struct uhci_hcd *uhci, char *buf, int len) 271static 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, \
69Randy Dunlap, Georg Acher, Deti Fliegl, Thomas Sailer, Roman Weissgaerber, \ 69Randy Dunlap, Georg Acher, Deti Fliegl, Thomas Sailer, Roman Weissgaerber, \
70Alan Stern" 70Alan 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
112static 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
139static void reset_hc(struct uhci_hcd *uhci) 112static 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
161static void suspend_hc(struct uhci_hcd *uhci) 134static 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
166static 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
177static void wakeup_hc(struct uhci_hcd *uhci) 218static 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
218static int start_hc(struct uhci_hcd *uhci) 257static 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
260static void hc_state_transitions(struct uhci_hcd *uhci) 298static 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)
701static int uhci_resume(struct usb_hcd *hcd) 722static 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,
750static int uhci_hcd_get_frame_number(struct usb_hcd *hcd) 761static 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 */
329enum uhci_state { 326enum 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}