1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* |
3 | * multi.c -- Multifunction Composite driver |
4 | * |
5 | * Copyright (C) 2008 David Brownell |
6 | * Copyright (C) 2008 Nokia Corporation |
7 | * Copyright (C) 2009 Samsung Electronics |
8 | * Author: Michal Nazarewicz (mina86@mina86.com) |
9 | */ |
10 | |
11 | |
12 | #include <linux/kernel.h> |
13 | #include <linux/module.h> |
14 | #include <linux/netdevice.h> |
15 | |
16 | #include "u_serial.h" |
17 | #if defined USB_ETH_RNDIS |
18 | # undef USB_ETH_RNDIS |
19 | #endif |
20 | #ifdef CONFIG_USB_G_MULTI_RNDIS |
21 | # define USB_ETH_RNDIS y |
22 | #endif |
23 | |
24 | |
25 | #define DRIVER_DESC "Multifunction Composite Gadget" |
26 | |
27 | MODULE_DESCRIPTION(DRIVER_DESC); |
28 | MODULE_AUTHOR("Michal Nazarewicz" ); |
29 | MODULE_LICENSE("GPL" ); |
30 | |
31 | |
32 | #include "f_mass_storage.h" |
33 | |
34 | #include "u_ecm.h" |
35 | #ifdef USB_ETH_RNDIS |
36 | # include "u_rndis.h" |
37 | # include "rndis.h" |
38 | #endif |
39 | #include "u_ether.h" |
40 | |
41 | USB_GADGET_COMPOSITE_OPTIONS(); |
42 | |
43 | USB_ETHERNET_MODULE_PARAMETERS(); |
44 | |
45 | /***************************** Device Descriptor ****************************/ |
46 | |
47 | #define MULTI_VENDOR_NUM 0x1d6b /* Linux Foundation */ |
48 | #define MULTI_PRODUCT_NUM 0x0104 /* Multifunction Composite Gadget */ |
49 | |
50 | |
51 | enum { |
52 | __MULTI_NO_CONFIG, |
53 | #ifdef CONFIG_USB_G_MULTI_RNDIS |
54 | MULTI_RNDIS_CONFIG_NUM, |
55 | #endif |
56 | #ifdef CONFIG_USB_G_MULTI_CDC |
57 | MULTI_CDC_CONFIG_NUM, |
58 | #endif |
59 | }; |
60 | |
61 | |
62 | static struct usb_device_descriptor device_desc = { |
63 | .bLength = sizeof device_desc, |
64 | .bDescriptorType = USB_DT_DEVICE, |
65 | |
66 | /* .bcdUSB = DYNAMIC */ |
67 | |
68 | .bDeviceClass = USB_CLASS_MISC /* 0xEF */, |
69 | .bDeviceSubClass = 2, |
70 | .bDeviceProtocol = 1, |
71 | |
72 | /* Vendor and product id can be overridden by module parameters. */ |
73 | .idVendor = cpu_to_le16(MULTI_VENDOR_NUM), |
74 | .idProduct = cpu_to_le16(MULTI_PRODUCT_NUM), |
75 | }; |
76 | |
77 | static const struct usb_descriptor_header *otg_desc[2]; |
78 | |
79 | enum { |
80 | MULTI_STRING_RNDIS_CONFIG_IDX = USB_GADGET_FIRST_AVAIL_IDX, |
81 | MULTI_STRING_CDC_CONFIG_IDX, |
82 | }; |
83 | |
84 | static struct usb_string strings_dev[] = { |
85 | [USB_GADGET_MANUFACTURER_IDX].s = "" , |
86 | [USB_GADGET_PRODUCT_IDX].s = DRIVER_DESC, |
87 | [USB_GADGET_SERIAL_IDX].s = "" , |
88 | [MULTI_STRING_RNDIS_CONFIG_IDX].s = "Multifunction with RNDIS" , |
89 | [MULTI_STRING_CDC_CONFIG_IDX].s = "Multifunction with CDC ECM" , |
90 | { } /* end of list */ |
91 | }; |
92 | |
93 | static struct usb_gadget_strings *dev_strings[] = { |
94 | &(struct usb_gadget_strings){ |
95 | .language = 0x0409, /* en-us */ |
96 | .strings = strings_dev, |
97 | }, |
98 | NULL, |
99 | }; |
100 | |
101 | |
102 | |
103 | |
104 | /****************************** Configurations ******************************/ |
105 | |
106 | static struct fsg_module_parameters fsg_mod_data = { .stall = 1 }; |
107 | #ifdef CONFIG_USB_GADGET_DEBUG_FILES |
108 | |
109 | static unsigned int fsg_num_buffers = CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS; |
110 | |
111 | #else |
112 | |
113 | /* |
114 | * Number of buffers we will use. |
115 | * 2 is usually enough for good buffering pipeline |
116 | */ |
117 | #define fsg_num_buffers CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS |
118 | |
119 | #endif /* CONFIG_USB_GADGET_DEBUG_FILES */ |
120 | |
121 | FSG_MODULE_PARAMETERS(/* no prefix */, fsg_mod_data); |
122 | |
123 | static struct usb_function_instance *fi_acm; |
124 | static struct usb_function_instance *fi_msg; |
125 | |
126 | /********** RNDIS **********/ |
127 | |
128 | #ifdef USB_ETH_RNDIS |
129 | static struct usb_function_instance *fi_rndis; |
130 | static struct usb_function *f_acm_rndis; |
131 | static struct usb_function *f_rndis; |
132 | static struct usb_function *f_msg_rndis; |
133 | |
134 | static int rndis_do_config(struct usb_configuration *c) |
135 | { |
136 | int ret; |
137 | |
138 | if (gadget_is_otg(g: c->cdev->gadget)) { |
139 | c->descriptors = otg_desc; |
140 | c->bmAttributes |= USB_CONFIG_ATT_WAKEUP; |
141 | } |
142 | |
143 | f_rndis = usb_get_function(fi: fi_rndis); |
144 | if (IS_ERR(ptr: f_rndis)) |
145 | return PTR_ERR(ptr: f_rndis); |
146 | |
147 | ret = usb_add_function(c, f_rndis); |
148 | if (ret < 0) |
149 | goto err_func_rndis; |
150 | |
151 | f_acm_rndis = usb_get_function(fi: fi_acm); |
152 | if (IS_ERR(ptr: f_acm_rndis)) { |
153 | ret = PTR_ERR(ptr: f_acm_rndis); |
154 | goto err_func_acm; |
155 | } |
156 | |
157 | ret = usb_add_function(c, f_acm_rndis); |
158 | if (ret) |
159 | goto err_conf; |
160 | |
161 | f_msg_rndis = usb_get_function(fi: fi_msg); |
162 | if (IS_ERR(ptr: f_msg_rndis)) { |
163 | ret = PTR_ERR(ptr: f_msg_rndis); |
164 | goto err_fsg; |
165 | } |
166 | |
167 | ret = usb_add_function(c, f_msg_rndis); |
168 | if (ret) |
169 | goto err_run; |
170 | |
171 | return 0; |
172 | err_run: |
173 | usb_put_function(f: f_msg_rndis); |
174 | err_fsg: |
175 | usb_remove_function(c, f: f_acm_rndis); |
176 | err_conf: |
177 | usb_put_function(f: f_acm_rndis); |
178 | err_func_acm: |
179 | usb_remove_function(c, f: f_rndis); |
180 | err_func_rndis: |
181 | usb_put_function(f: f_rndis); |
182 | return ret; |
183 | } |
184 | |
185 | static int rndis_config_register(struct usb_composite_dev *cdev) |
186 | { |
187 | static struct usb_configuration config = { |
188 | .bConfigurationValue = MULTI_RNDIS_CONFIG_NUM, |
189 | .bmAttributes = USB_CONFIG_ATT_SELFPOWER, |
190 | }; |
191 | |
192 | config.label = strings_dev[MULTI_STRING_RNDIS_CONFIG_IDX].s; |
193 | config.iConfiguration = strings_dev[MULTI_STRING_RNDIS_CONFIG_IDX].id; |
194 | |
195 | return usb_add_config(cdev, &config, rndis_do_config); |
196 | } |
197 | |
198 | #else |
199 | |
200 | static int rndis_config_register(struct usb_composite_dev *cdev) |
201 | { |
202 | return 0; |
203 | } |
204 | |
205 | #endif |
206 | |
207 | |
208 | /********** CDC ECM **********/ |
209 | |
210 | #ifdef CONFIG_USB_G_MULTI_CDC |
211 | static struct usb_function_instance *fi_ecm; |
212 | static struct usb_function *f_acm_multi; |
213 | static struct usb_function *f_ecm; |
214 | static struct usb_function *f_msg_multi; |
215 | |
216 | static int cdc_do_config(struct usb_configuration *c) |
217 | { |
218 | int ret; |
219 | |
220 | if (gadget_is_otg(g: c->cdev->gadget)) { |
221 | c->descriptors = otg_desc; |
222 | c->bmAttributes |= USB_CONFIG_ATT_WAKEUP; |
223 | } |
224 | |
225 | f_ecm = usb_get_function(fi: fi_ecm); |
226 | if (IS_ERR(ptr: f_ecm)) |
227 | return PTR_ERR(ptr: f_ecm); |
228 | |
229 | ret = usb_add_function(c, f_ecm); |
230 | if (ret < 0) |
231 | goto err_func_ecm; |
232 | |
233 | /* implicit port_num is zero */ |
234 | f_acm_multi = usb_get_function(fi: fi_acm); |
235 | if (IS_ERR(ptr: f_acm_multi)) { |
236 | ret = PTR_ERR(ptr: f_acm_multi); |
237 | goto err_func_acm; |
238 | } |
239 | |
240 | ret = usb_add_function(c, f_acm_multi); |
241 | if (ret) |
242 | goto err_conf; |
243 | |
244 | f_msg_multi = usb_get_function(fi: fi_msg); |
245 | if (IS_ERR(ptr: f_msg_multi)) { |
246 | ret = PTR_ERR(ptr: f_msg_multi); |
247 | goto err_fsg; |
248 | } |
249 | |
250 | ret = usb_add_function(c, f_msg_multi); |
251 | if (ret) |
252 | goto err_run; |
253 | |
254 | return 0; |
255 | err_run: |
256 | usb_put_function(f: f_msg_multi); |
257 | err_fsg: |
258 | usb_remove_function(c, f: f_acm_multi); |
259 | err_conf: |
260 | usb_put_function(f: f_acm_multi); |
261 | err_func_acm: |
262 | usb_remove_function(c, f: f_ecm); |
263 | err_func_ecm: |
264 | usb_put_function(f: f_ecm); |
265 | return ret; |
266 | } |
267 | |
268 | static int cdc_config_register(struct usb_composite_dev *cdev) |
269 | { |
270 | static struct usb_configuration config = { |
271 | .bConfigurationValue = MULTI_CDC_CONFIG_NUM, |
272 | .bmAttributes = USB_CONFIG_ATT_SELFPOWER, |
273 | }; |
274 | |
275 | config.label = strings_dev[MULTI_STRING_CDC_CONFIG_IDX].s; |
276 | config.iConfiguration = strings_dev[MULTI_STRING_CDC_CONFIG_IDX].id; |
277 | |
278 | return usb_add_config(cdev, &config, cdc_do_config); |
279 | } |
280 | |
281 | #else |
282 | |
283 | static int cdc_config_register(struct usb_composite_dev *cdev) |
284 | { |
285 | return 0; |
286 | } |
287 | |
288 | #endif |
289 | |
290 | |
291 | |
292 | /****************************** Gadget Bind ******************************/ |
293 | |
294 | static int multi_bind(struct usb_composite_dev *cdev) |
295 | { |
296 | struct usb_gadget *gadget = cdev->gadget; |
297 | #ifdef CONFIG_USB_G_MULTI_CDC |
298 | struct f_ecm_opts *ecm_opts; |
299 | #endif |
300 | #ifdef USB_ETH_RNDIS |
301 | struct f_rndis_opts *rndis_opts; |
302 | #endif |
303 | struct fsg_opts *fsg_opts; |
304 | struct fsg_config config; |
305 | int status; |
306 | |
307 | if (!can_support_ecm(gadget: cdev->gadget)) { |
308 | dev_err(&gadget->dev, "controller '%s' not usable\n" , |
309 | gadget->name); |
310 | return -EINVAL; |
311 | } |
312 | |
313 | #ifdef CONFIG_USB_G_MULTI_CDC |
314 | fi_ecm = usb_get_function_instance(name: "ecm" ); |
315 | if (IS_ERR(ptr: fi_ecm)) |
316 | return PTR_ERR(ptr: fi_ecm); |
317 | |
318 | ecm_opts = container_of(fi_ecm, struct f_ecm_opts, func_inst); |
319 | |
320 | gether_set_qmult(net: ecm_opts->net, qmult); |
321 | if (!gether_set_host_addr(net: ecm_opts->net, host_addr)) |
322 | pr_info("using host ethernet address: %s" , host_addr); |
323 | if (!gether_set_dev_addr(net: ecm_opts->net, dev_addr)) |
324 | pr_info("using self ethernet address: %s" , dev_addr); |
325 | #endif |
326 | |
327 | #ifdef USB_ETH_RNDIS |
328 | fi_rndis = usb_get_function_instance(name: "rndis" ); |
329 | if (IS_ERR(ptr: fi_rndis)) { |
330 | status = PTR_ERR(ptr: fi_rndis); |
331 | goto fail; |
332 | } |
333 | |
334 | rndis_opts = container_of(fi_rndis, struct f_rndis_opts, func_inst); |
335 | |
336 | gether_set_qmult(net: rndis_opts->net, qmult); |
337 | if (!gether_set_host_addr(net: rndis_opts->net, host_addr)) |
338 | pr_info("using host ethernet address: %s" , host_addr); |
339 | if (!gether_set_dev_addr(net: rndis_opts->net, dev_addr)) |
340 | pr_info("using self ethernet address: %s" , dev_addr); |
341 | #endif |
342 | |
343 | #if (defined CONFIG_USB_G_MULTI_CDC && defined USB_ETH_RNDIS) |
344 | /* |
345 | * If both ecm and rndis are selected then: |
346 | * 1) rndis borrows the net interface from ecm |
347 | * 2) since the interface is shared it must not be bound |
348 | * twice - in ecm's _and_ rndis' binds, so do it here. |
349 | */ |
350 | gether_set_gadget(net: ecm_opts->net, g: cdev->gadget); |
351 | status = gether_register_netdev(net: ecm_opts->net); |
352 | if (status) |
353 | goto fail0; |
354 | |
355 | rndis_borrow_net(f: fi_rndis, net: ecm_opts->net); |
356 | ecm_opts->bound = true; |
357 | #endif |
358 | |
359 | /* set up serial link layer */ |
360 | fi_acm = usb_get_function_instance(name: "acm" ); |
361 | if (IS_ERR(ptr: fi_acm)) { |
362 | status = PTR_ERR(ptr: fi_acm); |
363 | goto fail0; |
364 | } |
365 | |
366 | /* set up mass storage function */ |
367 | fi_msg = usb_get_function_instance(name: "mass_storage" ); |
368 | if (IS_ERR(ptr: fi_msg)) { |
369 | status = PTR_ERR(ptr: fi_msg); |
370 | goto fail1; |
371 | } |
372 | fsg_config_from_params(cfg: &config, params: &fsg_mod_data, fsg_num_buffers); |
373 | fsg_opts = fsg_opts_from_func_inst(fi: fi_msg); |
374 | |
375 | fsg_opts->no_configfs = true; |
376 | status = fsg_common_set_num_buffers(common: fsg_opts->common, n: fsg_num_buffers); |
377 | if (status) |
378 | goto fail2; |
379 | |
380 | status = fsg_common_set_cdev(common: fsg_opts->common, cdev, can_stall: config.can_stall); |
381 | if (status) |
382 | goto fail_set_cdev; |
383 | |
384 | fsg_common_set_sysfs(common: fsg_opts->common, sysfs: true); |
385 | status = fsg_common_create_luns(common: fsg_opts->common, cfg: &config); |
386 | if (status) |
387 | goto fail_set_cdev; |
388 | |
389 | fsg_common_set_inquiry_string(common: fsg_opts->common, vn: config.vendor_name, |
390 | pn: config.product_name); |
391 | |
392 | /* allocate string IDs */ |
393 | status = usb_string_ids_tab(c: cdev, str: strings_dev); |
394 | if (unlikely(status < 0)) |
395 | goto fail_string_ids; |
396 | device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id; |
397 | |
398 | if (gadget_is_otg(g: gadget) && !otg_desc[0]) { |
399 | struct usb_descriptor_header *usb_desc; |
400 | |
401 | usb_desc = usb_otg_descriptor_alloc(gadget); |
402 | if (!usb_desc) { |
403 | status = -ENOMEM; |
404 | goto fail_string_ids; |
405 | } |
406 | usb_otg_descriptor_init(gadget, otg_desc: usb_desc); |
407 | otg_desc[0] = usb_desc; |
408 | otg_desc[1] = NULL; |
409 | } |
410 | |
411 | /* register configurations */ |
412 | status = rndis_config_register(cdev); |
413 | if (unlikely(status < 0)) |
414 | goto fail_otg_desc; |
415 | |
416 | status = cdc_config_register(cdev); |
417 | if (unlikely(status < 0)) |
418 | goto fail_otg_desc; |
419 | usb_composite_overwrite_options(cdev, covr: &coverwrite); |
420 | |
421 | /* we're done */ |
422 | dev_info(&gadget->dev, DRIVER_DESC "\n" ); |
423 | return 0; |
424 | |
425 | |
426 | /* error recovery */ |
427 | fail_otg_desc: |
428 | kfree(objp: otg_desc[0]); |
429 | otg_desc[0] = NULL; |
430 | fail_string_ids: |
431 | fsg_common_remove_luns(common: fsg_opts->common); |
432 | fail_set_cdev: |
433 | fsg_common_free_buffers(common: fsg_opts->common); |
434 | fail2: |
435 | usb_put_function_instance(fi: fi_msg); |
436 | fail1: |
437 | usb_put_function_instance(fi: fi_acm); |
438 | fail0: |
439 | #ifdef USB_ETH_RNDIS |
440 | usb_put_function_instance(fi: fi_rndis); |
441 | fail: |
442 | #endif |
443 | #ifdef CONFIG_USB_G_MULTI_CDC |
444 | usb_put_function_instance(fi: fi_ecm); |
445 | #endif |
446 | return status; |
447 | } |
448 | |
449 | static int multi_unbind(struct usb_composite_dev *cdev) |
450 | { |
451 | #ifdef CONFIG_USB_G_MULTI_CDC |
452 | usb_put_function(f: f_msg_multi); |
453 | #endif |
454 | #ifdef USB_ETH_RNDIS |
455 | usb_put_function(f: f_msg_rndis); |
456 | #endif |
457 | usb_put_function_instance(fi: fi_msg); |
458 | #ifdef CONFIG_USB_G_MULTI_CDC |
459 | usb_put_function(f: f_acm_multi); |
460 | #endif |
461 | #ifdef USB_ETH_RNDIS |
462 | usb_put_function(f: f_acm_rndis); |
463 | #endif |
464 | usb_put_function_instance(fi: fi_acm); |
465 | #ifdef USB_ETH_RNDIS |
466 | usb_put_function(f: f_rndis); |
467 | usb_put_function_instance(fi: fi_rndis); |
468 | #endif |
469 | #ifdef CONFIG_USB_G_MULTI_CDC |
470 | usb_put_function(f: f_ecm); |
471 | usb_put_function_instance(fi: fi_ecm); |
472 | #endif |
473 | kfree(objp: otg_desc[0]); |
474 | otg_desc[0] = NULL; |
475 | |
476 | return 0; |
477 | } |
478 | |
479 | |
480 | /****************************** Some noise ******************************/ |
481 | |
482 | |
483 | static struct usb_composite_driver multi_driver = { |
484 | .name = "g_multi" , |
485 | .dev = &device_desc, |
486 | .strings = dev_strings, |
487 | .max_speed = USB_SPEED_SUPER, |
488 | .bind = multi_bind, |
489 | .unbind = multi_unbind, |
490 | .needs_serial = 1, |
491 | }; |
492 | |
493 | module_usb_composite_driver(multi_driver); |
494 | |