Re: [PATCH 1/4] Allow to build more than one usb gadget driver

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

 



On Tue, 15 Mar 2011, Matthieu CASTET wrote:

> Even if the usb gadget framework is limited to work with one driver, it
> could be useful to have a kernel build with more than driver.
> This allow to make generic kernel that work with different udc controller.
> 
> The only blocker to do that is usb_gadget_register_driver
> and usb_gadget_unregister_driver function are declared in each driver.
> 
> For avoiding that a redirection is done for these functions :
> At probe time the driver register them (usb_gadget_register and
> usb_gadget_unregister), and the generic usb_gadget_register_driver and
> usb_gadget_unregister_driver call these callback.
> We pass struct *usb_gadget in usb_gadget_register and usb_gadget_unregister
> for flexibility (we can latter do a more complex dispatcher).
> 
> Signed-off-by: Matthieu CASTET <matthieu.castet@xxxxxxxxxx>
> Ack-by: Alan Stern <stern@xxxxxxxxxxxxxxxxxxx>

Actually, there are a few things in this patch which should be 
improved.  See below...

> --- a/drivers/Makefile
> +++ b/drivers/Makefile
> @@ -68,7 +68,7 @@ obj-$(CONFIG_USB_OTG_UTILS)	+= usb/otg/
>  obj-$(CONFIG_USB)		+= usb/
>  obj-$(CONFIG_USB_MUSB_HDRC)	+= usb/musb/
>  obj-$(CONFIG_PCI)		+= usb/
> -obj-$(CONFIG_USB_GADGET)	+= usb/gadget/
> +obj-y					+= usb/gadget/

Why was this changed?  And why doesn't the spacing match the lines
above?

>  obj-$(CONFIG_SERIO)		+= input/serio/
>  obj-$(CONFIG_GAMEPORT)		+= input/gameport/
>  obj-$(CONFIG_INPUT)		+= input/
> diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
> index d500996..d088bb0 100644
> --- a/drivers/usb/gadget/Kconfig
> +++ b/drivers/usb/gadget/Kconfig
> @@ -559,6 +559,12 @@ config USB_CI13XXX_MSM
>  	default USB_GADGET
>  	select USB_GADGET_SELECTED
> 
> +config USB_GADGET_MULTIUDC
> +	boolean "multi USB Device Port"
> +	select USB_GADGET_SELECTED
> +	help
> +		Allow to build more than one udc.
> +
>  #
>  # LAST -- dummy/emulated controller
>  #
> diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
> index 55f5e8a..5798697 100644
> --- a/drivers/usb/gadget/Makefile
> +++ b/drivers/usb/gadget/Makefile
> @@ -29,6 +29,8 @@ obj-$(CONFIG_USB_PXA_U2O)	+= mv_udc.o
>  mv_udc-y			:= mv_udc_core.o mv_udc_phy.o
>  obj-$(CONFIG_USB_CI13XXX_MSM)	+= ci13xxx_msm.o
> 
> +obj-$(CONFIG_USB_GADGET_MULTIUDC) += core_udc.o
> +
>  #
>  # USB gadget drivers
>  #
> diff --git a/drivers/usb/gadget/core_udc.c b/drivers/usb/gadget/core_udc.c
> new file mode 100644
> index 0000000..8339883
> --- /dev/null
> +++ b/drivers/usb/gadget/core_udc.c
> @@ -0,0 +1,61 @@
> +/*
> + * Copyright (C) 2010 Matthieu CASTET <matthieu.castet@xxxxxxxxxx>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU Lesser General Public License as published
> + * by the Free Software Foundation; either version 2.1 of the License, or
> + * (at your option) any later version.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/init.h>
> +#include <linux/errno.h>
> +#include <linux/dma-mapping.h>
> +#include <linux/platform_device.h>
> +#include <linux/usb/ch9.h>
> +#include <linux/usb/gadget.h>
> +
> +static struct usb_gadget *usb_gadget_udc;
> +
> +int usb_gadget_register(struct usb_gadget *gadget)

This name is confusing because it doesn't mention "udc".  Change it to 
usb_gadget_register_udc_driver.  And don't forget to change the name 
wherever it occurs in comments as well as in the code!

> +{
> +	if (!gadget->udc ||
> +		!gadget->udc->probe_driver || !gadget->udc->unregister_driver)
> +		return -EINVAL;
> +
> +	if (usb_gadget_udc)
> +		return -EBUSY;
> +
> +	usb_gadget_udc = gadget;

In theory this should be protected by a mutex.  But it probably doesn't 
matter.

> +
> +	return device_register(&gadget->dev);

You can't do this.  If device_register() fails, you have to clean up by
calling put_device() -- but the caller has no way of knowing what to
do.  Therefore you have to check the return code from device_register()
and clean up here before returning.

> +}
> +EXPORT_SYMBOL(usb_gadget_register);
> +
> +void usb_gadget_unregister(struct usb_gadget *gadget)

Change this name to usb_gadget_unregister_udc_driver.

> +{
> +	if (!usb_gadget_udc || usb_gadget_udc != gadget)
> +		return;
> +
> +	usb_gadget_udc = NULL;
> +
> +	device_unregister(&gadget->dev);

What happens if a gadget driver is currently registered for this 
gadget?  It will have no way to unregister, because 
usb_gadget_unregister_driver() will return -ENODEV without doing 
anything.

> +}
> +EXPORT_SYMBOL(usb_gadget_unregister);
> +
> +int usb_gadget_probe_driver(struct usb_gadget_driver *driver, int (*bind)(struct usb_gadget *))

Wrap this long line after the first parameter.

> +{
> +	if (!usb_gadget_udc)
> +		return -ENODEV;
> +	return usb_gadget_udc->udc->probe_driver(driver, bind, usb_gadget_udc);
> +}
> +EXPORT_SYMBOL (usb_gadget_probe_driver);
> +
> +int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
> +{
> +	if (!usb_gadget_udc)
> +		return -ENODEV;
> +	return usb_gadget_udc->udc->unregister_driver(driver, usb_gadget_udc);
> +}
> +EXPORT_SYMBOL (usb_gadget_unregister_driver);
> diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
> index 006412c..5391c18 100644
> --- a/include/linux/usb/gadget.h
> +++ b/include/linux/usb/gadget.h
> @@ -432,6 +432,33 @@ struct usb_gadget_ops {
>  				unsigned code, unsigned long param);
>  };
> 
> +#ifdef CONFIG_USB_GADGET_MULTIUDC
> +struct usb_gadget_driver;
> +/**
> + * struct usb_gadget_udc - driver for udc device
> + * @probe_driver:register a gadget driver
> + * @unregister_driver:unregister a gadget driver
> + *
> + * @see usb_gadget_register_driver and usb_gadget_unregister_driver

Do you really want the '@' before "see"?  Is this a kerneldoc markup 
I'm not familiar with?

Since this structure represents a udc device driver, it should be 
called struct usb_gadget_udc_driver.

> + */
> +struct usb_gadget_udc {
> +    int (*probe_driver) (struct usb_gadget_driver *driver, int (*bind)(struct usb_gadget *), struct usb_gadget *gadget);
> +    int (*unregister_driver) (struct usb_gadget_driver *driver, struct usb_gadget *gadget);

Again, wrap these long lines.

> +};
> +
> +/**
> + * usb_gadget_register - register a udc driver
> + * @gadget:the driver being registered
> + */
> +int usb_gadget_register(struct usb_gadget *gadget);
> +
> +/**
> + * usb_gadget_unregister - unregister a udc driver
> + * @gadget:the driver being registered
> + */
> +void usb_gadget_unregister(struct usb_gadget *gadget);
> +#endif
> +
>  /**
>   * struct usb_gadget - represents a usb slave device
>   * @ops: Function pointers used to access hardware-specific operations.
> @@ -487,6 +514,9 @@ struct usb_gadget {
>  	unsigned			a_hnp_support:1;
>  	unsigned			a_alt_hnp_support:1;
>  	const char			*name;
> +#ifdef CONFIG_USB_GADGET_MULTIUDC
> +	struct usb_gadget_udc *udc;
> +#endif

The spacing should agree with the surrounding lines.

>  	struct device			dev;
>  };

Alan Stern

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


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

  Powered by Linux