Linux Audio

Check our new training course

Loading...
Note: File does not exist in v4.17.
  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#include <linux/module.h>
 28
 29
 30#if defined USB_ETH_RNDIS
 31#  undef USB_ETH_RNDIS
 32#endif
 33#ifdef CONFIG_USB_G_MULTI_RNDIS
 34#  define USB_ETH_RNDIS y
 35#endif
 36
 37
 38#define DRIVER_DESC		"Multifunction Composite Gadget"
 39
 40MODULE_DESCRIPTION(DRIVER_DESC);
 41MODULE_AUTHOR("Michal Nazarewicz");
 42MODULE_LICENSE("GPL");
 43
 44
 45/***************************** All the files... *****************************/
 46
 47/*
 48 * kbuild is not very cooperative with respect to linking separately
 49 * compiled library objects into one module.  So for now we won't use
 50 * separate compilation ... ensuring init/exit sections work to shrink
 51 * the runtime footprint, and giving us at least some parts of what
 52 * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
 53 */
 54
 55#include "composite.c"
 56#include "usbstring.c"
 57#include "config.c"
 58#include "epautoconf.c"
 59
 60#include "f_mass_storage.c"
 61
 62#include "u_serial.c"
 63#include "f_acm.c"
 64
 65#include "f_ecm.c"
 66#include "f_subset.c"
 67#ifdef USB_ETH_RNDIS
 68#  include "f_rndis.c"
 69#  include "rndis.c"
 70#endif
 71#include "u_ether.c"
 72
 73
 74
 75/***************************** Device Descriptor ****************************/
 76
 77#define MULTI_VENDOR_NUM	0x1d6b	/* Linux Foundation */
 78#define MULTI_PRODUCT_NUM	0x0104	/* Multifunction Composite Gadget */
 79
 80
 81enum {
 82	__MULTI_NO_CONFIG,
 83#ifdef CONFIG_USB_G_MULTI_RNDIS
 84	MULTI_RNDIS_CONFIG_NUM,
 85#endif
 86#ifdef CONFIG_USB_G_MULTI_CDC
 87	MULTI_CDC_CONFIG_NUM,
 88#endif
 89};
 90
 91
 92static struct usb_device_descriptor device_desc = {
 93	.bLength =		sizeof device_desc,
 94	.bDescriptorType =	USB_DT_DEVICE,
 95
 96	.bcdUSB =		cpu_to_le16(0x0200),
 97
 98	.bDeviceClass =		USB_CLASS_MISC /* 0xEF */,
 99	.bDeviceSubClass =	2,
100	.bDeviceProtocol =	1,
101
102	/* Vendor and product id can be overridden by module parameters.  */
103	.idVendor =		cpu_to_le16(MULTI_VENDOR_NUM),
104	.idProduct =		cpu_to_le16(MULTI_PRODUCT_NUM),
105};
106
107
108static const struct usb_descriptor_header *otg_desc[] = {
109	(struct usb_descriptor_header *) &(struct usb_otg_descriptor){
110		.bLength =		sizeof(struct usb_otg_descriptor),
111		.bDescriptorType =	USB_DT_OTG,
112
113		/*
114		 * REVISIT SRP-only hardware is possible, although
115		 * it would not be called "OTG" ...
116		 */
117		.bmAttributes =		USB_OTG_SRP | USB_OTG_HNP,
118	},
119	NULL,
120};
121
122
123enum {
124#ifdef CONFIG_USB_G_MULTI_RNDIS
125	MULTI_STRING_RNDIS_CONFIG_IDX,
126#endif
127#ifdef CONFIG_USB_G_MULTI_CDC
128	MULTI_STRING_CDC_CONFIG_IDX,
129#endif
130};
131
132static struct usb_string strings_dev[] = {
133#ifdef CONFIG_USB_G_MULTI_RNDIS
134	[MULTI_STRING_RNDIS_CONFIG_IDX].s = "Multifunction with RNDIS",
135#endif
136#ifdef CONFIG_USB_G_MULTI_CDC
137	[MULTI_STRING_CDC_CONFIG_IDX].s   = "Multifunction with CDC ECM",
138#endif
139	{  } /* end of list */
140};
141
142static struct usb_gadget_strings *dev_strings[] = {
143	&(struct usb_gadget_strings){
144		.language	= 0x0409,	/* en-us */
145		.strings	= strings_dev,
146	},
147	NULL,
148};
149
150
151
152
153/****************************** Configurations ******************************/
154
155static struct fsg_module_parameters fsg_mod_data = { .stall = 1 };
156FSG_MODULE_PARAMETERS(/* no prefix */, fsg_mod_data);
157
158static struct fsg_common fsg_common;
159
160static u8 hostaddr[ETH_ALEN];
161
162
163/********** RNDIS **********/
164
165#ifdef USB_ETH_RNDIS
166
167static __init int rndis_do_config(struct usb_configuration *c)
168{
169	int ret;
170
171	if (gadget_is_otg(c->cdev->gadget)) {
172		c->descriptors = otg_desc;
173		c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
174	}
175
176	ret = rndis_bind_config(c, hostaddr);
177	if (ret < 0)
178		return ret;
179
180	ret = acm_bind_config(c, 0);
181	if (ret < 0)
182		return ret;
183
184	ret = fsg_bind_config(c->cdev, c, &fsg_common);
185	if (ret < 0)
186		return ret;
187
188	return 0;
189}
190
191static int rndis_config_register(struct usb_composite_dev *cdev)
192{
193	static struct usb_configuration config = {
194		.bConfigurationValue	= MULTI_RNDIS_CONFIG_NUM,
195		.bmAttributes		= USB_CONFIG_ATT_SELFPOWER,
196	};
197
198	config.label          = strings_dev[MULTI_STRING_RNDIS_CONFIG_IDX].s;
199	config.iConfiguration = strings_dev[MULTI_STRING_RNDIS_CONFIG_IDX].id;
200
201	return usb_add_config(cdev, &config, rndis_do_config);
202}
203
204#else
205
206static int rndis_config_register(struct usb_composite_dev *cdev)
207{
208	return 0;
209}
210
211#endif
212
213
214/********** CDC ECM **********/
215
216#ifdef CONFIG_USB_G_MULTI_CDC
217
218static __init int cdc_do_config(struct usb_configuration *c)
219{
220	int ret;
221
222	if (gadget_is_otg(c->cdev->gadget)) {
223		c->descriptors = otg_desc;
224		c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
225	}
226
227	ret = ecm_bind_config(c, hostaddr);
228	if (ret < 0)
229		return ret;
230
231	ret = acm_bind_config(c, 0);
232	if (ret < 0)
233		return ret;
234
235	ret = fsg_bind_config(c->cdev, c, &fsg_common);
236	if (ret < 0)
237		return ret;
238
239	return 0;
240}
241
242static int cdc_config_register(struct usb_composite_dev *cdev)
243{
244	static struct usb_configuration config = {
245		.bConfigurationValue	= MULTI_CDC_CONFIG_NUM,
246		.bmAttributes		= USB_CONFIG_ATT_SELFPOWER,
247	};
248
249	config.label          = strings_dev[MULTI_STRING_CDC_CONFIG_IDX].s;
250	config.iConfiguration = strings_dev[MULTI_STRING_CDC_CONFIG_IDX].id;
251
252	return usb_add_config(cdev, &config, cdc_do_config);
253}
254
255#else
256
257static int cdc_config_register(struct usb_composite_dev *cdev)
258{
259	return 0;
260}
261
262#endif
263
264
265
266/****************************** Gadget Bind ******************************/
267
268
269static int __ref multi_bind(struct usb_composite_dev *cdev)
270{
271	struct usb_gadget *gadget = cdev->gadget;
272	int status, gcnum;
273
274	if (!can_support_ecm(cdev->gadget)) {
275		dev_err(&gadget->dev, "controller '%s' not usable\n",
276		        gadget->name);
277		return -EINVAL;
278	}
279
280	/* set up network link layer */
281	status = gether_setup(cdev->gadget, hostaddr);
282	if (status < 0)
283		return status;
284
285	/* set up serial link layer */
286	status = gserial_setup(cdev->gadget, 1);
287	if (status < 0)
288		goto fail0;
289
290	/* set up mass storage function */
291	{
292		void *retp;
293		retp = fsg_common_from_params(&fsg_common, cdev, &fsg_mod_data);
294		if (IS_ERR(retp)) {
295			status = PTR_ERR(retp);
296			goto fail1;
297		}
298	}
299
300	/* set bcdDevice */
301	gcnum = usb_gadget_controller_number(gadget);
302	if (gcnum >= 0) {
303		device_desc.bcdDevice = cpu_to_le16(0x0300 | gcnum);
304	} else {
305		WARNING(cdev, "controller '%s' not recognized\n", gadget->name);
306		device_desc.bcdDevice = cpu_to_le16(0x0300 | 0x0099);
307	}
308
309	/* allocate string IDs */
310	status = usb_string_ids_tab(cdev, strings_dev);
311	if (unlikely(status < 0))
312		goto fail2;
313
314	/* register configurations */
315	status = rndis_config_register(cdev);
316	if (unlikely(status < 0))
317		goto fail2;
318
319	status = cdc_config_register(cdev);
320	if (unlikely(status < 0))
321		goto fail2;
322
323	/* we're done */
324	dev_info(&gadget->dev, DRIVER_DESC "\n");
325	fsg_common_put(&fsg_common);
326	return 0;
327
328
329	/* error recovery */
330fail2:
331	fsg_common_put(&fsg_common);
332fail1:
333	gserial_cleanup();
334fail0:
335	gether_cleanup();
336	return status;
337}
338
339static int __exit multi_unbind(struct usb_composite_dev *cdev)
340{
341	gserial_cleanup();
342	gether_cleanup();
343	return 0;
344}
345
346
347/****************************** Some noise ******************************/
348
349
350static struct usb_composite_driver multi_driver = {
351	.name		= "g_multi",
352	.dev		= &device_desc,
353	.strings	= dev_strings,
354	.max_speed	= USB_SPEED_HIGH,
355	.unbind		= __exit_p(multi_unbind),
356	.iProduct	= DRIVER_DESC,
357	.needs_serial	= 1,
358};
359
360
361static int __init multi_init(void)
362{
363	return usb_composite_probe(&multi_driver, multi_bind);
364}
365module_init(multi_init);
366
367static void __exit multi_exit(void)
368{
369	usb_composite_unregister(&multi_driver);
370}
371module_exit(multi_exit);