diff options
author | Len Brown <len.brown@intel.com> | 2005-12-06 17:31:30 -0500 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2005-12-06 17:31:30 -0500 |
commit | 3d5271f9883cba7b54762bc4fe027d4172f06db7 (patch) | |
tree | ab8a881a14478598a0c8bda0d26c62cdccfffd6d /drivers/usb/host/ohci-hub.c | |
parent | 378b2556f4e09fa6f87ff0cb5c4395ff28257d02 (diff) | |
parent | 9115a6c787596e687df03010d97fccc5e0762506 (diff) |
Pull release into acpica branch
Diffstat (limited to 'drivers/usb/host/ohci-hub.c')
-rw-r--r-- | drivers/usb/host/ohci-hub.c | 76 |
1 files changed, 37 insertions, 39 deletions
diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c index ce7b28da7a15..72e3b12a1926 100644 --- a/drivers/usb/host/ohci-hub.c +++ b/drivers/usb/host/ohci-hub.c | |||
@@ -36,7 +36,7 @@ | |||
36 | 36 | ||
37 | /*-------------------------------------------------------------------------*/ | 37 | /*-------------------------------------------------------------------------*/ |
38 | 38 | ||
39 | #if defined(CONFIG_USB_SUSPEND) || defined(CONFIG_PM) | 39 | #ifdef CONFIG_PM |
40 | 40 | ||
41 | #define OHCI_SCHED_ENABLES \ | 41 | #define OHCI_SCHED_ENABLES \ |
42 | (OHCI_CTRL_CLE|OHCI_CTRL_BLE|OHCI_CTRL_PLE|OHCI_CTRL_IE) | 42 | (OHCI_CTRL_CLE|OHCI_CTRL_BLE|OHCI_CTRL_PLE|OHCI_CTRL_IE) |
@@ -45,7 +45,7 @@ static void dl_done_list (struct ohci_hcd *, struct pt_regs *); | |||
45 | static void finish_unlinks (struct ohci_hcd *, u16 , struct pt_regs *); | 45 | static void finish_unlinks (struct ohci_hcd *, u16 , struct pt_regs *); |
46 | static int ohci_restart (struct ohci_hcd *ohci); | 46 | static int ohci_restart (struct ohci_hcd *ohci); |
47 | 47 | ||
48 | static int ohci_hub_suspend (struct usb_hcd *hcd) | 48 | static int ohci_bus_suspend (struct usb_hcd *hcd) |
49 | { | 49 | { |
50 | struct ohci_hcd *ohci = hcd_to_ohci (hcd); | 50 | struct ohci_hcd *ohci = hcd_to_ohci (hcd); |
51 | int status = 0; | 51 | int status = 0; |
@@ -53,6 +53,11 @@ static int ohci_hub_suspend (struct usb_hcd *hcd) | |||
53 | 53 | ||
54 | spin_lock_irqsave (&ohci->lock, flags); | 54 | spin_lock_irqsave (&ohci->lock, flags); |
55 | 55 | ||
56 | if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))) { | ||
57 | spin_unlock_irqrestore (&ohci->lock, flags); | ||
58 | return -ESHUTDOWN; | ||
59 | } | ||
60 | |||
56 | ohci->hc_control = ohci_readl (ohci, &ohci->regs->control); | 61 | ohci->hc_control = ohci_readl (ohci, &ohci->regs->control); |
57 | switch (ohci->hc_control & OHCI_CTRL_HCFS) { | 62 | switch (ohci->hc_control & OHCI_CTRL_HCFS) { |
58 | case OHCI_USB_RESUME: | 63 | case OHCI_USB_RESUME: |
@@ -73,7 +78,6 @@ static int ohci_hub_suspend (struct usb_hcd *hcd) | |||
73 | ohci_dbg (ohci, "suspend root hub\n"); | 78 | ohci_dbg (ohci, "suspend root hub\n"); |
74 | 79 | ||
75 | /* First stop any processing */ | 80 | /* First stop any processing */ |
76 | hcd->state = HC_STATE_QUIESCING; | ||
77 | if (ohci->hc_control & OHCI_SCHED_ENABLES) { | 81 | if (ohci->hc_control & OHCI_SCHED_ENABLES) { |
78 | int limit; | 82 | int limit; |
79 | 83 | ||
@@ -108,7 +112,9 @@ static int ohci_hub_suspend (struct usb_hcd *hcd) | |||
108 | else | 112 | else |
109 | ohci->hc_control &= ~OHCI_CTRL_RWE; | 113 | ohci->hc_control &= ~OHCI_CTRL_RWE; |
110 | 114 | ||
111 | /* Suspend hub */ | 115 | /* Suspend hub ... this is the "global (to this bus) suspend" mode, |
116 | * which doesn't imply ports will first be individually suspended. | ||
117 | */ | ||
112 | ohci->hc_control &= ~OHCI_CTRL_HCFS; | 118 | ohci->hc_control &= ~OHCI_CTRL_HCFS; |
113 | ohci->hc_control |= OHCI_USB_SUSPEND; | 119 | ohci->hc_control |= OHCI_USB_SUSPEND; |
114 | ohci_writel (ohci, ohci->hc_control, &ohci->regs->control); | 120 | ohci_writel (ohci, ohci->hc_control, &ohci->regs->control); |
@@ -118,8 +124,9 @@ static int ohci_hub_suspend (struct usb_hcd *hcd) | |||
118 | ohci->next_statechange = jiffies + msecs_to_jiffies (5); | 124 | ohci->next_statechange = jiffies + msecs_to_jiffies (5); |
119 | 125 | ||
120 | done: | 126 | done: |
127 | /* external suspend vs self autosuspend ... same effect */ | ||
121 | if (status == 0) | 128 | if (status == 0) |
122 | hcd->state = HC_STATE_SUSPENDED; | 129 | usb_hcd_suspend_root_hub(hcd); |
123 | spin_unlock_irqrestore (&ohci->lock, flags); | 130 | spin_unlock_irqrestore (&ohci->lock, flags); |
124 | return status; | 131 | return status; |
125 | } | 132 | } |
@@ -133,20 +140,28 @@ static inline struct ed *find_head (struct ed *ed) | |||
133 | } | 140 | } |
134 | 141 | ||
135 | /* caller has locked the root hub */ | 142 | /* caller has locked the root hub */ |
136 | static int ohci_hub_resume (struct usb_hcd *hcd) | 143 | static int ohci_bus_resume (struct usb_hcd *hcd) |
137 | { | 144 | { |
138 | struct ohci_hcd *ohci = hcd_to_ohci (hcd); | 145 | struct ohci_hcd *ohci = hcd_to_ohci (hcd); |
139 | u32 temp, enables; | 146 | u32 temp, enables; |
140 | int status = -EINPROGRESS; | 147 | int status = -EINPROGRESS; |
148 | unsigned long flags; | ||
141 | 149 | ||
142 | if (time_before (jiffies, ohci->next_statechange)) | 150 | if (time_before (jiffies, ohci->next_statechange)) |
143 | msleep(5); | 151 | msleep(5); |
144 | 152 | ||
145 | spin_lock_irq (&ohci->lock); | 153 | spin_lock_irqsave (&ohci->lock, flags); |
154 | |||
155 | if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))) { | ||
156 | spin_unlock_irqrestore (&ohci->lock, flags); | ||
157 | return -ESHUTDOWN; | ||
158 | } | ||
159 | |||
160 | |||
146 | ohci->hc_control = ohci_readl (ohci, &ohci->regs->control); | 161 | ohci->hc_control = ohci_readl (ohci, &ohci->regs->control); |
147 | 162 | ||
148 | if (ohci->hc_control & (OHCI_CTRL_IR | OHCI_SCHED_ENABLES)) { | 163 | if (ohci->hc_control & (OHCI_CTRL_IR | OHCI_SCHED_ENABLES)) { |
149 | /* this can happen after suspend-to-disk */ | 164 | /* this can happen after resuming a swsusp snapshot */ |
150 | if (hcd->state == HC_STATE_RESUMING) { | 165 | if (hcd->state == HC_STATE_RESUMING) { |
151 | ohci_dbg (ohci, "BIOS/SMM active, control %03x\n", | 166 | ohci_dbg (ohci, "BIOS/SMM active, control %03x\n", |
152 | ohci->hc_control); | 167 | ohci->hc_control); |
@@ -169,14 +184,15 @@ static int ohci_hub_resume (struct usb_hcd *hcd) | |||
169 | ohci_info (ohci, "wakeup\n"); | 184 | ohci_info (ohci, "wakeup\n"); |
170 | break; | 185 | break; |
171 | case OHCI_USB_OPER: | 186 | case OHCI_USB_OPER: |
172 | ohci_dbg (ohci, "already resumed\n"); | 187 | /* this can happen after resuming a swsusp snapshot */ |
173 | status = 0; | 188 | ohci_dbg (ohci, "snapshot resume? reinit\n"); |
189 | status = -EBUSY; | ||
174 | break; | 190 | break; |
175 | default: /* RESET, we lost power */ | 191 | default: /* RESET, we lost power */ |
176 | ohci_dbg (ohci, "root hub hardware reset\n"); | 192 | ohci_dbg (ohci, "lost power\n"); |
177 | status = -EBUSY; | 193 | status = -EBUSY; |
178 | } | 194 | } |
179 | spin_unlock_irq (&ohci->lock); | 195 | spin_unlock_irqrestore (&ohci->lock, flags); |
180 | if (status == -EBUSY) { | 196 | if (status == -EBUSY) { |
181 | (void) ohci_init (ohci); | 197 | (void) ohci_init (ohci); |
182 | return ohci_restart (ohci); | 198 | return ohci_restart (ohci); |
@@ -198,8 +214,7 @@ static int ohci_hub_resume (struct usb_hcd *hcd) | |||
198 | } | 214 | } |
199 | 215 | ||
200 | /* Some controllers (lucent erratum) need extra-long delays */ | 216 | /* Some controllers (lucent erratum) need extra-long delays */ |
201 | hcd->state = HC_STATE_RESUMING; | 217 | msleep (20 /* usb 11.5.1.10 */ + 12 /* 32 msec counter */ + 1); |
202 | mdelay (20 /* usb 11.5.1.10 */ + 15); | ||
203 | 218 | ||
204 | temp = ohci_readl (ohci, &ohci->regs->control); | 219 | temp = ohci_readl (ohci, &ohci->regs->control); |
205 | temp &= OHCI_CTRL_HCFS; | 220 | temp &= OHCI_CTRL_HCFS; |
@@ -273,28 +288,10 @@ static int ohci_hub_resume (struct usb_hcd *hcd) | |||
273 | (void) ohci_readl (ohci, &ohci->regs->control); | 288 | (void) ohci_readl (ohci, &ohci->regs->control); |
274 | } | 289 | } |
275 | 290 | ||
276 | hcd->state = HC_STATE_RUNNING; | ||
277 | return 0; | 291 | return 0; |
278 | } | 292 | } |
279 | 293 | ||
280 | static void ohci_rh_resume (void *_hcd) | 294 | #endif /* CONFIG_PM */ |
281 | { | ||
282 | struct usb_hcd *hcd = _hcd; | ||
283 | |||
284 | usb_lock_device (hcd->self.root_hub); | ||
285 | (void) ohci_hub_resume (hcd); | ||
286 | usb_unlock_device (hcd->self.root_hub); | ||
287 | } | ||
288 | |||
289 | #else | ||
290 | |||
291 | static void ohci_rh_resume (void *_hcd) | ||
292 | { | ||
293 | struct ohci_hcd *ohci = hcd_to_ohci (_hcd); | ||
294 | ohci_dbg(ohci, "rh_resume ??\n"); | ||
295 | } | ||
296 | |||
297 | #endif /* CONFIG_USB_SUSPEND || CONFIG_PM */ | ||
298 | 295 | ||
299 | /*-------------------------------------------------------------------------*/ | 296 | /*-------------------------------------------------------------------------*/ |
300 | 297 | ||
@@ -313,8 +310,8 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf) | |||
313 | /* handle autosuspended root: finish resuming before | 310 | /* handle autosuspended root: finish resuming before |
314 | * letting khubd or root hub timer see state changes. | 311 | * letting khubd or root hub timer see state changes. |
315 | */ | 312 | */ |
316 | if ((ohci->hc_control & OHCI_CTRL_HCFS) != OHCI_USB_OPER | 313 | if (unlikely((ohci->hc_control & OHCI_CTRL_HCFS) != OHCI_USB_OPER |
317 | || !HC_IS_RUNNING(hcd->state)) { | 314 | || !HC_IS_RUNNING(hcd->state))) { |
318 | can_suspend = 0; | 315 | can_suspend = 0; |
319 | goto done; | 316 | goto done; |
320 | } | 317 | } |
@@ -367,7 +364,6 @@ done: | |||
367 | #ifdef CONFIG_PM | 364 | #ifdef CONFIG_PM |
368 | /* save power by suspending idle root hubs; | 365 | /* save power by suspending idle root hubs; |
369 | * INTR_RD wakes us when there's work | 366 | * INTR_RD wakes us when there's work |
370 | * NOTE: if we can do this, we don't need a root hub timer! | ||
371 | */ | 367 | */ |
372 | if (can_suspend | 368 | if (can_suspend |
373 | && !changed | 369 | && !changed |
@@ -379,8 +375,7 @@ done: | |||
379 | && usb_trylock_device (hcd->self.root_hub) | 375 | && usb_trylock_device (hcd->self.root_hub) |
380 | ) { | 376 | ) { |
381 | ohci_vdbg (ohci, "autosuspend\n"); | 377 | ohci_vdbg (ohci, "autosuspend\n"); |
382 | (void) ohci_hub_suspend (hcd); | 378 | (void) ohci_bus_suspend (hcd); |
383 | hcd->state = HC_STATE_RUNNING; | ||
384 | usb_unlock_device (hcd->self.root_hub); | 379 | usb_unlock_device (hcd->self.root_hub); |
385 | } | 380 | } |
386 | #endif | 381 | #endif |
@@ -526,6 +521,9 @@ static int ohci_hub_control ( | |||
526 | u32 temp; | 521 | u32 temp; |
527 | int retval = 0; | 522 | int retval = 0; |
528 | 523 | ||
524 | if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))) | ||
525 | return -ESHUTDOWN; | ||
526 | |||
529 | switch (typeReq) { | 527 | switch (typeReq) { |
530 | case ClearHubFeature: | 528 | case ClearHubFeature: |
531 | switch (wValue) { | 529 | switch (wValue) { |
@@ -554,7 +552,7 @@ static int ohci_hub_control ( | |||
554 | temp = RH_PS_POCI; | 552 | temp = RH_PS_POCI; |
555 | if ((ohci->hc_control & OHCI_CTRL_HCFS) | 553 | if ((ohci->hc_control & OHCI_CTRL_HCFS) |
556 | != OHCI_USB_OPER) | 554 | != OHCI_USB_OPER) |
557 | schedule_work (&ohci->rh_resume); | 555 | usb_hcd_resume_root_hub(hcd); |
558 | break; | 556 | break; |
559 | case USB_PORT_FEAT_C_SUSPEND: | 557 | case USB_PORT_FEAT_C_SUSPEND: |
560 | temp = RH_PS_PSSC; | 558 | temp = RH_PS_PSSC; |