blob: 34427553271e9aea12807044c9ee72917c262c45 [file] [log] [blame]
Michal Nazarewiczf176a5d2009-11-09 14:15:27 +01001/*
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
Michal Nazarewicz54b83602012-01-13 15:05:16 +01007 * Author: Michal Nazarewicz (mina86@mina86.com)
Michal Nazarewiczf176a5d2009-11-09 14:15:27 +01008 *
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.
Michal Nazarewiczf176a5d2009-11-09 14:15:27 +010013 */
14
15
16#include <linux/kernel.h>
Michal Nazarewicz279cc492010-06-21 13:57:03 +020017#include <linux/module.h>
Michal Nazarewiczf176a5d2009-11-09 14:15:27 +010018
Sebastian Andrzej Siewior59835ad2012-12-23 21:10:10 +010019#include "u_serial.h"
Michal Nazarewicz396cda92009-11-30 10:55:40 +010020#if defined USB_ETH_RNDIS
21# undef USB_ETH_RNDIS
22#endif
Michal Nazarewiczdbe4a992010-01-22 15:18:21 +010023#ifdef CONFIG_USB_G_MULTI_RNDIS
Michal Nazarewicz396cda92009-11-30 10:55:40 +010024# define USB_ETH_RNDIS y
Michal Nazarewiczf176a5d2009-11-09 14:15:27 +010025#endif
26
27
28#define DRIVER_DESC "Multifunction Composite Gadget"
Michal Nazarewiczf176a5d2009-11-09 14:15:27 +010029
Michal Nazarewicz279cc492010-06-21 13:57:03 +020030MODULE_DESCRIPTION(DRIVER_DESC);
31MODULE_AUTHOR("Michal Nazarewicz");
32MODULE_LICENSE("GPL");
Michal Nazarewiczf176a5d2009-11-09 14:15:27 +010033
Michal Nazarewiczf176a5d2009-11-09 14:15:27 +010034
Michal Nazarewicz279cc492010-06-21 13:57:03 +020035/***************************** All the files... *****************************/
Michal Nazarewiczf176a5d2009-11-09 14:15:27 +010036
37/*
38 * kbuild is not very cooperative with respect to linking separately
39 * compiled library objects into one module. So for now we won't use
40 * separate compilation ... ensuring init/exit sections work to shrink
41 * the runtime footprint, and giving us at least some parts of what
42 * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
43 */
Michal Nazarewicz279cc492010-06-21 13:57:03 +020044#include "f_mass_storage.c"
Michal Nazarewiczf176a5d2009-11-09 14:15:27 +010045
46#include "f_ecm.c"
47#include "f_subset.c"
Michal Nazarewicz396cda92009-11-30 10:55:40 +010048#ifdef USB_ETH_RNDIS
Michal Nazarewiczf176a5d2009-11-09 14:15:27 +010049# include "f_rndis.c"
50# include "rndis.c"
51#endif
52#include "u_ether.c"
53
Sebastian Andrzej Siewior7d16e8d2012-09-10 15:01:53 +020054USB_GADGET_COMPOSITE_OPTIONS();
Michal Nazarewicz279cc492010-06-21 13:57:03 +020055
56/***************************** Device Descriptor ****************************/
57
Michal Nazarewicz1c6529e2010-08-12 17:43:44 +020058#define MULTI_VENDOR_NUM 0x1d6b /* Linux Foundation */
59#define MULTI_PRODUCT_NUM 0x0104 /* Multifunction Composite Gadget */
Michal Nazarewicz279cc492010-06-21 13:57:03 +020060
61
62enum {
63 __MULTI_NO_CONFIG,
64#ifdef CONFIG_USB_G_MULTI_RNDIS
65 MULTI_RNDIS_CONFIG_NUM,
66#endif
67#ifdef CONFIG_USB_G_MULTI_CDC
68 MULTI_CDC_CONFIG_NUM,
69#endif
70};
71
Michal Nazarewiczf176a5d2009-11-09 14:15:27 +010072
73static struct usb_device_descriptor device_desc = {
74 .bLength = sizeof device_desc,
75 .bDescriptorType = USB_DT_DEVICE,
76
77 .bcdUSB = cpu_to_le16(0x0200),
78
Michal Nazarewicz279cc492010-06-21 13:57:03 +020079 .bDeviceClass = USB_CLASS_MISC /* 0xEF */,
Michal Nazarewiczf176a5d2009-11-09 14:15:27 +010080 .bDeviceSubClass = 2,
81 .bDeviceProtocol = 1,
Michal Nazarewiczf176a5d2009-11-09 14:15:27 +010082
83 /* Vendor and product id can be overridden by module parameters. */
84 .idVendor = cpu_to_le16(MULTI_VENDOR_NUM),
85 .idProduct = cpu_to_le16(MULTI_PRODUCT_NUM),
Michal Nazarewiczf176a5d2009-11-09 14:15:27 +010086};
87
Michal Nazarewiczf176a5d2009-11-09 14:15:27 +010088
89static const struct usb_descriptor_header *otg_desc[] = {
Michal Nazarewicz279cc492010-06-21 13:57:03 +020090 (struct usb_descriptor_header *) &(struct usb_otg_descriptor){
91 .bLength = sizeof(struct usb_otg_descriptor),
92 .bDescriptorType = USB_DT_OTG,
93
94 /*
95 * REVISIT SRP-only hardware is possible, although
96 * it would not be called "OTG" ...
97 */
98 .bmAttributes = USB_OTG_SRP | USB_OTG_HNP,
99 },
Michal Nazarewiczf176a5d2009-11-09 14:15:27 +0100100 NULL,
101};
102
103
Michal Nazarewicz279cc492010-06-21 13:57:03 +0200104enum {
Sebastian Andrzej Siewior276e2e42012-09-06 20:11:21 +0200105 MULTI_STRING_RNDIS_CONFIG_IDX = USB_GADGET_FIRST_AVAIL_IDX,
Michal Nazarewicz279cc492010-06-21 13:57:03 +0200106 MULTI_STRING_CDC_CONFIG_IDX,
Michal Nazarewicz279cc492010-06-21 13:57:03 +0200107};
Michal Nazarewiczf176a5d2009-11-09 14:15:27 +0100108
Michal Nazarewiczf176a5d2009-11-09 14:15:27 +0100109static struct usb_string strings_dev[] = {
Sebastian Andrzej Siewior276e2e42012-09-06 20:11:21 +0200110 [USB_GADGET_MANUFACTURER_IDX].s = "",
Sebastian Andrzej Siewiord33f74f2012-09-10 15:01:57 +0200111 [USB_GADGET_PRODUCT_IDX].s = DRIVER_DESC,
Sebastian Andrzej Siewior276e2e42012-09-06 20:11:21 +0200112 [USB_GADGET_SERIAL_IDX].s = "",
Michal Nazarewicz279cc492010-06-21 13:57:03 +0200113 [MULTI_STRING_RNDIS_CONFIG_IDX].s = "Multifunction with RNDIS",
Michal Nazarewicz279cc492010-06-21 13:57:03 +0200114 [MULTI_STRING_CDC_CONFIG_IDX].s = "Multifunction with CDC ECM",
Michal Nazarewiczf176a5d2009-11-09 14:15:27 +0100115 { } /* end of list */
116};
117
Michal Nazarewiczf176a5d2009-11-09 14:15:27 +0100118static struct usb_gadget_strings *dev_strings[] = {
Michal Nazarewicz279cc492010-06-21 13:57:03 +0200119 &(struct usb_gadget_strings){
120 .language = 0x0409, /* en-us */
121 .strings = strings_dev,
122 },
Michal Nazarewiczf176a5d2009-11-09 14:15:27 +0100123 NULL,
124};
125
Michal Nazarewiczf176a5d2009-11-09 14:15:27 +0100126
127
128
129/****************************** Configurations ******************************/
130
Michal Nazarewicz279cc492010-06-21 13:57:03 +0200131static struct fsg_module_parameters fsg_mod_data = { .stall = 1 };
132FSG_MODULE_PARAMETERS(/* no prefix */, fsg_mod_data);
Michal Nazarewiczf176a5d2009-11-09 14:15:27 +0100133
Michal Nazarewicz279cc492010-06-21 13:57:03 +0200134static struct fsg_common fsg_common;
Michal Nazarewiczf176a5d2009-11-09 14:15:27 +0100135
Michal Nazarewicz279cc492010-06-21 13:57:03 +0200136static u8 hostaddr[ETH_ALEN];
137
Sebastian Andrzej Siewior19b10a82012-12-23 21:10:06 +0100138static unsigned char tty_line;
Sebastian Andrzej Siewior59835ad2012-12-23 21:10:10 +0100139static struct usb_function_instance *fi_acm;
Sebastian Andrzej Siewiord6a01432012-12-23 21:10:12 +0100140static struct eth_dev *the_dev;
Michal Nazarewicz279cc492010-06-21 13:57:03 +0200141
142/********** RNDIS **********/
Michal Nazarewiczf176a5d2009-11-09 14:15:27 +0100143
Michal Nazarewicz396cda92009-11-30 10:55:40 +0100144#ifdef USB_ETH_RNDIS
Sebastian Andrzej Siewior59835ad2012-12-23 21:10:10 +0100145static struct usb_function *f_acm_rndis;
Michal Nazarewiczf176a5d2009-11-09 14:15:27 +0100146
Uwe Kleine-Königc9bfff92010-08-12 17:43:55 +0200147static __init int rndis_do_config(struct usb_configuration *c)
Michal Nazarewiczf176a5d2009-11-09 14:15:27 +0100148{
149 int ret;
150
151 if (gadget_is_otg(c->cdev->gadget)) {
152 c->descriptors = otg_desc;
153 c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
154 }
155
Sebastian Andrzej Siewiord6a01432012-12-23 21:10:12 +0100156 ret = rndis_bind_config(c, hostaddr, the_dev);
Michal Nazarewiczf176a5d2009-11-09 14:15:27 +0100157 if (ret < 0)
158 return ret;
159
Sebastian Andrzej Siewior59835ad2012-12-23 21:10:10 +0100160 f_acm_rndis = usb_get_function(fi_acm);
161 if (IS_ERR(f_acm_rndis))
162 goto err_func_acm;
163
164 ret = usb_add_function(c, f_acm_rndis);
165 if (ret)
166 goto err_conf;
Michal Nazarewiczf176a5d2009-11-09 14:15:27 +0100167
Michal Nazarewicz279cc492010-06-21 13:57:03 +0200168 ret = fsg_bind_config(c->cdev, c, &fsg_common);
Michal Nazarewiczf176a5d2009-11-09 14:15:27 +0100169 if (ret < 0)
Sebastian Andrzej Siewior59835ad2012-12-23 21:10:10 +0100170 goto err_fsg;
Michal Nazarewiczf176a5d2009-11-09 14:15:27 +0100171
172 return 0;
Sebastian Andrzej Siewior59835ad2012-12-23 21:10:10 +0100173err_fsg:
174 usb_remove_function(c, f_acm_rndis);
175err_conf:
176 usb_put_function(f_acm_rndis);
177err_func_acm:
178 return ret;
Michal Nazarewiczf176a5d2009-11-09 14:15:27 +0100179}
180
Michal Nazarewicz279cc492010-06-21 13:57:03 +0200181static int rndis_config_register(struct usb_composite_dev *cdev)
182{
183 static struct usb_configuration config = {
Michal Nazarewicz279cc492010-06-21 13:57:03 +0200184 .bConfigurationValue = MULTI_RNDIS_CONFIG_NUM,
185 .bmAttributes = USB_CONFIG_ATT_SELFPOWER,
186 };
187
188 config.label = strings_dev[MULTI_STRING_RNDIS_CONFIG_IDX].s;
189 config.iConfiguration = strings_dev[MULTI_STRING_RNDIS_CONFIG_IDX].id;
190
Uwe Kleine-Königc9bfff92010-08-12 17:43:55 +0200191 return usb_add_config(cdev, &config, rndis_do_config);
Michal Nazarewicz279cc492010-06-21 13:57:03 +0200192}
193
194#else
195
196static int rndis_config_register(struct usb_composite_dev *cdev)
197{
198 return 0;
199}
Michal Nazarewiczf176a5d2009-11-09 14:15:27 +0100200
201#endif
202
Michal Nazarewicz279cc492010-06-21 13:57:03 +0200203
204/********** CDC ECM **********/
205
Michal Nazarewiczf176a5d2009-11-09 14:15:27 +0100206#ifdef CONFIG_USB_G_MULTI_CDC
Sebastian Andrzej Siewior59835ad2012-12-23 21:10:10 +0100207static struct usb_function *f_acm_multi;
Michal Nazarewiczf176a5d2009-11-09 14:15:27 +0100208
Uwe Kleine-Königc9bfff92010-08-12 17:43:55 +0200209static __init int cdc_do_config(struct usb_configuration *c)
Michal Nazarewiczf176a5d2009-11-09 14:15:27 +0100210{
211 int ret;
212
213 if (gadget_is_otg(c->cdev->gadget)) {
214 c->descriptors = otg_desc;
215 c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
216 }
217
Sebastian Andrzej Siewiord6a01432012-12-23 21:10:12 +0100218 ret = ecm_bind_config(c, hostaddr, the_dev);
Michal Nazarewiczf176a5d2009-11-09 14:15:27 +0100219 if (ret < 0)
220 return ret;
221
Sebastian Andrzej Siewior59835ad2012-12-23 21:10:10 +0100222 /* implicit port_num is zero */
223 f_acm_multi = usb_get_function(fi_acm);
224 if (IS_ERR(f_acm_multi))
225 goto err_func_acm;
226
227 ret = usb_add_function(c, f_acm_multi);
228 if (ret)
229 goto err_conf;
Michal Nazarewiczf176a5d2009-11-09 14:15:27 +0100230
Michal Nazarewicz279cc492010-06-21 13:57:03 +0200231 ret = fsg_bind_config(c->cdev, c, &fsg_common);
Michal Nazarewiczf176a5d2009-11-09 14:15:27 +0100232 if (ret < 0)
Sebastian Andrzej Siewior59835ad2012-12-23 21:10:10 +0100233 goto err_fsg;
Michal Nazarewiczf176a5d2009-11-09 14:15:27 +0100234
235 return 0;
Sebastian Andrzej Siewior59835ad2012-12-23 21:10:10 +0100236err_fsg:
237 usb_remove_function(c, f_acm_multi);
238err_conf:
239 usb_put_function(f_acm_multi);
240err_func_acm:
241 return ret;
Michal Nazarewiczf176a5d2009-11-09 14:15:27 +0100242}
243
Michal Nazarewicz279cc492010-06-21 13:57:03 +0200244static int cdc_config_register(struct usb_composite_dev *cdev)
245{
246 static struct usb_configuration config = {
Michal Nazarewicz279cc492010-06-21 13:57:03 +0200247 .bConfigurationValue = MULTI_CDC_CONFIG_NUM,
248 .bmAttributes = USB_CONFIG_ATT_SELFPOWER,
249 };
250
251 config.label = strings_dev[MULTI_STRING_CDC_CONFIG_IDX].s;
252 config.iConfiguration = strings_dev[MULTI_STRING_CDC_CONFIG_IDX].id;
253
Uwe Kleine-Königc9bfff92010-08-12 17:43:55 +0200254 return usb_add_config(cdev, &config, cdc_do_config);
Michal Nazarewicz279cc492010-06-21 13:57:03 +0200255}
256
257#else
258
259static int cdc_config_register(struct usb_composite_dev *cdev)
260{
261 return 0;
262}
Michal Nazarewiczf176a5d2009-11-09 14:15:27 +0100263
264#endif
265
266
267
268/****************************** Gadget Bind ******************************/
269
Michal Nazarewicz279cc492010-06-21 13:57:03 +0200270static int __ref multi_bind(struct usb_composite_dev *cdev)
Michal Nazarewiczf176a5d2009-11-09 14:15:27 +0100271{
272 struct usb_gadget *gadget = cdev->gadget;
Sebastian Andrzej Siewior59835ad2012-12-23 21:10:10 +0100273 struct f_serial_opts *opts;
Sebastian Andrzej Siewiored9cbda2012-09-10 09:16:07 +0200274 int status;
Michal Nazarewiczf176a5d2009-11-09 14:15:27 +0100275
276 if (!can_support_ecm(cdev->gadget)) {
277 dev_err(&gadget->dev, "controller '%s' not usable\n",
278 gadget->name);
279 return -EINVAL;
280 }
281
282 /* set up network link layer */
Sebastian Andrzej Siewiord6a01432012-12-23 21:10:12 +0100283 the_dev = gether_setup(cdev->gadget, hostaddr);
284 if (IS_ERR(the_dev))
285 return PTR_ERR(the_dev);
Michal Nazarewiczf176a5d2009-11-09 14:15:27 +0100286
287 /* set up serial link layer */
Sebastian Andrzej Siewior19b10a82012-12-23 21:10:06 +0100288 status = gserial_alloc_line(&tty_line);
Michal Nazarewiczf176a5d2009-11-09 14:15:27 +0100289 if (status < 0)
290 goto fail0;
291
Sebastian Andrzej Siewior59835ad2012-12-23 21:10:10 +0100292 fi_acm = usb_get_function_instance("acm");
293 if (IS_ERR(fi_acm)) {
294 status = PTR_ERR(fi_acm);
295 goto fail0dot5;
296 }
297
298 opts = container_of(fi_acm, struct f_serial_opts, func_inst);
299 opts->port_num = tty_line;
300
Michal Nazarewiczf176a5d2009-11-09 14:15:27 +0100301 /* set up mass storage function */
Michal Nazarewicz279cc492010-06-21 13:57:03 +0200302 {
303 void *retp;
304 retp = fsg_common_from_params(&fsg_common, cdev, &fsg_mod_data);
305 if (IS_ERR(retp)) {
306 status = PTR_ERR(retp);
307 goto fail1;
308 }
Michal Nazarewiczf176a5d2009-11-09 14:15:27 +0100309 }
310
Michal Nazarewicza99d8a42010-08-12 17:43:49 +0200311 /* allocate string IDs */
Michal Nazarewicz279cc492010-06-21 13:57:03 +0200312 status = usb_string_ids_tab(cdev, strings_dev);
313 if (unlikely(status < 0))
Michal Nazarewiczf176a5d2009-11-09 14:15:27 +0100314 goto fail2;
Sebastian Andrzej Siewiord33f74f2012-09-10 15:01:57 +0200315 device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id;
Michal Nazarewiczf176a5d2009-11-09 14:15:27 +0100316
Michal Nazarewicz279cc492010-06-21 13:57:03 +0200317 /* register configurations */
318 status = rndis_config_register(cdev);
319 if (unlikely(status < 0))
Michal Nazarewiczf176a5d2009-11-09 14:15:27 +0100320 goto fail2;
Michal Nazarewiczf176a5d2009-11-09 14:15:27 +0100321
Michal Nazarewicz279cc492010-06-21 13:57:03 +0200322 status = cdc_config_register(cdev);
323 if (unlikely(status < 0))
Michal Nazarewiczf176a5d2009-11-09 14:15:27 +0100324 goto fail2;
Sebastian Andrzej Siewior7d16e8d2012-09-10 15:01:53 +0200325 usb_composite_overwrite_options(cdev, &coverwrite);
Michal Nazarewiczf176a5d2009-11-09 14:15:27 +0100326
Michal Nazarewicz279cc492010-06-21 13:57:03 +0200327 /* we're done */
328 dev_info(&gadget->dev, DRIVER_DESC "\n");
329 fsg_common_put(&fsg_common);
Michal Nazarewiczf176a5d2009-11-09 14:15:27 +0100330 return 0;
331
Michal Nazarewicz279cc492010-06-21 13:57:03 +0200332
333 /* error recovery */
Michal Nazarewiczf176a5d2009-11-09 14:15:27 +0100334fail2:
Michal Nazarewicz279cc492010-06-21 13:57:03 +0200335 fsg_common_put(&fsg_common);
Michal Nazarewiczf176a5d2009-11-09 14:15:27 +0100336fail1:
Sebastian Andrzej Siewior59835ad2012-12-23 21:10:10 +0100337 usb_put_function_instance(fi_acm);
338fail0dot5:
Sebastian Andrzej Siewior19b10a82012-12-23 21:10:06 +0100339 gserial_free_line(tty_line);
Michal Nazarewiczf176a5d2009-11-09 14:15:27 +0100340fail0:
Sebastian Andrzej Siewiord6a01432012-12-23 21:10:12 +0100341 gether_cleanup(the_dev);
Michal Nazarewiczf176a5d2009-11-09 14:15:27 +0100342 return status;
343}
344
345static int __exit multi_unbind(struct usb_composite_dev *cdev)
346{
Sebastian Andrzej Siewior59835ad2012-12-23 21:10:10 +0100347#ifdef CONFIG_USB_G_MULTI_CDC
348 usb_put_function(f_acm_multi);
349#endif
350#ifdef USB_ETH_RNDIS
351 usb_put_function(f_acm_rndis);
352#endif
353 usb_put_function_instance(fi_acm);
Sebastian Andrzej Siewior19b10a82012-12-23 21:10:06 +0100354 gserial_free_line(tty_line);
Sebastian Andrzej Siewiord6a01432012-12-23 21:10:12 +0100355 gether_cleanup(the_dev);
Michal Nazarewiczf176a5d2009-11-09 14:15:27 +0100356 return 0;
357}
358
359
360/****************************** Some noise ******************************/
361
362
Sebastian Andrzej Siewiorc2ec75c2012-09-06 20:11:03 +0200363static __refdata struct usb_composite_driver multi_driver = {
Michal Nazarewiczf176a5d2009-11-09 14:15:27 +0100364 .name = "g_multi",
365 .dev = &device_desc,
366 .strings = dev_strings,
Tatyana Brokhman35a0e0b2011-06-29 16:41:49 +0300367 .max_speed = USB_SPEED_HIGH,
Sebastian Andrzej Siewior03e42bd2012-09-06 20:11:04 +0200368 .bind = multi_bind,
Michal Nazarewiczf176a5d2009-11-09 14:15:27 +0100369 .unbind = __exit_p(multi_unbind),
Michal Nazarewicza99d8a42010-08-12 17:43:49 +0200370 .needs_serial = 1,
Michal Nazarewiczf176a5d2009-11-09 14:15:27 +0100371};
372
Michal Nazarewiczf176a5d2009-11-09 14:15:27 +0100373
Michal Nazarewicz279cc492010-06-21 13:57:03 +0200374static int __init multi_init(void)
Michal Nazarewiczf176a5d2009-11-09 14:15:27 +0100375{
Sebastian Andrzej Siewior03e42bd2012-09-06 20:11:04 +0200376 return usb_composite_probe(&multi_driver);
Michal Nazarewiczf176a5d2009-11-09 14:15:27 +0100377}
Michal Nazarewicz279cc492010-06-21 13:57:03 +0200378module_init(multi_init);
Michal Nazarewiczf176a5d2009-11-09 14:15:27 +0100379
Michal Nazarewicz279cc492010-06-21 13:57:03 +0200380static void __exit multi_exit(void)
Michal Nazarewiczf176a5d2009-11-09 14:15:27 +0100381{
382 usb_composite_unregister(&multi_driver);
383}
Michal Nazarewicz279cc492010-06-21 13:57:03 +0200384module_exit(multi_exit);