diff options
author | Sascha Hauer <s.hauer@pengutronix.de> | 2014-07-21 09:17:57 +0200 |
---|---|---|
committer | Sascha Hauer <s.hauer@pengutronix.de> | 2014-07-22 08:11:49 +0200 |
commit | ade522c6dd373c3d292de6a2ccd6ffb8d55371e9 (patch) | |
tree | 49eb30e9556561b5d24b0d34f416704e56e632f1 /drivers/usb | |
parent | 6f267eae9efe21e29c513643cd552e596a3ac53c (diff) | |
download | barebox-ade522c6dd373c3d292de6a2ccd6ffb8d55371e9.tar.gz barebox-ade522c6dd373c3d292de6a2ccd6ffb8d55371e9.tar.xz |
USB: gadget: DFU: register as USB function
Register DFU as usb_function_instance to make it work with composite
gadgets. Also use this internally for registering as DFU device (with
the 'dfu' command).
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Diffstat (limited to 'drivers/usb')
-rw-r--r-- | drivers/usb/gadget/dfu.c | 141 |
1 files changed, 96 insertions, 45 deletions
diff --git a/drivers/usb/gadget/dfu.c b/drivers/usb/gadget/dfu.c index ca7462b315..3684edd63c 100644 --- a/drivers/usb/gadget/dfu.c +++ b/drivers/usb/gadget/dfu.c @@ -182,6 +182,13 @@ dfu_bind(struct usb_configuration *c, struct usb_function *f) int status; struct usb_string *us; + if (!dfu_files) { + const struct usb_function_instance *fi = f->fi; + struct f_dfu_opts *opts = container_of(fi, struct f_dfu_opts, func_inst); + + dfu_files = opts->files; + } + dfu_string_defs = xzalloc(sizeof(struct usb_string) * (dfu_files->num_entries + 2)); dfu_string_defs[0].s = "Generic DFU"; i = 0; @@ -652,42 +659,6 @@ static struct usb_gadget_strings *dev_strings[] = { NULL, }; -static int dfu_bind_config(struct usb_configuration *c) -{ - struct f_dfu *dfu; - struct usb_function *func; - int status; - - /* config description */ - status = usb_string_id(c->cdev); - if (status < 0) - return status; - strings_dev[STRING_DESCRIPTION_IDX].id = status; - - /* allocate and initialize one new instance */ - dfu = xzalloc(sizeof *dfu); - - func = &dfu->func; - func->name = "DFU"; - func->strings = dfu_strings; - /* descriptors are per-instance copies */ - func->bind = dfu_bind; - func->unbind = dfu_unbind; - func->set_alt = dfu_set_alt; - func->setup = dfu_setup; - func->disable = dfu_disable; - - status = usb_add_function(c, func); - if (status) - goto out; - - return 0; -out: - free(dfu); - - return status; -} - static void dfu_unbind_config(struct usb_configuration *c) { free(dfu_string_defs); @@ -713,6 +684,9 @@ static struct usb_device_descriptor dfu_dev_descriptor = { .bNumConfigurations = 0x01, }; +static struct usb_function_instance *fi_dfu; +static struct usb_function *f_dfu; + static int dfu_driver_bind(struct usb_composite_dev *cdev) { struct usb_gadget *gadget = cdev->gadget; @@ -748,52 +722,129 @@ static int dfu_driver_bind(struct usb_composite_dev *cdev) strings_dev[STRING_DESCRIPTION_IDX].id = status; dfu_config_driver.iConfiguration = status; - status = usb_add_config(cdev, &dfu_config_driver, dfu_bind_config); + status = usb_add_config_only(cdev, &dfu_config_driver); if (status < 0) goto fail; + fi_dfu = usb_get_function_instance("dfu"); + if (IS_ERR(fi_dfu)) { + status = PTR_ERR(fi_dfu); + goto fail; + } + + f_dfu = usb_get_function(fi_dfu); + if (IS_ERR(f_dfu)) { + status = PTR_ERR(f_dfu); + goto fail; + } + + status = usb_add_function(&dfu_config_driver, f_dfu); + if (status) + goto fail; + return 0; fail: return status; } +static int dfu_driver_unbind(struct usb_composite_dev *cdev) +{ + usb_put_function(f_dfu); + usb_put_function_instance(fi_dfu); + + return 0; +} + static struct usb_composite_driver dfu_driver = { .name = "g_dfu", .dev = &dfu_dev_descriptor, .strings = dev_strings, .bind = dfu_driver_bind, + .unbind = dfu_driver_unbind, }; -int usb_dfu_register(struct usb_dfu_pdata *pdata) +int usb_dfu_register(struct f_dfu_opts *opts) { int ret; - dfu_files = pdata->files; + if (dfu_files) + return -EBUSY; + + dfu_files = opts->files; ret = usb_composite_probe(&dfu_driver); if (ret) - return ret; + goto out; while (1) { ret = usb_gadget_poll(); if (ret < 0) - goto out; + goto out1; if (dfudetach) { ret = 0; - goto out; + goto out1; } if (ctrlc()) { ret = -EINTR; - goto out; + goto out1; } } -out: +out1: dfudetach = 0; usb_composite_unregister(&dfu_driver); +out: + dfu_files = NULL; - return 0; + return ret; +} + +static void dfu_free_func(struct usb_function *f) +{ + struct f_dfu *dfu = container_of(f, struct f_dfu, func); + + free(dfu); +} + +static struct usb_function *dfu_alloc_func(struct usb_function_instance *fi) +{ + struct f_dfu *dfu; + + dfu = xzalloc(sizeof(*dfu)); + + dfu->func.name = "dfu"; + dfu->func.strings = dfu_strings; + /* descriptors are per-instance copies */ + dfu->func.bind = dfu_bind; + dfu->func.set_alt = dfu_set_alt; + dfu->func.setup = dfu_setup; + dfu->func.disable = dfu_disable; + dfu->func.unbind = dfu_unbind; + dfu->func.free_func = dfu_free_func; + + return &dfu->func; +} + +static void dfu_free_instance(struct usb_function_instance *fi) +{ + struct f_dfu_opts *opts; + + opts = container_of(fi, struct f_dfu_opts, func_inst); + kfree(opts); +} + +static struct usb_function_instance *dfu_alloc_instance(void) +{ + struct f_dfu_opts *opts; + + opts = kzalloc(sizeof(*opts), GFP_KERNEL); + if (!opts) + return ERR_PTR(-ENOMEM); + opts->func_inst.free_func_inst = dfu_free_instance; + + return &opts->func_inst; } +DECLARE_USB_FUNCTION_INIT(dfu, dfu_alloc_instance, dfu_alloc_func); |