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;
};