summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/usb/gadget/f_sourcesink.c70
1 files changed, 45 insertions, 25 deletions
diff --git a/drivers/usb/gadget/f_sourcesink.c b/drivers/usb/gadget/f_sourcesink.c
index de608864c6db..bac04b0c628e 100644
--- a/drivers/usb/gadget/f_sourcesink.c
+++ b/drivers/usb/gadget/f_sourcesink.c
@@ -449,11 +449,14 @@ no_iso:
return 0;
}
+static struct usb_function *global_ss_func;
+
static void
sourcesink_unbind(struct usb_configuration *c, 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 */
@@ -756,32 +759,10 @@ static void sourcesink_disable(struct usb_function *f)
}
/*-------------------------------------------------------------------------*/
-
-static int __init sourcesink_bind_config(struct usb_configuration *c)
-{
- struct f_sourcesink *ss;
- int status;
-
- ss = kzalloc(sizeof *ss, GFP_KERNEL);
- if (!ss)
- return -ENOMEM;
-
- 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;
-
- status = usb_add_function(c, &ss->function);
- if (status)
- kfree(ss);
- return status;
-}
-
-static int sourcesink_setup(struct usb_configuration *c,
+static int sourcesink_setup(struct usb_function *f,
const struct usb_ctrlrequest *ctrl)
{
+ struct usb_configuration *c = f->config;
struct usb_request *req = c->cdev->req;
int value = -EOPNOTSUPP;
u16 w_index = le16_to_cpu(ctrl->wIndex);
@@ -850,10 +831,49 @@ unknown:
return value;
}
+static int __init sourcesink_bind_config(struct usb_configuration *c)
+{
+ struct f_sourcesink *ss;
+ int status;
+
+ ss = kzalloc(sizeof(*ss), GFP_KERNEL);
+ if (!ss)
+ return -ENOMEM;
+
+ global_ss_func = &ss->function;
+
+ 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;
+
+ status = usb_add_function(c, &ss->function);
+ if (status)
+ kfree(ss);
+ return status;
+}
+
+static int ss_config_setup(struct usb_configuration *c,
+ const struct usb_ctrlrequest *ctrl)
+{
+ 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;
+ }
+}
+
static struct usb_configuration sourcesink_driver = {
.label = "source/sink",
.strings = sourcesink_strings,
- .setup = sourcesink_setup,
+ .setup = ss_config_setup,
.bConfigurationValue = 3,
.bmAttributes = USB_CONFIG_ATT_SELFPOWER,
/* .iConfiguration = DYNAMIC */
OpenPOWER on IntegriCloud