aboutsummaryrefslogtreecommitdiff
path: root/drivers/usb/gadget/f_sourcesink.c
diff options
context:
space:
mode:
authorSebastian Andrzej Siewior <bigeasy@linutronix.de>2012-12-23 21:10:01 +0100
committerFelipe Balbi <balbi@ti.com>2013-01-21 20:52:40 +0200
commitcf9a08ae5aece88987bbeee8eb0dd0ebb5015815 (patch)
treebbc7e204bd532b6ff84586653f57bc7ec6bf6380 /drivers/usb/gadget/f_sourcesink.c
parentde53c25447117eae6b3f8952f663f08a09e0dbb7 (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/gadget/f_sourcesink.c')
-rw-r--r--drivers/usb/gadget/f_sourcesink.c165
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");