Signed-off-by: Sebastian Andrzej Siewior <bigeasy@xxxxxxxxxxxxx> --- drivers/usb/gadget/Kconfig | 4 ++ drivers/usb/gadget/Makefile | 1 + drivers/usb/gadget/f_loopback.c | 129 +++++++++++++++++++++++++++++++++------ drivers/usb/gadget/g_zero.h | 22 ------- drivers/usb/gadget/zero.c | 129 ++++++++++++++++----------------------- 5 files changed, 167 insertions(+), 118 deletions(-) delete mode 100644 drivers/usb/gadget/g_zero.h diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 881cd63..fd64769 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -500,6 +500,9 @@ config USB_LIBCOMPOSITE tristate depends on USB_GADGET +config USB_F_LOOPBACK + tristate + config USB_F_SOURCESINK tristate @@ -527,6 +530,7 @@ choice config USB_ZERO tristate "Gadget Zero (DEVELOPMENT)" select USB_LIBCOMPOSITE + select USB_F_LOOPBACK select USB_F_SOURCESINK help Gadget Zero is a two-configuration device. It either sinks and diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index a68f306..1829524 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -78,4 +78,5 @@ obj-$(CONFIG_USB_G_ACM_MS) += g_acm_ms.o obj-$(CONFIG_USB_GADGET_TARGET) += tcm_usb_gadget.o # USB Functions +obj-$(CONFIG_USB_F_LOOPBACK) += f_loopback.o obj-$(CONFIG_USB_F_SOURCESINK) += f_sourcesink.o diff --git a/drivers/usb/gadget/f_loopback.c b/drivers/usb/gadget/f_loopback.c index 3d103a2..5b4e3a4 100644 --- a/drivers/usb/gadget/f_loopback.c +++ b/drivers/usb/gadget/f_loopback.c @@ -15,10 +15,9 @@ #include <linux/slab.h> #include <linux/kernel.h> #include <linux/device.h> - -#include "g_zero.h" -#include "gadget_chips.h" - +#include <linux/module.h> +#include <linux/err.h> +#include <linux/usb/composite.h> /* * LOOPBACK FUNCTION ... a testing vehicle for USB peripherals, @@ -44,9 +43,8 @@ static inline struct f_loopback *func_to_loop(struct usb_function *f) return container_of(f, struct f_loopback, function); } -static unsigned qlen = 32; -module_param(qlen, uint, 0); -MODULE_PARM_DESC(qlenn, "depth of loopback queue"); +static unsigned qlen; +static unsigned buflen; /*-------------------------------------------------------------------------*/ @@ -171,14 +169,77 @@ static struct usb_gadget_strings *loopback_strings[] = { /*-------------------------------------------------------------------------*/ -static int __init -loopback_bind(struct usb_configuration *c, struct usb_function *f) +static struct usb_request *alloc_ep_req(struct usb_ep *ep, int len) +{ + struct usb_request *req; + + req = usb_ep_alloc_request(ep, GFP_ATOMIC); + if (req) { + if (len) + req->length = len; + else + req->length = buflen; + req->buf = kmalloc(req->length, GFP_ATOMIC); + if (!req->buf) { + usb_ep_free_request(ep, req); + req = NULL; + } + } + return req; +} + +static void free_ep_req(struct usb_ep *ep, struct usb_request *req) +{ + kfree(req->buf); + usb_ep_free_request(ep, req); +} + +static void disable_ep(struct usb_composite_dev *cdev, struct usb_ep *ep) +{ + int value; + + if (ep->driver_data) { + value = usb_ep_disable(ep); + if (value < 0) + DBG(cdev, "disable %s --> %d\n", + ep->name, value); + ep->driver_data = NULL; + } +} + +static void disable_endpoints(struct usb_composite_dev *cdev, + struct usb_ep *in, struct usb_ep *out, + struct usb_ep *iso_in, struct usb_ep *iso_out) +{ + disable_ep(cdev, in); + disable_ep(cdev, out); + if (iso_in) + disable_ep(cdev, iso_in); + if (iso_out) + disable_ep(cdev, iso_out); +} + +static int lb_check_param(void) +{ + if (!buflen) + return -EINVAL; + if (!qlen) + return -EINVAL; + return 0; +} + +static int loopback_bind(struct usb_configuration *c, struct usb_function *f) { struct usb_composite_dev *cdev = c->cdev; struct f_loopback *loop = func_to_loop(f); int id; int ret; + ret = lb_check_param(); + if (ret) + return ret; + + /* allocate interface ID(s) */ id = usb_interface_id(c, f); if (id < 0) @@ -229,8 +290,7 @@ loopback_bind(struct usb_configuration *c, struct usb_function *f) return 0; } -static void -loopback_unbind(struct usb_configuration *c, struct usb_function *f) +static void lb_free_func(struct usb_function *f) { usb_free_all_descriptors(f); kfree(func_to_loop(f)); @@ -372,25 +432,54 @@ static void loopback_disable(struct usb_function *f) disable_loopback(loop); } -/*-------------------------------------------------------------------------*/ +static const struct usbf_option lb_options[] = { + { + .type = USBF_OPTION_INT, + .name = "bulk_buflen", + }, { + .type = USBF_OPTION_INT, + .name = "queue_length", + }, +}; -static int __init loopback_bind_config(struct usb_configuration *c) +static int lb_configure(struct usb_function *f, struct usbf_option *options, + int num) +{ + int i; + + for (i = 0; i < num; i++) { + if (!strcmp("bulk_buflen", options->name)) + buflen = options->val.o_int; + else if (!strcmp("queue_length", options->name)) + qlen = options->val.o_int; + else + return -EINVAL; + options++; + } + return 0; +} + +static struct usb_function *loopback_alloc(void) { struct f_loopback *loop; - int status; loop = kzalloc(sizeof *loop, GFP_KERNEL); if (!loop) - return -ENOMEM; + return ERR_PTR(-ENOMEM); loop->function.name = "loopback"; loop->function.bind = loopback_bind; - loop->function.unbind = loopback_unbind; loop->function.set_alt = loopback_set_alt; loop->function.disable = loopback_disable; + loop->function.strings = loopback_strings; - status = usb_add_function(c, &loop->function); - if (status) - kfree(loop); - return status; + loop->function.avail_options = lb_options; + loop->function.avail_options_num = ARRAY_SIZE(lb_options); + loop->function.configure = lb_configure; + loop->function.free_func = lb_free_func; + + return &loop->function; } + +DECLARE_USB_FUNCTION(Loopback, loopback_alloc); +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/gadget/g_zero.h b/drivers/usb/gadget/g_zero.h deleted file mode 100644 index 281239c..0000000 --- a/drivers/usb/gadget/g_zero.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * This header declares the utility functions used by "Gadget Zero", plus - * interfaces to its two single-configuration function drivers. - */ - -#ifndef __G_ZERO_H -#define __G_ZERO_H - -#include <linux/usb/composite.h> - -/* global state */ -extern unsigned buflen; -extern const struct usb_descriptor_header *otg_desc[]; - -/* common utilities */ -struct usb_request *alloc_ep_req(struct usb_ep *ep, int len); -void free_ep_req(struct usb_ep *ep, struct usb_request *req); -void disable_endpoints(struct usb_composite_dev *cdev, - struct usb_ep *in, struct usb_ep *out, - struct usb_ep *iso_in, struct usb_ep *iso_out); - -#endif /* __G_ZERO_H */ diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c index bf4e37f..61337e6 100644 --- a/drivers/usb/gadget/zero.c +++ b/drivers/usb/gadget/zero.c @@ -45,20 +45,7 @@ #include <linux/device.h> #include <linux/module.h> #include <linux/err.h> - -#include "g_zero.h" -#include "gadget_chips.h" - -/*-------------------------------------------------------------------------*/ - -/* - * Kbuild is not very cooperative with respect to linking separately - * compiled library objects into one module. So for now we won't use - * separate compilation ... ensuring init/exit sections work to shrink - * the runtime footprint, and giving us at least some parts of what - * a "gcc --combine ... part1.c part2.c part3.c ... " build would. - */ -#include "f_loopback.c" +#include <linux/usb/composite.h> /*-------------------------------------------------------------------------*/ USB_GADGET_COMPOSITE_OPTIONS(); @@ -67,9 +54,6 @@ USB_GADGET_COMPOSITE_OPTIONS(); static const char longname[] = "Gadget Zero"; -unsigned buflen = 4096; /* only used for bulk endpoints */ -module_param(buflen, uint, 0); - /* * Normally the "loopback" configuration is second (index 1) so * it's not the default. Here's where to change that order, to @@ -129,10 +113,12 @@ static struct usb_otg_descriptor otg_descriptor = { .bmAttributes = USB_OTG_SRP | USB_OTG_HNP, }; -const struct usb_descriptor_header *otg_desc[] = { +static const struct usb_descriptor_header *otg_desc[] = { (struct usb_descriptor_header *) &otg_descriptor, NULL, }; +#else +extern const struct usb_descriptor_header *otg_desc[]; #endif /* string IDs are assigned dynamically */ @@ -163,58 +149,6 @@ static struct usb_gadget_strings *dev_strings[] = { /*-------------------------------------------------------------------------*/ -struct usb_request *alloc_ep_req(struct usb_ep *ep, int len) -{ - struct usb_request *req; - - req = usb_ep_alloc_request(ep, GFP_ATOMIC); - if (req) { - if (len) - req->length = len; - else - req->length = buflen; - req->buf = kmalloc(req->length, GFP_ATOMIC); - if (!req->buf) { - usb_ep_free_request(ep, req); - req = NULL; - } - } - return req; -} - -void free_ep_req(struct usb_ep *ep, struct usb_request *req) -{ - kfree(req->buf); - usb_ep_free_request(ep, req); -} - -static void disable_ep(struct usb_composite_dev *cdev, struct usb_ep *ep) -{ - int value; - - if (ep->driver_data) { - value = usb_ep_disable(ep); - if (value < 0) - DBG(cdev, "disable %s --> %d\n", - ep->name, value); - ep->driver_data = NULL; - } -} - -void disable_endpoints(struct usb_composite_dev *cdev, - struct usb_ep *in, struct usb_ep *out, - struct usb_ep *iso_in, struct usb_ep *iso_out) -{ - disable_ep(cdev, in); - disable_ep(cdev, out); - if (iso_in) - disable_ep(cdev, iso_in); - if (iso_out) - disable_ep(cdev, iso_out); -} - -/*-------------------------------------------------------------------------*/ - static struct timer_list autoresume_timer; static void zero_autoresume(unsigned long _c) @@ -258,7 +192,6 @@ static void zero_resume(struct usb_composite_dev *cdev) static struct usb_configuration loopback_driver = { .label = "loopback", - .strings = loopback_strings, .bConfigurationValue = 2, .bmAttributes = USB_CONFIG_ATT_SELFPOWER, /* .iConfiguration = DYNAMIC */ @@ -338,6 +271,29 @@ module_param_named(isoc_maxburst, fss_options[SS_OPT_ISOC_MAXBURST].val.o_int, uint, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(isoc_maxburst, "0 - 15 (ss only)"); +module_param_named(buflen, fss_options[SS_OPT_BULK_BUFLEN].val.o_int, uint, + S_IRUGO|S_IWUSR); + +static struct usb_function *func_lb; +enum { + LB_OPT_BULK_BUFLEN, + LB_OPT_QLEN, +}; + +static struct usbf_option flb_options[] = { + [LB_OPT_BULK_BUFLEN] = { + .name = "bulk_buflen", + }, + [LB_OPT_QLEN] = { + .name = "queue_length", + .val.o_int = 32, + }, +}; + +module_param_named(qlen, flb_options[LB_OPT_QLEN].val.o_int, uint, + S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(qlen, "depth of loopback queue"); + static int __init zero_bind(struct usb_composite_dev *cdev) { int status; @@ -359,12 +315,23 @@ static int __init zero_bind(struct usb_composite_dev *cdev) if (IS_ERR(func_ss)) return PTR_ERR(func_ss); - fss_options[SS_OPT_BULK_BUFLEN].val.o_int = buflen; - status = usbf_configure(func_ss, fss_options); if (status) goto err_conf_fss; + func_lb = usb_get_function("Loopback"); + if (IS_ERR(func_lb)) { + status = PTR_ERR(func_lb); + goto err_conf_fss; + } + + flb_options[LB_OPT_BULK_BUFLEN].val.o_int = + fss_options[SS_OPT_BULK_BUFLEN].val.o_int; + + status = usbf_configure(func_lb, flb_options); + if (status) + goto err_conf_flb; + sourcesink_driver.iConfiguration = strings_dev[USB_GZERO_SS_DESC].id; loopback_driver.iConfiguration = strings_dev[USB_GZERO_LB_DESC].id; @@ -390,15 +357,20 @@ static int __init zero_bind(struct usb_composite_dev *cdev) * SH3 only allows one config... */ if (loopdefault) { - usb_add_config(cdev, &loopback_driver, loopback_bind_config); + usb_add_config_only(cdev, &loopback_driver); usb_add_config_only(cdev, &sourcesink_driver); } else { usb_add_config_only(cdev, &sourcesink_driver); - usb_add_config(cdev, &loopback_driver, loopback_bind_config); + usb_add_config_only(cdev, &loopback_driver); } status = usb_add_function(&sourcesink_driver, func_ss); if (status) - goto err_conf_fss; + goto err_conf_flb; + + usb_ep_autoconfig_reset(cdev->gadget); + status = usb_add_function(&loopback_driver, func_lb); + if (status) + goto err_conf_flb; usb_ep_autoconfig_reset(cdev->gadget); usb_composite_overwrite_options(cdev, &coverwrite); @@ -406,6 +378,9 @@ static int __init zero_bind(struct usb_composite_dev *cdev) INFO(cdev, "%s, version: " DRIVER_VERSION "\n", longname); return 0; +err_conf_flb: + usb_put_function(func_lb); + func_lb = NULL; err_conf_fss: usb_put_function(func_ss); func_ss = NULL; @@ -417,6 +392,8 @@ static int zero_unbind(struct usb_composite_dev *cdev) del_timer_sync(&autoresume_timer); if (!IS_ERR_OR_NULL(func_ss)) usb_put_function(func_ss); + if (!IS_ERR_OR_NULL(func_lb)) + usb_put_function(func_lb); return 0; } -- 1.7.10.4 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html