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