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> --- drivers/Makefile | 2 +- drivers/usb/gadget/Kconfig | 6 ++++ drivers/usb/gadget/Makefile | 2 + drivers/usb/gadget/core_udc.c | 61 +++++++++++++++++++++++++++++++++++++++++ include/linux/usb/gadget.h | 30 ++++++++++++++++++++ 5 files changed, 100 insertions(+), 1 deletions(-) create mode 100644 drivers/usb/gadget/core_udc.c diff --git a/drivers/Makefile b/drivers/Makefile index b423bb1..34d1a54 100644 --- 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/ 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) +{ + if (!gadget->udc || + !gadget->udc->probe_driver || !gadget->udc->unregister_driver) + return -EINVAL; + + if (usb_gadget_udc) + return -EBUSY; + + usb_gadget_udc = gadget; + + return device_register(&gadget->dev); +} +EXPORT_SYMBOL(usb_gadget_register); + +void usb_gadget_unregister(struct usb_gadget *gadget) +{ + if (!usb_gadget_udc || usb_gadget_udc != gadget) + return; + + usb_gadget_udc = NULL; + + device_unregister(&gadget->dev); +} +EXPORT_SYMBOL(usb_gadget_unregister); + +int usb_gadget_probe_driver(struct usb_gadget_driver *driver, int (*bind)(struct usb_gadget *)) +{ + 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 + */ +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); +}; + +/** + * 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 struct device dev; }; -- 1.7.4.1 -- 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