diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-11-01 18:08:04 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-11-01 18:08:04 -0400 |
commit | 528a506e4bcd77dfce5d405e73a95e340bb6e8fd (patch) | |
tree | 2ed701d69aea839b461ca8a9107a7b59692d3452 /drivers/usb/gadget/function/f_loopback.c | |
parent | 4f4274af7009890f0d4724909bf9038193955489 (diff) | |
parent | 9c19db5b11487da704d29dee48345c4841831bac (diff) |
Merge tag 'usb-3.18-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb
Pull USB fixes from Greg KH:
"Here are a bunch of USB fixes for 3.18-rc3.
Mostly usb-serial device ids and gadget fixes for issues that have
been reported. Full details are in the shortlog.
All of these have been in linux-next for a while"
* tag 'usb-3.18-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (42 commits)
usb: chipidea: Fix oops when removing the ci_hdrc module
usb: gadget: function: Fixed the return value on error path
usb: dwc2: gadget: disable phy before turning off power regulators
usb: gadget: function: Remove redundant usb_free_all_descriptors
usb: dwc3: gadget: Properly initialize LINK TRB
usb: dwc2: gadget: fix gadget unregistration in udc_stop() function
usb: dwc2: Bits in bitfield should add up to 32
usb: dwc2: gadget: sparse warning of context imbalance
usb: gadget: udc: core: fix kernel oops with soft-connect
usb: musb: musb_dsps: fix NULL pointer in suspend
usb: musb: dsps: start OTG timer on resume again
usb: gadget: loopback: don't queue requests to bogus endpoints
usb: ffs: fix regression when quirk_ep_out_aligned_size flag is set
usb: gadget: f_fs: remove redundant ffs_data_get()
usb: gadget: udc: USB_GADGET_XILINX should depend on HAS_DMA
Revert "usb: dwc3: dwc3-omap: Disable/Enable only wrapper interrupts in prepare/complete"
usb: gadget: composite: enable BESL support
usb: musb: cppi41: restart hrtimer only if not yet done
usb: dwc3: ep0: fix Data Phase for transfer sizes aligned to wMaxPacketSize
usb: serial: ftdi_sio: add "bricked" FTDI device PID
...
Diffstat (limited to 'drivers/usb/gadget/function/f_loopback.c')
-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 | } |