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 | |
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')
-rw-r--r-- | drivers/usb/host/hwa-hc.c | 102 | ||||
-rw-r--r-- | drivers/usb/host/whci/whcd.h | 2 | ||||
-rw-r--r-- | drivers/usb/host/whci/whci-hc.h | 2 | ||||
-rw-r--r-- | drivers/usb/host/whci/wusb.c | 15 |
4 files changed, 63 insertions, 58 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 | * |
diff --git a/drivers/usb/host/whci/whcd.h b/drivers/usb/host/whci/whcd.h index 1d2a53bd39fd..1bbb8cb6bf80 100644 --- a/drivers/usb/host/whci/whcd.h +++ b/drivers/usb/host/whci/whcd.h | |||
@@ -136,7 +136,7 @@ int whc_do_gencmd(struct whc *whc, u32 cmd, u32 params, void *addr, size_t len); | |||
136 | 136 | ||
137 | /* wusb.c */ | 137 | /* wusb.c */ |
138 | int whc_wusbhc_start(struct wusbhc *wusbhc); | 138 | int whc_wusbhc_start(struct wusbhc *wusbhc); |
139 | void whc_wusbhc_stop(struct wusbhc *wusbhc); | 139 | void whc_wusbhc_stop(struct wusbhc *wusbhc, int delay); |
140 | int whc_mmcie_add(struct wusbhc *wusbhc, u8 interval, u8 repeat_cnt, | 140 | int whc_mmcie_add(struct wusbhc *wusbhc, u8 interval, u8 repeat_cnt, |
141 | u8 handle, struct wuie_hdr *wuie); | 141 | u8 handle, struct wuie_hdr *wuie); |
142 | int whc_mmcie_rm(struct wusbhc *wusbhc, u8 handle); | 142 | int whc_mmcie_rm(struct wusbhc *wusbhc, u8 handle); |
diff --git a/drivers/usb/host/whci/whci-hc.h b/drivers/usb/host/whci/whci-hc.h index bff1eb7a35cf..51df7e313b38 100644 --- a/drivers/usb/host/whci/whci-hc.h +++ b/drivers/usb/host/whci/whci-hc.h | |||
@@ -410,6 +410,8 @@ struct dn_buf_entry { | |||
410 | # define WUSBDNTSCTRL_SLOTS(s) ((s) << 0) | 410 | # define WUSBDNTSCTRL_SLOTS(s) ((s) << 0) |
411 | 411 | ||
412 | #define WUSBTIME 0x68 | 412 | #define WUSBTIME 0x68 |
413 | # define WUSBTIME_CHANNEL_TIME_MASK 0x00ffffff | ||
414 | |||
413 | #define WUSBBPST 0x6c | 415 | #define WUSBBPST 0x6c |
414 | #define WUSBDIBUPDATED 0x70 | 416 | #define WUSBDIBUPDATED 0x70 |
415 | 417 | ||
diff --git a/drivers/usb/host/whci/wusb.c b/drivers/usb/host/whci/wusb.c index 66e4ddcd961d..2befd475def4 100644 --- a/drivers/usb/host/whci/wusb.c +++ b/drivers/usb/host/whci/wusb.c | |||
@@ -64,8 +64,9 @@ static int whc_update_di(struct whc *whc, int idx) | |||
64 | } | 64 | } |
65 | 65 | ||
66 | /* | 66 | /* |
67 | * WHCI starts and stops MMCs based on there being a valid GTK so | 67 | * WHCI starts MMCs based on there being a valid GTK so these need |
68 | * these need only start/stop the asynchronous and periodic schedules. | 68 | * only start/stop the asynchronous and periodic schedules and send a |
69 | * channel stop command. | ||
69 | */ | 70 | */ |
70 | 71 | ||
71 | int whc_wusbhc_start(struct wusbhc *wusbhc) | 72 | int whc_wusbhc_start(struct wusbhc *wusbhc) |
@@ -78,12 +79,20 @@ int whc_wusbhc_start(struct wusbhc *wusbhc) | |||
78 | return 0; | 79 | return 0; |
79 | } | 80 | } |
80 | 81 | ||
81 | void whc_wusbhc_stop(struct wusbhc *wusbhc) | 82 | void whc_wusbhc_stop(struct wusbhc *wusbhc, int delay) |
82 | { | 83 | { |
83 | struct whc *whc = wusbhc_to_whc(wusbhc); | 84 | struct whc *whc = wusbhc_to_whc(wusbhc); |
85 | u32 stop_time, now_time; | ||
86 | int ret; | ||
84 | 87 | ||
85 | pzl_stop(whc); | 88 | pzl_stop(whc); |
86 | asl_stop(whc); | 89 | asl_stop(whc); |
90 | |||
91 | now_time = le_readl(whc->base + WUSBTIME) & WUSBTIME_CHANNEL_TIME_MASK; | ||
92 | stop_time = (now_time + ((delay * 8) << 7)) & 0x00ffffff; | ||
93 | ret = whc_do_gencmd(whc, WUSBGENCMDSTS_CHAN_STOP, stop_time, NULL, 0); | ||
94 | if (ret == 0) | ||
95 | msleep(delay); | ||
87 | } | 96 | } |
88 | 97 | ||
89 | int whc_mmcie_add(struct wusbhc *wusbhc, u8 interval, u8 repeat_cnt, | 98 | int whc_mmcie_add(struct wusbhc *wusbhc, u8 interval, u8 repeat_cnt, |