Re: [RFC] GADGET : allow to build multi udc

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

 



Hi,

Michał Nazarewicz a écrit :
On Mon, 06 Sep 2010 01:44:11 +0200, David Vrabel <david.vrabel@xxxxxxx> wrote:
There's no WUSB UDC driver in the kernel yet though so this
functionality isn't needed for now.

Yep, but since Matthieu proposed to change the API I think it's best to
change it in such a way as to anticipate future needs so that the same
work (changing UDCs) won't have to be done twice.

Here a new version of the patch that pass struct usb_gadget in the register/unregister callback.
This allow to :
- get gadget->name for future need.
- pass struct usb_gadget* to (un)register_driver callback instead of a private data.
- put the device_(un)register in the common code.

Matthieu
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index cd27f9b..8807035 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -424,46 +424,6 @@ config USB_FSL_QE
 	default USB_GADGET
 	select USB_GADGET_SELECTED
 
-config USB_GADGET_CI13XXX
-	boolean "MIPS USB CI13xxx"
-	depends on PCI
-	select USB_GADGET_DUALSPEED
-	help
-	  MIPS USB IP core family device controller
-	  Currently it only supports IP part number CI13412
-
-	  Say "y" to link the driver statically, or "m" to build a
-	  dynamically linked module called "ci13xxx_udc" and force all
-	  gadget drivers to also be dynamically linked.
-
-config USB_CI13XXX
-	tristate
-	depends on USB_GADGET_CI13XXX
-	default USB_GADGET
-	select USB_GADGET_SELECTED
-
-config USB_GADGET_NET2280
-	boolean "NetChip 228x"
-	depends on PCI
-	select USB_GADGET_DUALSPEED
-	help
-	   NetChip 2280 / 2282 is a PCI based USB peripheral controller which
-	   supports both full and high speed USB 2.0 data transfers.
-
-	   It has six configurable endpoints, as well as endpoint zero
-	   (for control transfers) and several endpoints with dedicated
-	   functions.
-
-	   Say "y" to link the driver statically, or "m" to build a
-	   dynamically linked module called "net2280" and force all
-	   gadget drivers to also be dynamically linked.
-
-config USB_NET2280
-	tristate
-	depends on USB_GADGET_NET2280
-	default USB_GADGET
-	select USB_GADGET_SELECTED
-
 config USB_GADGET_GOKU
 	boolean "Toshiba TC86C001 'Goku-S'"
 	depends on PCI
@@ -505,6 +465,11 @@ config USB_LANGWELL
 	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
@@ -544,6 +509,50 @@ config USB_DUMMY_HCD
 
 endchoice
 
+menu "multi USB Peripheral Controller"
+	depends on USB_GADGET_MULTIUDC
+
+config USB_GADGET_CI13XXX
+	boolean "MIPS USB CI13xxx"
+	depends on PCI
+	select USB_GADGET_DUALSPEED
+	help
+	  MIPS USB IP core family device controller
+	  Currently it only supports IP part number CI13412
+
+	  Say "y" to link the driver statically, or "m" to build a
+	  dynamically linked module called "ci13xxx_udc" and force all
+	  gadget drivers to also be dynamically linked.
+
+config USB_CI13XXX
+	tristate
+	depends on USB_GADGET_CI13XXX
+	default USB_GADGET
+	select USB_GADGET_SELECTED
+
+config USB_GADGET_NET2280
+	boolean "NetChip 228x"
+	depends on PCI
+	select USB_GADGET_DUALSPEED
+	help
+	   NetChip 2280 / 2282 is a PCI based USB peripheral controller which
+	   supports both full and high speed USB 2.0 data transfers.
+
+	   It has six configurable endpoints, as well as endpoint zero
+	   (for control transfers) and several endpoints with dedicated
+	   functions.
+
+	   Say "y" to link the driver statically, or "m" to build a
+	   dynamically linked module called "net2280" and force all
+	   gadget drivers to also be dynamically linked.
+
+config USB_NET2280
+	tristate
+	depends on USB_GADGET_NET2280
+	default USB_GADGET
+	select USB_GADGET_SELECTED
+endmenu
+
 config USB_GADGET_DUALSPEED
 	bool
 	depends on USB_GADGET
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index 27283df..b64ccaa 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -29,6 +29,8 @@ obj-$(CONFIG_USB_CI13XXX)	+= ci13xxx_udc.o
 obj-$(CONFIG_USB_S3C_HSOTG)	+= s3c-hsotg.o
 obj-$(CONFIG_USB_LANGWELL)	+= langwell_udc.o
 
+obj-$(CONFIG_USB_GADGET_MULTIUDC) += core_udc.o
+
 #
 # USB gadget drivers
 #
diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c
index 6996951..8ee53bf 100644
--- a/drivers/usb/gadget/ci13xxx_udc.c
+++ b/drivers/usb/gadget/ci13xxx_udc.c
@@ -2339,15 +2339,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, struct usb_gadget *gadget);
 /**
- * usb_gadget_register_driver: register a gadget driver
+ * cil_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, struct usb_gadget *gadget)
 {
-	struct ci13xxx *udc = _udc;
+	struct ci13xxx *udc = container_of(gadget, struct ci13xxx, gadget);
 	unsigned long i, k, flags;
 	int retval = -ENOMEM;
 
@@ -2444,19 +2445,18 @@ 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, gadget);
 	return retval;
 }
-EXPORT_SYMBOL(usb_gadget_register_driver);
 
 /**
- * usb_gadget_unregister_driver: unregister a gadget driver
+ * cil_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, struct usb_gadget *gadget)
 {
-	struct ci13xxx *udc = _udc;
+	struct ci13xxx *udc = container_of(gadget, struct ci13xxx, gadget);
 	unsigned long i, k, flags;
 
 	trace("%p", driver);
@@ -2517,7 +2517,11 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
 
 	return 0;
 }
-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
@@ -2625,6 +2629,7 @@ static int udc_probe(struct device *dev, void __iomem *regs, const char *name)
 	udc->gadget.is_dualspeed = 1;
 	udc->gadget.is_otg       = 0;
 	udc->gadget.name         = name;
+	udc->gadget.udc          = &cil_driver;
 
 	INIT_LIST_HEAD(&udc->gadget.ep_list);
 	udc->gadget.ep0 = NULL;
@@ -2634,7 +2639,8 @@ static int udc_probe(struct device *dev, void __iomem *regs, const char *name)
 	udc->gadget.dev.parent   = dev;
 	udc->gadget.dev.release  = udc_release;
 
-	retval = device_register(&udc->gadget.dev);
+	_udc = udc;
+	retval = usb_gadget_register(&udc->gadget);
 	if (retval)
 		goto done;
 
@@ -2642,11 +2648,10 @@ static int udc_probe(struct device *dev, void __iomem *regs, const char *name)
 	retval = dbg_create_files(&udc->gadget.dev);
 #endif
 	if (retval) {
-		device_unregister(&udc->gadget.dev);
+		usb_gadget_unregister(&udc->gadget);
 		goto done;
 	}
 
-	_udc = udc;
 	return retval;
 
  done:
@@ -2673,7 +2678,7 @@ static void udc_remove(void)
 #ifdef CONFIG_USB_GADGET_DEBUG_FILES
 	dbg_remove_files(&udc->gadget.dev);
 #endif
-	device_unregister(&udc->gadget.dev);
+	usb_gadget_unregister(&udc->gadget);
 
 	kfree(udc);
 	_udc = NULL;
diff --git a/drivers/usb/gadget/core_udc.c b/drivers/usb/gadget/core_udc.c
new file mode 100644
index 0000000..f319ac3
--- /dev/null
+++ b/drivers/usb/gadget/core_udc.c
@@ -0,0 +1,51 @@
+#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->register_driver || !gadget->udc->unregister_driver)
+		return -EINVAL;
+
+	if (usb_gadget_udc)
+		return -EBUSY;
+
+	usb_gadget_udc = gadget;
+
+	return device_register(&gadget->dev);
+}
+
+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);
+}
+
+
+int usb_gadget_register_driver (struct usb_gadget_driver *driver)
+{
+	if (!usb_gadget_udc)
+		return -ENODEV;
+	return usb_gadget_udc->udc->register_driver(driver, usb_gadget_udc);
+}
+EXPORT_SYMBOL (usb_gadget_register_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/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c
index 9498be8..37c6185 100644
--- a/drivers/usb/gadget/net2280.c
+++ b/drivers/usb/gadget/net2280.c
@@ -1802,8 +1802,6 @@ EXPORT_SYMBOL (net2280_set_fifo_mode);
  * perhaps to bind specific drivers to specific devices.
  */
 
-static struct net2280	*the_controller;
-
 static void usb_reset (struct net2280 *dev)
 {
 	u32	tmp;
@@ -1929,9 +1927,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, struct usb_gadget *gadget)
 {
-	struct net2280		*dev = the_controller;
+	struct net2280		*dev = container_of (gadget, struct net2280, gadget);
 	int			retval;
 	unsigned		i;
 
@@ -1993,7 +1991,6 @@ err_unbind:
 	dev->driver = NULL;
 	return retval;
 }
-EXPORT_SYMBOL (usb_gadget_register_driver);
 
 static void
 stop_activity (struct net2280 *dev, struct usb_gadget_driver *driver)
@@ -2021,9 +2018,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, struct usb_gadget *gadget)
 {
-	struct net2280	*dev = the_controller;
+	struct net2280	*dev = container_of (gadget, struct net2280, gadget);
 	unsigned long	flags;
 
 	if (!dev)
@@ -2048,7 +2045,11 @@ 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);
+
+struct usb_gadget_udc net2280_driver = {
+	.register_driver = net2280_usb_gadget_register_driver,
+	.unregister_driver = net2280_usb_gadget_unregister_driver,
+};
 
 
 /*-------------------------------------------------------------------------*/
@@ -2754,13 +2755,11 @@ static void net2280_remove (struct pci_dev *pdev)
 				pci_resource_len (pdev, 0));
 	if (dev->enabled)
 		pci_disable_device (pdev);
-	device_unregister (&dev->gadget.dev);
+	usb_gadget_unregister(&dev->gadget);
 	device_remove_file (&pdev->dev, &dev_attr_registers);
 	pci_set_drvdata (pdev, NULL);
 
 	INFO (dev, "unbind\n");
-
-	the_controller = NULL;
 }
 
 /* wrap this driver around the specified device, but
@@ -2774,14 +2773,6 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id)
 	void			__iomem *base = NULL;
 	int			retval, i;
 
-	/* if you want to support more than one controller in a system,
-	 * usb_gadget_driver_{register,unregister}() must change.
-	 */
-	if (the_controller) {
-		dev_warn (&pdev->dev, "ignoring\n");
-		return -EBUSY;
-	}
-
 	/* alloc, and start init */
 	dev = kzalloc (sizeof *dev, GFP_KERNEL);
 	if (dev == NULL){
@@ -2908,9 +2899,8 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id)
 			use_dma
 				? (use_dma_chaining ? "chaining" : "enabled")
 				: "disabled");
-	the_controller = dev;
-
-	retval = device_register (&dev->gadget.dev);
+	dev->gadget.udc = &net2280_driver;
+	retval = usb_gadget_register(&dev->gadget);
 	if (retval) goto done;
 	retval = device_create_file (&pdev->dev, &dev_attr_registers);
 	if (retval) goto done;
diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
index d3ef42d..748d4c6 100644
--- a/include/linux/usb/gadget.h
+++ b/include/linux/usb/gadget.h
@@ -432,6 +432,32 @@ 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
+ * @register_driver:register a gadget driver
+ * @unregister_driver:unregister a gadget driver
+ *
+ * @priv:private context
+ *
+ * @see usb_gadget_register_driver and usb_gadget_unregister_driver
+ */
+struct usb_gadget_udc {
+    int (*register_driver) (struct usb_gadget_driver *driver, struct usb_gadget *gadget);
+    int (*unregister_driver) (struct usb_gadget_driver *driver, struct usb_gadget *gadget);
+};
+
+/**
+ * usb_gadget_register_udc - register a udc driver
+ * @priv:driver context
+ * @udc:the driver being registered
+ */
+int usb_gadget_register(struct usb_gadget *gadget);
+
+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 +513,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;
 };
 

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

  Powered by Linux