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