Linux Audio

Check our new training course

Loading...
Note: File does not exist in v4.6.
  1/*
  2 * acm_ms.c -- Composite driver, with ACM and mass storage support
  3 *
  4 * Copyright (C) 2008 David Brownell
  5 * Copyright (C) 2008 Nokia Corporation
  6 * Author: David Brownell
  7 * Modified: Klaus Schwarzkopf <schwarzkopf@sensortherm.de>
  8 *
  9 * Heavily based on multi.c and cdc2.c
 10 *
 11 * This program is free software; you can redistribute it and/or modify
 12 * it under the terms of the GNU General Public License as published by
 13 * the Free Software Foundation; either version 2 of the License, or
 14 * (at your option) any later version.
 15 */
 16
 17#include <linux/kernel.h>
 18#include <linux/module.h>
 19
 20#include "u_serial.h"
 21
 22#define DRIVER_DESC		"Composite Gadget (ACM + MS)"
 23#define DRIVER_VERSION		"2011/10/10"
 24
 25/*-------------------------------------------------------------------------*/
 26
 27/*
 28 * DO NOT REUSE THESE IDs with a protocol-incompatible driver!!  Ever!!
 29 * Instead:  allocate your own, using normal USB-IF procedures.
 30 */
 31#define ACM_MS_VENDOR_NUM	0x1d6b	/* Linux Foundation */
 32#define ACM_MS_PRODUCT_NUM	0x0106	/* Composite Gadget: ACM + MS*/
 33
 34#include "f_mass_storage.h"
 35
 36/*-------------------------------------------------------------------------*/
 37USB_GADGET_COMPOSITE_OPTIONS();
 38
 39static struct usb_device_descriptor device_desc = {
 40	.bLength =		sizeof device_desc,
 41	.bDescriptorType =	USB_DT_DEVICE,
 42
 43	.bcdUSB =		cpu_to_le16(0x0200),
 44
 45	.bDeviceClass =		USB_CLASS_MISC /* 0xEF */,
 46	.bDeviceSubClass =	2,
 47	.bDeviceProtocol =	1,
 48
 49	/* .bMaxPacketSize0 = f(hardware) */
 50
 51	/* Vendor and product id can be overridden by module parameters.  */
 52	.idVendor =		cpu_to_le16(ACM_MS_VENDOR_NUM),
 53	.idProduct =		cpu_to_le16(ACM_MS_PRODUCT_NUM),
 54	/* .bcdDevice = f(hardware) */
 55	/* .iManufacturer = DYNAMIC */
 56	/* .iProduct = DYNAMIC */
 57	/* NO SERIAL NUMBER */
 58	/*.bNumConfigurations =	DYNAMIC*/
 59};
 60
 61static struct usb_otg_descriptor otg_descriptor = {
 62	.bLength =		sizeof otg_descriptor,
 63	.bDescriptorType =	USB_DT_OTG,
 64
 65	/*
 66	 * REVISIT SRP-only hardware is possible, although
 67	 * it would not be called "OTG" ...
 68	 */
 69	.bmAttributes =		USB_OTG_SRP | USB_OTG_HNP,
 70};
 71
 72static const struct usb_descriptor_header *otg_desc[] = {
 73	(struct usb_descriptor_header *) &otg_descriptor,
 74	NULL,
 75};
 76
 77/* string IDs are assigned dynamically */
 78static struct usb_string strings_dev[] = {
 79	[USB_GADGET_MANUFACTURER_IDX].s = "",
 80	[USB_GADGET_PRODUCT_IDX].s = DRIVER_DESC,
 81	[USB_GADGET_SERIAL_IDX].s = "",
 82	{  } /* end of list */
 83};
 84
 85static struct usb_gadget_strings stringtab_dev = {
 86	.language	= 0x0409,	/* en-us */
 87	.strings	= strings_dev,
 88};
 89
 90static struct usb_gadget_strings *dev_strings[] = {
 91	&stringtab_dev,
 92	NULL,
 93};
 94
 95/****************************** Configurations ******************************/
 96
 97static struct fsg_module_parameters fsg_mod_data = { .stall = 1 };
 98#ifdef CONFIG_USB_GADGET_DEBUG_FILES
 99
100static unsigned int fsg_num_buffers = CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS;
101
102#else
103
104/*
105 * Number of buffers we will use.
106 * 2 is usually enough for good buffering pipeline
107 */
108#define fsg_num_buffers	CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS
109
110#endif /* CONFIG_USB_GADGET_DEBUG_FILES */
111
112FSG_MODULE_PARAMETERS(/* no prefix */, fsg_mod_data);
113
114/*-------------------------------------------------------------------------*/
115static struct usb_function *f_acm;
116static struct usb_function_instance *f_acm_inst;
117
118static struct usb_function_instance *fi_msg;
119static struct usb_function *f_msg;
120
121/*
122 * We _always_ have both ACM and mass storage functions.
123 */
124static int __init acm_ms_do_config(struct usb_configuration *c)
125{
126	struct fsg_opts *opts;
127	int	status;
128
129	if (gadget_is_otg(c->cdev->gadget)) {
130		c->descriptors = otg_desc;
131		c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
132	}
133
134	opts = fsg_opts_from_func_inst(fi_msg);
135
136	f_acm = usb_get_function(f_acm_inst);
137	if (IS_ERR(f_acm))
138		return PTR_ERR(f_acm);
139
140	f_msg = usb_get_function(fi_msg);
141	if (IS_ERR(f_msg)) {
142		status = PTR_ERR(f_msg);
143		goto put_acm;
144	}
145
146	status = usb_add_function(c, f_acm);
147	if (status < 0)
148		goto put_msg;
149
150	status = fsg_common_run_thread(opts->common);
151	if (status)
152		goto remove_acm;
153
154	status = usb_add_function(c, f_msg);
155	if (status)
156		goto remove_acm;
157
158	return 0;
159remove_acm:
160	usb_remove_function(c, f_acm);
161put_msg:
162	usb_put_function(f_msg);
163put_acm:
164	usb_put_function(f_acm);
165	return status;
166}
167
168static struct usb_configuration acm_ms_config_driver = {
169	.label			= DRIVER_DESC,
170	.bConfigurationValue	= 1,
171	/* .iConfiguration = DYNAMIC */
172	.bmAttributes		= USB_CONFIG_ATT_SELFPOWER,
173};
174
175/*-------------------------------------------------------------------------*/
176
177static int __init acm_ms_bind(struct usb_composite_dev *cdev)
178{
179	struct usb_gadget	*gadget = cdev->gadget;
180	struct fsg_opts		*opts;
181	struct fsg_config	config;
182	int			status;
183
184	f_acm_inst = usb_get_function_instance("acm");
185	if (IS_ERR(f_acm_inst))
186		return PTR_ERR(f_acm_inst);
187
188	fi_msg = usb_get_function_instance("mass_storage");
189	if (IS_ERR(fi_msg)) {
190		status = PTR_ERR(fi_msg);
191		goto fail_get_msg;
192	}
193
194	/* set up mass storage function */
195	fsg_config_from_params(&config, &fsg_mod_data, fsg_num_buffers);
196	opts = fsg_opts_from_func_inst(fi_msg);
197
198	opts->no_configfs = true;
199	status = fsg_common_set_num_buffers(opts->common, fsg_num_buffers);
200	if (status)
201		goto fail;
202
203	status = fsg_common_set_nluns(opts->common, config.nluns);
204	if (status)
205		goto fail_set_nluns;
206
207	status = fsg_common_set_cdev(opts->common, cdev, config.can_stall);
208	if (status)
209		goto fail_set_cdev;
210
211	fsg_common_set_sysfs(opts->common, true);
212	status = fsg_common_create_luns(opts->common, &config);
213	if (status)
214		goto fail_set_cdev;
215
216	fsg_common_set_inquiry_string(opts->common, config.vendor_name,
217				      config.product_name);
218	/*
219	 * Allocate string descriptor numbers ... note that string
220	 * contents can be overridden by the composite_dev glue.
221	 */
222	status = usb_string_ids_tab(cdev, strings_dev);
223	if (status < 0)
224		goto fail_string_ids;
225	device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id;
226	device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id;
227
228	/* register our configuration */
229	status = usb_add_config(cdev, &acm_ms_config_driver, acm_ms_do_config);
230	if (status < 0)
231		goto fail_string_ids;
232
233	usb_composite_overwrite_options(cdev, &coverwrite);
234	dev_info(&gadget->dev, "%s, version: " DRIVER_VERSION "\n",
235			DRIVER_DESC);
236	return 0;
237
238	/* error recovery */
239fail_string_ids:
240	fsg_common_remove_luns(opts->common);
241fail_set_cdev:
242	fsg_common_free_luns(opts->common);
243fail_set_nluns:
244	fsg_common_free_buffers(opts->common);
245fail:
246	usb_put_function_instance(fi_msg);
247fail_get_msg:
248	usb_put_function_instance(f_acm_inst);
249	return status;
250}
251
252static int __exit acm_ms_unbind(struct usb_composite_dev *cdev)
253{
254	usb_put_function(f_msg);
255	usb_put_function_instance(fi_msg);
256	usb_put_function(f_acm);
257	usb_put_function_instance(f_acm_inst);
258	return 0;
259}
260
261static __refdata struct usb_composite_driver acm_ms_driver = {
262	.name		= "g_acm_ms",
263	.dev		= &device_desc,
264	.max_speed	= USB_SPEED_SUPER,
265	.strings	= dev_strings,
266	.bind		= acm_ms_bind,
267	.unbind		= __exit_p(acm_ms_unbind),
268};
269
270MODULE_DESCRIPTION(DRIVER_DESC);
271MODULE_AUTHOR("Klaus Schwarzkopf <schwarzkopf@sensortherm.de>");
272MODULE_LICENSE("GPL v2");
273
274static int __init init(void)
275{
276	return usb_composite_probe(&acm_ms_driver);
277}
278module_init(init);
279
280static void __exit cleanup(void)
281{
282	usb_composite_unregister(&acm_ms_driver);
283}
284module_exit(cleanup);