Hi, On Wed, Nov 14, 2012 at 06:14:55PM +0100, Sebastian Andrzej Siewior wrote: > This patch provides an infrastructure to register & unregister a USB > function. This allows to turn a function into a module and avoid the > '#include "f_.*.c"' magic and we get a clear API / cut between the bare > gadget and its functions. > The concept is simple: > Each function defines the DECLARE_USB_FUNCTION_INIT macro whith an unique > name of the function and an allocation function. The name is used for > automaticaly loading the module if it is not yet present and request the > function from the gadget because we don't include the functions anymore. > The allocate function is mostly the "old" bind-callback which was passed > to usb_add_config() with a minor change: > - a function de-allocate function > This is mostly the same thing that is done by the unbind function. It > is called from within the function on "free" instead from the unbind > path on gadget removal. > > Signed-off-by: Sebastian Andrzej Siewior <[email protected]> > --- > drivers/usb/gadget/Makefile | 2 +- > drivers/usb/gadget/composite.c | 53 +++++++++++++--------- > drivers/usb/gadget/functions.c | 96 > ++++++++++++++++++++++++++++++++++++++++ > include/linux/usb/composite.h | 44 ++++++++++++++++++ > 4 files changed, 174 insertions(+), 21 deletions(-) > create mode 100644 drivers/usb/gadget/functions.c > > diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile > index 307be5f..fa65050 100644 > --- a/drivers/usb/gadget/Makefile > +++ b/drivers/usb/gadget/Makefile > @@ -6,7 +6,7 @@ ccflags-$(CONFIG_USB_GADGET_DEBUG) := -DDEBUG > obj-$(CONFIG_USB_GADGET) += udc-core.o > obj-$(CONFIG_USB_LIBCOMPOSITE) += libcomposite.o > libcomposite-y := usbstring.o config.o epautoconf.o > -libcomposite-y += composite.o > +libcomposite-y += composite.o functions.o > obj-$(CONFIG_USB_DUMMY_HCD) += dummy_hcd.o > obj-$(CONFIG_USB_NET2272) += net2272.o > obj-$(CONFIG_USB_NET2280) += net2280.o > diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c > index 4eb07c7..c46ae24 100644 > --- a/drivers/usb/gadget/composite.c > +++ b/drivers/usb/gadget/composite.c > @@ -664,6 +664,35 @@ static int set_config(struct usb_composite_dev *cdev, > return result; > } > > +int usb_add_config_only(struct usb_composite_dev *cdev, > + struct usb_configuration *config) > +{ > + struct usb_configuration *c; > + > + DBG(cdev, "adding config #%u '%s'/%p\n", > + config->bConfigurationValue, > + config->label, config); > + > + if (!config->bConfigurationValue) > + return -EINVAL; > + > + /* Prevent duplicate configuration identifiers */ > + list_for_each_entry(c, &cdev->configs, list) { > + if (c->bConfigurationValue == config->bConfigurationValue) > + return -EBUSY; > + }
no locking while traversing the list ?
> + config->cdev = cdev;
> + list_add_tail(&config->list, &cdev->configs);
> +
> + INIT_LIST_HEAD(&config->functions);
> + config->next_interface_id = 0;
> + memset(config->interface, 0, sizeof(config->interface));
> +
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(usb_add_config_only);
> +
> /**
> * usb_add_config() - add a configuration to a device.
> * @cdev: wraps the USB gadget
> @@ -684,29 +713,13 @@ int usb_add_config(struct usb_composite_dev *cdev,
> int (*bind)(struct usb_configuration *))
> {
> int status = -EINVAL;
> - struct usb_configuration *c;
> -
> - DBG(cdev, "adding config #%u '%s'/%p\n",
> - config->bConfigurationValue,
> - config->label, config);
>
> - if (!config->bConfigurationValue || !bind)
> + if (!bind)
> goto done;
>
> - /* Prevent duplicate configuration identifiers */
> - list_for_each_entry(c, &cdev->configs, list) {
> - if (c->bConfigurationValue == config->bConfigurationValue) {
> - status = -EBUSY;
> - goto done;
> - }
> - }
> -
> - config->cdev = cdev;
> - list_add_tail(&config->list, &cdev->configs);
> -
> - INIT_LIST_HEAD(&config->functions);
> - config->next_interface_id = 0;
> - memset(config->interface, 0, sizeof(config->interface));
> + status = usb_add_config_only(cdev, config);
> + if (status)
> + goto done;
>
> status = bind(config);
> if (status < 0) {
> diff --git a/drivers/usb/gadget/functions.c b/drivers/usb/gadget/functions.c
> new file mode 100644
> index 0000000..5e5fee5
> --- /dev/null
> +++ b/drivers/usb/gadget/functions.c
> @@ -0,0 +1,96 @@
> +#include <linux/kernel.h>
> +#include <linux/slab.h>
> +#include <linux/module.h>
> +#include <linux/err.h>
> +
> +#include <linux/usb/composite.h>
> +
> +static LIST_HEAD(func_list);
> +static DEFINE_MUTEX(func_lock);
> +
> +static struct usb_function *try_get_usb_function(const char *name)
> +{
> + struct usb_d_function *f;
this usb_d_function stuff still looks a bit 'peculiar' to me :-)
> + struct usb_function *uf;
> +
> + uf = ERR_PTR(-ENOENT);
> + mutex_lock(&func_lock);
> + list_for_each_entry(f, &func_list, list) {
> +
> + if (strcmp(name, f->name))
> + continue;
> +
> + if (!try_module_get(f->mod)) {
> + uf = ERR_PTR(-EBUSY);
> + break;
> + }
> + uf = f->alloc();
> + if (uf) {
> + uf->mod = f->mod;
> + } else {
> + module_put(f->mod);
> + uf = ERR_PTR(-ENOMEM);
> + }
> + break;
> + }
> + mutex_unlock(&func_lock);
> + return uf;
> +}
> +
> +struct usb_function *usb_get_function(const char *name)
> +{
> + struct usb_function *uf;
> + int ret;
> +
> + uf = try_get_usb_function(name);
> + if (!IS_ERR(uf))
> + return uf;
> + ret = PTR_ERR(uf);
> + if (ret != -ENOENT)
> + return uf;
> + ret = request_module("usbfunc:%s", name);
> + if (ret < 0)
> + return ERR_PTR(ret);
> + return try_get_usb_function(name);
> +}
> +EXPORT_SYMBOL_GPL(usb_get_function);
this is neat :-)
> +void usb_put_function(struct usb_function *f)
> +{
> + struct module *mod;
> +
> + if (!f)
> + return;
I'd add a blank line here, just saying it ;-)
> + mod = f->mod;
> + f->free_func(f);
> + module_put(mod);
> +}
> +EXPORT_SYMBOL_GPL(usb_put_function);
> +
> +int usb_function_register(struct usb_d_function *newf)
> +{
> + struct usb_d_function *f;
> + int ret;
> +
> + ret = -EEXIST;
> +
> + mutex_lock(&func_lock);
> + list_for_each_entry(f, &func_list, list) {
> + if (!strcmp(f->name, newf->name))
> + goto out;
> + }
> + ret = 0;
> + list_add_tail(&newf->list, &func_list);
> +out:
> + mutex_unlock(&func_lock);
> + return ret;
> +}
> +EXPORT_SYMBOL_GPL(usb_function_register);
> +
> +void usb_function_unregister(struct usb_d_function *f)
> +{
> + mutex_lock(&func_lock);
> + list_del(&f->list);
> + mutex_unlock(&func_lock);
> +}
> +EXPORT_SYMBOL_GPL(usb_function_unregister);
> diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h
> index b09c37e..0e2745e 100644
> --- a/include/linux/usb/composite.h
> +++ b/include/linux/usb/composite.h
> @@ -116,6 +116,7 @@ struct usb_configuration;
> * two or more distinct instances within the same configuration, providing
> * several independent logical data links to a USB host.
> */
> +
> struct usb_function {
> const char *name;
> struct usb_gadget_strings **strings;
> @@ -136,6 +137,9 @@ struct usb_function {
> struct usb_function *);
> void (*unbind)(struct usb_configuration *,
> struct usb_function *);
> + /* */
-ENOCOMMENT ?
> + void (*free_func)(struct usb_function *f);
> + struct module *mod;
>
> /* runtime state management */
> int (*set_alt)(struct usb_function *,
> @@ -431,6 +435,46 @@ static inline u16 get_default_bcdDevice(void)
> return bcdDevice;
> }
>
> +typedef struct usb_function *(*usb_func_alloc)(void);
> +typedef void (*usb_func_free)(struct usb_function *f);
isn't checkpatch.pl crying about this ? :-)
In any case, if you really want to typedef, then most other type
definitions in the kernel will append _t. irqreturn_t, irq_handler_t,
acc_t, async_cookie_t, sector_t, region_t and so on.
> +struct usb_d_function {
> + const char *name;
> + struct module *mod;
> + struct list_head list;
> + usb_func_alloc alloc;
> +};
this is killing me and I really don't know why. I guess it just looks
weird and error prone. usb_function and usb_d_function are pretty close
to each other. Also without proper documentation it's quite unclear what
usb_d_function is doing. It doesn't contain a usb_function so it's not a
wrapper structure. What are the semantics you have for this ?
I wonder if you *really* a new structure or could usb_function itself be
used.
> +void usb_function_unregister(struct usb_d_function *f);
> +int usb_function_register(struct usb_d_function *newf);
> +void usb_put_function(struct usb_function *f);
> +struct usb_function *usb_get_function(const char *name);
> +struct usb_configuration *usb_get_config(struct usb_composite_dev *cdev,
> + int val);
> +int usb_add_config_only(struct usb_composite_dev *cdev,
> + struct usb_configuration *config);
> +
> +#define DECLARE_USB_FUNCTION(_name, _alloc) \
> + static struct usb_d_function _name ## usb_func = { \
I would require uses to add the static *and* const modifiers, no strong
feelings however.
> + .name = __stringify(_name), \
> + .mod = THIS_MODULE, \
> + .alloc = _alloc, \
> + }; \
> + MODULE_ALIAS("usbfunc:"__stringify(_name));
> +
> +#define DECLARE_USB_FUNCTION_INIT(_name, _alloc) \
> + DECLARE_USB_FUNCTION(_name, _alloc) \
> + static int __init _name ## mod_init(void) \
> + { \
> + return usb_function_register(&_name ## usb_func); \
> + } \
> + static void __exit _name ## mod_exit(void) \
> + { \
> + usb_function_unregister(&_name ## usb_func); \
> + } \
> + module_init(_name ## mod_init); \
> + module_exit(_name ## mod_exit)
> +
> /* messaging utils */
> #define DBG(d, fmt, args...) \
> dev_dbg(&(d)->gadget->dev , fmt , ## args)
--
balbi
signature.asc
Description: Digital signature
