import PULS_20160108
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / drivers / usb / gadget / f_loopback.c
CommitLineData
e5760fda
DB
1/*
2 * f_loopback.c - USB peripheral loopback configuration driver
3 *
4 * Copyright (C) 2003-2008 David Brownell
5 * Copyright (C) 2008 by Nokia Corporation
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
e5760fda
DB
11 */
12
13/* #define VERBOSE_DEBUG */
14
5a0e3ad6 15#include <linux/slab.h>
e5760fda 16#include <linux/kernel.h>
e5760fda 17#include <linux/device.h>
cf9a08ae
SAS
18#include <linux/module.h>
19#include <linux/err.h>
20#include <linux/usb/composite.h>
e5760fda
DB
21
22#include "g_zero.h"
e5760fda
DB
23
24/*
25 * LOOPBACK FUNCTION ... a testing vehicle for USB peripherals,
26 *
27 * This takes messages of various sizes written OUT to a device, and loops
28 * them back so they can be read IN from it. It has been used by certain
29 * test applications. It supports limited testing of data queueing logic.
30 *
31 *
32 * This is currently packaged as a configuration driver, which can't be
33 * combined with other functions to make composite devices. However, it
34 * can be combined with other independent configurations.
35 */
36struct f_loopback {
37 struct usb_function function;
38
39 struct usb_ep *in_ep;
40 struct usb_ep *out_ep;
41};
42
43static inline struct f_loopback *func_to_loop(struct usb_function *f)
44{
45 return container_of(f, struct f_loopback, function);
46}
47
cf9a08ae
SAS
48static unsigned qlen;
49static unsigned buflen;
e5760fda
DB
50
51/*-------------------------------------------------------------------------*/
52
53static struct usb_interface_descriptor loopback_intf = {
54 .bLength = sizeof loopback_intf,
55 .bDescriptorType = USB_DT_INTERFACE,
56
57 .bNumEndpoints = 2,
58 .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
59 /* .iInterface = DYNAMIC */
60};
61
62/* full speed support: */
63
7e75bc0f 64static struct usb_endpoint_descriptor fs_loop_source_desc = {
e5760fda
DB
65 .bLength = USB_DT_ENDPOINT_SIZE,
66 .bDescriptorType = USB_DT_ENDPOINT,
67
68 .bEndpointAddress = USB_DIR_IN,
69 .bmAttributes = USB_ENDPOINT_XFER_BULK,
70};
71
7e75bc0f 72static struct usb_endpoint_descriptor fs_loop_sink_desc = {
e5760fda
DB
73 .bLength = USB_DT_ENDPOINT_SIZE,
74 .bDescriptorType = USB_DT_ENDPOINT,
75
76 .bEndpointAddress = USB_DIR_OUT,
77 .bmAttributes = USB_ENDPOINT_XFER_BULK,
78};
79
80static struct usb_descriptor_header *fs_loopback_descs[] = {
81 (struct usb_descriptor_header *) &loopback_intf,
7e75bc0f
DB
82 (struct usb_descriptor_header *) &fs_loop_sink_desc,
83 (struct usb_descriptor_header *) &fs_loop_source_desc,
e5760fda
DB
84 NULL,
85};
86
87/* high speed support: */
88
7e75bc0f 89static struct usb_endpoint_descriptor hs_loop_source_desc = {
e5760fda
DB
90 .bLength = USB_DT_ENDPOINT_SIZE,
91 .bDescriptorType = USB_DT_ENDPOINT,
92
93 .bmAttributes = USB_ENDPOINT_XFER_BULK,
551509d2 94 .wMaxPacketSize = cpu_to_le16(512),
e5760fda
DB
95};
96
7e75bc0f 97static struct usb_endpoint_descriptor hs_loop_sink_desc = {
e5760fda
DB
98 .bLength = USB_DT_ENDPOINT_SIZE,
99 .bDescriptorType = USB_DT_ENDPOINT,
100
101 .bmAttributes = USB_ENDPOINT_XFER_BULK,
551509d2 102 .wMaxPacketSize = cpu_to_le16(512),
e5760fda
DB
103};
104
105static struct usb_descriptor_header *hs_loopback_descs[] = {
106 (struct usb_descriptor_header *) &loopback_intf,
7e75bc0f
DB
107 (struct usb_descriptor_header *) &hs_loop_source_desc,
108 (struct usb_descriptor_header *) &hs_loop_sink_desc,
e5760fda
DB
109 NULL,
110};
111
57c97c02
AB
112/* super speed support: */
113
114static struct usb_endpoint_descriptor ss_loop_source_desc = {
115 .bLength = USB_DT_ENDPOINT_SIZE,
116 .bDescriptorType = USB_DT_ENDPOINT,
117
118 .bmAttributes = USB_ENDPOINT_XFER_BULK,
119 .wMaxPacketSize = cpu_to_le16(1024),
120};
121
122struct usb_ss_ep_comp_descriptor ss_loop_source_comp_desc = {
123 .bLength = USB_DT_SS_EP_COMP_SIZE,
124 .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
125 .bMaxBurst = 0,
126 .bmAttributes = 0,
127 .wBytesPerInterval = 0,
128};
129
130static struct usb_endpoint_descriptor ss_loop_sink_desc = {
131 .bLength = USB_DT_ENDPOINT_SIZE,
132 .bDescriptorType = USB_DT_ENDPOINT,
133
134 .bmAttributes = USB_ENDPOINT_XFER_BULK,
135 .wMaxPacketSize = cpu_to_le16(1024),
136};
137
138struct usb_ss_ep_comp_descriptor ss_loop_sink_comp_desc = {
139 .bLength = USB_DT_SS_EP_COMP_SIZE,
140 .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
141 .bMaxBurst = 0,
142 .bmAttributes = 0,
143 .wBytesPerInterval = 0,
144};
145
146static struct usb_descriptor_header *ss_loopback_descs[] = {
147 (struct usb_descriptor_header *) &loopback_intf,
148 (struct usb_descriptor_header *) &ss_loop_source_desc,
149 (struct usb_descriptor_header *) &ss_loop_source_comp_desc,
150 (struct usb_descriptor_header *) &ss_loop_sink_desc,
151 (struct usb_descriptor_header *) &ss_loop_sink_comp_desc,
152 NULL,
153};
154
e5760fda
DB
155/* function-specific strings: */
156
157static struct usb_string strings_loopback[] = {
158 [0].s = "loop input to output",
159 { } /* end of list */
160};
161
162static struct usb_gadget_strings stringtab_loop = {
163 .language = 0x0409, /* en-us */
164 .strings = strings_loopback,
165};
166
167static struct usb_gadget_strings *loopback_strings[] = {
168 &stringtab_loop,
169 NULL,
170};
171
172/*-------------------------------------------------------------------------*/
173
6fa3eb70
S
174struct usb_request *alloc_ep_req(struct usb_ep *ep, int len)
175{
176 struct usb_request *req;
177
178 req = usb_ep_alloc_request(ep, GFP_ATOMIC);
179 if (req) {
180 if (len)
181 req->length = len;
182 else
183 req->length = buflen;
184 req->buf = kmalloc(req->length, GFP_ATOMIC);
185 if (!req->buf) {
186 usb_ep_free_request(ep, req);
187 req = NULL;
188 }
189 }
190 return req;
191}
192
193void free_ep_req(struct usb_ep *ep, struct usb_request *req)
194{
195 kfree(req->buf);
196 usb_ep_free_request(ep, req);
197}
198
199static void disable_ep(struct usb_composite_dev *cdev, struct usb_ep *ep)
200{
201 int value;
202
203 if (ep->driver_data) {
204 value = usb_ep_disable(ep);
205 if (value < 0)
206 DBG(cdev, "disable %s --> %d\n",
207 ep->name, value);
208 ep->driver_data = NULL;
209 }
210}
211
212void disable_endpoints(struct usb_composite_dev *cdev,
213 struct usb_ep *in, struct usb_ep *out,
214 struct usb_ep *iso_in, struct usb_ep *iso_out)
215{
216 disable_ep(cdev, in);
217 disable_ep(cdev, out);
218 if (iso_in)
219 disable_ep(cdev, iso_in);
220 if (iso_out)
221 disable_ep(cdev, iso_out);
222}
223
cf9a08ae 224static int loopback_bind(struct usb_configuration *c, struct usb_function *f)
e5760fda
DB
225{
226 struct usb_composite_dev *cdev = c->cdev;
227 struct f_loopback *loop = func_to_loop(f);
228 int id;
10287bae 229 int ret;
e5760fda
DB
230
231 /* allocate interface ID(s) */
232 id = usb_interface_id(c, f);
233 if (id < 0)
234 return id;
235 loopback_intf.bInterfaceNumber = id;
236
78f46f09
SAS
237 id = usb_string_id(cdev);
238 if (id < 0)
239 return id;
240 strings_loopback[0].id = id;
241 loopback_intf.iInterface = id;
242
e5760fda
DB
243 /* allocate endpoints */
244
7e75bc0f 245 loop->in_ep = usb_ep_autoconfig(cdev->gadget, &fs_loop_source_desc);
e5760fda
DB
246 if (!loop->in_ep) {
247autoconf_fail:
248 ERROR(cdev, "%s: can't autoconfigure on %s\n",
249 f->name, cdev->gadget->name);
250 return -ENODEV;
251 }
252 loop->in_ep->driver_data = cdev; /* claim */
253
7e75bc0f 254 loop->out_ep = usb_ep_autoconfig(cdev->gadget, &fs_loop_sink_desc);
e5760fda
DB
255 if (!loop->out_ep)
256 goto autoconf_fail;
257 loop->out_ep->driver_data = cdev; /* claim */
258
259 /* support high speed hardware */
10287bae
SAS
260 hs_loop_source_desc.bEndpointAddress =
261 fs_loop_source_desc.bEndpointAddress;
262 hs_loop_sink_desc.bEndpointAddress = fs_loop_sink_desc.bEndpointAddress;
e5760fda 263
57c97c02 264 /* support super speed hardware */
10287bae
SAS
265 ss_loop_source_desc.bEndpointAddress =
266 fs_loop_source_desc.bEndpointAddress;
267 ss_loop_sink_desc.bEndpointAddress = fs_loop_sink_desc.bEndpointAddress;
268
269 ret = usb_assign_descriptors(f, fs_loopback_descs, hs_loopback_descs,
270 ss_loopback_descs);
271 if (ret)
272 return ret;
57c97c02 273
e5760fda 274 DBG(cdev, "%s speed %s: IN/%s, OUT/%s\n",
57c97c02
AB
275 (gadget_is_superspeed(c->cdev->gadget) ? "super" :
276 (gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full")),
e5760fda
DB
277 f->name, loop->in_ep->name, loop->out_ep->name);
278 return 0;
279}
280
cf9a08ae 281static void lb_free_func(struct usb_function *f)
e5760fda 282{
10287bae 283 usb_free_all_descriptors(f);
e5760fda
DB
284 kfree(func_to_loop(f));
285}
286
287static void loopback_complete(struct usb_ep *ep, struct usb_request *req)
288{
289 struct f_loopback *loop = ep->driver_data;
290 struct usb_composite_dev *cdev = loop->function.config->cdev;
291 int status = req->status;
292
293 switch (status) {
294
295 case 0: /* normal completion? */
296 if (ep == loop->out_ep) {
297 /* loop this OUT packet back IN to the host */
6fa3eb70
S
298 struct usb_request *in_req = req->context;
299 in_req->zero = (req->actual % ep->maxpacket == 0)?1:0;
300 in_req->length = req->actual;
301 in_req->actual = 0;
302
303 memcpy(in_req->buf, req->buf, req->length);
304
305 status = usb_ep_queue(loop->in_ep, in_req, GFP_ATOMIC);
e5760fda
DB
306 if (status == 0)
307 return;
308
309 /* "should never get here" */
310 ERROR(cdev, "can't loop %s to %s: %d\n",
311 ep->name, loop->in_ep->name,
312 status);
313 }
314
6fa3eb70
S
315 if (ep == loop->in_ep) {
316 struct usb_request *out_req = req->context;
317 /* queue the buffer for some later OUT packet */
318 out_req->length = buflen;
319 status = usb_ep_queue(loop->out_ep, out_req, GFP_ATOMIC);
320 if (status == 0)
321 return;
322 }
e5760fda
DB
323
324 /* "should never get here" */
325 /* FALLTHROUGH */
326
327 default:
328 ERROR(cdev, "%s loop complete --> %d, %d/%d\n", ep->name,
329 status, req->actual, req->length);
330 /* FALLTHROUGH */
331
332 /* NOTE: since this driver doesn't maintain an explicit record
333 * of requests it submitted (just maintains qlen count), we
334 * rely on the hardware driver to clean up on disconnect or
335 * endpoint disable.
336 */
337 case -ECONNABORTED: /* hardware forced ep reset */
338 case -ECONNRESET: /* request dequeued */
339 case -ESHUTDOWN: /* disconnect from host */
340 free_ep_req(ep, req);
341 return;
342 }
343}
344
345static void disable_loopback(struct f_loopback *loop)
346{
347 struct usb_composite_dev *cdev;
348
349 cdev = loop->function.config->cdev;
b4036ccd 350 disable_endpoints(cdev, loop->in_ep, loop->out_ep, NULL, NULL);
e5760fda
DB
351 VDBG(cdev, "%s disabled\n", loop->function.name);
352}
353
354static int
355enable_loopback(struct usb_composite_dev *cdev, struct f_loopback *loop)
356{
357 int result = 0;
e5760fda 358 struct usb_ep *ep;
e5760fda
DB
359 unsigned i;
360
e5760fda
DB
361 /* one endpoint writes data back IN to the host */
362 ep = loop->in_ep;
ea2a1df7
TB
363 result = config_ep_by_speed(cdev->gadget, &(loop->function), ep);
364 if (result)
365 return result;
72c973dd 366 result = usb_ep_enable(ep);
e5760fda
DB
367 if (result < 0)
368 return result;
369 ep->driver_data = loop;
370
371 /* one endpoint just reads OUT packets */
372 ep = loop->out_ep;
ea2a1df7
TB
373 result = config_ep_by_speed(cdev->gadget, &(loop->function), ep);
374 if (result)
375 goto fail0;
376
72c973dd 377 result = usb_ep_enable(ep);
e5760fda
DB
378 if (result < 0) {
379fail0:
380 ep = loop->in_ep;
381 usb_ep_disable(ep);
382 ep->driver_data = NULL;
383 return result;
384 }
385 ep->driver_data = loop;
386
387 /* allocate a bunch of read buffers and queue them all at once.
388 * we buffer at most 'qlen' transfers; fewer if any need more
389 * than 'buflen' bytes each.
390 */
391 for (i = 0; i < qlen && result == 0; i++) {
6fa3eb70
S
392 struct usb_request *out_req;
393 struct usb_request *in_req;
394 out_req = alloc_ep_req(loop->out_ep, 0);
395 if (out_req) {
396 out_req->complete = loopback_complete;
397 result = usb_ep_queue(loop->out_ep, out_req, GFP_ATOMIC);
e5760fda
DB
398 if (result)
399 ERROR(cdev, "%s queue req --> %d\n",
6fa3eb70 400 loop->out_ep->name, result);
e5760fda 401 } else {
6fa3eb70
S
402 usb_ep_disable(loop->out_ep);
403 loop->out_ep->driver_data = NULL;
e5760fda
DB
404 result = -ENOMEM;
405 goto fail0;
406 }
6fa3eb70
S
407 in_req = alloc_ep_req(loop->in_ep, 0);
408 if (in_req) {
409 in_req->complete = loopback_complete;
410 } else {
411 usb_ep_disable(loop->in_ep);
412 loop->in_ep->driver_data = NULL;
413 result = -ENOMEM;
414 goto fail0;
415 }
416 in_req->context = out_req;
417 out_req->context = in_req;
e5760fda
DB
418 }
419
420 DBG(cdev, "%s enabled\n", loop->function.name);
421 return result;
422}
423
424static int loopback_set_alt(struct usb_function *f,
425 unsigned intf, unsigned alt)
426{
427 struct f_loopback *loop = func_to_loop(f);
428 struct usb_composite_dev *cdev = f->config->cdev;
429
430 /* we know alt is zero */
431 if (loop->in_ep->driver_data)
432 disable_loopback(loop);
433 return enable_loopback(cdev, loop);
434}
435
436static void loopback_disable(struct usb_function *f)
437{
438 struct f_loopback *loop = func_to_loop(f);
439
440 disable_loopback(loop);
441}
442
cf9a08ae 443static struct usb_function *loopback_alloc(struct usb_function_instance *fi)
e5760fda
DB
444{
445 struct f_loopback *loop;
cf9a08ae 446 struct f_lb_opts *lb_opts;
e5760fda
DB
447
448 loop = kzalloc(sizeof *loop, GFP_KERNEL);
449 if (!loop)
cf9a08ae
SAS
450 return ERR_PTR(-ENOMEM);
451
452 lb_opts = container_of(fi, struct f_lb_opts, func_inst);
453 buflen = lb_opts->bulk_buflen;
6fa3eb70
S
454 if (!buflen)
455 buflen = 512;
456
cf9a08ae
SAS
457 qlen = lb_opts->qlen;
458 if (!qlen)
6fa3eb70 459 qlen = 8;
e5760fda
DB
460
461 loop->function.name = "loopback";
e5760fda 462 loop->function.bind = loopback_bind;
e5760fda
DB
463 loop->function.set_alt = loopback_set_alt;
464 loop->function.disable = loopback_disable;
cf9a08ae
SAS
465 loop->function.strings = loopback_strings;
466
467 loop->function.free_func = lb_free_func;
468
469 return &loop->function;
470}
471
472static void lb_free_instance(struct usb_function_instance *fi)
473{
474 struct f_lb_opts *lb_opts;
e5760fda 475
cf9a08ae
SAS
476 lb_opts = container_of(fi, struct f_lb_opts, func_inst);
477 kfree(lb_opts);
e5760fda 478}
cf9a08ae
SAS
479
480static struct usb_function_instance *loopback_alloc_instance(void)
481{
482 struct f_lb_opts *lb_opts;
483
484 lb_opts = kzalloc(sizeof(*lb_opts), GFP_KERNEL);
485 if (!lb_opts)
486 return ERR_PTR(-ENOMEM);
487 lb_opts->func_inst.free_func_inst = lb_free_instance;
488 return &lb_opts->func_inst;
489}
6fa3eb70 490DECLARE_USB_FUNCTION_INIT(loopback, loopback_alloc_instance, loopback_alloc);
cf9a08ae 491
6fa3eb70 492#if 0
cf9a08ae
SAS
493int __init lb_modinit(void)
494{
495 int ret;
496
497 ret = usb_function_register(&Loopbackusb_func);
498 if (ret)
499 return ret;
500 return ret;
501}
502void __exit lb_modexit(void)
503{
504 usb_function_unregister(&Loopbackusb_func);
505}
6fa3eb70 506#endif
cf9a08ae 507MODULE_LICENSE("GPL");