diff options
author | David Vrabel <david.vrabel@csr.com> | 2008-10-27 11:42:31 -0400 |
---|---|---|
committer | David Vrabel <david.vrabel@csr.com> | 2008-10-28 08:08:46 -0400 |
commit | 4d2bea4ca0adb4cebfbf89d34869c74081c42577 (patch) | |
tree | 3ed316eca5ab3228e2e01fc4a83c04297becd105 /drivers/usb/host/hwa-hc.c | |
parent | d409f3bf47c5e5ae10601d079204e263bc176bcf (diff) |
wusb: do a proper channel stop
When stopping the WUSB channel the host should send Channel Stop IEs giving
the WUSB Channel Time of the last MMC. Both WHCI and HWA hosts provide a
channel stop command for this.
Signed-off-by: David Vrabel <david.vrabel@csr.com>
Diffstat (limited to 'drivers/usb/host/hwa-hc.c')
-rw-r--r-- | drivers/usb/host/hwa-hc.c | 102 |
1 files changed, 48 insertions, 54 deletions
diff --git a/drivers/usb/host/hwa-hc.c b/drivers/usb/host/hwa-hc.c index 64be4d88df11..0e18989e1658 100644 --- a/drivers/usb/host/hwa-hc.c +++ b/drivers/usb/host/hwa-hc.c | |||
@@ -171,11 +171,6 @@ static int hwahc_op_start(struct usb_hcd *usb_hcd) | |||
171 | if (result < 0) | 171 | if (result < 0) |
172 | goto error_set_cluster_id; | 172 | goto error_set_cluster_id; |
173 | 173 | ||
174 | result = wa_nep_arm(&hwahc->wa, GFP_KERNEL); | ||
175 | if (result < 0) { | ||
176 | dev_err(dev, "cannot listen to notifications: %d\n", result); | ||
177 | goto error_stop; | ||
178 | } | ||
179 | usb_hcd->uses_new_polling = 1; | 174 | usb_hcd->uses_new_polling = 1; |
180 | usb_hcd->poll_rh = 1; | 175 | usb_hcd->poll_rh = 1; |
181 | usb_hcd->state = HC_STATE_RUNNING; | 176 | usb_hcd->state = HC_STATE_RUNNING; |
@@ -185,8 +180,6 @@ out: | |||
185 | d_fnend(4, dev, "(hwahc %p) = %d\n", hwahc, result); | 180 | d_fnend(4, dev, "(hwahc %p) = %d\n", hwahc, result); |
186 | return result; | 181 | return result; |
187 | 182 | ||
188 | error_stop: | ||
189 | __wa_stop(&hwahc->wa); | ||
190 | error_set_cluster_id: | 183 | error_set_cluster_id: |
191 | wusb_cluster_id_put(wusbhc->cluster_id); | 184 | wusb_cluster_id_put(wusbhc->cluster_id); |
192 | error_cluster_id_get: | 185 | error_cluster_id_get: |
@@ -194,39 +187,6 @@ error_cluster_id_get: | |||
194 | 187 | ||
195 | } | 188 | } |
196 | 189 | ||
197 | /* | ||
198 | * FIXME: break this function up | ||
199 | */ | ||
200 | static int __hwahc_op_wusbhc_start(struct wusbhc *wusbhc) | ||
201 | { | ||
202 | int result; | ||
203 | struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc); | ||
204 | struct device *dev = &hwahc->wa.usb_iface->dev; | ||
205 | |||
206 | /* Set up a Host Info WUSB Information Element */ | ||
207 | d_fnstart(4, dev, "(hwahc %p)\n", hwahc); | ||
208 | result = -ENOSPC; | ||
209 | |||
210 | result = __wa_set_feature(&hwahc->wa, WA_ENABLE); | ||
211 | if (result < 0) { | ||
212 | dev_err(dev, "error commanding HC to start: %d\n", result); | ||
213 | goto error_stop; | ||
214 | } | ||
215 | result = __wa_wait_status(&hwahc->wa, WA_ENABLE, WA_ENABLE); | ||
216 | if (result < 0) { | ||
217 | dev_err(dev, "error waiting for HC to start: %d\n", result); | ||
218 | goto error_stop; | ||
219 | } | ||
220 | result = 0; | ||
221 | out: | ||
222 | d_fnend(4, dev, "(hwahc %p) = %d\n", hwahc, result); | ||
223 | return result; | ||
224 | |||
225 | error_stop: | ||
226 | result = __wa_clear_feature(&hwahc->wa, WA_ENABLE); | ||
227 | goto out; | ||
228 | } | ||
229 | |||
230 | static int hwahc_op_suspend(struct usb_hcd *usb_hcd, pm_message_t msg) | 190 | static int hwahc_op_suspend(struct usb_hcd *usb_hcd, pm_message_t msg) |
231 | { | 191 | { |
232 | struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd); | 192 | struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd); |
@@ -246,18 +206,6 @@ static int hwahc_op_resume(struct usb_hcd *usb_hcd) | |||
246 | return -ENOSYS; | 206 | return -ENOSYS; |
247 | } | 207 | } |
248 | 208 | ||
249 | static void __hwahc_op_wusbhc_stop(struct wusbhc *wusbhc) | ||
250 | { | ||
251 | int result; | ||
252 | struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc); | ||
253 | struct device *dev = &hwahc->wa.usb_iface->dev; | ||
254 | |||
255 | d_fnstart(4, dev, "(hwahc %p)\n", hwahc); | ||
256 | /* Nothing for now */ | ||
257 | d_fnend(4, dev, "(hwahc %p) = %d\n", hwahc, result); | ||
258 | return; | ||
259 | } | ||
260 | |||
261 | /* | 209 | /* |
262 | * No need to abort pipes, as when this is called, all the children | 210 | * No need to abort pipes, as when this is called, all the children |
263 | * has been disconnected and that has done it [through | 211 | * has been disconnected and that has done it [through |
@@ -275,8 +223,6 @@ static void hwahc_op_stop(struct usb_hcd *usb_hcd) | |||
275 | d_fnstart(4, dev, "(hwahc %p)\n", hwahc); | 223 | d_fnstart(4, dev, "(hwahc %p)\n", hwahc); |
276 | mutex_lock(&wusbhc->mutex); | 224 | mutex_lock(&wusbhc->mutex); |
277 | wusbhc_stop(wusbhc); | 225 | wusbhc_stop(wusbhc); |
278 | wa_nep_disarm(&hwahc->wa); | ||
279 | result = __wa_stop(&hwahc->wa); | ||
280 | wusb_cluster_id_put(wusbhc->cluster_id); | 226 | wusb_cluster_id_put(wusbhc->cluster_id); |
281 | mutex_unlock(&wusbhc->mutex); | 227 | mutex_unlock(&wusbhc->mutex); |
282 | d_fnend(4, dev, "(hwahc %p) = %d\n", hwahc, result); | 228 | d_fnend(4, dev, "(hwahc %p) = %d\n", hwahc, result); |
@@ -325,6 +271,54 @@ static void hwahc_op_endpoint_disable(struct usb_hcd *usb_hcd, | |||
325 | rpipe_ep_disable(&hwahc->wa, ep); | 271 | rpipe_ep_disable(&hwahc->wa, ep); |
326 | } | 272 | } |
327 | 273 | ||
274 | static int __hwahc_op_wusbhc_start(struct wusbhc *wusbhc) | ||
275 | { | ||
276 | int result; | ||
277 | struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc); | ||
278 | struct device *dev = &hwahc->wa.usb_iface->dev; | ||
279 | |||
280 | result = __wa_set_feature(&hwahc->wa, WA_ENABLE); | ||
281 | if (result < 0) { | ||
282 | dev_err(dev, "error commanding HC to start: %d\n", result); | ||
283 | goto error_stop; | ||
284 | } | ||
285 | result = __wa_wait_status(&hwahc->wa, WA_ENABLE, WA_ENABLE); | ||
286 | if (result < 0) { | ||
287 | dev_err(dev, "error waiting for HC to start: %d\n", result); | ||
288 | goto error_stop; | ||
289 | } | ||
290 | result = wa_nep_arm(&hwahc->wa, GFP_KERNEL); | ||
291 | if (result < 0) { | ||
292 | dev_err(dev, "cannot listen to notifications: %d\n", result); | ||
293 | goto error_stop; | ||
294 | } | ||
295 | return result; | ||
296 | |||
297 | error_stop: | ||
298 | __wa_clear_feature(&hwahc->wa, WA_ENABLE); | ||
299 | return result; | ||
300 | } | ||
301 | |||
302 | static void __hwahc_op_wusbhc_stop(struct wusbhc *wusbhc, int delay) | ||
303 | { | ||
304 | struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc); | ||
305 | struct wahc *wa = &hwahc->wa; | ||
306 | u8 iface_no = wa->usb_iface->cur_altsetting->desc.bInterfaceNumber; | ||
307 | int ret; | ||
308 | |||
309 | ret = usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0), | ||
310 | WUSB_REQ_CHAN_STOP, | ||
311 | USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, | ||
312 | delay * 1000, | ||
313 | iface_no, | ||
314 | NULL, 0, 1000 /* FIXME: arbitrary */); | ||
315 | if (ret == 0) | ||
316 | msleep(delay); | ||
317 | |||
318 | wa_nep_disarm(&hwahc->wa); | ||
319 | __wa_stop(&hwahc->wa); | ||
320 | } | ||
321 | |||
328 | /* | 322 | /* |
329 | * Set the UWB MAS allocation for the WUSB cluster | 323 | * Set the UWB MAS allocation for the WUSB cluster |
330 | * | 324 | * |