1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* |
3 | * f_loopback.c - USB peripheral loopback configuration driver |
4 | * |
5 | * Copyright (C) 2003-2008 David Brownell |
6 | * Copyright (C) 2008 by Nokia Corporation |
7 | */ |
8 | |
9 | /* #define VERBOSE_DEBUG */ |
10 | |
11 | #include <linux/slab.h> |
12 | #include <linux/kernel.h> |
13 | #include <linux/device.h> |
14 | #include <linux/module.h> |
15 | #include <linux/err.h> |
16 | #include <linux/usb/composite.h> |
17 | |
18 | #include "g_zero.h" |
19 | #include "u_f.h" |
20 | |
21 | /* |
22 | * LOOPBACK FUNCTION ... a testing vehicle for USB peripherals, |
23 | * |
24 | * This takes messages of various sizes written OUT to a device, and loops |
25 | * them back so they can be read IN from it. It has been used by certain |
26 | * test applications. It supports limited testing of data queueing logic. |
27 | */ |
28 | struct f_loopback { |
29 | struct usb_function function; |
30 | |
31 | struct usb_ep *in_ep; |
32 | struct usb_ep *out_ep; |
33 | |
34 | unsigned qlen; |
35 | unsigned buflen; |
36 | }; |
37 | |
38 | static inline struct f_loopback *func_to_loop(struct usb_function *f) |
39 | { |
40 | return container_of(f, struct f_loopback, function); |
41 | } |
42 | |
43 | /*-------------------------------------------------------------------------*/ |
44 | |
45 | static struct usb_interface_descriptor loopback_intf = { |
46 | .bLength = sizeof(loopback_intf), |
47 | .bDescriptorType = USB_DT_INTERFACE, |
48 | |
49 | .bNumEndpoints = 2, |
50 | .bInterfaceClass = USB_CLASS_VENDOR_SPEC, |
51 | /* .iInterface = DYNAMIC */ |
52 | }; |
53 | |
54 | /* full speed support: */ |
55 | |
56 | static struct usb_endpoint_descriptor fs_loop_source_desc = { |
57 | .bLength = USB_DT_ENDPOINT_SIZE, |
58 | .bDescriptorType = USB_DT_ENDPOINT, |
59 | |
60 | .bEndpointAddress = USB_DIR_IN, |
61 | .bmAttributes = USB_ENDPOINT_XFER_BULK, |
62 | }; |
63 | |
64 | static struct usb_endpoint_descriptor fs_loop_sink_desc = { |
65 | .bLength = USB_DT_ENDPOINT_SIZE, |
66 | .bDescriptorType = USB_DT_ENDPOINT, |
67 | |
68 | .bEndpointAddress = USB_DIR_OUT, |
69 | .bmAttributes = USB_ENDPOINT_XFER_BULK, |
70 | }; |
71 | |
72 | static struct usb_descriptor_header *fs_loopback_descs[] = { |
73 | (struct usb_descriptor_header *) &loopback_intf, |
74 | (struct usb_descriptor_header *) &fs_loop_sink_desc, |
75 | (struct usb_descriptor_header *) &fs_loop_source_desc, |
76 | NULL, |
77 | }; |
78 | |
79 | /* high speed support: */ |
80 | |
81 | static struct usb_endpoint_descriptor hs_loop_source_desc = { |
82 | .bLength = USB_DT_ENDPOINT_SIZE, |
83 | .bDescriptorType = USB_DT_ENDPOINT, |
84 | |
85 | .bmAttributes = USB_ENDPOINT_XFER_BULK, |
86 | .wMaxPacketSize = cpu_to_le16(512), |
87 | }; |
88 | |
89 | static struct usb_endpoint_descriptor hs_loop_sink_desc = { |
90 | .bLength = USB_DT_ENDPOINT_SIZE, |
91 | .bDescriptorType = USB_DT_ENDPOINT, |
92 | |
93 | .bmAttributes = USB_ENDPOINT_XFER_BULK, |
94 | .wMaxPacketSize = cpu_to_le16(512), |
95 | }; |
96 | |
97 | static struct usb_descriptor_header *hs_loopback_descs[] = { |
98 | (struct usb_descriptor_header *) &loopback_intf, |
99 | (struct usb_descriptor_header *) &hs_loop_source_desc, |
100 | (struct usb_descriptor_header *) &hs_loop_sink_desc, |
101 | NULL, |
102 | }; |
103 | |
104 | /* super speed support: */ |
105 | |
106 | static struct usb_endpoint_descriptor ss_loop_source_desc = { |
107 | .bLength = USB_DT_ENDPOINT_SIZE, |
108 | .bDescriptorType = USB_DT_ENDPOINT, |
109 | |
110 | .bmAttributes = USB_ENDPOINT_XFER_BULK, |
111 | .wMaxPacketSize = cpu_to_le16(1024), |
112 | }; |
113 | |
114 | static struct usb_ss_ep_comp_descriptor ss_loop_source_comp_desc = { |
115 | .bLength = USB_DT_SS_EP_COMP_SIZE, |
116 | .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, |
117 | .bMaxBurst = 0, |
118 | .bmAttributes = 0, |
119 | .wBytesPerInterval = 0, |
120 | }; |
121 | |
122 | static struct usb_endpoint_descriptor ss_loop_sink_desc = { |
123 | .bLength = USB_DT_ENDPOINT_SIZE, |
124 | .bDescriptorType = USB_DT_ENDPOINT, |
125 | |
126 | .bmAttributes = USB_ENDPOINT_XFER_BULK, |
127 | .wMaxPacketSize = cpu_to_le16(1024), |
128 | }; |
129 | |
130 | static struct usb_ss_ep_comp_descriptor ss_loop_sink_comp_desc = { |
131 | .bLength = USB_DT_SS_EP_COMP_SIZE, |
132 | .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, |
133 | .bMaxBurst = 0, |
134 | .bmAttributes = 0, |
135 | .wBytesPerInterval = 0, |
136 | }; |
137 | |
138 | static struct usb_descriptor_header *ss_loopback_descs[] = { |
139 | (struct usb_descriptor_header *) &loopback_intf, |
140 | (struct usb_descriptor_header *) &ss_loop_source_desc, |
141 | (struct usb_descriptor_header *) &ss_loop_source_comp_desc, |
142 | (struct usb_descriptor_header *) &ss_loop_sink_desc, |
143 | (struct usb_descriptor_header *) &ss_loop_sink_comp_desc, |
144 | NULL, |
145 | }; |
146 | |
147 | /* function-specific strings: */ |
148 | |
149 | static struct usb_string strings_loopback[] = { |
150 | [0].s = "loop input to output" , |
151 | { } /* end of list */ |
152 | }; |
153 | |
154 | static struct usb_gadget_strings stringtab_loop = { |
155 | .language = 0x0409, /* en-us */ |
156 | .strings = strings_loopback, |
157 | }; |
158 | |
159 | static struct usb_gadget_strings *loopback_strings[] = { |
160 | &stringtab_loop, |
161 | NULL, |
162 | }; |
163 | |
164 | /*-------------------------------------------------------------------------*/ |
165 | |
166 | static int loopback_bind(struct usb_configuration *c, struct usb_function *f) |
167 | { |
168 | struct usb_composite_dev *cdev = c->cdev; |
169 | struct f_loopback *loop = func_to_loop(f); |
170 | int id; |
171 | int ret; |
172 | |
173 | /* allocate interface ID(s) */ |
174 | id = usb_interface_id(c, f); |
175 | if (id < 0) |
176 | return id; |
177 | loopback_intf.bInterfaceNumber = id; |
178 | |
179 | id = usb_string_id(c: cdev); |
180 | if (id < 0) |
181 | return id; |
182 | strings_loopback[0].id = id; |
183 | loopback_intf.iInterface = id; |
184 | |
185 | /* allocate endpoints */ |
186 | |
187 | loop->in_ep = usb_ep_autoconfig(cdev->gadget, &fs_loop_source_desc); |
188 | if (!loop->in_ep) { |
189 | autoconf_fail: |
190 | ERROR(cdev, "%s: can't autoconfigure on %s\n" , |
191 | f->name, cdev->gadget->name); |
192 | return -ENODEV; |
193 | } |
194 | |
195 | loop->out_ep = usb_ep_autoconfig(cdev->gadget, &fs_loop_sink_desc); |
196 | if (!loop->out_ep) |
197 | goto autoconf_fail; |
198 | |
199 | /* support high speed hardware */ |
200 | hs_loop_source_desc.bEndpointAddress = |
201 | fs_loop_source_desc.bEndpointAddress; |
202 | hs_loop_sink_desc.bEndpointAddress = fs_loop_sink_desc.bEndpointAddress; |
203 | |
204 | /* support super speed hardware */ |
205 | ss_loop_source_desc.bEndpointAddress = |
206 | fs_loop_source_desc.bEndpointAddress; |
207 | ss_loop_sink_desc.bEndpointAddress = fs_loop_sink_desc.bEndpointAddress; |
208 | |
209 | ret = usb_assign_descriptors(f, fs: fs_loopback_descs, hs: hs_loopback_descs, |
210 | ss: ss_loopback_descs, ssp: ss_loopback_descs); |
211 | if (ret) |
212 | return ret; |
213 | |
214 | DBG(cdev, "%s: IN/%s, OUT/%s\n" , |
215 | f->name, loop->in_ep->name, loop->out_ep->name); |
216 | return 0; |
217 | } |
218 | |
219 | static void lb_free_func(struct usb_function *f) |
220 | { |
221 | struct f_lb_opts *opts; |
222 | |
223 | opts = container_of(f->fi, struct f_lb_opts, func_inst); |
224 | |
225 | mutex_lock(&opts->lock); |
226 | opts->refcnt--; |
227 | mutex_unlock(lock: &opts->lock); |
228 | |
229 | usb_free_all_descriptors(f); |
230 | kfree(objp: func_to_loop(f)); |
231 | } |
232 | |
233 | static void loopback_complete(struct usb_ep *ep, struct usb_request *req) |
234 | { |
235 | struct f_loopback *loop = ep->driver_data; |
236 | struct usb_composite_dev *cdev = loop->function.config->cdev; |
237 | int status = req->status; |
238 | |
239 | switch (status) { |
240 | case 0: /* normal completion? */ |
241 | if (ep == loop->out_ep) { |
242 | /* |
243 | * We received some data from the host so let's |
244 | * queue it so host can read the from our in ep |
245 | */ |
246 | struct usb_request *in_req = req->context; |
247 | |
248 | in_req->zero = (req->actual < req->length); |
249 | in_req->length = req->actual; |
250 | ep = loop->in_ep; |
251 | req = in_req; |
252 | } else { |
253 | /* |
254 | * We have just looped back a bunch of data |
255 | * to host. Now let's wait for some more data. |
256 | */ |
257 | req = req->context; |
258 | ep = loop->out_ep; |
259 | } |
260 | |
261 | /* queue the buffer back to host or for next bunch of data */ |
262 | status = usb_ep_queue(ep, req, GFP_ATOMIC); |
263 | if (status == 0) { |
264 | return; |
265 | } else { |
266 | ERROR(cdev, "Unable to loop back buffer to %s: %d\n" , |
267 | ep->name, status); |
268 | goto free_req; |
269 | } |
270 | |
271 | /* "should never get here" */ |
272 | default: |
273 | ERROR(cdev, "%s loop complete --> %d, %d/%d\n" , ep->name, |
274 | status, req->actual, req->length); |
275 | fallthrough; |
276 | |
277 | /* NOTE: since this driver doesn't maintain an explicit record |
278 | * of requests it submitted (just maintains qlen count), we |
279 | * rely on the hardware driver to clean up on disconnect or |
280 | * endpoint disable. |
281 | */ |
282 | case -ECONNABORTED: /* hardware forced ep reset */ |
283 | case -ECONNRESET: /* request dequeued */ |
284 | case -ESHUTDOWN: /* disconnect from host */ |
285 | free_req: |
286 | usb_ep_free_request(ep: ep == loop->in_ep ? |
287 | loop->out_ep : loop->in_ep, |
288 | req: req->context); |
289 | free_ep_req(ep, req); |
290 | return; |
291 | } |
292 | } |
293 | |
294 | static void disable_loopback(struct f_loopback *loop) |
295 | { |
296 | struct usb_composite_dev *cdev; |
297 | |
298 | cdev = loop->function.config->cdev; |
299 | disable_endpoints(cdev, in: loop->in_ep, out: loop->out_ep, NULL, NULL); |
300 | VDBG(cdev, "%s disabled\n" , loop->function.name); |
301 | } |
302 | |
303 | static inline struct usb_request *lb_alloc_ep_req(struct usb_ep *ep, int len) |
304 | { |
305 | return alloc_ep_req(ep, len); |
306 | } |
307 | |
308 | static int alloc_requests(struct usb_composite_dev *cdev, |
309 | struct f_loopback *loop) |
310 | { |
311 | struct usb_request *in_req, *out_req; |
312 | int i; |
313 | int result = 0; |
314 | |
315 | /* |
316 | * allocate a bunch of read buffers and queue them all at once. |
317 | * we buffer at most 'qlen' transfers; We allocate buffers only |
318 | * for out transfer and reuse them in IN transfers to implement |
319 | * our loopback functionality |
320 | */ |
321 | for (i = 0; i < loop->qlen && result == 0; i++) { |
322 | result = -ENOMEM; |
323 | |
324 | in_req = usb_ep_alloc_request(ep: loop->in_ep, GFP_ATOMIC); |
325 | if (!in_req) |
326 | goto fail; |
327 | |
328 | out_req = lb_alloc_ep_req(ep: loop->out_ep, len: loop->buflen); |
329 | if (!out_req) |
330 | goto fail_in; |
331 | |
332 | in_req->complete = loopback_complete; |
333 | out_req->complete = loopback_complete; |
334 | |
335 | in_req->buf = out_req->buf; |
336 | /* length will be set in complete routine */ |
337 | in_req->context = out_req; |
338 | out_req->context = in_req; |
339 | |
340 | result = usb_ep_queue(ep: loop->out_ep, req: out_req, GFP_ATOMIC); |
341 | if (result) { |
342 | ERROR(cdev, "%s queue req --> %d\n" , |
343 | loop->out_ep->name, result); |
344 | goto fail_out; |
345 | } |
346 | } |
347 | |
348 | return 0; |
349 | |
350 | fail_out: |
351 | free_ep_req(ep: loop->out_ep, req: out_req); |
352 | fail_in: |
353 | usb_ep_free_request(ep: loop->in_ep, req: in_req); |
354 | fail: |
355 | return result; |
356 | } |
357 | |
358 | static int enable_endpoint(struct usb_composite_dev *cdev, |
359 | struct f_loopback *loop, struct usb_ep *ep) |
360 | { |
361 | int result; |
362 | |
363 | result = config_ep_by_speed(g: cdev->gadget, f: &(loop->function), ep: ep); |
364 | if (result) |
365 | goto out; |
366 | |
367 | result = usb_ep_enable(ep); |
368 | if (result < 0) |
369 | goto out; |
370 | ep->driver_data = loop; |
371 | result = 0; |
372 | |
373 | out: |
374 | return result; |
375 | } |
376 | |
377 | static int |
378 | enable_loopback(struct usb_composite_dev *cdev, struct f_loopback *loop) |
379 | { |
380 | int result = 0; |
381 | |
382 | result = enable_endpoint(cdev, loop, ep: loop->in_ep); |
383 | if (result) |
384 | goto out; |
385 | |
386 | result = enable_endpoint(cdev, loop, ep: loop->out_ep); |
387 | if (result) |
388 | goto disable_in; |
389 | |
390 | result = alloc_requests(cdev, loop); |
391 | if (result) |
392 | goto disable_out; |
393 | |
394 | DBG(cdev, "%s enabled\n" , loop->function.name); |
395 | return 0; |
396 | |
397 | disable_out: |
398 | usb_ep_disable(ep: loop->out_ep); |
399 | disable_in: |
400 | usb_ep_disable(ep: loop->in_ep); |
401 | out: |
402 | return result; |
403 | } |
404 | |
405 | static int loopback_set_alt(struct usb_function *f, |
406 | unsigned intf, unsigned alt) |
407 | { |
408 | struct f_loopback *loop = func_to_loop(f); |
409 | struct usb_composite_dev *cdev = f->config->cdev; |
410 | |
411 | /* we know alt is zero */ |
412 | disable_loopback(loop); |
413 | return enable_loopback(cdev, loop); |
414 | } |
415 | |
416 | static void loopback_disable(struct usb_function *f) |
417 | { |
418 | struct f_loopback *loop = func_to_loop(f); |
419 | |
420 | disable_loopback(loop); |
421 | } |
422 | |
423 | static struct usb_function *loopback_alloc(struct usb_function_instance *fi) |
424 | { |
425 | struct f_loopback *loop; |
426 | struct f_lb_opts *lb_opts; |
427 | |
428 | loop = kzalloc(size: sizeof *loop, GFP_KERNEL); |
429 | if (!loop) |
430 | return ERR_PTR(error: -ENOMEM); |
431 | |
432 | lb_opts = container_of(fi, struct f_lb_opts, func_inst); |
433 | |
434 | mutex_lock(&lb_opts->lock); |
435 | lb_opts->refcnt++; |
436 | mutex_unlock(lock: &lb_opts->lock); |
437 | |
438 | loop->buflen = lb_opts->bulk_buflen; |
439 | loop->qlen = lb_opts->qlen; |
440 | if (!loop->qlen) |
441 | loop->qlen = 32; |
442 | |
443 | loop->function.name = "loopback" ; |
444 | loop->function.bind = loopback_bind; |
445 | loop->function.set_alt = loopback_set_alt; |
446 | loop->function.disable = loopback_disable; |
447 | loop->function.strings = loopback_strings; |
448 | |
449 | loop->function.free_func = lb_free_func; |
450 | |
451 | return &loop->function; |
452 | } |
453 | |
454 | static inline struct f_lb_opts *to_f_lb_opts(struct config_item *item) |
455 | { |
456 | return container_of(to_config_group(item), struct f_lb_opts, |
457 | func_inst.group); |
458 | } |
459 | |
460 | static void lb_attr_release(struct config_item *item) |
461 | { |
462 | struct f_lb_opts *lb_opts = to_f_lb_opts(item); |
463 | |
464 | usb_put_function_instance(fi: &lb_opts->func_inst); |
465 | } |
466 | |
467 | static struct configfs_item_operations lb_item_ops = { |
468 | .release = lb_attr_release, |
469 | }; |
470 | |
471 | static ssize_t f_lb_opts_qlen_show(struct config_item *item, char *page) |
472 | { |
473 | struct f_lb_opts *opts = to_f_lb_opts(item); |
474 | int result; |
475 | |
476 | mutex_lock(&opts->lock); |
477 | result = sprintf(buf: page, fmt: "%d\n" , opts->qlen); |
478 | mutex_unlock(lock: &opts->lock); |
479 | |
480 | return result; |
481 | } |
482 | |
483 | static ssize_t f_lb_opts_qlen_store(struct config_item *item, |
484 | const char *page, size_t len) |
485 | { |
486 | struct f_lb_opts *opts = to_f_lb_opts(item); |
487 | int ret; |
488 | u32 num; |
489 | |
490 | mutex_lock(&opts->lock); |
491 | if (opts->refcnt) { |
492 | ret = -EBUSY; |
493 | goto end; |
494 | } |
495 | |
496 | ret = kstrtou32(s: page, base: 0, res: &num); |
497 | if (ret) |
498 | goto end; |
499 | |
500 | opts->qlen = num; |
501 | ret = len; |
502 | end: |
503 | mutex_unlock(lock: &opts->lock); |
504 | return ret; |
505 | } |
506 | |
507 | CONFIGFS_ATTR(f_lb_opts_, qlen); |
508 | |
509 | static ssize_t f_lb_opts_bulk_buflen_show(struct config_item *item, char *page) |
510 | { |
511 | struct f_lb_opts *opts = to_f_lb_opts(item); |
512 | int result; |
513 | |
514 | mutex_lock(&opts->lock); |
515 | result = sprintf(buf: page, fmt: "%d\n" , opts->bulk_buflen); |
516 | mutex_unlock(lock: &opts->lock); |
517 | |
518 | return result; |
519 | } |
520 | |
521 | static ssize_t f_lb_opts_bulk_buflen_store(struct config_item *item, |
522 | const char *page, size_t len) |
523 | { |
524 | struct f_lb_opts *opts = to_f_lb_opts(item); |
525 | int ret; |
526 | u32 num; |
527 | |
528 | mutex_lock(&opts->lock); |
529 | if (opts->refcnt) { |
530 | ret = -EBUSY; |
531 | goto end; |
532 | } |
533 | |
534 | ret = kstrtou32(s: page, base: 0, res: &num); |
535 | if (ret) |
536 | goto end; |
537 | |
538 | opts->bulk_buflen = num; |
539 | ret = len; |
540 | end: |
541 | mutex_unlock(lock: &opts->lock); |
542 | return ret; |
543 | } |
544 | |
545 | CONFIGFS_ATTR(f_lb_opts_, bulk_buflen); |
546 | |
547 | static struct configfs_attribute *lb_attrs[] = { |
548 | &f_lb_opts_attr_qlen, |
549 | &f_lb_opts_attr_bulk_buflen, |
550 | NULL, |
551 | }; |
552 | |
553 | static const struct config_item_type lb_func_type = { |
554 | .ct_item_ops = &lb_item_ops, |
555 | .ct_attrs = lb_attrs, |
556 | .ct_owner = THIS_MODULE, |
557 | }; |
558 | |
559 | static void lb_free_instance(struct usb_function_instance *fi) |
560 | { |
561 | struct f_lb_opts *lb_opts; |
562 | |
563 | lb_opts = container_of(fi, struct f_lb_opts, func_inst); |
564 | kfree(objp: lb_opts); |
565 | } |
566 | |
567 | static struct usb_function_instance *loopback_alloc_instance(void) |
568 | { |
569 | struct f_lb_opts *lb_opts; |
570 | |
571 | lb_opts = kzalloc(size: sizeof(*lb_opts), GFP_KERNEL); |
572 | if (!lb_opts) |
573 | return ERR_PTR(error: -ENOMEM); |
574 | mutex_init(&lb_opts->lock); |
575 | lb_opts->func_inst.free_func_inst = lb_free_instance; |
576 | lb_opts->bulk_buflen = GZERO_BULK_BUFLEN; |
577 | lb_opts->qlen = GZERO_QLEN; |
578 | |
579 | config_group_init_type_name(group: &lb_opts->func_inst.group, name: "" , |
580 | type: &lb_func_type); |
581 | |
582 | return &lb_opts->func_inst; |
583 | } |
584 | DECLARE_USB_FUNCTION(Loopback, loopback_alloc_instance, loopback_alloc); |
585 | |
586 | int __init lb_modinit(void) |
587 | { |
588 | return usb_function_register(newf: &Loopbackusb_func); |
589 | } |
590 | |
591 | void __exit lb_modexit(void) |
592 | { |
593 | usb_function_unregister(f: &Loopbackusb_func); |
594 | } |
595 | |
596 | MODULE_LICENSE("GPL" ); |
597 | |