diff options
Diffstat (limited to 'drivers/usb/host/ohci-hub.c')
-rw-r--r-- | drivers/usb/host/ohci-hub.c | 265 |
1 files changed, 155 insertions, 110 deletions
diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c index 0b899339cac8..ec75774abeac 100644 --- a/drivers/usb/host/ohci-hub.c +++ b/drivers/usb/host/ohci-hub.c | |||
@@ -44,27 +44,17 @@ static void ohci_rhsc_enable (struct usb_hcd *hcd) | |||
44 | ohci_writel (ohci, OHCI_INTR_RHSC, &ohci->regs->intrenable); | 44 | ohci_writel (ohci, OHCI_INTR_RHSC, &ohci->regs->intrenable); |
45 | } | 45 | } |
46 | 46 | ||
47 | #ifdef CONFIG_PM | ||
48 | |||
49 | #define OHCI_SCHED_ENABLES \ | 47 | #define OHCI_SCHED_ENABLES \ |
50 | (OHCI_CTRL_CLE|OHCI_CTRL_BLE|OHCI_CTRL_PLE|OHCI_CTRL_IE) | 48 | (OHCI_CTRL_CLE|OHCI_CTRL_BLE|OHCI_CTRL_PLE|OHCI_CTRL_IE) |
51 | 49 | ||
52 | static void dl_done_list (struct ohci_hcd *, struct pt_regs *); | 50 | static void dl_done_list (struct ohci_hcd *, struct pt_regs *); |
53 | static void finish_unlinks (struct ohci_hcd *, u16 , struct pt_regs *); | 51 | static void finish_unlinks (struct ohci_hcd *, u16 , struct pt_regs *); |
54 | static int ohci_restart (struct ohci_hcd *ohci); | ||
55 | 52 | ||
56 | static int ohci_bus_suspend (struct usb_hcd *hcd) | 53 | static int ohci_rh_suspend (struct ohci_hcd *ohci, int autostop) |
54 | __releases(ohci->lock) | ||
55 | __acquires(ohci->lock) | ||
57 | { | 56 | { |
58 | struct ohci_hcd *ohci = hcd_to_ohci (hcd); | ||
59 | int status = 0; | 57 | int status = 0; |
60 | unsigned long flags; | ||
61 | |||
62 | spin_lock_irqsave (&ohci->lock, flags); | ||
63 | |||
64 | if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))) { | ||
65 | spin_unlock_irqrestore (&ohci->lock, flags); | ||
66 | return -ESHUTDOWN; | ||
67 | } | ||
68 | 58 | ||
69 | ohci->hc_control = ohci_readl (ohci, &ohci->regs->control); | 59 | ohci->hc_control = ohci_readl (ohci, &ohci->regs->control); |
70 | switch (ohci->hc_control & OHCI_CTRL_HCFS) { | 60 | switch (ohci->hc_control & OHCI_CTRL_HCFS) { |
@@ -80,15 +70,16 @@ static int ohci_bus_suspend (struct usb_hcd *hcd) | |||
80 | ohci_dbg (ohci, "needs reinit!\n"); | 70 | ohci_dbg (ohci, "needs reinit!\n"); |
81 | goto done; | 71 | goto done; |
82 | case OHCI_USB_SUSPEND: | 72 | case OHCI_USB_SUSPEND: |
83 | ohci_dbg (ohci, "already suspended\n"); | 73 | if (!ohci->autostop) { |
84 | goto done; | 74 | ohci_dbg (ohci, "already suspended\n"); |
75 | goto done; | ||
76 | } | ||
85 | } | 77 | } |
86 | ohci_dbg (ohci, "suspend root hub\n"); | 78 | ohci_dbg (ohci, "%s root hub\n", |
79 | autostop ? "auto-stop" : "suspend"); | ||
87 | 80 | ||
88 | /* First stop any processing */ | 81 | /* First stop any processing */ |
89 | if (ohci->hc_control & OHCI_SCHED_ENABLES) { | 82 | if (!autostop && (ohci->hc_control & OHCI_SCHED_ENABLES)) { |
90 | int limit; | ||
91 | |||
92 | ohci->hc_control &= ~OHCI_SCHED_ENABLES; | 83 | ohci->hc_control &= ~OHCI_SCHED_ENABLES; |
93 | ohci_writel (ohci, ohci->hc_control, &ohci->regs->control); | 84 | ohci_writel (ohci, ohci->hc_control, &ohci->regs->control); |
94 | ohci->hc_control = ohci_readl (ohci, &ohci->regs->control); | 85 | ohci->hc_control = ohci_readl (ohci, &ohci->regs->control); |
@@ -98,27 +89,22 @@ static int ohci_bus_suspend (struct usb_hcd *hcd) | |||
98 | * then the last WDH could take 6+ msec | 89 | * then the last WDH could take 6+ msec |
99 | */ | 90 | */ |
100 | ohci_dbg (ohci, "stopping schedules ...\n"); | 91 | ohci_dbg (ohci, "stopping schedules ...\n"); |
101 | limit = 2000; | 92 | ohci->autostop = 0; |
102 | while (limit > 0) { | 93 | spin_unlock_irq (&ohci->lock); |
103 | udelay (250); | 94 | msleep (8); |
104 | limit =- 250; | 95 | spin_lock_irq (&ohci->lock); |
105 | if (ohci_readl (ohci, &ohci->regs->intrstatus) | ||
106 | & OHCI_INTR_SF) | ||
107 | break; | ||
108 | } | ||
109 | dl_done_list (ohci, NULL); | ||
110 | mdelay (7); | ||
111 | } | 96 | } |
112 | dl_done_list (ohci, NULL); | 97 | dl_done_list (ohci, NULL); |
113 | finish_unlinks (ohci, ohci_frame_no(ohci), NULL); | 98 | finish_unlinks (ohci, ohci_frame_no(ohci), NULL); |
114 | ohci_writel (ohci, ohci_readl (ohci, &ohci->regs->intrstatus), | ||
115 | &ohci->regs->intrstatus); | ||
116 | 99 | ||
117 | /* maybe resume can wake root hub */ | 100 | /* maybe resume can wake root hub */ |
118 | if (device_may_wakeup(&ohci_to_hcd(ohci)->self.root_hub->dev)) | 101 | if (device_may_wakeup(&ohci_to_hcd(ohci)->self.root_hub->dev) || |
102 | autostop) | ||
119 | ohci->hc_control |= OHCI_CTRL_RWE; | 103 | ohci->hc_control |= OHCI_CTRL_RWE; |
120 | else | 104 | else { |
105 | ohci_writel (ohci, OHCI_INTR_RHSC, &ohci->regs->intrdisable); | ||
121 | ohci->hc_control &= ~OHCI_CTRL_RWE; | 106 | ohci->hc_control &= ~OHCI_CTRL_RWE; |
107 | } | ||
122 | 108 | ||
123 | /* Suspend hub ... this is the "global (to this bus) suspend" mode, | 109 | /* Suspend hub ... this is the "global (to this bus) suspend" mode, |
124 | * which doesn't imply ports will first be individually suspended. | 110 | * which doesn't imply ports will first be individually suspended. |
@@ -129,13 +115,12 @@ static int ohci_bus_suspend (struct usb_hcd *hcd) | |||
129 | (void) ohci_readl (ohci, &ohci->regs->control); | 115 | (void) ohci_readl (ohci, &ohci->regs->control); |
130 | 116 | ||
131 | /* no resumes until devices finish suspending */ | 117 | /* no resumes until devices finish suspending */ |
132 | ohci->next_statechange = jiffies + msecs_to_jiffies (5); | 118 | if (!autostop) { |
133 | 119 | ohci->next_statechange = jiffies + msecs_to_jiffies (5); | |
134 | /* no timer polling */ | 120 | ohci->autostop = 0; |
135 | hcd->poll_rh = 0; | 121 | } |
136 | 122 | ||
137 | done: | 123 | done: |
138 | spin_unlock_irqrestore (&ohci->lock, flags); | ||
139 | return status; | 124 | return status; |
140 | } | 125 | } |
141 | 126 | ||
@@ -147,25 +132,19 @@ static inline struct ed *find_head (struct ed *ed) | |||
147 | return ed; | 132 | return ed; |
148 | } | 133 | } |
149 | 134 | ||
135 | static int ohci_restart (struct ohci_hcd *ohci); | ||
136 | |||
150 | /* caller has locked the root hub */ | 137 | /* caller has locked the root hub */ |
151 | static int ohci_bus_resume (struct usb_hcd *hcd) | 138 | static int ohci_rh_resume (struct ohci_hcd *ohci) |
139 | __releases(ohci->lock) | ||
140 | __acquires(ohci->lock) | ||
152 | { | 141 | { |
153 | struct ohci_hcd *ohci = hcd_to_ohci (hcd); | 142 | struct usb_hcd *hcd = ohci_to_hcd (ohci); |
154 | u32 temp, enables; | 143 | u32 temp, enables; |
155 | int status = -EINPROGRESS; | 144 | int status = -EINPROGRESS; |
156 | unsigned long flags; | 145 | int autostopped = ohci->autostop; |
157 | |||
158 | if (time_before (jiffies, ohci->next_statechange)) | ||
159 | msleep(5); | ||
160 | |||
161 | spin_lock_irqsave (&ohci->lock, flags); | ||
162 | |||
163 | if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))) { | ||
164 | spin_unlock_irqrestore (&ohci->lock, flags); | ||
165 | return -ESHUTDOWN; | ||
166 | } | ||
167 | |||
168 | 146 | ||
147 | ohci->autostop = 0; | ||
169 | ohci->hc_control = ohci_readl (ohci, &ohci->regs->control); | 148 | ohci->hc_control = ohci_readl (ohci, &ohci->regs->control); |
170 | 149 | ||
171 | if (ohci->hc_control & (OHCI_CTRL_IR | OHCI_SCHED_ENABLES)) { | 150 | if (ohci->hc_control & (OHCI_CTRL_IR | OHCI_SCHED_ENABLES)) { |
@@ -185,7 +164,8 @@ static int ohci_bus_resume (struct usb_hcd *hcd) | |||
185 | ohci->hc_control |= OHCI_USB_RESUME; | 164 | ohci->hc_control |= OHCI_USB_RESUME; |
186 | ohci_writel (ohci, ohci->hc_control, &ohci->regs->control); | 165 | ohci_writel (ohci, ohci->hc_control, &ohci->regs->control); |
187 | (void) ohci_readl (ohci, &ohci->regs->control); | 166 | (void) ohci_readl (ohci, &ohci->regs->control); |
188 | ohci_dbg (ohci, "resume root hub\n"); | 167 | ohci_dbg (ohci, "%s root hub\n", |
168 | autostopped ? "auto-start" : "resume"); | ||
189 | break; | 169 | break; |
190 | case OHCI_USB_RESUME: | 170 | case OHCI_USB_RESUME: |
191 | /* HCFS changes sometime after INTR_RD */ | 171 | /* HCFS changes sometime after INTR_RD */ |
@@ -200,16 +180,24 @@ static int ohci_bus_resume (struct usb_hcd *hcd) | |||
200 | ohci_dbg (ohci, "lost power\n"); | 180 | ohci_dbg (ohci, "lost power\n"); |
201 | status = -EBUSY; | 181 | status = -EBUSY; |
202 | } | 182 | } |
203 | spin_unlock_irqrestore (&ohci->lock, flags); | 183 | #ifdef CONFIG_PM |
204 | if (status == -EBUSY) { | 184 | if (status == -EBUSY) { |
205 | (void) ohci_init (ohci); | 185 | if (!autostopped) { |
206 | return ohci_restart (ohci); | 186 | spin_unlock_irq (&ohci->lock); |
187 | (void) ohci_init (ohci); | ||
188 | status = ohci_restart (ohci); | ||
189 | spin_lock_irq (&ohci->lock); | ||
190 | } | ||
191 | return status; | ||
207 | } | 192 | } |
193 | #endif | ||
208 | if (status != -EINPROGRESS) | 194 | if (status != -EINPROGRESS) |
209 | return status; | 195 | return status; |
196 | if (autostopped) | ||
197 | goto skip_resume; | ||
198 | spin_unlock_irq (&ohci->lock); | ||
210 | 199 | ||
211 | temp = ohci->num_ports; | 200 | temp = ohci->num_ports; |
212 | enables = 0; | ||
213 | while (temp--) { | 201 | while (temp--) { |
214 | u32 stat = ohci_readl (ohci, | 202 | u32 stat = ohci_readl (ohci, |
215 | &ohci->regs->roothub.portstatus [temp]); | 203 | &ohci->regs->roothub.portstatus [temp]); |
@@ -242,17 +230,21 @@ static int ohci_bus_resume (struct usb_hcd *hcd) | |||
242 | /* Sometimes PCI D3 suspend trashes frame timings ... */ | 230 | /* Sometimes PCI D3 suspend trashes frame timings ... */ |
243 | periodic_reinit (ohci); | 231 | periodic_reinit (ohci); |
244 | 232 | ||
233 | /* the following code is executed with ohci->lock held and | ||
234 | * irqs disabled if and only if autostopped is true | ||
235 | */ | ||
236 | |||
237 | skip_resume: | ||
245 | /* interrupts might have been disabled */ | 238 | /* interrupts might have been disabled */ |
246 | ohci_writel (ohci, OHCI_INTR_INIT, &ohci->regs->intrenable); | 239 | ohci_writel (ohci, OHCI_INTR_INIT, &ohci->regs->intrenable); |
247 | if (ohci->ed_rm_list) | 240 | if (ohci->ed_rm_list) |
248 | ohci_writel (ohci, OHCI_INTR_SF, &ohci->regs->intrenable); | 241 | ohci_writel (ohci, OHCI_INTR_SF, &ohci->regs->intrenable); |
249 | ohci_writel (ohci, ohci_readl (ohci, &ohci->regs->intrstatus), | ||
250 | &ohci->regs->intrstatus); | ||
251 | 242 | ||
252 | /* Then re-enable operations */ | 243 | /* Then re-enable operations */ |
253 | ohci_writel (ohci, OHCI_USB_OPER, &ohci->regs->control); | 244 | ohci_writel (ohci, OHCI_USB_OPER, &ohci->regs->control); |
254 | (void) ohci_readl (ohci, &ohci->regs->control); | 245 | (void) ohci_readl (ohci, &ohci->regs->control); |
255 | msleep (3); | 246 | if (!autostopped) |
247 | msleep (3); | ||
256 | 248 | ||
257 | temp = ohci->hc_control; | 249 | temp = ohci->hc_control; |
258 | temp &= OHCI_CTRL_RWC; | 250 | temp &= OHCI_CTRL_RWC; |
@@ -262,7 +254,11 @@ static int ohci_bus_resume (struct usb_hcd *hcd) | |||
262 | (void) ohci_readl (ohci, &ohci->regs->control); | 254 | (void) ohci_readl (ohci, &ohci->regs->control); |
263 | 255 | ||
264 | /* TRSMRCY */ | 256 | /* TRSMRCY */ |
265 | msleep (10); | 257 | if (!autostopped) { |
258 | msleep (10); | ||
259 | spin_lock_irq (&ohci->lock); | ||
260 | } | ||
261 | /* now ohci->lock is always held and irqs are always disabled */ | ||
266 | 262 | ||
267 | /* keep it alive for more than ~5x suspend + resume costs */ | 263 | /* keep it alive for more than ~5x suspend + resume costs */ |
268 | ohci->next_statechange = jiffies + STATECHANGE_DELAY; | 264 | ohci->next_statechange = jiffies + STATECHANGE_DELAY; |
@@ -299,6 +295,45 @@ static int ohci_bus_resume (struct usb_hcd *hcd) | |||
299 | return 0; | 295 | return 0; |
300 | } | 296 | } |
301 | 297 | ||
298 | #ifdef CONFIG_PM | ||
299 | |||
300 | static int ohci_bus_suspend (struct usb_hcd *hcd) | ||
301 | { | ||
302 | struct ohci_hcd *ohci = hcd_to_ohci (hcd); | ||
303 | int rc; | ||
304 | |||
305 | spin_lock_irq (&ohci->lock); | ||
306 | |||
307 | if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))) | ||
308 | rc = -ESHUTDOWN; | ||
309 | else | ||
310 | rc = ohci_rh_suspend (ohci, 0); | ||
311 | spin_unlock_irq (&ohci->lock); | ||
312 | return rc; | ||
313 | } | ||
314 | |||
315 | static int ohci_bus_resume (struct usb_hcd *hcd) | ||
316 | { | ||
317 | struct ohci_hcd *ohci = hcd_to_ohci (hcd); | ||
318 | int rc; | ||
319 | |||
320 | if (time_before (jiffies, ohci->next_statechange)) | ||
321 | msleep(5); | ||
322 | |||
323 | spin_lock_irq (&ohci->lock); | ||
324 | |||
325 | if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))) | ||
326 | rc = -ESHUTDOWN; | ||
327 | else | ||
328 | rc = ohci_rh_resume (ohci); | ||
329 | spin_unlock_irq (&ohci->lock); | ||
330 | |||
331 | /* poll until we know a device is connected or we autostop */ | ||
332 | if (rc == 0) | ||
333 | usb_hcd_poll_rh_status(hcd); | ||
334 | return rc; | ||
335 | } | ||
336 | |||
302 | #endif /* CONFIG_PM */ | 337 | #endif /* CONFIG_PM */ |
303 | 338 | ||
304 | /*-------------------------------------------------------------------------*/ | 339 | /*-------------------------------------------------------------------------*/ |
@@ -310,21 +345,11 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf) | |||
310 | { | 345 | { |
311 | struct ohci_hcd *ohci = hcd_to_ohci (hcd); | 346 | struct ohci_hcd *ohci = hcd_to_ohci (hcd); |
312 | int i, changed = 0, length = 1; | 347 | int i, changed = 0, length = 1; |
313 | int can_suspend; | 348 | int any_connected = 0, rhsc_enabled = 1; |
314 | unsigned long flags; | 349 | unsigned long flags; |
315 | 350 | ||
316 | can_suspend = device_may_wakeup(&hcd->self.root_hub->dev); | ||
317 | spin_lock_irqsave (&ohci->lock, flags); | 351 | spin_lock_irqsave (&ohci->lock, flags); |
318 | 352 | ||
319 | /* handle autosuspended root: finish resuming before | ||
320 | * letting khubd or root hub timer see state changes. | ||
321 | */ | ||
322 | if (unlikely((ohci->hc_control & OHCI_CTRL_HCFS) != OHCI_USB_OPER | ||
323 | || !HC_IS_RUNNING(hcd->state))) { | ||
324 | can_suspend = 0; | ||
325 | goto done; | ||
326 | } | ||
327 | |||
328 | /* undocumented erratum seen on at least rev D */ | 353 | /* undocumented erratum seen on at least rev D */ |
329 | if ((ohci->flags & OHCI_QUIRK_AMD756) | 354 | if ((ohci->flags & OHCI_QUIRK_AMD756) |
330 | && (roothub_a (ohci) & RH_A_NDP) > MAX_ROOT_PORTS) { | 355 | && (roothub_a (ohci) & RH_A_NDP) > MAX_ROOT_PORTS) { |
@@ -348,9 +373,8 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf) | |||
348 | for (i = 0; i < ohci->num_ports; i++) { | 373 | for (i = 0; i < ohci->num_ports; i++) { |
349 | u32 status = roothub_portstatus (ohci, i); | 374 | u32 status = roothub_portstatus (ohci, i); |
350 | 375 | ||
351 | /* can't autosuspend with active ports */ | 376 | /* can't autostop if ports are connected */ |
352 | if ((status & RH_PS_PES) && !(status & RH_PS_PSS)) | 377 | any_connected |= (status & RH_PS_CCS); |
353 | can_suspend = 0; | ||
354 | 378 | ||
355 | if (status & (RH_PS_CSC | RH_PS_PESC | RH_PS_PSSC | 379 | if (status & (RH_PS_CSC | RH_PS_PESC | RH_PS_PSSC |
356 | | RH_PS_OCIC | RH_PS_PRSC)) { | 380 | | RH_PS_OCIC | RH_PS_PRSC)) { |
@@ -359,49 +383,73 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf) | |||
359 | buf [0] |= 1 << (i + 1); | 383 | buf [0] |= 1 << (i + 1); |
360 | else | 384 | else |
361 | buf [1] |= 1 << (i - 7); | 385 | buf [1] |= 1 << (i - 7); |
362 | continue; | ||
363 | } | 386 | } |
364 | } | 387 | } |
365 | 388 | ||
366 | /* after root hub changes, stop polling after debouncing | 389 | /* NOTE: vendors didn't always make the same implementation |
367 | * for a while and maybe kicking in autosuspend | 390 | * choices for RHSC. Sometimes it triggers on an edge (like |
391 | * setting and maybe clearing a port status change bit); and | ||
392 | * it's level-triggered on other silicon, active until khubd | ||
393 | * clears all active port status change bits. If it's still | ||
394 | * set (level-triggered) we must disable it and rely on | ||
395 | * polling until khubd re-enables it. | ||
368 | */ | 396 | */ |
369 | if (changed) { | 397 | if (ohci_readl (ohci, &ohci->regs->intrstatus) & OHCI_INTR_RHSC) { |
370 | ohci->next_statechange = jiffies + STATECHANGE_DELAY; | 398 | ohci_writel (ohci, OHCI_INTR_RHSC, &ohci->regs->intrdisable); |
371 | can_suspend = 0; | 399 | (void) ohci_readl (ohci, &ohci->regs->intrdisable); |
372 | } else if (time_before (jiffies, ohci->next_statechange)) { | 400 | rhsc_enabled = 0; |
373 | can_suspend = 0; | 401 | } |
374 | } else { | 402 | hcd->poll_rh = 1; |
375 | #ifdef CONFIG_PM | 403 | |
376 | can_suspend = can_suspend | 404 | /* carry out appropriate state changes */ |
377 | && !ohci->ed_rm_list | 405 | switch (ohci->hc_control & OHCI_CTRL_HCFS) { |
378 | && ((OHCI_CTRL_HCFS | OHCI_SCHED_ENABLES) | 406 | |
379 | & ohci->hc_control) | 407 | case OHCI_USB_OPER: |
380 | == OHCI_USB_OPER; | 408 | /* keep on polling until we know a device is connected |
381 | #endif | 409 | * and RHSC is enabled */ |
382 | if (hcd->uses_new_polling) { | 410 | if (!ohci->autostop) { |
411 | if (any_connected) { | ||
412 | if (rhsc_enabled) | ||
413 | hcd->poll_rh = 0; | ||
414 | } else { | ||
415 | ohci->autostop = 1; | ||
416 | ohci->next_statechange = jiffies + HZ; | ||
417 | } | ||
418 | |||
419 | /* if no devices have been attached for one second, autostop */ | ||
420 | } else { | ||
421 | if (changed || any_connected) { | ||
422 | ohci->autostop = 0; | ||
423 | ohci->next_statechange = jiffies + | ||
424 | STATECHANGE_DELAY; | ||
425 | } else if (time_after_eq (jiffies, | ||
426 | ohci->next_statechange) | ||
427 | && !ohci->ed_rm_list | ||
428 | && !(ohci->hc_control & | ||
429 | OHCI_SCHED_ENABLES)) { | ||
430 | ohci_rh_suspend (ohci, 1); | ||
431 | } | ||
432 | } | ||
433 | break; | ||
434 | |||
435 | /* if there is a port change, autostart or ask to be resumed */ | ||
436 | case OHCI_USB_SUSPEND: | ||
437 | case OHCI_USB_RESUME: | ||
438 | if (changed) { | ||
439 | if (ohci->autostop) | ||
440 | ohci_rh_resume (ohci); | ||
441 | else | ||
442 | usb_hcd_resume_root_hub (hcd); | ||
443 | } else { | ||
444 | /* everything is idle, no need for polling */ | ||
383 | hcd->poll_rh = 0; | 445 | hcd->poll_rh = 0; |
384 | /* use INTR_RHSC iff INTR_RD won't apply */ | ||
385 | if (!can_suspend) | ||
386 | ohci_writel (ohci, OHCI_INTR_RHSC, | ||
387 | &ohci->regs->intrenable); | ||
388 | } | 446 | } |
447 | break; | ||
389 | } | 448 | } |
390 | 449 | ||
391 | done: | 450 | done: |
392 | spin_unlock_irqrestore (&ohci->lock, flags); | 451 | spin_unlock_irqrestore (&ohci->lock, flags); |
393 | 452 | ||
394 | #ifdef CONFIG_PM | ||
395 | /* save power by autosuspending idle root hubs; | ||
396 | * INTR_RD wakes us when there's work | ||
397 | */ | ||
398 | if (can_suspend && usb_trylock_device (hcd->self.root_hub) == 0) { | ||
399 | ohci_vdbg (ohci, "autosuspend\n"); | ||
400 | (void) ohci_bus_suspend (hcd); | ||
401 | usb_unlock_device (hcd->self.root_hub); | ||
402 | } | ||
403 | #endif | ||
404 | |||
405 | return changed ? length : 0; | 453 | return changed ? length : 0; |
406 | } | 454 | } |
407 | 455 | ||
@@ -572,9 +620,6 @@ static int ohci_hub_control ( | |||
572 | break; | 620 | break; |
573 | case USB_PORT_FEAT_SUSPEND: | 621 | case USB_PORT_FEAT_SUSPEND: |
574 | temp = RH_PS_POCI; | 622 | temp = RH_PS_POCI; |
575 | if ((ohci->hc_control & OHCI_CTRL_HCFS) | ||
576 | != OHCI_USB_OPER) | ||
577 | usb_hcd_resume_root_hub(hcd); | ||
578 | break; | 623 | break; |
579 | case USB_PORT_FEAT_C_SUSPEND: | 624 | case USB_PORT_FEAT_C_SUSPEND: |
580 | temp = RH_PS_PSSC; | 625 | temp = RH_PS_PSSC; |