diff options
author | Sebastian Andrzej Siewior <bigeasy@linutronix.de> | 2012-12-24 00:10:01 +0400 |
---|---|---|
committer | Felipe Balbi <balbi@ti.com> | 2013-01-21 22:52:40 +0400 |
commit | cf9a08ae5aece88987bbeee8eb0dd0ebb5015815 (patch) | |
tree | bbc7e204bd532b6ff84586653f57bc7ec6bf6380 /drivers/usb/gadget/f_sourcesink.c | |
parent | de53c25447117eae6b3f8952f663f08a09e0dbb7 (diff) | |
download | linux-cf9a08ae5aece88987bbeee8eb0dd0ebb5015815.tar.xz |
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/f_sourcesink.c')
-rw-r--r-- | drivers/usb/gadget/f_sourcesink.c | 165 |
1 files changed, 114 insertions, 51 deletions
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 @@ #include <linux/kernel.h> #include <linux/device.h> #include <linux/module.h> +#include <linux/usb/composite.h> +#include <linux/err.h> #include "g_zero.h" #include "gadget_chips.h" - /* * SOURCE/SINK FUNCTION ... a primary testing vehicle for USB peripheral * controller drivers. @@ -62,24 +63,11 @@ static inline struct f_sourcesink *func_to_ss(struct usb_function *f) } static unsigned pattern; -module_param(pattern, uint, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(pattern, "0 = all zeroes, 1 = mod63, 2 = none"); - -static unsigned isoc_interval = 4; -module_param(isoc_interval, uint, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(isoc_interval, "1 - 16"); - -static unsigned isoc_maxpacket = 1024; -module_param(isoc_maxpacket, uint, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(isoc_maxpacket, "0 - 1023 (fs), 0 - 1024 (hs/ss)"); - +static unsigned isoc_interval; +static unsigned isoc_maxpacket; static unsigned isoc_mult; -module_param(isoc_mult, uint, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(isoc_mult, "0 - 2 (hs/ss only)"); - static unsigned isoc_maxburst; -module_param(isoc_maxburst, uint, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(isoc_maxburst, "0 - 15 (ss only)"); +static unsigned buflen; /*-------------------------------------------------------------------------*/ @@ -313,7 +301,57 @@ static struct usb_gadget_strings *sourcesink_strings[] = { /*-------------------------------------------------------------------------*/ -static int __init +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 int sourcesink_bind(struct usb_configuration *c, struct usb_function *f) { struct usb_composite_dev *cdev = c->cdev; @@ -328,14 +366,6 @@ sourcesink_bind(struct usb_configuration *c, struct usb_function *f) source_sink_intf_alt0.bInterfaceNumber = id; source_sink_intf_alt1.bInterfaceNumber = id; - /* allocate string ID(s) */ - id = usb_string_id(cdev); - if (id < 0) - return id; - strings_sourcesink[0].id = id; - source_sink_intf_alt0.iInterface = id; - source_sink_intf_alt1.iInterface = id; - /* allocate bulk endpoints */ ss->in_ep = usb_ep_autoconfig(cdev->gadget, &fs_source_desc); if (!ss->in_ep) { @@ -457,14 +487,11 @@ no_iso: return 0; } -static struct usb_function *global_ss_func; - static void -sourcesink_unbind(struct usb_configuration *c, struct usb_function *f) +sourcesink_free_func(struct usb_function *f) { usb_free_all_descriptors(f); kfree(func_to_ss(f)); - global_ss_func = NULL; } /* optionally require specific source/sink data patterns */ @@ -767,6 +794,7 @@ static void sourcesink_disable(struct usb_function *f) } /*-------------------------------------------------------------------------*/ + static int sourcesink_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl) { @@ -839,41 +867,76 @@ unknown: return value; } -static int __init sourcesink_bind_config(struct usb_configuration *c) +static struct usb_function *source_sink_alloc_func( + struct usb_function_instance *fi) { - struct f_sourcesink *ss; - int status; + struct f_sourcesink *ss; + struct f_ss_opts *ss_opts; ss = kzalloc(sizeof(*ss), GFP_KERNEL); if (!ss) - return -ENOMEM; + return NULL; - global_ss_func = &ss->function; + ss_opts = container_of(fi, struct f_ss_opts, func_inst); + pattern = ss_opts->pattern; + isoc_interval = ss_opts->isoc_interval; + isoc_maxpacket = ss_opts->isoc_maxpacket; + isoc_mult = ss_opts->isoc_mult; + isoc_maxburst = ss_opts->isoc_maxburst; + buflen = ss_opts->bulk_buflen; ss->function.name = "source/sink"; ss->function.bind = sourcesink_bind; - ss->function.unbind = sourcesink_unbind; ss->function.set_alt = sourcesink_set_alt; ss->function.get_alt = sourcesink_get_alt; ss->function.disable = sourcesink_disable; ss->function.setup = sourcesink_setup; + ss->function.strings = sourcesink_strings; - status = usb_add_function(c, &ss->function); - if (status) - kfree(ss); - return status; + ss->function.free_func = sourcesink_free_func; + + return &ss->function; } -static int ss_config_setup(struct usb_configuration *c, - const struct usb_ctrlrequest *ctrl) +static void acm_free_instance(struct usb_function_instance *fi) { - if (!global_ss_func) - return -EOPNOTSUPP; - switch (ctrl->bRequest) { - case 0x5b: - case 0x5c: - return global_ss_func->setup(global_ss_func, ctrl); - default: - return -EOPNOTSUPP; - } + struct f_ss_opts *ss_opts; + + ss_opts = container_of(fi, struct f_ss_opts, func_inst); + kfree(ss_opts); } + +static struct usb_function_instance *source_sink_alloc_inst(void) +{ + struct f_ss_opts *ss_opts; + + ss_opts = kzalloc(sizeof(*ss_opts), GFP_KERNEL); + if (!ss_opts) + return ERR_PTR(-ENOMEM); + ss_opts->func_inst.free_func_inst = acm_free_instance; + return &ss_opts->func_inst; +} +DECLARE_USB_FUNCTION(SourceSink, source_sink_alloc_inst, + source_sink_alloc_func); + +static int __init sslb_modinit(void) +{ + int ret; + + ret = usb_function_register(&SourceSinkusb_func); + if (ret) + return ret; + ret = lb_modinit(); + if (ret) + usb_function_unregister(&SourceSinkusb_func); + return ret; +} +static void __exit sslb_modexit(void) +{ + usb_function_unregister(&SourceSinkusb_func); + lb_modexit(); +} +module_init(sslb_modinit); +module_exit(sslb_modexit); + +MODULE_LICENSE("GPL"); |