1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* |
3 | * g_ffs.c -- user mode file system API for USB composite function controllers |
4 | * |
5 | * Copyright (C) 2010 Samsung Electronics |
6 | * Author: Michal Nazarewicz <mina86@mina86.com> |
7 | */ |
8 | |
9 | #define pr_fmt(fmt) "g_ffs: " fmt |
10 | |
11 | #include <linux/module.h> |
12 | |
13 | #if defined CONFIG_USB_FUNCTIONFS_ETH || defined CONFIG_USB_FUNCTIONFS_RNDIS |
14 | #include <linux/netdevice.h> |
15 | |
16 | # if defined USB_ETH_RNDIS |
17 | # undef USB_ETH_RNDIS |
18 | # endif |
19 | # ifdef CONFIG_USB_FUNCTIONFS_RNDIS |
20 | # define USB_ETH_RNDIS y |
21 | # endif |
22 | |
23 | # include "u_ecm.h" |
24 | # include "u_gether.h" |
25 | # ifdef USB_ETH_RNDIS |
26 | # include "u_rndis.h" |
27 | # include "rndis.h" |
28 | # endif |
29 | # include "u_ether.h" |
30 | |
31 | USB_ETHERNET_MODULE_PARAMETERS(); |
32 | |
33 | # ifdef CONFIG_USB_FUNCTIONFS_ETH |
34 | static int eth_bind_config(struct usb_configuration *c); |
35 | static struct usb_function_instance *fi_ecm; |
36 | static struct usb_function *f_ecm; |
37 | static struct usb_function_instance *fi_geth; |
38 | static struct usb_function *f_geth; |
39 | # endif |
40 | # ifdef CONFIG_USB_FUNCTIONFS_RNDIS |
41 | static int bind_rndis_config(struct usb_configuration *c); |
42 | static struct usb_function_instance *fi_rndis; |
43 | static struct usb_function *f_rndis; |
44 | # endif |
45 | #endif |
46 | |
47 | #include "u_fs.h" |
48 | |
49 | #define DRIVER_NAME "g_ffs" |
50 | #define DRIVER_DESC "USB Function Filesystem" |
51 | #define DRIVER_VERSION "24 Aug 2004" |
52 | |
53 | MODULE_DESCRIPTION(DRIVER_DESC); |
54 | MODULE_AUTHOR("Michal Nazarewicz" ); |
55 | MODULE_LICENSE("GPL" ); |
56 | |
57 | #define GFS_VENDOR_ID 0x1d6b /* Linux Foundation */ |
58 | #define GFS_PRODUCT_ID 0x0105 /* FunctionFS Gadget */ |
59 | |
60 | #define GFS_MAX_DEVS 10 |
61 | |
62 | USB_GADGET_COMPOSITE_OPTIONS(); |
63 | |
64 | static struct usb_device_descriptor gfs_dev_desc = { |
65 | .bLength = sizeof gfs_dev_desc, |
66 | .bDescriptorType = USB_DT_DEVICE, |
67 | |
68 | /* .bcdUSB = DYNAMIC */ |
69 | .bDeviceClass = USB_CLASS_PER_INTERFACE, |
70 | |
71 | .idVendor = cpu_to_le16(GFS_VENDOR_ID), |
72 | .idProduct = cpu_to_le16(GFS_PRODUCT_ID), |
73 | }; |
74 | |
75 | static char *func_names[GFS_MAX_DEVS]; |
76 | static unsigned int func_num; |
77 | |
78 | module_param_named(bDeviceClass, gfs_dev_desc.bDeviceClass, byte, 0644); |
79 | MODULE_PARM_DESC(bDeviceClass, "USB Device class" ); |
80 | module_param_named(bDeviceSubClass, gfs_dev_desc.bDeviceSubClass, byte, 0644); |
81 | MODULE_PARM_DESC(bDeviceSubClass, "USB Device subclass" ); |
82 | module_param_named(bDeviceProtocol, gfs_dev_desc.bDeviceProtocol, byte, 0644); |
83 | MODULE_PARM_DESC(bDeviceProtocol, "USB Device protocol" ); |
84 | module_param_array_named(functions, func_names, charp, &func_num, 0); |
85 | MODULE_PARM_DESC(functions, "USB Functions list" ); |
86 | |
87 | static const struct usb_descriptor_header *gfs_otg_desc[2]; |
88 | |
89 | /* String IDs are assigned dynamically */ |
90 | static struct usb_string gfs_strings[] = { |
91 | [USB_GADGET_MANUFACTURER_IDX].s = "" , |
92 | [USB_GADGET_PRODUCT_IDX].s = DRIVER_DESC, |
93 | [USB_GADGET_SERIAL_IDX].s = "" , |
94 | #ifdef CONFIG_USB_FUNCTIONFS_RNDIS |
95 | { .s = "FunctionFS + RNDIS" }, |
96 | #endif |
97 | #ifdef CONFIG_USB_FUNCTIONFS_ETH |
98 | { .s = "FunctionFS + ECM" }, |
99 | #endif |
100 | #ifdef CONFIG_USB_FUNCTIONFS_GENERIC |
101 | { .s = "FunctionFS" }, |
102 | #endif |
103 | { } /* end of list */ |
104 | }; |
105 | |
106 | static struct usb_gadget_strings *gfs_dev_strings[] = { |
107 | &(struct usb_gadget_strings) { |
108 | .language = 0x0409, /* en-us */ |
109 | .strings = gfs_strings, |
110 | }, |
111 | NULL, |
112 | }; |
113 | |
114 | struct gfs_configuration { |
115 | struct usb_configuration c; |
116 | int (*eth)(struct usb_configuration *c); |
117 | int num; |
118 | }; |
119 | |
120 | static struct gfs_configuration gfs_configurations[] = { |
121 | #ifdef CONFIG_USB_FUNCTIONFS_RNDIS |
122 | { |
123 | .eth = bind_rndis_config, |
124 | }, |
125 | #endif |
126 | |
127 | #ifdef CONFIG_USB_FUNCTIONFS_ETH |
128 | { |
129 | .eth = eth_bind_config, |
130 | }, |
131 | #endif |
132 | |
133 | #ifdef CONFIG_USB_FUNCTIONFS_GENERIC |
134 | { |
135 | }, |
136 | #endif |
137 | }; |
138 | |
139 | static void *functionfs_acquire_dev(struct ffs_dev *dev); |
140 | static void functionfs_release_dev(struct ffs_dev *dev); |
141 | static int functionfs_ready_callback(struct ffs_data *ffs); |
142 | static void functionfs_closed_callback(struct ffs_data *ffs); |
143 | static int gfs_bind(struct usb_composite_dev *cdev); |
144 | static int gfs_unbind(struct usb_composite_dev *cdev); |
145 | static int gfs_do_config(struct usb_configuration *c); |
146 | |
147 | |
148 | static struct usb_composite_driver gfs_driver = { |
149 | .name = DRIVER_NAME, |
150 | .dev = &gfs_dev_desc, |
151 | .strings = gfs_dev_strings, |
152 | .max_speed = USB_SPEED_SUPER, |
153 | .bind = gfs_bind, |
154 | .unbind = gfs_unbind, |
155 | }; |
156 | |
157 | static unsigned int missing_funcs; |
158 | static bool gfs_registered; |
159 | static bool gfs_single_func; |
160 | static struct usb_function_instance **fi_ffs; |
161 | static struct usb_function **f_ffs[] = { |
162 | #ifdef CONFIG_USB_FUNCTIONFS_RNDIS |
163 | NULL, |
164 | #endif |
165 | |
166 | #ifdef CONFIG_USB_FUNCTIONFS_ETH |
167 | NULL, |
168 | #endif |
169 | |
170 | #ifdef CONFIG_USB_FUNCTIONFS_GENERIC |
171 | NULL, |
172 | #endif |
173 | }; |
174 | |
175 | #define N_CONF ARRAY_SIZE(f_ffs) |
176 | |
177 | static int __init gfs_init(void) |
178 | { |
179 | struct f_fs_opts *opts; |
180 | int i; |
181 | int ret = 0; |
182 | |
183 | if (func_num < 2) { |
184 | gfs_single_func = true; |
185 | func_num = 1; |
186 | } |
187 | |
188 | /* |
189 | * Allocate in one chunk for easier maintenance |
190 | */ |
191 | f_ffs[0] = kcalloc(n: func_num * N_CONF, size: sizeof(*f_ffs), GFP_KERNEL); |
192 | if (!f_ffs[0]) { |
193 | ret = -ENOMEM; |
194 | goto no_func; |
195 | } |
196 | for (i = 1; i < N_CONF; ++i) |
197 | f_ffs[i] = f_ffs[0] + i * func_num; |
198 | |
199 | fi_ffs = kcalloc(n: func_num, size: sizeof(*fi_ffs), GFP_KERNEL); |
200 | if (!fi_ffs) { |
201 | ret = -ENOMEM; |
202 | goto no_func; |
203 | } |
204 | |
205 | for (i = 0; i < func_num; i++) { |
206 | fi_ffs[i] = usb_get_function_instance(name: "ffs" ); |
207 | if (IS_ERR(ptr: fi_ffs[i])) { |
208 | ret = PTR_ERR(ptr: fi_ffs[i]); |
209 | --i; |
210 | goto no_dev; |
211 | } |
212 | opts = to_f_fs_opts(fi: fi_ffs[i]); |
213 | if (gfs_single_func) |
214 | ret = ffs_single_dev(dev: opts->dev); |
215 | else |
216 | ret = ffs_name_dev(dev: opts->dev, name: func_names[i]); |
217 | if (ret) |
218 | goto no_dev; |
219 | opts->dev->ffs_ready_callback = functionfs_ready_callback; |
220 | opts->dev->ffs_closed_callback = functionfs_closed_callback; |
221 | opts->dev->ffs_acquire_dev_callback = functionfs_acquire_dev; |
222 | opts->dev->ffs_release_dev_callback = functionfs_release_dev; |
223 | opts->no_configfs = true; |
224 | } |
225 | |
226 | missing_funcs = func_num; |
227 | |
228 | return 0; |
229 | no_dev: |
230 | while (i >= 0) |
231 | usb_put_function_instance(fi: fi_ffs[i--]); |
232 | kfree(objp: fi_ffs); |
233 | no_func: |
234 | kfree(objp: f_ffs[0]); |
235 | return ret; |
236 | } |
237 | module_init(gfs_init); |
238 | |
239 | static void __exit gfs_exit(void) |
240 | { |
241 | int i; |
242 | |
243 | if (gfs_registered) |
244 | usb_composite_unregister(driver: &gfs_driver); |
245 | gfs_registered = false; |
246 | |
247 | kfree(objp: f_ffs[0]); |
248 | |
249 | for (i = 0; i < func_num; i++) |
250 | usb_put_function_instance(fi: fi_ffs[i]); |
251 | |
252 | kfree(objp: fi_ffs); |
253 | } |
254 | module_exit(gfs_exit); |
255 | |
256 | static void *functionfs_acquire_dev(struct ffs_dev *dev) |
257 | { |
258 | if (!try_module_get(THIS_MODULE)) |
259 | return ERR_PTR(error: -ENOENT); |
260 | |
261 | return NULL; |
262 | } |
263 | |
264 | static void functionfs_release_dev(struct ffs_dev *dev) |
265 | { |
266 | module_put(THIS_MODULE); |
267 | } |
268 | |
269 | /* |
270 | * The caller of this function takes ffs_lock |
271 | */ |
272 | static int functionfs_ready_callback(struct ffs_data *ffs) |
273 | { |
274 | int ret = 0; |
275 | |
276 | if (--missing_funcs) |
277 | return 0; |
278 | |
279 | if (gfs_registered) |
280 | return -EBUSY; |
281 | |
282 | gfs_registered = true; |
283 | |
284 | ret = usb_composite_probe(driver: &gfs_driver); |
285 | if (unlikely(ret < 0)) { |
286 | ++missing_funcs; |
287 | gfs_registered = false; |
288 | } |
289 | |
290 | return ret; |
291 | } |
292 | |
293 | /* |
294 | * The caller of this function takes ffs_lock |
295 | */ |
296 | static void functionfs_closed_callback(struct ffs_data *ffs) |
297 | { |
298 | missing_funcs++; |
299 | |
300 | if (gfs_registered) |
301 | usb_composite_unregister(driver: &gfs_driver); |
302 | gfs_registered = false; |
303 | } |
304 | |
305 | /* |
306 | * It is assumed that gfs_bind is called from a context where ffs_lock is held |
307 | */ |
308 | static int gfs_bind(struct usb_composite_dev *cdev) |
309 | { |
310 | #if defined CONFIG_USB_FUNCTIONFS_ETH || defined CONFIG_USB_FUNCTIONFS_RNDIS |
311 | struct net_device *net; |
312 | #endif |
313 | int ret, i; |
314 | |
315 | if (missing_funcs) |
316 | return -ENODEV; |
317 | #if defined CONFIG_USB_FUNCTIONFS_ETH |
318 | if (can_support_ecm(gadget: cdev->gadget)) { |
319 | struct f_ecm_opts *ecm_opts; |
320 | |
321 | fi_ecm = usb_get_function_instance(name: "ecm" ); |
322 | if (IS_ERR(ptr: fi_ecm)) |
323 | return PTR_ERR(ptr: fi_ecm); |
324 | ecm_opts = container_of(fi_ecm, struct f_ecm_opts, func_inst); |
325 | net = ecm_opts->net; |
326 | } else { |
327 | struct f_gether_opts *geth_opts; |
328 | |
329 | fi_geth = usb_get_function_instance(name: "geth" ); |
330 | if (IS_ERR(ptr: fi_geth)) |
331 | return PTR_ERR(ptr: fi_geth); |
332 | geth_opts = container_of(fi_geth, struct f_gether_opts, |
333 | func_inst); |
334 | net = geth_opts->net; |
335 | } |
336 | #endif |
337 | |
338 | #ifdef CONFIG_USB_FUNCTIONFS_RNDIS |
339 | { |
340 | fi_rndis = usb_get_function_instance(name: "rndis" ); |
341 | if (IS_ERR(ptr: fi_rndis)) { |
342 | ret = PTR_ERR(ptr: fi_rndis); |
343 | goto error; |
344 | } |
345 | #ifndef CONFIG_USB_FUNCTIONFS_ETH |
346 | net = container_of(fi_rndis, struct f_rndis_opts, |
347 | func_inst)->net; |
348 | #endif |
349 | } |
350 | #endif |
351 | |
352 | #if defined CONFIG_USB_FUNCTIONFS_ETH || defined CONFIG_USB_FUNCTIONFS_RNDIS |
353 | gether_set_qmult(net, qmult); |
354 | if (!gether_set_host_addr(net, host_addr)) |
355 | pr_info("using host ethernet address: %s" , host_addr); |
356 | if (!gether_set_dev_addr(net, dev_addr)) |
357 | pr_info("using self ethernet address: %s" , dev_addr); |
358 | #endif |
359 | |
360 | #if defined CONFIG_USB_FUNCTIONFS_RNDIS && defined CONFIG_USB_FUNCTIONFS_ETH |
361 | gether_set_gadget(net, g: cdev->gadget); |
362 | ret = gether_register_netdev(net); |
363 | if (ret) |
364 | goto error_rndis; |
365 | |
366 | if (can_support_ecm(gadget: cdev->gadget)) { |
367 | struct f_ecm_opts *ecm_opts; |
368 | |
369 | ecm_opts = container_of(fi_ecm, struct f_ecm_opts, func_inst); |
370 | ecm_opts->bound = true; |
371 | } else { |
372 | struct f_gether_opts *geth_opts; |
373 | |
374 | geth_opts = container_of(fi_geth, struct f_gether_opts, |
375 | func_inst); |
376 | geth_opts->bound = true; |
377 | } |
378 | |
379 | rndis_borrow_net(f: fi_rndis, net); |
380 | #endif |
381 | |
382 | /* TODO: gstrings_attach? */ |
383 | ret = usb_string_ids_tab(c: cdev, str: gfs_strings); |
384 | if (unlikely(ret < 0)) |
385 | goto error_rndis; |
386 | gfs_dev_desc.iProduct = gfs_strings[USB_GADGET_PRODUCT_IDX].id; |
387 | |
388 | if (gadget_is_otg(g: cdev->gadget) && !gfs_otg_desc[0]) { |
389 | struct usb_descriptor_header *usb_desc; |
390 | |
391 | usb_desc = usb_otg_descriptor_alloc(gadget: cdev->gadget); |
392 | if (!usb_desc) { |
393 | ret = -ENOMEM; |
394 | goto error_rndis; |
395 | } |
396 | usb_otg_descriptor_init(gadget: cdev->gadget, otg_desc: usb_desc); |
397 | gfs_otg_desc[0] = usb_desc; |
398 | gfs_otg_desc[1] = NULL; |
399 | } |
400 | |
401 | for (i = 0; i < ARRAY_SIZE(gfs_configurations); ++i) { |
402 | struct gfs_configuration *c = gfs_configurations + i; |
403 | int sid = USB_GADGET_FIRST_AVAIL_IDX + i; |
404 | |
405 | c->c.label = gfs_strings[sid].s; |
406 | c->c.iConfiguration = gfs_strings[sid].id; |
407 | c->c.bConfigurationValue = 1 + i; |
408 | c->c.bmAttributes = USB_CONFIG_ATT_SELFPOWER; |
409 | |
410 | c->num = i; |
411 | |
412 | ret = usb_add_config(cdev, &c->c, gfs_do_config); |
413 | if (unlikely(ret < 0)) |
414 | goto error_unbind; |
415 | } |
416 | usb_composite_overwrite_options(cdev, covr: &coverwrite); |
417 | return 0; |
418 | |
419 | /* TODO */ |
420 | error_unbind: |
421 | kfree(objp: gfs_otg_desc[0]); |
422 | gfs_otg_desc[0] = NULL; |
423 | error_rndis: |
424 | #ifdef CONFIG_USB_FUNCTIONFS_RNDIS |
425 | usb_put_function_instance(fi: fi_rndis); |
426 | error: |
427 | #endif |
428 | #if defined CONFIG_USB_FUNCTIONFS_ETH |
429 | if (can_support_ecm(gadget: cdev->gadget)) |
430 | usb_put_function_instance(fi: fi_ecm); |
431 | else |
432 | usb_put_function_instance(fi: fi_geth); |
433 | #endif |
434 | return ret; |
435 | } |
436 | |
437 | /* |
438 | * It is assumed that gfs_unbind is called from a context where ffs_lock is held |
439 | */ |
440 | static int gfs_unbind(struct usb_composite_dev *cdev) |
441 | { |
442 | int i; |
443 | |
444 | #ifdef CONFIG_USB_FUNCTIONFS_RNDIS |
445 | usb_put_function(f: f_rndis); |
446 | usb_put_function_instance(fi: fi_rndis); |
447 | #endif |
448 | |
449 | #if defined CONFIG_USB_FUNCTIONFS_ETH |
450 | if (can_support_ecm(gadget: cdev->gadget)) { |
451 | usb_put_function(f: f_ecm); |
452 | usb_put_function_instance(fi: fi_ecm); |
453 | } else { |
454 | usb_put_function(f: f_geth); |
455 | usb_put_function_instance(fi: fi_geth); |
456 | } |
457 | #endif |
458 | for (i = 0; i < N_CONF * func_num; ++i) |
459 | usb_put_function(f: *(f_ffs[0] + i)); |
460 | |
461 | kfree(objp: gfs_otg_desc[0]); |
462 | gfs_otg_desc[0] = NULL; |
463 | |
464 | return 0; |
465 | } |
466 | |
467 | /* |
468 | * It is assumed that gfs_do_config is called from a context where |
469 | * ffs_lock is held |
470 | */ |
471 | static int gfs_do_config(struct usb_configuration *c) |
472 | { |
473 | struct gfs_configuration *gc = |
474 | container_of(c, struct gfs_configuration, c); |
475 | int i; |
476 | int ret; |
477 | |
478 | if (missing_funcs) |
479 | return -ENODEV; |
480 | |
481 | if (gadget_is_otg(g: c->cdev->gadget)) { |
482 | c->descriptors = gfs_otg_desc; |
483 | c->bmAttributes |= USB_CONFIG_ATT_WAKEUP; |
484 | } |
485 | |
486 | if (gc->eth) { |
487 | ret = gc->eth(c); |
488 | if (unlikely(ret < 0)) |
489 | return ret; |
490 | } |
491 | |
492 | for (i = 0; i < func_num; i++) { |
493 | f_ffs[gc->num][i] = usb_get_function(fi: fi_ffs[i]); |
494 | if (IS_ERR(ptr: f_ffs[gc->num][i])) { |
495 | ret = PTR_ERR(ptr: f_ffs[gc->num][i]); |
496 | goto error; |
497 | } |
498 | ret = usb_add_function(c, f_ffs[gc->num][i]); |
499 | if (ret < 0) { |
500 | usb_put_function(f: f_ffs[gc->num][i]); |
501 | goto error; |
502 | } |
503 | } |
504 | |
505 | /* |
506 | * After previous do_configs there may be some invalid |
507 | * pointers in c->interface array. This happens every time |
508 | * a user space function with fewer interfaces than a user |
509 | * space function that was run before the new one is run. The |
510 | * compasit's set_config() assumes that if there is no more |
511 | * then MAX_CONFIG_INTERFACES interfaces in a configuration |
512 | * then there is a NULL pointer after the last interface in |
513 | * c->interface array. We need to make sure this is true. |
514 | */ |
515 | if (c->next_interface_id < ARRAY_SIZE(c->interface)) |
516 | c->interface[c->next_interface_id] = NULL; |
517 | |
518 | return 0; |
519 | error: |
520 | while (--i >= 0) { |
521 | if (!IS_ERR(ptr: f_ffs[gc->num][i])) |
522 | usb_remove_function(c, f: f_ffs[gc->num][i]); |
523 | usb_put_function(f: f_ffs[gc->num][i]); |
524 | } |
525 | return ret; |
526 | } |
527 | |
528 | #ifdef CONFIG_USB_FUNCTIONFS_ETH |
529 | |
530 | static int eth_bind_config(struct usb_configuration *c) |
531 | { |
532 | int status = 0; |
533 | |
534 | if (can_support_ecm(gadget: c->cdev->gadget)) { |
535 | f_ecm = usb_get_function(fi: fi_ecm); |
536 | if (IS_ERR(ptr: f_ecm)) |
537 | return PTR_ERR(ptr: f_ecm); |
538 | |
539 | status = usb_add_function(c, f_ecm); |
540 | if (status < 0) |
541 | usb_put_function(f: f_ecm); |
542 | |
543 | } else { |
544 | f_geth = usb_get_function(fi: fi_geth); |
545 | if (IS_ERR(ptr: f_geth)) |
546 | return PTR_ERR(ptr: f_geth); |
547 | |
548 | status = usb_add_function(c, f_geth); |
549 | if (status < 0) |
550 | usb_put_function(f: f_geth); |
551 | } |
552 | return status; |
553 | } |
554 | |
555 | #endif |
556 | |
557 | #ifdef CONFIG_USB_FUNCTIONFS_RNDIS |
558 | |
559 | static int bind_rndis_config(struct usb_configuration *c) |
560 | { |
561 | int status = 0; |
562 | |
563 | f_rndis = usb_get_function(fi: fi_rndis); |
564 | if (IS_ERR(ptr: f_rndis)) |
565 | return PTR_ERR(ptr: f_rndis); |
566 | |
567 | status = usb_add_function(c, f_rndis); |
568 | if (status < 0) |
569 | usb_put_function(f: f_rndis); |
570 | |
571 | return status; |
572 | } |
573 | |
574 | #endif |
575 | |