aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/gadget/multi.c
diff options
context:
space:
mode:
authorMichal Nazarewicz <m.nazarewicz@samsung.com>2009-11-09 08:15:27 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2009-12-11 14:55:23 -0500
commitf176a5d81214864904d285912da02c4bc0e9041a (patch)
tree83a3c24aa437c1ac565df7c3873ceb13370d8ab6 /drivers/usb/gadget/multi.c
parentc85efcb9657a7c15e24c1d4745826a80f9a53bbe (diff)
USB: g_multi: Multifunction Composite Gadget added
The Multifunction Composite Gadget has two configurations consisting of Ethernet (RNDIS in first and CDC Ethernet in second configuration), CDC Serial and File-backed Storage functions. When connected to a Windows host, the first configuration is chosen thus gadget provides RNDIS Ethernet, serial and mass storage whereas when connected to Linux host, second configuration is chosen thus providing CDC Ethernet, serial and mass storage. Which configurations are built can be configured via KConfig options. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/gadget/multi.c')
-rw-r--r--drivers/usb/gadget/multi.c355
1 files changed, 355 insertions, 0 deletions
diff --git a/drivers/usb/gadget/multi.c b/drivers/usb/gadget/multi.c
new file mode 100644
index 000000000000..64711feca845
--- /dev/null
+++ b/drivers/usb/gadget/multi.c
@@ -0,0 +1,355 @@
1/*
2 * multi.c -- Multifunction Composite driver
3 *
4 * Copyright (C) 2008 David Brownell
5 * Copyright (C) 2008 Nokia Corporation
6 * Copyright (C) 2009 Samsung Electronics
7 * Author: Michal Nazarewicz (m.nazarewicz@samsung.com)
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23
24
25#include <linux/kernel.h>
26#include <linux/utsname.h>
27
28
29#if defined CONFIG_USB_G_MULTI_RNDIS
30# define CONFIG_USB_ETH_RNDIS y
31#endif
32
33
34#define DRIVER_DESC "Multifunction Composite Gadget"
35#define DRIVER_VERSION "2009/07/21"
36
37/*-------------------------------------------------------------------------*/
38
39#define MULTI_VENDOR_NUM 0x0525 /* XXX NetChip */
40#define MULTI_PRODUCT_NUM 0xa4ab /* XXX */
41
42/*-------------------------------------------------------------------------*/
43
44/*
45 * kbuild is not very cooperative with respect to linking separately
46 * compiled library objects into one module. So for now we won't use
47 * separate compilation ... ensuring init/exit sections work to shrink
48 * the runtime footprint, and giving us at least some parts of what
49 * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
50 */
51
52#include "composite.c"
53#include "usbstring.c"
54#include "config.c"
55#include "epautoconf.c"
56
57#include "u_serial.c"
58#include "f_acm.c"
59
60#include "f_ecm.c"
61#include "f_subset.c"
62#ifdef CONFIG_USB_ETH_RNDIS
63# include "f_rndis.c"
64# include "rndis.c"
65#endif
66#include "u_ether.c"
67
68#undef DBG /* u_ether.c has broken idea about macros */
69#undef VDBG /* so clean up after it */
70#undef ERROR
71#undef INFO
72#include "f_mass_storage.c"
73
74/*-------------------------------------------------------------------------*/
75
76static struct usb_device_descriptor device_desc = {
77 .bLength = sizeof device_desc,
78 .bDescriptorType = USB_DT_DEVICE,
79
80 .bcdUSB = cpu_to_le16(0x0200),
81
82 /* .bDeviceClass = USB_CLASS_COMM, */
83 /* .bDeviceSubClass = 0, */
84 /* .bDeviceProtocol = 0, */
85 .bDeviceClass = 0xEF,
86 .bDeviceSubClass = 2,
87 .bDeviceProtocol = 1,
88 /* .bMaxPacketSize0 = f(hardware) */
89
90 /* Vendor and product id can be overridden by module parameters. */
91 .idVendor = cpu_to_le16(MULTI_VENDOR_NUM),
92 .idProduct = cpu_to_le16(MULTI_PRODUCT_NUM),
93 /* .bcdDevice = f(hardware) */
94 /* .iManufacturer = DYNAMIC */
95 /* .iProduct = DYNAMIC */
96 /* NO SERIAL NUMBER */
97 .bNumConfigurations = 1,
98};
99
100static struct usb_otg_descriptor otg_descriptor = {
101 .bLength = sizeof otg_descriptor,
102 .bDescriptorType = USB_DT_OTG,
103
104 /* REVISIT SRP-only hardware is possible, although
105 * it would not be called "OTG" ...
106 */
107 .bmAttributes = USB_OTG_SRP | USB_OTG_HNP,
108};
109
110static const struct usb_descriptor_header *otg_desc[] = {
111 (struct usb_descriptor_header *) &otg_descriptor,
112 NULL,
113};
114
115
116/* string IDs are assigned dynamically */
117
118#define STRING_MANUFACTURER_IDX 0
119#define STRING_PRODUCT_IDX 1
120
121static char manufacturer[50];
122
123static struct usb_string strings_dev[] = {
124 [STRING_MANUFACTURER_IDX].s = manufacturer,
125 [STRING_PRODUCT_IDX].s = DRIVER_DESC,
126 { } /* end of list */
127};
128
129static struct usb_gadget_strings stringtab_dev = {
130 .language = 0x0409, /* en-us */
131 .strings = strings_dev,
132};
133
134static struct usb_gadget_strings *dev_strings[] = {
135 &stringtab_dev,
136 NULL,
137};
138
139static u8 hostaddr[ETH_ALEN];
140
141
142
143/****************************** Configurations ******************************/
144
145static struct fsg_module_parameters mod_data = {
146 .stall = 1
147};
148FSG_MODULE_PARAMETERS(/* no prefix */, mod_data);
149
150static struct fsg_common *fsg_common;
151
152
153#ifdef CONFIG_USB_ETH_RNDIS
154
155static int __init rndis_do_config(struct usb_configuration *c)
156{
157 int ret;
158
159 if (gadget_is_otg(c->cdev->gadget)) {
160 c->descriptors = otg_desc;
161 c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
162 }
163
164 ret = rndis_bind_config(c, hostaddr);
165 if (ret < 0)
166 return ret;
167
168 ret = acm_bind_config(c, 0);
169 if (ret < 0)
170 return ret;
171
172 ret = fsg_add(c->cdev, c, fsg_common);
173 if (ret < 0)
174 return ret;
175
176 return 0;
177}
178
179static struct usb_configuration rndis_config_driver = {
180 .label = "Multifunction Composite (RNDIS + MS + ACM)",
181 .bind = rndis_do_config,
182 .bConfigurationValue = 2,
183 /* .iConfiguration = DYNAMIC */
184 .bmAttributes = USB_CONFIG_ATT_SELFPOWER,
185};
186
187#endif
188
189#ifdef CONFIG_USB_G_MULTI_CDC
190
191static int __init cdc_do_config(struct usb_configuration *c)
192{
193 int ret;
194
195 if (gadget_is_otg(c->cdev->gadget)) {
196 c->descriptors = otg_desc;
197 c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
198 }
199
200 ret = ecm_bind_config(c, hostaddr);
201 if (ret < 0)
202 return ret;
203
204 ret = acm_bind_config(c, 0);
205 if (ret < 0)
206 return ret;
207
208 ret = fsg_add(c->cdev, c, fsg_common);
209 if (ret < 0)
210 return ret;
211 if (ret < 0)
212 return ret;
213
214 return 0;
215}
216
217static struct usb_configuration cdc_config_driver = {
218 .label = "Multifunction Composite (CDC + MS + ACM)",
219 .bind = cdc_do_config,
220 .bConfigurationValue = 1,
221 /* .iConfiguration = DYNAMIC */
222 .bmAttributes = USB_CONFIG_ATT_SELFPOWER,
223};
224
225#endif
226
227
228
229/****************************** Gadget Bind ******************************/
230
231
232static int __init multi_bind(struct usb_composite_dev *cdev)
233{
234 struct usb_gadget *gadget = cdev->gadget;
235 int status, gcnum;
236
237 if (!can_support_ecm(cdev->gadget)) {
238 dev_err(&gadget->dev, "controller '%s' not usable\n",
239 gadget->name);
240 return -EINVAL;
241 }
242
243 /* set up network link layer */
244 status = gether_setup(cdev->gadget, hostaddr);
245 if (status < 0)
246 return status;
247
248 /* set up serial link layer */
249 status = gserial_setup(cdev->gadget, 1);
250 if (status < 0)
251 goto fail0;
252
253 /* set up mass storage function */
254 fsg_common = fsg_common_from_params(0, cdev, &mod_data);
255 if (IS_ERR(fsg_common)) {
256 status = PTR_ERR(fsg_common);
257 goto fail1;
258 }
259
260
261 gcnum = usb_gadget_controller_number(gadget);
262 if (gcnum >= 0)
263 device_desc.bcdDevice = cpu_to_le16(0x0300 | gcnum);
264 else {
265 /* We assume that can_support_ecm() tells the truth;
266 * but if the controller isn't recognized at all then
267 * that assumption is a bit more likely to be wrong.
268 */
269 WARNING(cdev, "controller '%s' not recognized\n",
270 gadget->name);
271 device_desc.bcdDevice = cpu_to_le16(0x0300 | 0x0099);
272 }
273
274
275 /* Allocate string descriptor numbers ... note that string
276 * contents can be overridden by the composite_dev glue.
277 */
278
279 /* device descriptor strings: manufacturer, product */
280 snprintf(manufacturer, sizeof manufacturer, "%s %s with %s",
281 init_utsname()->sysname, init_utsname()->release,
282 gadget->name);
283 status = usb_string_id(cdev);
284 if (status < 0)
285 goto fail2;
286 strings_dev[STRING_MANUFACTURER_IDX].id = status;
287 device_desc.iManufacturer = status;
288
289 status = usb_string_id(cdev);
290 if (status < 0)
291 goto fail2;
292 strings_dev[STRING_PRODUCT_IDX].id = status;
293 device_desc.iProduct = status;
294
295#ifdef CONFIG_USB_ETH_RNDIS
296 /* register our first configuration */
297 status = usb_add_config(cdev, &rndis_config_driver);
298 if (status < 0)
299 goto fail2;
300#endif
301
302#ifdef CONFIG_USB_G_MULTI_CDC
303 /* register our second configuration */
304 status = usb_add_config(cdev, &cdc_config_driver);
305 if (status < 0)
306 goto fail2;
307#endif
308
309 dev_info(&gadget->dev, DRIVER_DESC ", version: " DRIVER_VERSION "\n");
310 fsg_common_put(fsg_common);
311 return 0;
312
313fail2:
314 fsg_common_put(fsg_common);
315fail1:
316 gserial_cleanup();
317fail0:
318 gether_cleanup();
319 return status;
320}
321
322static int __exit multi_unbind(struct usb_composite_dev *cdev)
323{
324 gserial_cleanup();
325 gether_cleanup();
326 return 0;
327}
328
329
330/****************************** Some noise ******************************/
331
332
333static struct usb_composite_driver multi_driver = {
334 .name = "g_multi",
335 .dev = &device_desc,
336 .strings = dev_strings,
337 .bind = multi_bind,
338 .unbind = __exit_p(multi_unbind),
339};
340
341MODULE_DESCRIPTION(DRIVER_DESC);
342MODULE_AUTHOR("Michal Nazarewicz");
343MODULE_LICENSE("GPL");
344
345static int __init g_multi_init(void)
346{
347 return usb_composite_register(&multi_driver);
348}
349module_init(g_multi_init);
350
351static void __exit g_multi_cleanup(void)
352{
353 usb_composite_unregister(&multi_driver);
354}
355module_exit(g_multi_cleanup);