• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6.36/drivers/usb/gadget/
1/*
2 * f_serial.c - generic USB serial function driver
3 *
4 * Copyright (C) 2003 Al Borchers (alborchers@steinerpoint.com)
5 * Copyright (C) 2008 by David Brownell
6 * Copyright (C) 2008 by Nokia Corporation
7 *
8 * This software is distributed under the terms of the GNU General
9 * Public License ("GPL") as published by the Free Software Foundation,
10 * either version 2 of that License or (at your option) any later version.
11 */
12
13#include <linux/slab.h>
14#include <linux/kernel.h>
15#include <linux/device.h>
16
17#include "u_serial.h"
18#include "gadget_chips.h"
19
20
21/*
22 * This function packages a simple "generic serial" port with no real
23 * control mechanisms, just raw data transfer over two bulk endpoints.
24 *
25 * Because it's not standardized, this isn't as interoperable as the
26 * CDC ACM driver.  However, for many purposes it's just as functional
27 * if you can arrange appropriate host side drivers.
28 */
29
30struct gser_descs {
31	struct usb_endpoint_descriptor	*in;
32	struct usb_endpoint_descriptor	*out;
33};
34
35struct f_gser {
36	struct gserial			port;
37	u8				data_id;
38	u8				port_num;
39
40	struct gser_descs		fs;
41	struct gser_descs		hs;
42};
43
44static inline struct f_gser *func_to_gser(struct usb_function *f)
45{
46	return container_of(f, struct f_gser, port.func);
47}
48
49/*-------------------------------------------------------------------------*/
50
51/* interface descriptor: */
52
53static struct usb_interface_descriptor gser_interface_desc __initdata = {
54	.bLength =		USB_DT_INTERFACE_SIZE,
55	.bDescriptorType =	USB_DT_INTERFACE,
56	/* .bInterfaceNumber = DYNAMIC */
57	.bNumEndpoints =	2,
58	.bInterfaceClass =	USB_CLASS_VENDOR_SPEC,
59	.bInterfaceSubClass =	0,
60	.bInterfaceProtocol =	0,
61	/* .iInterface = DYNAMIC */
62};
63
64/* full speed support: */
65
66static struct usb_endpoint_descriptor gser_fs_in_desc __initdata = {
67	.bLength =		USB_DT_ENDPOINT_SIZE,
68	.bDescriptorType =	USB_DT_ENDPOINT,
69	.bEndpointAddress =	USB_DIR_IN,
70	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
71};
72
73static struct usb_endpoint_descriptor gser_fs_out_desc __initdata = {
74	.bLength =		USB_DT_ENDPOINT_SIZE,
75	.bDescriptorType =	USB_DT_ENDPOINT,
76	.bEndpointAddress =	USB_DIR_OUT,
77	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
78};
79
80static struct usb_descriptor_header *gser_fs_function[] __initdata = {
81	(struct usb_descriptor_header *) &gser_interface_desc,
82	(struct usb_descriptor_header *) &gser_fs_in_desc,
83	(struct usb_descriptor_header *) &gser_fs_out_desc,
84	NULL,
85};
86
87/* high speed support: */
88
89static struct usb_endpoint_descriptor gser_hs_in_desc __initdata = {
90	.bLength =		USB_DT_ENDPOINT_SIZE,
91	.bDescriptorType =	USB_DT_ENDPOINT,
92	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
93	.wMaxPacketSize =	cpu_to_le16(512),
94};
95
96static struct usb_endpoint_descriptor gser_hs_out_desc __initdata = {
97	.bLength =		USB_DT_ENDPOINT_SIZE,
98	.bDescriptorType =	USB_DT_ENDPOINT,
99	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
100	.wMaxPacketSize =	cpu_to_le16(512),
101};
102
103static struct usb_descriptor_header *gser_hs_function[] __initdata = {
104	(struct usb_descriptor_header *) &gser_interface_desc,
105	(struct usb_descriptor_header *) &gser_hs_in_desc,
106	(struct usb_descriptor_header *) &gser_hs_out_desc,
107	NULL,
108};
109
110/* string descriptors: */
111
112static struct usb_string gser_string_defs[] = {
113	[0].s = "Generic Serial",
114	{  } /* end of list */
115};
116
117static struct usb_gadget_strings gser_string_table = {
118	.language =		0x0409,	/* en-us */
119	.strings =		gser_string_defs,
120};
121
122static struct usb_gadget_strings *gser_strings[] = {
123	&gser_string_table,
124	NULL,
125};
126
127/*-------------------------------------------------------------------------*/
128
129static int gser_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
130{
131	struct f_gser		*gser = func_to_gser(f);
132	struct usb_composite_dev *cdev = f->config->cdev;
133
134	/* we know alt == 0, so this is an activation or a reset */
135
136	if (gser->port.in->driver_data) {
137		DBG(cdev, "reset generic ttyGS%d\n", gser->port_num);
138		gserial_disconnect(&gser->port);
139	} else {
140		DBG(cdev, "activate generic ttyGS%d\n", gser->port_num);
141		gser->port.in_desc = ep_choose(cdev->gadget,
142				gser->hs.in, gser->fs.in);
143		gser->port.out_desc = ep_choose(cdev->gadget,
144				gser->hs.out, gser->fs.out);
145	}
146	gserial_connect(&gser->port, gser->port_num);
147	return 0;
148}
149
150static void gser_disable(struct usb_function *f)
151{
152	struct f_gser	*gser = func_to_gser(f);
153	struct usb_composite_dev *cdev = f->config->cdev;
154
155	DBG(cdev, "generic ttyGS%d deactivated\n", gser->port_num);
156	gserial_disconnect(&gser->port);
157}
158
159/*-------------------------------------------------------------------------*/
160
161/* serial function driver setup/binding */
162
163static int __init
164gser_bind(struct usb_configuration *c, struct usb_function *f)
165{
166	struct usb_composite_dev *cdev = c->cdev;
167	struct f_gser		*gser = func_to_gser(f);
168	int			status;
169	struct usb_ep		*ep;
170
171	/* allocate instance-specific interface IDs */
172	status = usb_interface_id(c, f);
173	if (status < 0)
174		goto fail;
175	gser->data_id = status;
176	gser_interface_desc.bInterfaceNumber = status;
177
178	status = -ENODEV;
179
180	/* allocate instance-specific endpoints */
181	ep = usb_ep_autoconfig(cdev->gadget, &gser_fs_in_desc);
182	if (!ep)
183		goto fail;
184	gser->port.in = ep;
185	ep->driver_data = cdev;	/* claim */
186
187	ep = usb_ep_autoconfig(cdev->gadget, &gser_fs_out_desc);
188	if (!ep)
189		goto fail;
190	gser->port.out = ep;
191	ep->driver_data = cdev;	/* claim */
192
193	/* copy descriptors, and track endpoint copies */
194	f->descriptors = usb_copy_descriptors(gser_fs_function);
195
196	gser->fs.in = usb_find_endpoint(gser_fs_function,
197			f->descriptors, &gser_fs_in_desc);
198	gser->fs.out = usb_find_endpoint(gser_fs_function,
199			f->descriptors, &gser_fs_out_desc);
200
201
202	/* support all relevant hardware speeds... we expect that when
203	 * hardware is dual speed, all bulk-capable endpoints work at
204	 * both speeds
205	 */
206	if (gadget_is_dualspeed(c->cdev->gadget)) {
207		gser_hs_in_desc.bEndpointAddress =
208				gser_fs_in_desc.bEndpointAddress;
209		gser_hs_out_desc.bEndpointAddress =
210				gser_fs_out_desc.bEndpointAddress;
211
212		/* copy descriptors, and track endpoint copies */
213		f->hs_descriptors = usb_copy_descriptors(gser_hs_function);
214
215		gser->hs.in = usb_find_endpoint(gser_hs_function,
216				f->hs_descriptors, &gser_hs_in_desc);
217		gser->hs.out = usb_find_endpoint(gser_hs_function,
218				f->hs_descriptors, &gser_hs_out_desc);
219	}
220
221	DBG(cdev, "generic ttyGS%d: %s speed IN/%s OUT/%s\n",
222			gser->port_num,
223			gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
224			gser->port.in->name, gser->port.out->name);
225	return 0;
226
227fail:
228	/* we might as well release our claims on endpoints */
229	if (gser->port.out)
230		gser->port.out->driver_data = NULL;
231	if (gser->port.in)
232		gser->port.in->driver_data = NULL;
233
234	ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
235
236	return status;
237}
238
239static void
240gser_unbind(struct usb_configuration *c, struct usb_function *f)
241{
242	if (gadget_is_dualspeed(c->cdev->gadget))
243		usb_free_descriptors(f->hs_descriptors);
244	usb_free_descriptors(f->descriptors);
245	kfree(func_to_gser(f));
246}
247
248/**
249 * gser_bind_config - add a generic serial function to a configuration
250 * @c: the configuration to support the serial instance
251 * @port_num: /dev/ttyGS* port this interface will use
252 * Context: single threaded during gadget setup
253 *
254 * Returns zero on success, else negative errno.
255 *
256 * Caller must have called @gserial_setup() with enough ports to
257 * handle all the ones it binds.  Caller is also responsible
258 * for calling @gserial_cleanup() before module unload.
259 */
260int __init gser_bind_config(struct usb_configuration *c, u8 port_num)
261{
262	struct f_gser	*gser;
263	int		status;
264
265	/* REVISIT might want instance-specific strings to help
266	 * distinguish instances ...
267	 */
268
269	/* maybe allocate device-global string ID */
270	if (gser_string_defs[0].id == 0) {
271		status = usb_string_id(c->cdev);
272		if (status < 0)
273			return status;
274		gser_string_defs[0].id = status;
275	}
276
277	/* allocate and initialize one new instance */
278	gser = kzalloc(sizeof *gser, GFP_KERNEL);
279	if (!gser)
280		return -ENOMEM;
281
282	gser->port_num = port_num;
283
284	gser->port.func.name = "gser";
285	gser->port.func.strings = gser_strings;
286	gser->port.func.bind = gser_bind;
287	gser->port.func.unbind = gser_unbind;
288	gser->port.func.set_alt = gser_set_alt;
289	gser->port.func.disable = gser_disable;
290
291	status = usb_add_function(c, &gser->port.func);
292	if (status)
293		kfree(gser);
294	return status;
295}
296