diff options
author | Felipe Balbi <balbi@ti.com> | 2014-10-13 16:30:52 -0400 |
---|---|---|
committer | Felipe Balbi <balbi@ti.com> | 2014-10-23 10:55:42 -0400 |
commit | e0857ce58e8658657f5f12fe25272b93cfeb16aa (patch) | |
tree | bfc7fd6444aecd682879f427c7474e7527078a5f /drivers/usb/gadget/function | |
parent | c0d31b3c3d9a025b8d5a57c35671e60c5f388bf7 (diff) |
usb: gadget: loopback: don't queue requests to bogus endpoints
A request allocated from e.g. ep1out cannot
be queued to any other endpoint. This bug has
been in f_loopback at least since mid-2011 and
since nobody has really screamed about it, we're
not backporting to any stable kernels.
Debugged with MUSB since that's the only controller
which complains about this case.
Signed-off-by: Felipe Balbi <balbi@ti.com>
Diffstat (limited to 'drivers/usb/gadget/function')
-rw-r--r-- | drivers/usb/gadget/function/f_loopback.c | 87 |
1 files changed, 42 insertions, 45 deletions
diff --git a/drivers/usb/gadget/function/f_loopback.c b/drivers/usb/gadget/function/f_loopback.c index bf04389137e6..298b46112b1a 100644 --- a/drivers/usb/gadget/function/f_loopback.c +++ b/drivers/usb/gadget/function/f_loopback.c | |||
@@ -253,22 +253,13 @@ static void loopback_complete(struct usb_ep *ep, struct usb_request *req) | |||
253 | 253 | ||
254 | case 0: /* normal completion? */ | 254 | case 0: /* normal completion? */ |
255 | if (ep == loop->out_ep) { | 255 | if (ep == loop->out_ep) { |
256 | /* loop this OUT packet back IN to the host */ | ||
257 | req->zero = (req->actual < req->length); | 256 | req->zero = (req->actual < req->length); |
258 | req->length = req->actual; | 257 | req->length = req->actual; |
259 | status = usb_ep_queue(loop->in_ep, req, GFP_ATOMIC); | ||
260 | if (status == 0) | ||
261 | return; | ||
262 | |||
263 | /* "should never get here" */ | ||
264 | ERROR(cdev, "can't loop %s to %s: %d\n", | ||
265 | ep->name, loop->in_ep->name, | ||
266 | status); | ||
267 | } | 258 | } |
268 | 259 | ||
269 | /* queue the buffer for some later OUT packet */ | 260 | /* queue the buffer for some later OUT packet */ |
270 | req->length = buflen; | 261 | req->length = buflen; |
271 | status = usb_ep_queue(loop->out_ep, req, GFP_ATOMIC); | 262 | status = usb_ep_queue(ep, req, GFP_ATOMIC); |
272 | if (status == 0) | 263 | if (status == 0) |
273 | return; | 264 | return; |
274 | 265 | ||
@@ -308,60 +299,66 @@ static inline struct usb_request *lb_alloc_ep_req(struct usb_ep *ep, int len) | |||
308 | return alloc_ep_req(ep, len, buflen); | 299 | return alloc_ep_req(ep, len, buflen); |
309 | } | 300 | } |
310 | 301 | ||
311 | static int | 302 | static int enable_endpoint(struct usb_composite_dev *cdev, struct f_loopback *loop, |
312 | enable_loopback(struct usb_composite_dev *cdev, struct f_loopback *loop) | 303 | struct usb_ep *ep) |
313 | { | 304 | { |
314 | int result = 0; | ||
315 | struct usb_ep *ep; | ||
316 | struct usb_request *req; | 305 | struct usb_request *req; |
317 | unsigned i; | 306 | unsigned i; |
307 | int result; | ||
318 | 308 | ||
319 | /* one endpoint writes data back IN to the host */ | 309 | /* |
320 | ep = loop->in_ep; | 310 | * one endpoint writes data back IN to the host while another endpoint |
311 | * just reads OUT packets | ||
312 | */ | ||
321 | result = config_ep_by_speed(cdev->gadget, &(loop->function), ep); | 313 | result = config_ep_by_speed(cdev->gadget, &(loop->function), ep); |
322 | if (result) | 314 | if (result) |
323 | return result; | 315 | goto fail0; |
324 | result = usb_ep_enable(ep); | 316 | result = usb_ep_enable(ep); |
325 | if (result < 0) | 317 | if (result < 0) |
326 | return result; | ||
327 | ep->driver_data = loop; | ||
328 | |||
329 | /* one endpoint just reads OUT packets */ | ||
330 | ep = loop->out_ep; | ||
331 | result = config_ep_by_speed(cdev->gadget, &(loop->function), ep); | ||
332 | if (result) | ||
333 | goto fail0; | 318 | goto fail0; |
334 | |||
335 | result = usb_ep_enable(ep); | ||
336 | if (result < 0) { | ||
337 | fail0: | ||
338 | ep = loop->in_ep; | ||
339 | usb_ep_disable(ep); | ||
340 | ep->driver_data = NULL; | ||
341 | return result; | ||
342 | } | ||
343 | ep->driver_data = loop; | 319 | ep->driver_data = loop; |
344 | 320 | ||
345 | /* allocate a bunch of read buffers and queue them all at once. | 321 | /* |
322 | * allocate a bunch of read buffers and queue them all at once. | ||
346 | * we buffer at most 'qlen' transfers; fewer if any need more | 323 | * we buffer at most 'qlen' transfers; fewer if any need more |
347 | * than 'buflen' bytes each. | 324 | * than 'buflen' bytes each. |
348 | */ | 325 | */ |
349 | for (i = 0; i < qlen && result == 0; i++) { | 326 | for (i = 0; i < qlen && result == 0; i++) { |
350 | req = lb_alloc_ep_req(ep, 0); | 327 | req = lb_alloc_ep_req(ep, 0); |
351 | if (req) { | 328 | if (!req) |
352 | req->complete = loopback_complete; | 329 | goto fail1; |
353 | result = usb_ep_queue(ep, req, GFP_ATOMIC); | 330 | |
354 | if (result) | 331 | req->complete = loopback_complete; |
355 | ERROR(cdev, "%s queue req --> %d\n", | 332 | result = usb_ep_queue(ep, req, GFP_ATOMIC); |
356 | ep->name, result); | 333 | if (result) { |
357 | } else { | 334 | ERROR(cdev, "%s queue req --> %d\n", |
358 | usb_ep_disable(ep); | 335 | ep->name, result); |
359 | ep->driver_data = NULL; | 336 | goto fail1; |
360 | result = -ENOMEM; | ||
361 | goto fail0; | ||
362 | } | 337 | } |
363 | } | 338 | } |
364 | 339 | ||
340 | return 0; | ||
341 | |||
342 | fail1: | ||
343 | usb_ep_disable(ep); | ||
344 | |||
345 | fail0: | ||
346 | return result; | ||
347 | } | ||
348 | |||
349 | static int | ||
350 | enable_loopback(struct usb_composite_dev *cdev, struct f_loopback *loop) | ||
351 | { | ||
352 | int result = 0; | ||
353 | |||
354 | result = enable_endpoint(cdev, loop, loop->in_ep); | ||
355 | if (result) | ||
356 | return result; | ||
357 | |||
358 | result = enable_endpoint(cdev, loop, loop->out_ep); | ||
359 | if (result) | ||
360 | return result; | ||
361 | |||
365 | DBG(cdev, "%s enabled\n", loop->function.name); | 362 | DBG(cdev, "%s enabled\n", loop->function.name); |
366 | return result; | 363 | return result; |
367 | } | 364 | } |