]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/blob - drivers/usb/gadget/f_loopback.c
usb: gadget: add usb_endpoint_descriptor to struct usb_ep
[mirror_ubuntu-hirsute-kernel.git] / drivers / usb / gadget / f_loopback.c
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.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
22 /* #define VERBOSE_DEBUG */
23
24 #include <linux/slab.h>
25 #include <linux/kernel.h>
26 #include <linux/device.h>
27
28 #include "g_zero.h"
29 #include "gadget_chips.h"
30
31
32 /*
33 * LOOPBACK FUNCTION ... a testing vehicle for USB peripherals,
34 *
35 * This takes messages of various sizes written OUT to a device, and loops
36 * them back so they can be read IN from it. It has been used by certain
37 * test applications. It supports limited testing of data queueing logic.
38 *
39 *
40 * This is currently packaged as a configuration driver, which can't be
41 * combined with other functions to make composite devices. However, it
42 * can be combined with other independent configurations.
43 */
44 struct f_loopback {
45 struct usb_function function;
46
47 struct usb_ep *in_ep;
48 struct usb_ep *out_ep;
49 };
50
51 static inline struct f_loopback *func_to_loop(struct usb_function *f)
52 {
53 return container_of(f, struct f_loopback, function);
54 }
55
56 static unsigned qlen = 32;
57 module_param(qlen, uint, 0);
58 MODULE_PARM_DESC(qlenn, "depth of loopback queue");
59
60 /*-------------------------------------------------------------------------*/
61
62 static struct usb_interface_descriptor loopback_intf = {
63 .bLength = sizeof loopback_intf,
64 .bDescriptorType = USB_DT_INTERFACE,
65
66 .bNumEndpoints = 2,
67 .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
68 /* .iInterface = DYNAMIC */
69 };
70
71 /* full speed support: */
72
73 static struct usb_endpoint_descriptor fs_loop_source_desc = {
74 .bLength = USB_DT_ENDPOINT_SIZE,
75 .bDescriptorType = USB_DT_ENDPOINT,
76
77 .bEndpointAddress = USB_DIR_IN,
78 .bmAttributes = USB_ENDPOINT_XFER_BULK,
79 };
80
81 static struct usb_endpoint_descriptor fs_loop_sink_desc = {
82 .bLength = USB_DT_ENDPOINT_SIZE,
83 .bDescriptorType = USB_DT_ENDPOINT,
84
85 .bEndpointAddress = USB_DIR_OUT,
86 .bmAttributes = USB_ENDPOINT_XFER_BULK,
87 };
88
89 static struct usb_descriptor_header *fs_loopback_descs[] = {
90 (struct usb_descriptor_header *) &loopback_intf,
91 (struct usb_descriptor_header *) &fs_loop_sink_desc,
92 (struct usb_descriptor_header *) &fs_loop_source_desc,
93 NULL,
94 };
95
96 /* high speed support: */
97
98 static struct usb_endpoint_descriptor hs_loop_source_desc = {
99 .bLength = USB_DT_ENDPOINT_SIZE,
100 .bDescriptorType = USB_DT_ENDPOINT,
101
102 .bmAttributes = USB_ENDPOINT_XFER_BULK,
103 .wMaxPacketSize = cpu_to_le16(512),
104 };
105
106 static struct usb_endpoint_descriptor hs_loop_sink_desc = {
107 .bLength = USB_DT_ENDPOINT_SIZE,
108 .bDescriptorType = USB_DT_ENDPOINT,
109
110 .bmAttributes = USB_ENDPOINT_XFER_BULK,
111 .wMaxPacketSize = cpu_to_le16(512),
112 };
113
114 static struct usb_descriptor_header *hs_loopback_descs[] = {
115 (struct usb_descriptor_header *) &loopback_intf,
116 (struct usb_descriptor_header *) &hs_loop_source_desc,
117 (struct usb_descriptor_header *) &hs_loop_sink_desc,
118 NULL,
119 };
120
121 /* function-specific strings: */
122
123 static struct usb_string strings_loopback[] = {
124 [0].s = "loop input to output",
125 { } /* end of list */
126 };
127
128 static struct usb_gadget_strings stringtab_loop = {
129 .language = 0x0409, /* en-us */
130 .strings = strings_loopback,
131 };
132
133 static struct usb_gadget_strings *loopback_strings[] = {
134 &stringtab_loop,
135 NULL,
136 };
137
138 /*-------------------------------------------------------------------------*/
139
140 static int __init
141 loopback_bind(struct usb_configuration *c, struct usb_function *f)
142 {
143 struct usb_composite_dev *cdev = c->cdev;
144 struct f_loopback *loop = func_to_loop(f);
145 int id;
146
147 /* allocate interface ID(s) */
148 id = usb_interface_id(c, f);
149 if (id < 0)
150 return id;
151 loopback_intf.bInterfaceNumber = id;
152
153 /* allocate endpoints */
154
155 loop->in_ep = usb_ep_autoconfig(cdev->gadget, &fs_loop_source_desc);
156 if (!loop->in_ep) {
157 autoconf_fail:
158 ERROR(cdev, "%s: can't autoconfigure on %s\n",
159 f->name, cdev->gadget->name);
160 return -ENODEV;
161 }
162 loop->in_ep->driver_data = cdev; /* claim */
163
164 loop->out_ep = usb_ep_autoconfig(cdev->gadget, &fs_loop_sink_desc);
165 if (!loop->out_ep)
166 goto autoconf_fail;
167 loop->out_ep->driver_data = cdev; /* claim */
168
169 /* support high speed hardware */
170 if (gadget_is_dualspeed(c->cdev->gadget)) {
171 hs_loop_source_desc.bEndpointAddress =
172 fs_loop_source_desc.bEndpointAddress;
173 hs_loop_sink_desc.bEndpointAddress =
174 fs_loop_sink_desc.bEndpointAddress;
175 f->hs_descriptors = hs_loopback_descs;
176 }
177
178 DBG(cdev, "%s speed %s: IN/%s, OUT/%s\n",
179 gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
180 f->name, loop->in_ep->name, loop->out_ep->name);
181 return 0;
182 }
183
184 static void
185 loopback_unbind(struct usb_configuration *c, struct usb_function *f)
186 {
187 kfree(func_to_loop(f));
188 }
189
190 static void loopback_complete(struct usb_ep *ep, struct usb_request *req)
191 {
192 struct f_loopback *loop = ep->driver_data;
193 struct usb_composite_dev *cdev = loop->function.config->cdev;
194 int status = req->status;
195
196 switch (status) {
197
198 case 0: /* normal completion? */
199 if (ep == loop->out_ep) {
200 /* loop this OUT packet back IN to the host */
201 req->zero = (req->actual < req->length);
202 req->length = req->actual;
203 status = usb_ep_queue(loop->in_ep, req, GFP_ATOMIC);
204 if (status == 0)
205 return;
206
207 /* "should never get here" */
208 ERROR(cdev, "can't loop %s to %s: %d\n",
209 ep->name, loop->in_ep->name,
210 status);
211 }
212
213 /* queue the buffer for some later OUT packet */
214 req->length = buflen;
215 status = usb_ep_queue(loop->out_ep, req, GFP_ATOMIC);
216 if (status == 0)
217 return;
218
219 /* "should never get here" */
220 /* FALLTHROUGH */
221
222 default:
223 ERROR(cdev, "%s loop complete --> %d, %d/%d\n", ep->name,
224 status, req->actual, req->length);
225 /* FALLTHROUGH */
226
227 /* NOTE: since this driver doesn't maintain an explicit record
228 * of requests it submitted (just maintains qlen count), we
229 * rely on the hardware driver to clean up on disconnect or
230 * endpoint disable.
231 */
232 case -ECONNABORTED: /* hardware forced ep reset */
233 case -ECONNRESET: /* request dequeued */
234 case -ESHUTDOWN: /* disconnect from host */
235 free_ep_req(ep, req);
236 return;
237 }
238 }
239
240 static void disable_loopback(struct f_loopback *loop)
241 {
242 struct usb_composite_dev *cdev;
243
244 cdev = loop->function.config->cdev;
245 disable_endpoints(cdev, loop->in_ep, loop->out_ep);
246 VDBG(cdev, "%s disabled\n", loop->function.name);
247 }
248
249 static int
250 enable_loopback(struct usb_composite_dev *cdev, struct f_loopback *loop)
251 {
252 int result = 0;
253 struct usb_ep *ep;
254 struct usb_request *req;
255 unsigned i;
256
257 /* one endpoint writes data back IN to the host */
258 ep = loop->in_ep;
259 ep->desc = ep_choose(cdev->gadget,
260 &hs_loop_source_desc, &fs_loop_source_desc);
261 result = usb_ep_enable(ep);
262 if (result < 0)
263 return result;
264 ep->driver_data = loop;
265
266 /* one endpoint just reads OUT packets */
267 ep = loop->out_ep;
268 ep->desc = ep_choose(cdev->gadget,
269 &hs_loop_sink_desc, &fs_loop_sink_desc);
270 result = usb_ep_enable(ep);
271 if (result < 0) {
272 fail0:
273 ep = loop->in_ep;
274 usb_ep_disable(ep);
275 ep->driver_data = NULL;
276 return result;
277 }
278 ep->driver_data = loop;
279
280 /* allocate a bunch of read buffers and queue them all at once.
281 * we buffer at most 'qlen' transfers; fewer if any need more
282 * than 'buflen' bytes each.
283 */
284 for (i = 0; i < qlen && result == 0; i++) {
285 req = alloc_ep_req(ep);
286 if (req) {
287 req->complete = loopback_complete;
288 result = usb_ep_queue(ep, req, GFP_ATOMIC);
289 if (result)
290 ERROR(cdev, "%s queue req --> %d\n",
291 ep->name, result);
292 } else {
293 usb_ep_disable(ep);
294 ep->driver_data = NULL;
295 result = -ENOMEM;
296 goto fail0;
297 }
298 }
299
300 DBG(cdev, "%s enabled\n", loop->function.name);
301 return result;
302 }
303
304 static int loopback_set_alt(struct usb_function *f,
305 unsigned intf, unsigned alt)
306 {
307 struct f_loopback *loop = func_to_loop(f);
308 struct usb_composite_dev *cdev = f->config->cdev;
309
310 /* we know alt is zero */
311 if (loop->in_ep->driver_data)
312 disable_loopback(loop);
313 return enable_loopback(cdev, loop);
314 }
315
316 static void loopback_disable(struct usb_function *f)
317 {
318 struct f_loopback *loop = func_to_loop(f);
319
320 disable_loopback(loop);
321 }
322
323 /*-------------------------------------------------------------------------*/
324
325 static int __init loopback_bind_config(struct usb_configuration *c)
326 {
327 struct f_loopback *loop;
328 int status;
329
330 loop = kzalloc(sizeof *loop, GFP_KERNEL);
331 if (!loop)
332 return -ENOMEM;
333
334 loop->function.name = "loopback";
335 loop->function.descriptors = fs_loopback_descs;
336 loop->function.bind = loopback_bind;
337 loop->function.unbind = loopback_unbind;
338 loop->function.set_alt = loopback_set_alt;
339 loop->function.disable = loopback_disable;
340
341 status = usb_add_function(c, &loop->function);
342 if (status)
343 kfree(loop);
344 return status;
345 }
346
347 static struct usb_configuration loopback_driver = {
348 .label = "loopback",
349 .strings = loopback_strings,
350 .bConfigurationValue = 2,
351 .bmAttributes = USB_CONFIG_ATT_SELFPOWER,
352 /* .iConfiguration = DYNAMIC */
353 };
354
355 /**
356 * loopback_add - add a loopback testing configuration to a device
357 * @cdev: the device to support the loopback configuration
358 */
359 int __init loopback_add(struct usb_composite_dev *cdev, bool autoresume)
360 {
361 int id;
362
363 /* allocate string ID(s) */
364 id = usb_string_id(cdev);
365 if (id < 0)
366 return id;
367 strings_loopback[0].id = id;
368
369 loopback_intf.iInterface = id;
370 loopback_driver.iConfiguration = id;
371
372 /* support autoresume for remote wakeup testing */
373 if (autoresume)
374 sourcesink_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
375
376 /* support OTG systems */
377 if (gadget_is_otg(cdev->gadget)) {
378 loopback_driver.descriptors = otg_desc;
379 loopback_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
380 }
381
382 return usb_add_config(cdev, &loopback_driver, loopback_bind_config);
383 }