Re: [PATCH 05/16] usb/gadget: add some infracture to register/unregister functions

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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 <bigeasy@xxxxxxxxxxxxx>
> ---
>  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

Attachment: signature.asc
Description: Digital signature


[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux