diff options
author | Sebastian Andrzej Siewior <bigeasy@linutronix.de> | 2012-12-23 21:10:01 +0100 |
---|---|---|
committer | Felipe Balbi <balbi@ti.com> | 2013-01-21 19:52:40 +0100 |
commit | cf9a08ae5aece88987bbeee8eb0dd0ebb5015815 (patch) | |
tree | bbc7e204bd532b6ff84586653f57bc7ec6bf6380 /drivers/usb/gadget/zero.c | |
parent | usb: gadget: add some infracture to register/unregister functions (diff) | |
download | linux-cf9a08ae5aece88987bbeee8eb0dd0ebb5015815.tar.xz linux-cf9a08ae5aece88987bbeee8eb0dd0ebb5015815.zip |
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/gadget/zero.c')
-rw-r--r-- | drivers/usb/gadget/zero.c | 196 |
1 files changed, 116 insertions, 80 deletions
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 @@ * (at your option) any later version. */ - /* * Gadget Zero only needs two bulk endpoints, and is an example of how you * can write a hardware-agnostic gadget driver running inside a USB device. @@ -43,23 +42,11 @@ #include <linux/kernel.h> #include <linux/slab.h> #include <linux/device.h> +#include <linux/module.h> +#include <linux/err.h> +#include <linux/usb/composite.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_sourcesink.c" -#include "f_loopback.c" - /*-------------------------------------------------------------------------*/ 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 @@ -79,6 +63,13 @@ module_param(buflen, uint, 0); static bool loopdefault = 0; module_param(loopdefault, bool, S_IRUGO|S_IWUSR); +struct usb_zero_options gzero_options = { + .isoc_interval = 4, + .isoc_maxpacket = 1024, + .bulk_buflen = 4096, + .qlen = 32, +}; + /*-------------------------------------------------------------------------*/ /* Thanks to NetChip Technologies for donating this product ID. @@ -129,10 +120,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 +#define otg_desc NULL #endif /* string IDs are assigned dynamically */ @@ -163,58 +156,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,23 +199,63 @@ 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 */ }; +static struct usb_function *func_ss; +static struct usb_function_instance *func_inst_ss; + +static int ss_config_setup(struct usb_configuration *c, + const struct usb_ctrlrequest *ctrl) +{ + switch (ctrl->bRequest) { + case 0x5b: + case 0x5c: + return func_ss->setup(func_ss, ctrl); + default: + return -EOPNOTSUPP; + } +} + static struct usb_configuration sourcesink_driver = { .label = "source/sink", - .strings = sourcesink_strings, .setup = ss_config_setup, .bConfigurationValue = 3, .bmAttributes = USB_CONFIG_ATT_SELFPOWER, /* .iConfiguration = DYNAMIC */ }; +module_param_named(buflen, gzero_options.bulk_buflen, uint, 0); +module_param_named(pattern, gzero_options.pattern, uint, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(pattern, "0 = all zeroes, 1 = mod63, 2 = none"); + +module_param_named(isoc_interval, gzero_options.isoc_interval, uint, + S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(isoc_interval, "1 - 16"); + +module_param_named(isoc_maxpacket, gzero_options.isoc_maxpacket, uint, + S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(isoc_maxpacket, "0 - 1023 (fs), 0 - 1024 (hs/ss)"); + +module_param_named(isoc_mult, gzero_options.isoc_mult, uint, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(isoc_mult, "0 - 2 (hs/ss only)"); + +module_param_named(isoc_maxburst, gzero_options.isoc_maxburst, uint, + S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(isoc_maxburst, "0 - 15 (ss only)"); + +static struct usb_function *func_lb; +static struct usb_function_instance *func_inst_lb; + +module_param_named(qlen, gzero_options.qlen, uint, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(qlen, "depth of loopback queue"); + static int __init zero_bind(struct usb_composite_dev *cdev) { + struct f_ss_opts *ss_opts; + struct f_lb_opts *lb_opts; int status; /* Allocate string descriptor numbers ... note that string @@ -290,6 +271,36 @@ static int __init zero_bind(struct usb_composite_dev *cdev) setup_timer(&autoresume_timer, zero_autoresume, (unsigned long) cdev); + func_inst_ss = usb_get_function_instance("SourceSink"); + if (IS_ERR(func_inst_ss)) + return PTR_ERR(func_inst_ss); + + ss_opts = container_of(func_inst_ss, struct f_ss_opts, func_inst); + ss_opts->pattern = gzero_options.pattern; + ss_opts->isoc_interval = gzero_options.isoc_interval; + ss_opts->isoc_maxpacket = gzero_options.isoc_maxpacket; + ss_opts->isoc_mult = gzero_options.isoc_mult; + ss_opts->isoc_maxburst = gzero_options.isoc_maxpacket; + ss_opts->bulk_buflen = gzero_options.bulk_buflen; + + func_ss = usb_get_function(func_inst_ss); + if (IS_ERR(func_ss)) + goto err_put_func_inst_ss; + + func_inst_lb = usb_get_function_instance("Loopback"); + if (IS_ERR(func_inst_lb)) + goto err_put_func_ss; + + lb_opts = container_of(func_inst_lb, struct f_lb_opts, func_inst); + lb_opts->bulk_buflen = gzero_options.bulk_buflen; + lb_opts->qlen = gzero_options.qlen; + + func_lb = usb_get_function(func_inst_lb); + if (IS_ERR(func_lb)) { + status = PTR_ERR(func_lb); + goto err_put_func_inst_lb; + } + sourcesink_driver.iConfiguration = strings_dev[USB_GZERO_SS_DESC].id; loopback_driver.iConfiguration = strings_dev[USB_GZERO_LB_DESC].id; @@ -315,25 +326,50 @@ 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(cdev, &sourcesink_driver, - sourcesink_bind_config); + usb_add_config_only(cdev, &loopback_driver); + usb_add_config_only(cdev, &sourcesink_driver); } else { - usb_add_config(cdev, &sourcesink_driver, - sourcesink_bind_config); - usb_add_config(cdev, &loopback_driver, loopback_bind_config); + usb_add_config_only(cdev, &sourcesink_driver); + usb_add_config_only(cdev, &loopback_driver); } + status = usb_add_function(&sourcesink_driver, func_ss); + if (status) + 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); INFO(cdev, "%s, version: " DRIVER_VERSION "\n", longname); return 0; + +err_conf_flb: + usb_put_function(func_lb); + func_lb = NULL; +err_put_func_inst_lb: + usb_put_function_instance(func_inst_lb); + func_inst_lb = NULL; +err_put_func_ss: + usb_put_function(func_ss); + func_ss = NULL; +err_put_func_inst_ss: + usb_put_function_instance(func_inst_ss); + func_inst_ss = NULL; + return status; } 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; } |