diff options
author | Sebastian Andrzej Siewior <bigeasy@linutronix.de> | 2012-12-23 15:10:01 -0500 |
---|---|---|
committer | Felipe Balbi <balbi@ti.com> | 2013-01-21 13:52:40 -0500 |
commit | cf9a08ae5aece88987bbeee8eb0dd0ebb5015815 (patch) | |
tree | bbc7e204bd532b6ff84586653f57bc7ec6bf6380 /drivers/usb | |
parent | de53c25447117eae6b3f8952f663f08a09e0dbb7 (diff) |
usb: gadget: convert source sink and loopback to new function interface
This patch converts the f_sourcesink and f_loopback file to the USB-function
module. Both functions shares a few common utility functions which are
currently implemented in g_zero.c itself. This patch moves the common
code into the sourcesink file and creates one module out of the the two
functions (source sink and loop back).
The g_zero gadget is function specific to source sink and loop back to
set a few options. This Symbol dependency enforces a modul load right
now.
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Signed-off-by: Felipe Balbi <balbi@ti.com>
Diffstat (limited to 'drivers/usb')
-rw-r--r-- | drivers/usb/gadget/Kconfig | 4 | ||||
-rw-r--r-- | drivers/usb/gadget/Makefile | 4 | ||||
-rw-r--r-- | drivers/usb/gadget/f_loopback.c | 75 | ||||
-rw-r--r-- | drivers/usb/gadget/f_sourcesink.c | 165 | ||||
-rw-r--r-- | drivers/usb/gadget/g_zero.h | 31 | ||||
-rw-r--r-- | drivers/usb/gadget/zero.c | 196 |
6 files changed, 321 insertions, 154 deletions
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 14625fd2cecd..0ef5549b6544 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig | |||
@@ -500,6 +500,9 @@ config USB_LIBCOMPOSITE | |||
500 | tristate | 500 | tristate |
501 | depends on USB_GADGET | 501 | depends on USB_GADGET |
502 | 502 | ||
503 | config USB_F_SS_LB | ||
504 | tristate | ||
505 | |||
503 | choice | 506 | choice |
504 | tristate "USB Gadget Drivers" | 507 | tristate "USB Gadget Drivers" |
505 | default USB_ETH | 508 | default USB_ETH |
@@ -524,6 +527,7 @@ choice | |||
524 | config USB_ZERO | 527 | config USB_ZERO |
525 | tristate "Gadget Zero (DEVELOPMENT)" | 528 | tristate "Gadget Zero (DEVELOPMENT)" |
526 | select USB_LIBCOMPOSITE | 529 | select USB_LIBCOMPOSITE |
530 | select USB_F_SS_LB | ||
527 | help | 531 | help |
528 | Gadget Zero is a two-configuration device. It either sinks and | 532 | Gadget Zero is a two-configuration device. It either sinks and |
529 | sources bulk data; or it loops back a configurable number of | 533 | sources bulk data; or it loops back a configurable number of |
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index fef41f5d6e8d..e412befa7a35 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile | |||
@@ -74,3 +74,7 @@ obj-$(CONFIG_USB_G_WEBCAM) += g_webcam.o | |||
74 | obj-$(CONFIG_USB_G_NCM) += g_ncm.o | 74 | obj-$(CONFIG_USB_G_NCM) += g_ncm.o |
75 | obj-$(CONFIG_USB_G_ACM_MS) += g_acm_ms.o | 75 | obj-$(CONFIG_USB_G_ACM_MS) += g_acm_ms.o |
76 | obj-$(CONFIG_USB_GADGET_TARGET) += tcm_usb_gadget.o | 76 | obj-$(CONFIG_USB_GADGET_TARGET) += tcm_usb_gadget.o |
77 | |||
78 | # USB Functions | ||
79 | f_ss_lb-y := f_loopback.o f_sourcesink.o | ||
80 | obj-$(CONFIG_USB_F_SS_LB) += f_ss_lb.o | ||
diff --git a/drivers/usb/gadget/f_loopback.c b/drivers/usb/gadget/f_loopback.c index 3d103a2f998f..4a3873a0f2d0 100644 --- a/drivers/usb/gadget/f_loopback.c +++ b/drivers/usb/gadget/f_loopback.c | |||
@@ -15,10 +15,11 @@ | |||
15 | #include <linux/slab.h> | 15 | #include <linux/slab.h> |
16 | #include <linux/kernel.h> | 16 | #include <linux/kernel.h> |
17 | #include <linux/device.h> | 17 | #include <linux/device.h> |
18 | #include <linux/module.h> | ||
19 | #include <linux/err.h> | ||
20 | #include <linux/usb/composite.h> | ||
18 | 21 | ||
19 | #include "g_zero.h" | 22 | #include "g_zero.h" |
20 | #include "gadget_chips.h" | ||
21 | |||
22 | 23 | ||
23 | /* | 24 | /* |
24 | * LOOPBACK FUNCTION ... a testing vehicle for USB peripherals, | 25 | * LOOPBACK FUNCTION ... a testing vehicle for USB peripherals, |
@@ -44,9 +45,8 @@ static inline struct f_loopback *func_to_loop(struct usb_function *f) | |||
44 | return container_of(f, struct f_loopback, function); | 45 | return container_of(f, struct f_loopback, function); |
45 | } | 46 | } |
46 | 47 | ||
47 | static unsigned qlen = 32; | 48 | static unsigned qlen; |
48 | module_param(qlen, uint, 0); | 49 | static unsigned buflen; |
49 | MODULE_PARM_DESC(qlenn, "depth of loopback queue"); | ||
50 | 50 | ||
51 | /*-------------------------------------------------------------------------*/ | 51 | /*-------------------------------------------------------------------------*/ |
52 | 52 | ||
@@ -171,8 +171,7 @@ static struct usb_gadget_strings *loopback_strings[] = { | |||
171 | 171 | ||
172 | /*-------------------------------------------------------------------------*/ | 172 | /*-------------------------------------------------------------------------*/ |
173 | 173 | ||
174 | static int __init | 174 | static int loopback_bind(struct usb_configuration *c, struct usb_function *f) |
175 | loopback_bind(struct usb_configuration *c, struct usb_function *f) | ||
176 | { | 175 | { |
177 | struct usb_composite_dev *cdev = c->cdev; | 176 | struct usb_composite_dev *cdev = c->cdev; |
178 | struct f_loopback *loop = func_to_loop(f); | 177 | struct f_loopback *loop = func_to_loop(f); |
@@ -229,8 +228,7 @@ autoconf_fail: | |||
229 | return 0; | 228 | return 0; |
230 | } | 229 | } |
231 | 230 | ||
232 | static void | 231 | static void lb_free_func(struct usb_function *f) |
233 | loopback_unbind(struct usb_configuration *c, struct usb_function *f) | ||
234 | { | 232 | { |
235 | usb_free_all_descriptors(f); | 233 | usb_free_all_descriptors(f); |
236 | kfree(func_to_loop(f)); | 234 | kfree(func_to_loop(f)); |
@@ -372,25 +370,64 @@ static void loopback_disable(struct usb_function *f) | |||
372 | disable_loopback(loop); | 370 | disable_loopback(loop); |
373 | } | 371 | } |
374 | 372 | ||
375 | /*-------------------------------------------------------------------------*/ | 373 | static struct usb_function *loopback_alloc(struct usb_function_instance *fi) |
376 | |||
377 | static int __init loopback_bind_config(struct usb_configuration *c) | ||
378 | { | 374 | { |
379 | struct f_loopback *loop; | 375 | struct f_loopback *loop; |
380 | int status; | 376 | struct f_lb_opts *lb_opts; |
381 | 377 | ||
382 | loop = kzalloc(sizeof *loop, GFP_KERNEL); | 378 | loop = kzalloc(sizeof *loop, GFP_KERNEL); |
383 | if (!loop) | 379 | if (!loop) |
384 | return -ENOMEM; | 380 | return ERR_PTR(-ENOMEM); |
381 | |||
382 | lb_opts = container_of(fi, struct f_lb_opts, func_inst); | ||
383 | buflen = lb_opts->bulk_buflen; | ||
384 | qlen = lb_opts->qlen; | ||
385 | if (!qlen) | ||
386 | qlen = 32; | ||
385 | 387 | ||
386 | loop->function.name = "loopback"; | 388 | loop->function.name = "loopback"; |
387 | loop->function.bind = loopback_bind; | 389 | loop->function.bind = loopback_bind; |
388 | loop->function.unbind = loopback_unbind; | ||
389 | loop->function.set_alt = loopback_set_alt; | 390 | loop->function.set_alt = loopback_set_alt; |
390 | loop->function.disable = loopback_disable; | 391 | loop->function.disable = loopback_disable; |
392 | loop->function.strings = loopback_strings; | ||
393 | |||
394 | loop->function.free_func = lb_free_func; | ||
395 | |||
396 | return &loop->function; | ||
397 | } | ||
398 | |||
399 | static void lb_free_instance(struct usb_function_instance *fi) | ||
400 | { | ||
401 | struct f_lb_opts *lb_opts; | ||
391 | 402 | ||
392 | status = usb_add_function(c, &loop->function); | 403 | lb_opts = container_of(fi, struct f_lb_opts, func_inst); |
393 | if (status) | 404 | kfree(lb_opts); |
394 | kfree(loop); | ||
395 | return status; | ||
396 | } | 405 | } |
406 | |||
407 | static struct usb_function_instance *loopback_alloc_instance(void) | ||
408 | { | ||
409 | struct f_lb_opts *lb_opts; | ||
410 | |||
411 | lb_opts = kzalloc(sizeof(*lb_opts), GFP_KERNEL); | ||
412 | if (!lb_opts) | ||
413 | return ERR_PTR(-ENOMEM); | ||
414 | lb_opts->func_inst.free_func_inst = lb_free_instance; | ||
415 | return &lb_opts->func_inst; | ||
416 | } | ||
417 | DECLARE_USB_FUNCTION(Loopback, loopback_alloc_instance, loopback_alloc); | ||
418 | |||
419 | int __init lb_modinit(void) | ||
420 | { | ||
421 | int ret; | ||
422 | |||
423 | ret = usb_function_register(&Loopbackusb_func); | ||
424 | if (ret) | ||
425 | return ret; | ||
426 | return ret; | ||
427 | } | ||
428 | void __exit lb_modexit(void) | ||
429 | { | ||
430 | usb_function_unregister(&Loopbackusb_func); | ||
431 | } | ||
432 | |||
433 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/usb/gadget/f_sourcesink.c b/drivers/usb/gadget/f_sourcesink.c index f785cbd59688..41adf3ef96c2 100644 --- a/drivers/usb/gadget/f_sourcesink.c +++ b/drivers/usb/gadget/f_sourcesink.c | |||
@@ -16,11 +16,12 @@ | |||
16 | #include <linux/kernel.h> | 16 | #include <linux/kernel.h> |
17 | #include <linux/device.h> | 17 | #include <linux/device.h> |
18 | #include <linux/module.h> | 18 | #include <linux/module.h> |
19 | #include <linux/usb/composite.h> | ||
20 | #include <linux/err.h> | ||
19 | 21 | ||
20 | #include "g_zero.h" | 22 | #include "g_zero.h" |
21 | #include "gadget_chips.h" | 23 | #include "gadget_chips.h" |
22 | 24 | ||
23 | |||
24 | /* | 25 | /* |
25 | * SOURCE/SINK FUNCTION ... a primary testing vehicle for USB peripheral | 26 | * SOURCE/SINK FUNCTION ... a primary testing vehicle for USB peripheral |
26 | * controller drivers. | 27 | * controller drivers. |
@@ -62,24 +63,11 @@ static inline struct f_sourcesink *func_to_ss(struct usb_function *f) | |||
62 | } | 63 | } |
63 | 64 | ||
64 | static unsigned pattern; | 65 | static unsigned pattern; |
65 | module_param(pattern, uint, S_IRUGO|S_IWUSR); | 66 | static unsigned isoc_interval; |
66 | MODULE_PARM_DESC(pattern, "0 = all zeroes, 1 = mod63, 2 = none"); | 67 | static unsigned isoc_maxpacket; |
67 | |||
68 | static unsigned isoc_interval = 4; | ||
69 | module_param(isoc_interval, uint, S_IRUGO|S_IWUSR); | ||
70 | MODULE_PARM_DESC(isoc_interval, "1 - 16"); | ||
71 | |||
72 | static unsigned isoc_maxpacket = 1024; | ||
73 | module_param(isoc_maxpacket, uint, S_IRUGO|S_IWUSR); | ||
74 | MODULE_PARM_DESC(isoc_maxpacket, "0 - 1023 (fs), 0 - 1024 (hs/ss)"); | ||
75 | |||
76 | static unsigned isoc_mult; | 68 | static unsigned isoc_mult; |
77 | module_param(isoc_mult, uint, S_IRUGO|S_IWUSR); | ||
78 | MODULE_PARM_DESC(isoc_mult, "0 - 2 (hs/ss only)"); | ||
79 | |||
80 | static unsigned isoc_maxburst; | 69 | static unsigned isoc_maxburst; |
81 | module_param(isoc_maxburst, uint, S_IRUGO|S_IWUSR); | 70 | static unsigned buflen; |
82 | MODULE_PARM_DESC(isoc_maxburst, "0 - 15 (ss only)"); | ||
83 | 71 | ||
84 | /*-------------------------------------------------------------------------*/ | 72 | /*-------------------------------------------------------------------------*/ |
85 | 73 | ||
@@ -313,7 +301,57 @@ static struct usb_gadget_strings *sourcesink_strings[] = { | |||
313 | 301 | ||
314 | /*-------------------------------------------------------------------------*/ | 302 | /*-------------------------------------------------------------------------*/ |
315 | 303 | ||
316 | static int __init | 304 | struct usb_request *alloc_ep_req(struct usb_ep *ep, int len) |
305 | { | ||
306 | struct usb_request *req; | ||
307 | |||
308 | req = usb_ep_alloc_request(ep, GFP_ATOMIC); | ||
309 | if (req) { | ||
310 | if (len) | ||
311 | req->length = len; | ||
312 | else | ||
313 | req->length = buflen; | ||
314 | req->buf = kmalloc(req->length, GFP_ATOMIC); | ||
315 | if (!req->buf) { | ||
316 | usb_ep_free_request(ep, req); | ||
317 | req = NULL; | ||
318 | } | ||
319 | } | ||
320 | return req; | ||
321 | } | ||
322 | |||
323 | void free_ep_req(struct usb_ep *ep, struct usb_request *req) | ||
324 | { | ||
325 | kfree(req->buf); | ||
326 | usb_ep_free_request(ep, req); | ||
327 | } | ||
328 | |||
329 | static void disable_ep(struct usb_composite_dev *cdev, struct usb_ep *ep) | ||
330 | { | ||
331 | int value; | ||
332 | |||
333 | if (ep->driver_data) { | ||
334 | value = usb_ep_disable(ep); | ||
335 | if (value < 0) | ||
336 | DBG(cdev, "disable %s --> %d\n", | ||
337 | ep->name, value); | ||
338 | ep->driver_data = NULL; | ||
339 | } | ||
340 | } | ||
341 | |||
342 | void disable_endpoints(struct usb_composite_dev *cdev, | ||
343 | struct usb_ep *in, struct usb_ep *out, | ||
344 | struct usb_ep *iso_in, struct usb_ep *iso_out) | ||
345 | { | ||
346 | disable_ep(cdev, in); | ||
347 | disable_ep(cdev, out); | ||
348 | if (iso_in) | ||
349 | disable_ep(cdev, iso_in); | ||
350 | if (iso_out) | ||
351 | disable_ep(cdev, iso_out); | ||
352 | } | ||
353 | |||
354 | static int | ||
317 | sourcesink_bind(struct usb_configuration *c, struct usb_function *f) | 355 | sourcesink_bind(struct usb_configuration *c, struct usb_function *f) |
318 | { | 356 | { |
319 | struct usb_composite_dev *cdev = c->cdev; | 357 | struct usb_composite_dev *cdev = c->cdev; |
@@ -328,14 +366,6 @@ sourcesink_bind(struct usb_configuration *c, struct usb_function *f) | |||
328 | source_sink_intf_alt0.bInterfaceNumber = id; | 366 | source_sink_intf_alt0.bInterfaceNumber = id; |
329 | source_sink_intf_alt1.bInterfaceNumber = id; | 367 | source_sink_intf_alt1.bInterfaceNumber = id; |
330 | 368 | ||
331 | /* allocate string ID(s) */ | ||
332 | id = usb_string_id(cdev); | ||
333 | if (id < 0) | ||
334 | return id; | ||
335 | strings_sourcesink[0].id = id; | ||
336 | source_sink_intf_alt0.iInterface = id; | ||
337 | source_sink_intf_alt1.iInterface = id; | ||
338 | |||
339 | /* allocate bulk endpoints */ | 369 | /* allocate bulk endpoints */ |
340 | ss->in_ep = usb_ep_autoconfig(cdev->gadget, &fs_source_desc); | 370 | ss->in_ep = usb_ep_autoconfig(cdev->gadget, &fs_source_desc); |
341 | if (!ss->in_ep) { | 371 | if (!ss->in_ep) { |
@@ -457,14 +487,11 @@ no_iso: | |||
457 | return 0; | 487 | return 0; |
458 | } | 488 | } |
459 | 489 | ||
460 | static struct usb_function *global_ss_func; | ||
461 | |||
462 | static void | 490 | static void |
463 | sourcesink_unbind(struct usb_configuration *c, struct usb_function *f) | 491 | sourcesink_free_func(struct usb_function *f) |
464 | { | 492 | { |
465 | usb_free_all_descriptors(f); | 493 | usb_free_all_descriptors(f); |
466 | kfree(func_to_ss(f)); | 494 | kfree(func_to_ss(f)); |
467 | global_ss_func = NULL; | ||
468 | } | 495 | } |
469 | 496 | ||
470 | /* optionally require specific source/sink data patterns */ | 497 | /* optionally require specific source/sink data patterns */ |
@@ -767,6 +794,7 @@ static void sourcesink_disable(struct usb_function *f) | |||
767 | } | 794 | } |
768 | 795 | ||
769 | /*-------------------------------------------------------------------------*/ | 796 | /*-------------------------------------------------------------------------*/ |
797 | |||
770 | static int sourcesink_setup(struct usb_function *f, | 798 | static int sourcesink_setup(struct usb_function *f, |
771 | const struct usb_ctrlrequest *ctrl) | 799 | const struct usb_ctrlrequest *ctrl) |
772 | { | 800 | { |
@@ -839,41 +867,76 @@ unknown: | |||
839 | return value; | 867 | return value; |
840 | } | 868 | } |
841 | 869 | ||
842 | static int __init sourcesink_bind_config(struct usb_configuration *c) | 870 | static struct usb_function *source_sink_alloc_func( |
871 | struct usb_function_instance *fi) | ||
843 | { | 872 | { |
844 | struct f_sourcesink *ss; | 873 | struct f_sourcesink *ss; |
845 | int status; | 874 | struct f_ss_opts *ss_opts; |
846 | 875 | ||
847 | ss = kzalloc(sizeof(*ss), GFP_KERNEL); | 876 | ss = kzalloc(sizeof(*ss), GFP_KERNEL); |
848 | if (!ss) | 877 | if (!ss) |
849 | return -ENOMEM; | 878 | return NULL; |
850 | 879 | ||
851 | global_ss_func = &ss->function; | 880 | ss_opts = container_of(fi, struct f_ss_opts, func_inst); |
881 | pattern = ss_opts->pattern; | ||
882 | isoc_interval = ss_opts->isoc_interval; | ||
883 | isoc_maxpacket = ss_opts->isoc_maxpacket; | ||
884 | isoc_mult = ss_opts->isoc_mult; | ||
885 | isoc_maxburst = ss_opts->isoc_maxburst; | ||
886 | buflen = ss_opts->bulk_buflen; | ||
852 | 887 | ||
853 | ss->function.name = "source/sink"; | 888 | ss->function.name = "source/sink"; |
854 | ss->function.bind = sourcesink_bind; | 889 | ss->function.bind = sourcesink_bind; |
855 | ss->function.unbind = sourcesink_unbind; | ||
856 | ss->function.set_alt = sourcesink_set_alt; | 890 | ss->function.set_alt = sourcesink_set_alt; |
857 | ss->function.get_alt = sourcesink_get_alt; | 891 | ss->function.get_alt = sourcesink_get_alt; |
858 | ss->function.disable = sourcesink_disable; | 892 | ss->function.disable = sourcesink_disable; |
859 | ss->function.setup = sourcesink_setup; | 893 | ss->function.setup = sourcesink_setup; |
894 | ss->function.strings = sourcesink_strings; | ||
860 | 895 | ||
861 | status = usb_add_function(c, &ss->function); | 896 | ss->function.free_func = sourcesink_free_func; |
862 | if (status) | 897 | |
863 | kfree(ss); | 898 | return &ss->function; |
864 | return status; | ||
865 | } | 899 | } |
866 | 900 | ||
867 | static int ss_config_setup(struct usb_configuration *c, | 901 | static void acm_free_instance(struct usb_function_instance *fi) |
868 | const struct usb_ctrlrequest *ctrl) | ||
869 | { | 902 | { |
870 | if (!global_ss_func) | 903 | struct f_ss_opts *ss_opts; |
871 | return -EOPNOTSUPP; | 904 | |
872 | switch (ctrl->bRequest) { | 905 | ss_opts = container_of(fi, struct f_ss_opts, func_inst); |
873 | case 0x5b: | 906 | kfree(ss_opts); |
874 | case 0x5c: | ||
875 | return global_ss_func->setup(global_ss_func, ctrl); | ||
876 | default: | ||
877 | return -EOPNOTSUPP; | ||
878 | } | ||
879 | } | 907 | } |
908 | |||
909 | static struct usb_function_instance *source_sink_alloc_inst(void) | ||
910 | { | ||
911 | struct f_ss_opts *ss_opts; | ||
912 | |||
913 | ss_opts = kzalloc(sizeof(*ss_opts), GFP_KERNEL); | ||
914 | if (!ss_opts) | ||
915 | return ERR_PTR(-ENOMEM); | ||
916 | ss_opts->func_inst.free_func_inst = acm_free_instance; | ||
917 | return &ss_opts->func_inst; | ||
918 | } | ||
919 | DECLARE_USB_FUNCTION(SourceSink, source_sink_alloc_inst, | ||
920 | source_sink_alloc_func); | ||
921 | |||
922 | static int __init sslb_modinit(void) | ||
923 | { | ||
924 | int ret; | ||
925 | |||
926 | ret = usb_function_register(&SourceSinkusb_func); | ||
927 | if (ret) | ||
928 | return ret; | ||
929 | ret = lb_modinit(); | ||
930 | if (ret) | ||
931 | usb_function_unregister(&SourceSinkusb_func); | ||
932 | return ret; | ||
933 | } | ||
934 | static void __exit sslb_modexit(void) | ||
935 | { | ||
936 | usb_function_unregister(&SourceSinkusb_func); | ||
937 | lb_modexit(); | ||
938 | } | ||
939 | module_init(sslb_modinit); | ||
940 | module_exit(sslb_modexit); | ||
941 | |||
942 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/usb/gadget/g_zero.h b/drivers/usb/gadget/g_zero.h index 281239c4e544..ef3e8515272b 100644 --- a/drivers/usb/gadget/g_zero.h +++ b/drivers/usb/gadget/g_zero.h | |||
@@ -6,11 +6,34 @@ | |||
6 | #ifndef __G_ZERO_H | 6 | #ifndef __G_ZERO_H |
7 | #define __G_ZERO_H | 7 | #define __G_ZERO_H |
8 | 8 | ||
9 | #include <linux/usb/composite.h> | 9 | struct usb_zero_options { |
10 | unsigned pattern; | ||
11 | unsigned isoc_interval; | ||
12 | unsigned isoc_maxpacket; | ||
13 | unsigned isoc_mult; | ||
14 | unsigned isoc_maxburst; | ||
15 | unsigned bulk_buflen; | ||
16 | unsigned qlen; | ||
17 | }; | ||
10 | 18 | ||
11 | /* global state */ | 19 | struct f_ss_opts { |
12 | extern unsigned buflen; | 20 | struct usb_function_instance func_inst; |
13 | extern const struct usb_descriptor_header *otg_desc[]; | 21 | unsigned pattern; |
22 | unsigned isoc_interval; | ||
23 | unsigned isoc_maxpacket; | ||
24 | unsigned isoc_mult; | ||
25 | unsigned isoc_maxburst; | ||
26 | unsigned bulk_buflen; | ||
27 | }; | ||
28 | |||
29 | struct f_lb_opts { | ||
30 | struct usb_function_instance func_inst; | ||
31 | unsigned bulk_buflen; | ||
32 | unsigned qlen; | ||
33 | }; | ||
34 | |||
35 | void lb_modexit(void); | ||
36 | int lb_modinit(void); | ||
14 | 37 | ||
15 | /* common utilities */ | 38 | /* common utilities */ |
16 | struct usb_request *alloc_ep_req(struct usb_ep *ep, int len); | 39 | struct usb_request *alloc_ep_req(struct usb_ep *ep, int len); |
diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c index 8ba0bee4e6c0..a331ab13f1e5 100644 --- a/drivers/usb/gadget/zero.c +++ b/drivers/usb/gadget/zero.c | |||
@@ -10,7 +10,6 @@ | |||
10 | * (at your option) any later version. | 10 | * (at your option) any later version. |
11 | */ | 11 | */ |
12 | 12 | ||
13 | |||
14 | /* | 13 | /* |
15 | * Gadget Zero only needs two bulk endpoints, and is an example of how you | 14 | * Gadget Zero only needs two bulk endpoints, and is an example of how you |
16 | * can write a hardware-agnostic gadget driver running inside a USB device. | 15 | * can write a hardware-agnostic gadget driver running inside a USB device. |
@@ -43,23 +42,11 @@ | |||
43 | #include <linux/kernel.h> | 42 | #include <linux/kernel.h> |
44 | #include <linux/slab.h> | 43 | #include <linux/slab.h> |
45 | #include <linux/device.h> | 44 | #include <linux/device.h> |
45 | #include <linux/module.h> | ||
46 | #include <linux/err.h> | ||
47 | #include <linux/usb/composite.h> | ||
46 | 48 | ||
47 | #include "g_zero.h" | 49 | #include "g_zero.h" |
48 | #include "gadget_chips.h" | ||
49 | |||
50 | |||
51 | /*-------------------------------------------------------------------------*/ | ||
52 | |||
53 | /* | ||
54 | * Kbuild is not very cooperative with respect to linking separately | ||
55 | * compiled library objects into one module. So for now we won't use | ||
56 | * separate compilation ... ensuring init/exit sections work to shrink | ||
57 | * the runtime footprint, and giving us at least some parts of what | ||
58 | * a "gcc --combine ... part1.c part2.c part3.c ... " build would. | ||
59 | */ | ||
60 | #include "f_sourcesink.c" | ||
61 | #include "f_loopback.c" | ||
62 | |||
63 | /*-------------------------------------------------------------------------*/ | 50 | /*-------------------------------------------------------------------------*/ |
64 | USB_GADGET_COMPOSITE_OPTIONS(); | 51 | USB_GADGET_COMPOSITE_OPTIONS(); |
65 | 52 | ||
@@ -67,9 +54,6 @@ USB_GADGET_COMPOSITE_OPTIONS(); | |||
67 | 54 | ||
68 | static const char longname[] = "Gadget Zero"; | 55 | static const char longname[] = "Gadget Zero"; |
69 | 56 | ||
70 | unsigned buflen = 4096; /* only used for bulk endpoints */ | ||
71 | module_param(buflen, uint, 0); | ||
72 | |||
73 | /* | 57 | /* |
74 | * Normally the "loopback" configuration is second (index 1) so | 58 | * Normally the "loopback" configuration is second (index 1) so |
75 | * it's not the default. Here's where to change that order, to | 59 | * it's not the default. Here's where to change that order, to |
@@ -79,6 +63,13 @@ module_param(buflen, uint, 0); | |||
79 | static bool loopdefault = 0; | 63 | static bool loopdefault = 0; |
80 | module_param(loopdefault, bool, S_IRUGO|S_IWUSR); | 64 | module_param(loopdefault, bool, S_IRUGO|S_IWUSR); |
81 | 65 | ||
66 | struct usb_zero_options gzero_options = { | ||
67 | .isoc_interval = 4, | ||
68 | .isoc_maxpacket = 1024, | ||
69 | .bulk_buflen = 4096, | ||
70 | .qlen = 32, | ||
71 | }; | ||
72 | |||
82 | /*-------------------------------------------------------------------------*/ | 73 | /*-------------------------------------------------------------------------*/ |
83 | 74 | ||
84 | /* Thanks to NetChip Technologies for donating this product ID. | 75 | /* Thanks to NetChip Technologies for donating this product ID. |
@@ -129,10 +120,12 @@ static struct usb_otg_descriptor otg_descriptor = { | |||
129 | .bmAttributes = USB_OTG_SRP | USB_OTG_HNP, | 120 | .bmAttributes = USB_OTG_SRP | USB_OTG_HNP, |
130 | }; | 121 | }; |
131 | 122 | ||
132 | const struct usb_descriptor_header *otg_desc[] = { | 123 | static const struct usb_descriptor_header *otg_desc[] = { |
133 | (struct usb_descriptor_header *) &otg_descriptor, | 124 | (struct usb_descriptor_header *) &otg_descriptor, |
134 | NULL, | 125 | NULL, |
135 | }; | 126 | }; |
127 | #else | ||
128 | #define otg_desc NULL | ||
136 | #endif | 129 | #endif |
137 | 130 | ||
138 | /* string IDs are assigned dynamically */ | 131 | /* string IDs are assigned dynamically */ |
@@ -163,58 +156,6 @@ static struct usb_gadget_strings *dev_strings[] = { | |||
163 | 156 | ||
164 | /*-------------------------------------------------------------------------*/ | 157 | /*-------------------------------------------------------------------------*/ |
165 | 158 | ||
166 | struct usb_request *alloc_ep_req(struct usb_ep *ep, int len) | ||
167 | { | ||
168 | struct usb_request *req; | ||
169 | |||
170 | req = usb_ep_alloc_request(ep, GFP_ATOMIC); | ||
171 | if (req) { | ||
172 | if (len) | ||
173 | req->length = len; | ||
174 | else | ||
175 | req->length = buflen; | ||
176 | req->buf = kmalloc(req->length, GFP_ATOMIC); | ||
177 | if (!req->buf) { | ||
178 | usb_ep_free_request(ep, req); | ||
179 | req = NULL; | ||
180 | } | ||
181 | } | ||
182 | return req; | ||
183 | } | ||
184 | |||
185 | void free_ep_req(struct usb_ep *ep, struct usb_request *req) | ||
186 | { | ||
187 | kfree(req->buf); | ||
188 | usb_ep_free_request(ep, req); | ||
189 | } | ||
190 | |||
191 | static void disable_ep(struct usb_composite_dev *cdev, struct usb_ep *ep) | ||
192 | { | ||
193 | int value; | ||
194 | |||
195 | if (ep->driver_data) { | ||
196 | value = usb_ep_disable(ep); | ||
197 | if (value < 0) | ||
198 | DBG(cdev, "disable %s --> %d\n", | ||
199 | ep->name, value); | ||
200 | ep->driver_data = NULL; | ||
201 | } | ||
202 | } | ||
203 | |||
204 | void disable_endpoints(struct usb_composite_dev *cdev, | ||
205 | struct usb_ep *in, struct usb_ep *out, | ||
206 | struct usb_ep *iso_in, struct usb_ep *iso_out) | ||
207 | { | ||
208 | disable_ep(cdev, in); | ||
209 | disable_ep(cdev, out); | ||
210 | if (iso_in) | ||
211 | disable_ep(cdev, iso_in); | ||
212 | if (iso_out) | ||
213 | disable_ep(cdev, iso_out); | ||
214 | } | ||
215 | |||
216 | /*-------------------------------------------------------------------------*/ | ||
217 | |||
218 | static struct timer_list autoresume_timer; | 159 | static struct timer_list autoresume_timer; |
219 | 160 | ||
220 | static void zero_autoresume(unsigned long _c) | 161 | static void zero_autoresume(unsigned long _c) |
@@ -258,23 +199,63 @@ static void zero_resume(struct usb_composite_dev *cdev) | |||
258 | 199 | ||
259 | static struct usb_configuration loopback_driver = { | 200 | static struct usb_configuration loopback_driver = { |
260 | .label = "loopback", | 201 | .label = "loopback", |
261 | .strings = loopback_strings, | ||
262 | .bConfigurationValue = 2, | 202 | .bConfigurationValue = 2, |
263 | .bmAttributes = USB_CONFIG_ATT_SELFPOWER, | 203 | .bmAttributes = USB_CONFIG_ATT_SELFPOWER, |
264 | /* .iConfiguration = DYNAMIC */ | 204 | /* .iConfiguration = DYNAMIC */ |
265 | }; | 205 | }; |
266 | 206 | ||
207 | static struct usb_function *func_ss; | ||
208 | static struct usb_function_instance *func_inst_ss; | ||
209 | |||
210 | static int ss_config_setup(struct usb_configuration *c, | ||
211 | const struct usb_ctrlrequest *ctrl) | ||
212 | { | ||
213 | switch (ctrl->bRequest) { | ||
214 | case 0x5b: | ||
215 | case 0x5c: | ||
216 | return func_ss->setup(func_ss, ctrl); | ||
217 | default: | ||
218 | return -EOPNOTSUPP; | ||
219 | } | ||
220 | } | ||
221 | |||
267 | static struct usb_configuration sourcesink_driver = { | 222 | static struct usb_configuration sourcesink_driver = { |
268 | .label = "source/sink", | 223 | .label = "source/sink", |
269 | .strings = sourcesink_strings, | ||
270 | .setup = ss_config_setup, | 224 | .setup = ss_config_setup, |
271 | .bConfigurationValue = 3, | 225 | .bConfigurationValue = 3, |
272 | .bmAttributes = USB_CONFIG_ATT_SELFPOWER, | 226 | .bmAttributes = USB_CONFIG_ATT_SELFPOWER, |
273 | /* .iConfiguration = DYNAMIC */ | 227 | /* .iConfiguration = DYNAMIC */ |
274 | }; | 228 | }; |
275 | 229 | ||
230 | module_param_named(buflen, gzero_options.bulk_buflen, uint, 0); | ||
231 | module_param_named(pattern, gzero_options.pattern, uint, S_IRUGO|S_IWUSR); | ||
232 | MODULE_PARM_DESC(pattern, "0 = all zeroes, 1 = mod63, 2 = none"); | ||
233 | |||
234 | module_param_named(isoc_interval, gzero_options.isoc_interval, uint, | ||
235 | S_IRUGO|S_IWUSR); | ||
236 | MODULE_PARM_DESC(isoc_interval, "1 - 16"); | ||
237 | |||
238 | module_param_named(isoc_maxpacket, gzero_options.isoc_maxpacket, uint, | ||
239 | S_IRUGO|S_IWUSR); | ||
240 | MODULE_PARM_DESC(isoc_maxpacket, "0 - 1023 (fs), 0 - 1024 (hs/ss)"); | ||
241 | |||
242 | module_param_named(isoc_mult, gzero_options.isoc_mult, uint, S_IRUGO|S_IWUSR); | ||
243 | MODULE_PARM_DESC(isoc_mult, "0 - 2 (hs/ss only)"); | ||
244 | |||
245 | module_param_named(isoc_maxburst, gzero_options.isoc_maxburst, uint, | ||
246 | S_IRUGO|S_IWUSR); | ||
247 | MODULE_PARM_DESC(isoc_maxburst, "0 - 15 (ss only)"); | ||
248 | |||
249 | static struct usb_function *func_lb; | ||
250 | static struct usb_function_instance *func_inst_lb; | ||
251 | |||
252 | module_param_named(qlen, gzero_options.qlen, uint, S_IRUGO|S_IWUSR); | ||
253 | MODULE_PARM_DESC(qlen, "depth of loopback queue"); | ||
254 | |||
276 | static int __init zero_bind(struct usb_composite_dev *cdev) | 255 | static int __init zero_bind(struct usb_composite_dev *cdev) |
277 | { | 256 | { |
257 | struct f_ss_opts *ss_opts; | ||
258 | struct f_lb_opts *lb_opts; | ||
278 | int status; | 259 | int status; |
279 | 260 | ||
280 | /* Allocate string descriptor numbers ... note that string | 261 | /* Allocate string descriptor numbers ... note that string |
@@ -290,6 +271,36 @@ static int __init zero_bind(struct usb_composite_dev *cdev) | |||
290 | 271 | ||
291 | setup_timer(&autoresume_timer, zero_autoresume, (unsigned long) cdev); | 272 | setup_timer(&autoresume_timer, zero_autoresume, (unsigned long) cdev); |
292 | 273 | ||
274 | func_inst_ss = usb_get_function_instance("SourceSink"); | ||
275 | if (IS_ERR(func_inst_ss)) | ||
276 | return PTR_ERR(func_inst_ss); | ||
277 | |||
278 | ss_opts = container_of(func_inst_ss, struct f_ss_opts, func_inst); | ||
279 | ss_opts->pattern = gzero_options.pattern; | ||
280 | ss_opts->isoc_interval = gzero_options.isoc_interval; | ||
281 | ss_opts->isoc_maxpacket = gzero_options.isoc_maxpacket; | ||
282 | ss_opts->isoc_mult = gzero_options.isoc_mult; | ||
283 | ss_opts->isoc_maxburst = gzero_options.isoc_maxpacket; | ||
284 | ss_opts->bulk_buflen = gzero_options.bulk_buflen; | ||
285 | |||
286 | func_ss = usb_get_function(func_inst_ss); | ||
287 | if (IS_ERR(func_ss)) | ||
288 | goto err_put_func_inst_ss; | ||
289 | |||
290 | func_inst_lb = usb_get_function_instance("Loopback"); | ||
291 | if (IS_ERR(func_inst_lb)) | ||
292 | goto err_put_func_ss; | ||
293 | |||
294 | lb_opts = container_of(func_inst_lb, struct f_lb_opts, func_inst); | ||
295 | lb_opts->bulk_buflen = gzero_options.bulk_buflen; | ||
296 | lb_opts->qlen = gzero_options.qlen; | ||
297 | |||
298 | func_lb = usb_get_function(func_inst_lb); | ||
299 | if (IS_ERR(func_lb)) { | ||
300 | status = PTR_ERR(func_lb); | ||
301 | goto err_put_func_inst_lb; | ||
302 | } | ||
303 | |||
293 | sourcesink_driver.iConfiguration = strings_dev[USB_GZERO_SS_DESC].id; | 304 | sourcesink_driver.iConfiguration = strings_dev[USB_GZERO_SS_DESC].id; |
294 | loopback_driver.iConfiguration = strings_dev[USB_GZERO_LB_DESC].id; | 305 | loopback_driver.iConfiguration = strings_dev[USB_GZERO_LB_DESC].id; |
295 | 306 | ||
@@ -315,25 +326,50 @@ static int __init zero_bind(struct usb_composite_dev *cdev) | |||
315 | * SH3 only allows one config... | 326 | * SH3 only allows one config... |
316 | */ | 327 | */ |
317 | if (loopdefault) { | 328 | if (loopdefault) { |
318 | usb_add_config(cdev, &loopback_driver, loopback_bind_config); | 329 | usb_add_config_only(cdev, &loopback_driver); |
319 | usb_add_config(cdev, &sourcesink_driver, | 330 | usb_add_config_only(cdev, &sourcesink_driver); |
320 | sourcesink_bind_config); | ||
321 | } else { | 331 | } else { |
322 | usb_add_config(cdev, &sourcesink_driver, | 332 | usb_add_config_only(cdev, &sourcesink_driver); |
323 | sourcesink_bind_config); | 333 | usb_add_config_only(cdev, &loopback_driver); |
324 | usb_add_config(cdev, &loopback_driver, loopback_bind_config); | ||
325 | } | 334 | } |
335 | status = usb_add_function(&sourcesink_driver, func_ss); | ||
336 | if (status) | ||
337 | goto err_conf_flb; | ||
326 | 338 | ||
339 | usb_ep_autoconfig_reset(cdev->gadget); | ||
340 | status = usb_add_function(&loopback_driver, func_lb); | ||
341 | if (status) | ||
342 | goto err_conf_flb; | ||
343 | |||
344 | usb_ep_autoconfig_reset(cdev->gadget); | ||
327 | usb_composite_overwrite_options(cdev, &coverwrite); | 345 | usb_composite_overwrite_options(cdev, &coverwrite); |
328 | 346 | ||
329 | INFO(cdev, "%s, version: " DRIVER_VERSION "\n", longname); | 347 | INFO(cdev, "%s, version: " DRIVER_VERSION "\n", longname); |
330 | 348 | ||
331 | return 0; | 349 | return 0; |
350 | |||
351 | err_conf_flb: | ||
352 | usb_put_function(func_lb); | ||
353 | func_lb = NULL; | ||
354 | err_put_func_inst_lb: | ||
355 | usb_put_function_instance(func_inst_lb); | ||
356 | func_inst_lb = NULL; | ||
357 | err_put_func_ss: | ||
358 | usb_put_function(func_ss); | ||
359 | func_ss = NULL; | ||
360 | err_put_func_inst_ss: | ||
361 | usb_put_function_instance(func_inst_ss); | ||
362 | func_inst_ss = NULL; | ||
363 | return status; | ||
332 | } | 364 | } |
333 | 365 | ||
334 | static int zero_unbind(struct usb_composite_dev *cdev) | 366 | static int zero_unbind(struct usb_composite_dev *cdev) |
335 | { | 367 | { |
336 | del_timer_sync(&autoresume_timer); | 368 | del_timer_sync(&autoresume_timer); |
369 | if (!IS_ERR_OR_NULL(func_ss)) | ||
370 | usb_put_function(func_ss); | ||
371 | if (!IS_ERR_OR_NULL(func_lb)) | ||
372 | usb_put_function(func_lb); | ||
337 | return 0; | 373 | return 0; |
338 | } | 374 | } |
339 | 375 | ||