diff options
-rw-r--r-- | drivers/usb/host/ohci-hcd.c | 18 | ||||
-rw-r--r-- | drivers/usb/host/ohci-hub.c | 229 | ||||
-rw-r--r-- | drivers/usb/host/ohci.h | 1 |
3 files changed, 164 insertions, 84 deletions
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 1027aa04583d..d1d68c402251 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c | |||
@@ -715,17 +715,8 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd, struct pt_regs *ptregs) | |||
715 | return IRQ_NOTMINE; | 715 | return IRQ_NOTMINE; |
716 | } | 716 | } |
717 | 717 | ||
718 | /* NOTE: vendors didn't always make the same implementation | ||
719 | * choices for RHSC. Sometimes it triggers on an edge (like | ||
720 | * setting and maybe clearing a port status change bit); and | ||
721 | * it's level-triggered on other silicon, active until khubd | ||
722 | * clears all active port status change bits. Poll by timer | ||
723 | * til it's fully debounced and the difference won't matter. | ||
724 | */ | ||
725 | if (ints & OHCI_INTR_RHSC) { | 718 | if (ints & OHCI_INTR_RHSC) { |
726 | ohci_vdbg (ohci, "rhsc\n"); | 719 | ohci_vdbg (ohci, "rhsc\n"); |
727 | ohci_writel (ohci, OHCI_INTR_RHSC, ®s->intrdisable); | ||
728 | hcd->poll_rh = 1; | ||
729 | ohci->next_statechange = jiffies + STATECHANGE_DELAY; | 720 | ohci->next_statechange = jiffies + STATECHANGE_DELAY; |
730 | ohci_writel (ohci, OHCI_INTR_RHSC, ®s->intrstatus); | 721 | ohci_writel (ohci, OHCI_INTR_RHSC, ®s->intrstatus); |
731 | usb_hcd_poll_rh_status(hcd); | 722 | usb_hcd_poll_rh_status(hcd); |
@@ -743,13 +734,18 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd, struct pt_regs *ptregs) | |||
743 | if (ints & OHCI_INTR_RD) { | 734 | if (ints & OHCI_INTR_RD) { |
744 | ohci_vdbg (ohci, "resume detect\n"); | 735 | ohci_vdbg (ohci, "resume detect\n"); |
745 | ohci_writel (ohci, OHCI_INTR_RD, ®s->intrstatus); | 736 | ohci_writel (ohci, OHCI_INTR_RD, ®s->intrstatus); |
746 | if (hcd->state != HC_STATE_QUIESCING) | 737 | hcd->poll_rh = 1; |
738 | if (ohci->autostop) { | ||
739 | spin_lock (&ohci->lock); | ||
740 | ohci_rh_resume (ohci); | ||
741 | spin_unlock (&ohci->lock); | ||
742 | } else | ||
747 | usb_hcd_resume_root_hub(hcd); | 743 | usb_hcd_resume_root_hub(hcd); |
748 | } | 744 | } |
749 | 745 | ||
750 | if (ints & OHCI_INTR_WDH) { | 746 | if (ints & OHCI_INTR_WDH) { |
751 | if (HC_IS_RUNNING(hcd->state)) | 747 | if (HC_IS_RUNNING(hcd->state)) |
752 | ohci_writel (ohci, OHCI_INTR_WDH, ®s->intrdisable); | 748 | ohci_writel (ohci, OHCI_INTR_WDH, ®s->intrdisable); |
753 | spin_lock (&ohci->lock); | 749 | spin_lock (&ohci->lock); |
754 | dl_done_list (ohci, ptregs); | 750 | dl_done_list (ohci, ptregs); |
755 | spin_unlock (&ohci->lock); | 751 | spin_unlock (&ohci->lock); |
diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c index ef4965450de5..f36cbd02736d 100644 --- a/drivers/usb/host/ohci-hub.c +++ b/drivers/usb/host/ohci-hub.c | |||
@@ -41,31 +41,20 @@ static void ohci_rhsc_enable (struct usb_hcd *hcd) | |||
41 | { | 41 | { |
42 | struct ohci_hcd *ohci = hcd_to_ohci (hcd); | 42 | struct ohci_hcd *ohci = hcd_to_ohci (hcd); |
43 | 43 | ||
44 | hcd->poll_rh = 0; | ||
45 | ohci_writel (ohci, OHCI_INTR_RHSC, &ohci->regs->intrenable); | 44 | ohci_writel (ohci, OHCI_INTR_RHSC, &ohci->regs->intrenable); |
46 | } | 45 | } |
47 | 46 | ||
48 | #ifdef CONFIG_PM | ||
49 | |||
50 | #define OHCI_SCHED_ENABLES \ | 47 | #define OHCI_SCHED_ENABLES \ |
51 | (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) |
52 | 49 | ||
53 | static void dl_done_list (struct ohci_hcd *, struct pt_regs *); | 50 | static void dl_done_list (struct ohci_hcd *, struct pt_regs *); |
54 | static void finish_unlinks (struct ohci_hcd *, u16 , struct pt_regs *); | 51 | static void finish_unlinks (struct ohci_hcd *, u16 , struct pt_regs *); |
55 | static int ohci_restart (struct ohci_hcd *ohci); | ||
56 | 52 | ||
57 | 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) | ||
58 | { | 56 | { |
59 | struct ohci_hcd *ohci = hcd_to_ohci (hcd); | ||
60 | int status = 0; | 57 | int status = 0; |
61 | unsigned long flags; | ||
62 | |||
63 | spin_lock_irqsave (&ohci->lock, flags); | ||
64 | |||
65 | if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))) { | ||
66 | spin_unlock_irqrestore (&ohci->lock, flags); | ||
67 | return -ESHUTDOWN; | ||
68 | } | ||
69 | 58 | ||
70 | ohci->hc_control = ohci_readl (ohci, &ohci->regs->control); | 59 | ohci->hc_control = ohci_readl (ohci, &ohci->regs->control); |
71 | switch (ohci->hc_control & OHCI_CTRL_HCFS) { | 60 | switch (ohci->hc_control & OHCI_CTRL_HCFS) { |
@@ -81,15 +70,16 @@ static int ohci_bus_suspend (struct usb_hcd *hcd) | |||
81 | ohci_dbg (ohci, "needs reinit!\n"); | 70 | ohci_dbg (ohci, "needs reinit!\n"); |
82 | goto done; | 71 | goto done; |
83 | case OHCI_USB_SUSPEND: | 72 | case OHCI_USB_SUSPEND: |
84 | ohci_dbg (ohci, "already suspended\n"); | 73 | if (!ohci->autostop) { |
85 | goto done; | 74 | ohci_dbg (ohci, "already suspended\n"); |
75 | goto done; | ||
76 | } | ||
86 | } | 77 | } |
87 | ohci_dbg (ohci, "suspend root hub\n"); | 78 | ohci_dbg (ohci, "%s root hub\n", |
79 | autostop ? "auto-stop" : "suspend"); | ||
88 | 80 | ||
89 | /* First stop any processing */ | 81 | /* First stop any processing */ |
90 | if (ohci->hc_control & OHCI_SCHED_ENABLES) { | 82 | if (!autostop && (ohci->hc_control & OHCI_SCHED_ENABLES)) { |
91 | int limit; | ||
92 | |||
93 | ohci->hc_control &= ~OHCI_SCHED_ENABLES; | 83 | ohci->hc_control &= ~OHCI_SCHED_ENABLES; |
94 | ohci_writel (ohci, ohci->hc_control, &ohci->regs->control); | 84 | ohci_writel (ohci, ohci->hc_control, &ohci->regs->control); |
95 | ohci->hc_control = ohci_readl (ohci, &ohci->regs->control); | 85 | ohci->hc_control = ohci_readl (ohci, &ohci->regs->control); |
@@ -99,24 +89,17 @@ static int ohci_bus_suspend (struct usb_hcd *hcd) | |||
99 | * then the last WDH could take 6+ msec | 89 | * then the last WDH could take 6+ msec |
100 | */ | 90 | */ |
101 | ohci_dbg (ohci, "stopping schedules ...\n"); | 91 | ohci_dbg (ohci, "stopping schedules ...\n"); |
102 | limit = 2000; | 92 | ohci->autostop = 0; |
103 | while (limit > 0) { | 93 | spin_unlock_irq (&ohci->lock); |
104 | udelay (250); | 94 | msleep (8); |
105 | limit =- 250; | 95 | spin_lock_irq (&ohci->lock); |
106 | if (ohci_readl (ohci, &ohci->regs->intrstatus) | ||
107 | & OHCI_INTR_SF) | ||
108 | break; | ||
109 | } | ||
110 | dl_done_list (ohci, NULL); | ||
111 | mdelay (7); | ||
112 | } | 96 | } |
113 | dl_done_list (ohci, NULL); | 97 | dl_done_list (ohci, NULL); |
114 | finish_unlinks (ohci, ohci_frame_no(ohci), NULL); | 98 | finish_unlinks (ohci, ohci_frame_no(ohci), NULL); |
115 | ohci_writel (ohci, ohci_readl (ohci, &ohci->regs->intrstatus), | ||
116 | &ohci->regs->intrstatus); | ||
117 | 99 | ||
118 | /* maybe resume can wake root hub */ | 100 | /* maybe resume can wake root hub */ |
119 | 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) | ||
120 | ohci->hc_control |= OHCI_CTRL_RWE; | 103 | ohci->hc_control |= OHCI_CTRL_RWE; |
121 | else { | 104 | else { |
122 | ohci_writel (ohci, OHCI_INTR_RHSC, &ohci->regs->intrdisable); | 105 | ohci_writel (ohci, OHCI_INTR_RHSC, &ohci->regs->intrdisable); |
@@ -132,13 +115,12 @@ static int ohci_bus_suspend (struct usb_hcd *hcd) | |||
132 | (void) ohci_readl (ohci, &ohci->regs->control); | 115 | (void) ohci_readl (ohci, &ohci->regs->control); |
133 | 116 | ||
134 | /* no resumes until devices finish suspending */ | 117 | /* no resumes until devices finish suspending */ |
135 | ohci->next_statechange = jiffies + msecs_to_jiffies (5); | 118 | if (!autostop) { |
136 | 119 | ohci->next_statechange = jiffies + msecs_to_jiffies (5); | |
137 | /* no timer polling */ | 120 | ohci->autostop = 0; |
138 | hcd->poll_rh = 0; | 121 | } |
139 | 122 | ||
140 | done: | 123 | done: |
141 | spin_unlock_irqrestore (&ohci->lock, flags); | ||
142 | return status; | 124 | return status; |
143 | } | 125 | } |
144 | 126 | ||
@@ -151,24 +133,16 @@ static inline struct ed *find_head (struct ed *ed) | |||
151 | } | 133 | } |
152 | 134 | ||
153 | /* caller has locked the root hub */ | 135 | /* caller has locked the root hub */ |
154 | static int ohci_bus_resume (struct usb_hcd *hcd) | 136 | static int ohci_rh_resume (struct ohci_hcd *ohci) |
137 | __releases(ohci->lock) | ||
138 | __acquires(ohci->lock) | ||
155 | { | 139 | { |
156 | struct ohci_hcd *ohci = hcd_to_ohci (hcd); | 140 | struct usb_hcd *hcd = ohci_to_hcd (ohci); |
157 | u32 temp, enables; | 141 | u32 temp, enables; |
158 | int status = -EINPROGRESS; | 142 | int status = -EINPROGRESS; |
159 | unsigned long flags; | 143 | int autostopped = ohci->autostop; |
160 | |||
161 | if (time_before (jiffies, ohci->next_statechange)) | ||
162 | msleep(5); | ||
163 | |||
164 | spin_lock_irqsave (&ohci->lock, flags); | ||
165 | |||
166 | if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))) { | ||
167 | spin_unlock_irqrestore (&ohci->lock, flags); | ||
168 | return -ESHUTDOWN; | ||
169 | } | ||
170 | |||
171 | 144 | ||
145 | ohci->autostop = 0; | ||
172 | ohci->hc_control = ohci_readl (ohci, &ohci->regs->control); | 146 | ohci->hc_control = ohci_readl (ohci, &ohci->regs->control); |
173 | 147 | ||
174 | if (ohci->hc_control & (OHCI_CTRL_IR | OHCI_SCHED_ENABLES)) { | 148 | if (ohci->hc_control & (OHCI_CTRL_IR | OHCI_SCHED_ENABLES)) { |
@@ -188,7 +162,8 @@ static int ohci_bus_resume (struct usb_hcd *hcd) | |||
188 | ohci->hc_control |= OHCI_USB_RESUME; | 162 | ohci->hc_control |= OHCI_USB_RESUME; |
189 | ohci_writel (ohci, ohci->hc_control, &ohci->regs->control); | 163 | ohci_writel (ohci, ohci->hc_control, &ohci->regs->control); |
190 | (void) ohci_readl (ohci, &ohci->regs->control); | 164 | (void) ohci_readl (ohci, &ohci->regs->control); |
191 | ohci_dbg (ohci, "resume root hub\n"); | 165 | ohci_dbg (ohci, "%s root hub\n", |
166 | autostopped ? "auto-start" : "resume"); | ||
192 | break; | 167 | break; |
193 | case OHCI_USB_RESUME: | 168 | case OHCI_USB_RESUME: |
194 | /* HCFS changes sometime after INTR_RD */ | 169 | /* HCFS changes sometime after INTR_RD */ |
@@ -203,16 +178,26 @@ static int ohci_bus_resume (struct usb_hcd *hcd) | |||
203 | ohci_dbg (ohci, "lost power\n"); | 178 | ohci_dbg (ohci, "lost power\n"); |
204 | status = -EBUSY; | 179 | status = -EBUSY; |
205 | } | 180 | } |
206 | spin_unlock_irqrestore (&ohci->lock, flags); | 181 | #ifdef CONFIG_PM |
207 | if (status == -EBUSY) { | 182 | if (status == -EBUSY) { |
208 | (void) ohci_init (ohci); | 183 | if (!autostopped) { |
209 | return ohci_restart (ohci); | 184 | static int ohci_restart (struct ohci_hcd *ohci); |
185 | |||
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; | ||
210 | } | 192 | } |
193 | #endif | ||
211 | if (status != -EINPROGRESS) | 194 | if (status != -EINPROGRESS) |
212 | return status; | 195 | return status; |
196 | if (autostopped) | ||
197 | goto skip_resume; | ||
198 | spin_unlock_irq (&ohci->lock); | ||
213 | 199 | ||
214 | temp = ohci->num_ports; | 200 | temp = ohci->num_ports; |
215 | enables = 0; | ||
216 | while (temp--) { | 201 | while (temp--) { |
217 | u32 stat = ohci_readl (ohci, | 202 | u32 stat = ohci_readl (ohci, |
218 | &ohci->regs->roothub.portstatus [temp]); | 203 | &ohci->regs->roothub.portstatus [temp]); |
@@ -245,17 +230,21 @@ static int ohci_bus_resume (struct usb_hcd *hcd) | |||
245 | /* Sometimes PCI D3 suspend trashes frame timings ... */ | 230 | /* Sometimes PCI D3 suspend trashes frame timings ... */ |
246 | periodic_reinit (ohci); | 231 | periodic_reinit (ohci); |
247 | 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: | ||
248 | /* interrupts might have been disabled */ | 238 | /* interrupts might have been disabled */ |
249 | ohci_writel (ohci, OHCI_INTR_INIT, &ohci->regs->intrenable); | 239 | ohci_writel (ohci, OHCI_INTR_INIT, &ohci->regs->intrenable); |
250 | if (ohci->ed_rm_list) | 240 | if (ohci->ed_rm_list) |
251 | ohci_writel (ohci, OHCI_INTR_SF, &ohci->regs->intrenable); | 241 | ohci_writel (ohci, OHCI_INTR_SF, &ohci->regs->intrenable); |
252 | ohci_writel (ohci, ohci_readl (ohci, &ohci->regs->intrstatus), | ||
253 | &ohci->regs->intrstatus); | ||
254 | 242 | ||
255 | /* Then re-enable operations */ | 243 | /* Then re-enable operations */ |
256 | ohci_writel (ohci, OHCI_USB_OPER, &ohci->regs->control); | 244 | ohci_writel (ohci, OHCI_USB_OPER, &ohci->regs->control); |
257 | (void) ohci_readl (ohci, &ohci->regs->control); | 245 | (void) ohci_readl (ohci, &ohci->regs->control); |
258 | msleep (3); | 246 | if (!autostopped) |
247 | msleep (3); | ||
259 | 248 | ||
260 | temp = ohci->hc_control; | 249 | temp = ohci->hc_control; |
261 | temp &= OHCI_CTRL_RWC; | 250 | temp &= OHCI_CTRL_RWC; |
@@ -265,7 +254,11 @@ static int ohci_bus_resume (struct usb_hcd *hcd) | |||
265 | (void) ohci_readl (ohci, &ohci->regs->control); | 254 | (void) ohci_readl (ohci, &ohci->regs->control); |
266 | 255 | ||
267 | /* TRSMRCY */ | 256 | /* TRSMRCY */ |
268 | 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 */ | ||
269 | 262 | ||
270 | /* keep it alive for more than ~5x suspend + resume costs */ | 263 | /* keep it alive for more than ~5x suspend + resume costs */ |
271 | ohci->next_statechange = jiffies + STATECHANGE_DELAY; | 264 | ohci->next_statechange = jiffies + STATECHANGE_DELAY; |
@@ -302,6 +295,45 @@ static int ohci_bus_resume (struct usb_hcd *hcd) | |||
302 | return 0; | 295 | return 0; |
303 | } | 296 | } |
304 | 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 | |||
305 | #endif /* CONFIG_PM */ | 337 | #endif /* CONFIG_PM */ |
306 | 338 | ||
307 | /*-------------------------------------------------------------------------*/ | 339 | /*-------------------------------------------------------------------------*/ |
@@ -313,17 +345,11 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf) | |||
313 | { | 345 | { |
314 | struct ohci_hcd *ohci = hcd_to_ohci (hcd); | 346 | struct ohci_hcd *ohci = hcd_to_ohci (hcd); |
315 | int i, changed = 0, length = 1; | 347 | int i, changed = 0, length = 1; |
348 | int any_connected = 0, rhsc_enabled = 1; | ||
316 | unsigned long flags; | 349 | unsigned long flags; |
317 | 350 | ||
318 | spin_lock_irqsave (&ohci->lock, flags); | 351 | spin_lock_irqsave (&ohci->lock, flags); |
319 | 352 | ||
320 | /* handle autosuspended root: finish resuming before | ||
321 | * letting khubd or root hub timer see state changes. | ||
322 | */ | ||
323 | if (unlikely((ohci->hc_control & OHCI_CTRL_HCFS) != OHCI_USB_OPER | ||
324 | || !HC_IS_RUNNING(hcd->state))) | ||
325 | goto done; | ||
326 | |||
327 | /* undocumented erratum seen on at least rev D */ | 353 | /* undocumented erratum seen on at least rev D */ |
328 | if ((ohci->flags & OHCI_QUIRK_AMD756) | 354 | if ((ohci->flags & OHCI_QUIRK_AMD756) |
329 | && (roothub_a (ohci) & RH_A_NDP) > MAX_ROOT_PORTS) { | 355 | && (roothub_a (ohci) & RH_A_NDP) > MAX_ROOT_PORTS) { |
@@ -347,6 +373,9 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf) | |||
347 | for (i = 0; i < ohci->num_ports; i++) { | 373 | for (i = 0; i < ohci->num_ports; i++) { |
348 | u32 status = roothub_portstatus (ohci, i); | 374 | u32 status = roothub_portstatus (ohci, i); |
349 | 375 | ||
376 | /* can't autostop if ports are connected */ | ||
377 | any_connected |= (status & RH_PS_CCS); | ||
378 | |||
350 | if (status & (RH_PS_CSC | RH_PS_PESC | RH_PS_PSSC | 379 | if (status & (RH_PS_CSC | RH_PS_PESC | RH_PS_PSSC |
351 | | RH_PS_OCIC | RH_PS_PRSC)) { | 380 | | RH_PS_OCIC | RH_PS_PRSC)) { |
352 | changed = 1; | 381 | changed = 1; |
@@ -354,15 +383,69 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf) | |||
354 | buf [0] |= 1 << (i + 1); | 383 | buf [0] |= 1 << (i + 1); |
355 | else | 384 | else |
356 | buf [1] |= 1 << (i - 7); | 385 | buf [1] |= 1 << (i - 7); |
357 | continue; | ||
358 | } | 386 | } |
359 | } | 387 | } |
360 | 388 | ||
361 | /* after root hub changes, stop polling after debouncing | 389 | /* NOTE: vendors didn't always make the same implementation |
362 | * 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. | ||
363 | */ | 396 | */ |
364 | if (changed) | 397 | if (ohci_readl (ohci, &ohci->regs->intrstatus) & OHCI_INTR_RHSC) { |
365 | ohci->next_statechange = jiffies + STATECHANGE_DELAY; | 398 | ohci_writel (ohci, OHCI_INTR_RHSC, &ohci->regs->intrdisable); |
399 | (void) ohci_readl (ohci, &ohci->regs->intrdisable); | ||
400 | rhsc_enabled = 0; | ||
401 | } | ||
402 | hcd->poll_rh = 1; | ||
403 | |||
404 | /* carry out appropriate state changes */ | ||
405 | switch (ohci->hc_control & OHCI_CTRL_HCFS) { | ||
406 | |||
407 | case OHCI_USB_OPER: | ||
408 | /* keep on polling until we know a device is connected | ||
409 | * and RHSC is enabled */ | ||
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 */ | ||
445 | hcd->poll_rh = 0; | ||
446 | } | ||
447 | break; | ||
448 | } | ||
366 | 449 | ||
367 | done: | 450 | done: |
368 | spin_unlock_irqrestore (&ohci->lock, flags); | 451 | spin_unlock_irqrestore (&ohci->lock, flags); |
diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h index 93fdc3c35341..a2f42a2f47c6 100644 --- a/drivers/usb/host/ohci.h +++ b/drivers/usb/host/ohci.h | |||
@@ -388,6 +388,7 @@ struct ohci_hcd { | |||
388 | u32 hc_control; /* copy of hc control reg */ | 388 | u32 hc_control; /* copy of hc control reg */ |
389 | unsigned long next_statechange; /* suspend/resume */ | 389 | unsigned long next_statechange; /* suspend/resume */ |
390 | u32 fminterval; /* saved register */ | 390 | u32 fminterval; /* saved register */ |
391 | unsigned autostop:1; /* rh auto stopping/stopped */ | ||
391 | 392 | ||
392 | unsigned long flags; /* for HC bugs */ | 393 | unsigned long flags; /* for HC bugs */ |
393 | #define OHCI_QUIRK_AMD756 0x01 /* erratum #4 */ | 394 | #define OHCI_QUIRK_AMD756 0x01 /* erratum #4 */ |