xref: /openbmc/linux/drivers/usb/gadget/legacy/acm_ms.c (revision c4c3c32d)
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 	int	status;
109 
110 	if (gadget_is_otg(c->cdev->gadget)) {
111 		c->descriptors = otg_desc;
112 		c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
113 	}
114 
115 	f_acm = usb_get_function(f_acm_inst);
116 	if (IS_ERR(f_acm))
117 		return PTR_ERR(f_acm);
118 
119 	f_msg = usb_get_function(fi_msg);
120 	if (IS_ERR(f_msg)) {
121 		status = PTR_ERR(f_msg);
122 		goto put_acm;
123 	}
124 
125 	status = usb_add_function(c, f_acm);
126 	if (status < 0)
127 		goto put_msg;
128 
129 	status = usb_add_function(c, f_msg);
130 	if (status)
131 		goto remove_acm;
132 
133 	return 0;
134 remove_acm:
135 	usb_remove_function(c, f_acm);
136 put_msg:
137 	usb_put_function(f_msg);
138 put_acm:
139 	usb_put_function(f_acm);
140 	return status;
141 }
142 
143 static struct usb_configuration acm_ms_config_driver = {
144 	.label			= DRIVER_DESC,
145 	.bConfigurationValue	= 1,
146 	/* .iConfiguration = DYNAMIC */
147 	.bmAttributes		= USB_CONFIG_ATT_SELFPOWER,
148 };
149 
150 /*-------------------------------------------------------------------------*/
151 
152 static int acm_ms_bind(struct usb_composite_dev *cdev)
153 {
154 	struct usb_gadget	*gadget = cdev->gadget;
155 	struct fsg_opts		*opts;
156 	struct fsg_config	config;
157 	int			status;
158 
159 	f_acm_inst = usb_get_function_instance("acm");
160 	if (IS_ERR(f_acm_inst))
161 		return PTR_ERR(f_acm_inst);
162 
163 	fi_msg = usb_get_function_instance("mass_storage");
164 	if (IS_ERR(fi_msg)) {
165 		status = PTR_ERR(fi_msg);
166 		goto fail_get_msg;
167 	}
168 
169 	/* set up mass storage function */
170 	fsg_config_from_params(&config, &fsg_mod_data, fsg_num_buffers);
171 	opts = fsg_opts_from_func_inst(fi_msg);
172 
173 	opts->no_configfs = true;
174 	status = fsg_common_set_num_buffers(opts->common, fsg_num_buffers);
175 	if (status)
176 		goto fail;
177 
178 	status = fsg_common_set_cdev(opts->common, cdev, config.can_stall);
179 	if (status)
180 		goto fail_set_cdev;
181 
182 	fsg_common_set_sysfs(opts->common, true);
183 	status = fsg_common_create_luns(opts->common, &config);
184 	if (status)
185 		goto fail_set_cdev;
186 
187 	fsg_common_set_inquiry_string(opts->common, config.vendor_name,
188 				      config.product_name);
189 	/*
190 	 * Allocate string descriptor numbers ... note that string
191 	 * contents can be overridden by the composite_dev glue.
192 	 */
193 	status = usb_string_ids_tab(cdev, strings_dev);
194 	if (status < 0)
195 		goto fail_string_ids;
196 	device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id;
197 	device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id;
198 
199 	if (gadget_is_otg(gadget) && !otg_desc[0]) {
200 		struct usb_descriptor_header *usb_desc;
201 
202 		usb_desc = usb_otg_descriptor_alloc(gadget);
203 		if (!usb_desc) {
204 			status = -ENOMEM;
205 			goto fail_string_ids;
206 		}
207 		usb_otg_descriptor_init(gadget, usb_desc);
208 		otg_desc[0] = usb_desc;
209 		otg_desc[1] = NULL;
210 	}
211 
212 	/* register our configuration */
213 	status = usb_add_config(cdev, &acm_ms_config_driver, acm_ms_do_config);
214 	if (status < 0)
215 		goto fail_otg_desc;
216 
217 	usb_composite_overwrite_options(cdev, &coverwrite);
218 	dev_info(&gadget->dev, "%s, version: " DRIVER_VERSION "\n",
219 			DRIVER_DESC);
220 	return 0;
221 
222 	/* error recovery */
223 fail_otg_desc:
224 	kfree(otg_desc[0]);
225 	otg_desc[0] = NULL;
226 fail_string_ids:
227 	fsg_common_remove_luns(opts->common);
228 fail_set_cdev:
229 	fsg_common_free_buffers(opts->common);
230 fail:
231 	usb_put_function_instance(fi_msg);
232 fail_get_msg:
233 	usb_put_function_instance(f_acm_inst);
234 	return status;
235 }
236 
237 static int acm_ms_unbind(struct usb_composite_dev *cdev)
238 {
239 	usb_put_function(f_msg);
240 	usb_put_function_instance(fi_msg);
241 	usb_put_function(f_acm);
242 	usb_put_function_instance(f_acm_inst);
243 	kfree(otg_desc[0]);
244 	otg_desc[0] = NULL;
245 
246 	return 0;
247 }
248 
249 static struct usb_composite_driver acm_ms_driver = {
250 	.name		= "g_acm_ms",
251 	.dev		= &device_desc,
252 	.max_speed	= USB_SPEED_SUPER,
253 	.strings	= dev_strings,
254 	.bind		= acm_ms_bind,
255 	.unbind		= acm_ms_unbind,
256 };
257 
258 module_usb_composite_driver(acm_ms_driver);
259 
260 MODULE_DESCRIPTION(DRIVER_DESC);
261 MODULE_AUTHOR("Klaus Schwarzkopf <schwarzkopf@sensortherm.de>");
262 MODULE_LICENSE("GPL v2");
263