[RFC] GADGET : allow to build multi udc

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

 



Hello,

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 similar platform (but different udc controller).

After looking at the current code, the only blocker to do that is usb_gadget_register_driver/usb_gadget_unregister_driver function that are declared in each driver.

For avoiding that I propose to do a redirection for these functions.
At probe time the driver register them (usb_gadget_register_udc), and usb_gadget_register_driver/usb_gadget_unregister_driver call these callback.

Only one probing should succeed, so only one call to usb_gadget_register_udc is done. It not, only the first one will succeed.

I attach a draft of that.

What do you think of it ?

Regards,

Matthieu
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 4642f38..c2b1865 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -85,14 +85,15 @@ config	USB_GADGET_SELECTED
 #
 # USB Peripheral Controller Support
 #
-choice
-	prompt "USB Peripheral Controller"
+#choice
+#	prompt "USB Peripheral Controller"
+menu "USB Peripheral Controller"
 	depends on USB_GADGET
-	help
-	   A USB device uses a controller to talk to its host.
-	   Systems should have only one such upstream link.
-	   Many controller drivers are platform-specific; these
-	   often need board-specific hooks.
+#	help
+#	   A USB device uses a controller to talk to its host.
+#	   Systems should have only one such upstream link.
+#	   Many controller drivers are platform-specific; these
+#	   often need board-specific hooks.
 
 config USB_GADGET_PARROT6
 	boolean "PARROT6 USB device controlle (Synopsys)"
@@ -422,7 +423,8 @@ config USB_DUMMY_HCD
 # NOTE:  Please keep dummy_hcd LAST so that "real hardware" appears
 # first and will be selected by default.
 
-endchoice
+#endchoice
+endmenu
 
 config USB_GADGET_DUALSPEED
 	bool
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index d426ac7..c13d156 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -52,3 +52,6 @@ obj-$(CONFIG_USB_MIDI_GADGET)	+= g_midi.o
 obj-$(CONFIG_USB_CDC_COMPOSITE) += g_cdc.o
 obj-$(CONFIG_USB_ANDROID)	+= g_android.o
 
+ifneq ($(CONFIG_USB_GADGET),)
+obj-y += core.o
+endif
diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c
index 0252bbc..9136529 100644
--- a/drivers/usb/gadget/ci13xxx_udc.c
+++ b/drivers/usb/gadget/ci13xxx_udc.c
@@ -2344,15 +2344,16 @@ static const struct usb_ep_ops usb_ep_ops = {
  */
 static const struct usb_gadget_ops usb_gadget_ops;
 
+static int cil_usb_gadget_unregister_driver(struct usb_gadget_driver *driver, void *priv);
 /**
  * usb_gadget_register_driver: register a gadget driver
  *
  * Check usb_gadget_register_driver() at "usb_gadget.h" for details
  * Interrupts are enabled here
  */
-int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+static int cil_usb_gadget_register_driver(struct usb_gadget_driver *driver, void *priv)
 {
-	struct ci13xxx *udc = _udc;
+	struct ci13xxx *udc = priv;
 	unsigned long i, k, flags;
 	int retval = -ENOMEM;
 
@@ -2449,19 +2450,19 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
  done:
 	spin_unlock_irqrestore(udc->lock, flags);
 	if (retval)
-		usb_gadget_unregister_driver(driver);
+		cil_usb_gadget_unregister_driver(driver, udc);
 	return retval;
 }
-EXPORT_SYMBOL(usb_gadget_register_driver);
+//EXPORT_SYMBOL(usb_gadget_register_driver);
 
 /**
  * usb_gadget_unregister_driver: unregister a gadget driver
  *
  * Check usb_gadget_unregister_driver() at "usb_gadget.h" for details
  */
-int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+static int cil_usb_gadget_unregister_driver(struct usb_gadget_driver *driver, void *priv)
 {
-	struct ci13xxx *udc = _udc;
+	struct ci13xxx *udc = priv;
 	unsigned long i, k, flags;
 
 	trace("%p", driver);
@@ -2522,7 +2523,12 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
 
 	return 0;
 }
-EXPORT_SYMBOL(usb_gadget_unregister_driver);
+//EXPORT_SYMBOL(usb_gadget_unregister_driver);
+
+struct usb_gadget_udc cil_driver = {
+	.register_driver = cil_usb_gadget_register_driver,
+	.unregister_driver = cil_usb_gadget_unregister_driver,
+};
 
 /******************************************************************************
  * BUS block
@@ -2653,6 +2659,12 @@ static int udc_probe(struct device *dev, void __iomem *regs, const char *name)
 	}
 
 	_udc = udc;
+	retval = usb_gadget_register_udc(udc, &cil_driver);
+	if (retval) {
+		device_unregister(&udc->gadget.dev);
+		goto done;
+	}
+
 	return retval;
 
  done:
diff --git a/drivers/usb/gadget/core.c b/drivers/usb/gadget/core.c
new file mode 100644
index 0000000..90a8033
--- /dev/null
+++ b/drivers/usb/gadget/core.c
@@ -0,0 +1,41 @@
+#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_udc usb_gadget_udc;
+
+int usb_gadget_register_udc(void *priv, struct usb_gadget_udc *callback)
+{
+	if (!callback->register_driver || !callback->unregister_driver)
+		return -EINVAL;
+
+	if (usb_gadget_udc.register_driver || usb_gadget_udc.unregister_driver)
+		return -EBUSY;
+
+	usb_gadget_udc = *callback;
+	usb_gadget_udc.priv = priv;
+
+	return 0;
+}
+
+
+int usb_gadget_register_driver (struct usb_gadget_driver *driver)
+{
+	if (!usb_gadget_udc.register_driver)
+		return -ENODEV;
+	return usb_gadget_udc.register_driver(driver, usb_gadget_udc.priv);
+}
+EXPORT_SYMBOL (usb_gadget_register_driver);
+
+int usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
+{
+	if (!usb_gadget_udc.register_driver)
+		return -ENODEV;
+	return usb_gadget_udc.unregister_driver(driver, usb_gadget_udc.priv);
+}
+EXPORT_SYMBOL (usb_gadget_unregister_driver);
diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c
index 5cfb5eb..6d42066 100644
--- a/drivers/usb/gadget/net2280.c
+++ b/drivers/usb/gadget/net2280.c
@@ -1908,9 +1908,9 @@ static void ep0_start (struct net2280 *dev)
  * disconnect is reported.  then a host may connect again, or
  * the driver might get unbound.
  */
-int usb_gadget_register_driver (struct usb_gadget_driver *driver)
+static int net2280_usb_gadget_register_driver (struct usb_gadget_driver *driver, void *priv)
 {
-	struct net2280		*dev = the_controller;
+	struct net2280		*dev = priv;
 	int			retval;
 	unsigned		i;
 
@@ -1972,7 +1972,7 @@ err_unbind:
 	dev->driver = NULL;
 	return retval;
 }
-EXPORT_SYMBOL (usb_gadget_register_driver);
+//EXPORT_SYMBOL (usb_gadget_register_driver);
 
 static void
 stop_activity (struct net2280 *dev, struct usb_gadget_driver *driver)
@@ -2000,9 +2000,9 @@ stop_activity (struct net2280 *dev, struct usb_gadget_driver *driver)
 	usb_reinit (dev);
 }
 
-int usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
+static int net2280_usb_gadget_unregister_driver (struct usb_gadget_driver *driver, void *priv)
 {
-	struct net2280	*dev = the_controller;
+	struct net2280	*dev = priv;
 	unsigned long	flags;
 
 	if (!dev)
@@ -2027,7 +2027,12 @@ int usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
 	DEBUG (dev, "unregistered driver '%s'\n", driver->driver.name);
 	return 0;
 }
-EXPORT_SYMBOL (usb_gadget_unregister_driver);
+//EXPORT_SYMBOL (usb_gadget_unregister_driver);
+
+struct usb_gadget_udc net2280_driver = {
+	.register_driver = net2280_usb_gadget_register_driver,
+	.unregister_driver = net2280_usb_gadget_unregister_driver,
+};
 
 
 /*-------------------------------------------------------------------------*/
@@ -2881,6 +2886,8 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id)
 				? (use_dma_chaining ? "chaining" : "enabled")
 				: "disabled");
 	the_controller = dev;
+	retval = usb_gadget_register_udc(dev, &net2280_driver);
+	if (retval) goto done;
 
 	retval = device_register (&dev->gadget.dev);
 	if (retval) goto done;
diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
index 0460a74..70c9c0b 100644
--- a/include/linux/usb/gadget.h
+++ b/include/linux/usb/gadget.h
@@ -817,6 +817,13 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver);
  */
 int usb_gadget_unregister_driver(struct usb_gadget_driver *driver);
 
+struct usb_gadget_udc {
+    int (*register_driver) (struct usb_gadget_driver *driver, void *priv);
+    int (*unregister_driver) (struct usb_gadget_driver *driver, void *priv);
+	void *priv;
+};
+int usb_gadget_register_udc(void *priv, struct usb_gadget_udc *callback);
+
 /*-------------------------------------------------------------------------*/
 
 /* utility to simplify dealing with string descriptors */

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

  Powered by Linux