summaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/renesas_usbhs/mod_gadget.c55
1 files changed, 41 insertions, 14 deletions
diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c
index cc3ad634d4f..ba79dbf5adb 100644
--- a/drivers/usb/renesas_usbhs/mod_gadget.c
+++ b/drivers/usb/renesas_usbhs/mod_gadget.c
@@ -44,6 +44,7 @@ struct usbhsg_uep {
struct usbhsg_gpriv {
struct usb_gadget gadget;
struct usbhs_mod mod;
+ struct list_head link;
struct usbhsg_uep *uep;
int uep_size;
@@ -113,6 +114,16 @@ struct usbhsg_recip_handle {
#define usbhsg_status_clr(gp, b) (gp->status &= ~b)
#define usbhsg_status_has(gp, b) (gp->status & b)
+/* controller */
+LIST_HEAD(the_controller_link);
+
+#define usbhsg_for_each_controller(gpriv)\
+ list_for_each_entry(gpriv, &the_controller_link, link)
+#define usbhsg_controller_register(gpriv)\
+ list_add_tail(&(gpriv)->link, &the_controller_link)
+#define usbhsg_controller_unregister(gpriv)\
+ list_del_init(&(gpriv)->link)
+
/*
* queue push/pop
*/
@@ -732,11 +743,10 @@ static int usbhsg_try_stop(struct usbhs_priv *priv, u32 status)
* linux usb function
*
*/
-struct usbhsg_gpriv *the_controller;
static int usbhsg_gadget_start(struct usb_gadget_driver *driver,
int (*bind)(struct usb_gadget *))
{
- struct usbhsg_gpriv *gpriv = the_controller;
+ struct usbhsg_gpriv *gpriv;
struct usbhs_priv *priv;
struct device *dev;
int ret;
@@ -746,10 +756,17 @@ static int usbhsg_gadget_start(struct usb_gadget_driver *driver,
!driver->setup ||
driver->speed != USB_SPEED_HIGH)
return -EINVAL;
- if (!gpriv)
- return -ENODEV;
- if (gpriv->driver)
- return -EBUSY;
+
+ /*
+ * find unused controller
+ */
+ usbhsg_for_each_controller(gpriv) {
+ if (!gpriv->driver)
+ goto find_unused_controller;
+ }
+ return -ENODEV;
+
+find_unused_controller:
dev = usbhsg_gpriv_to_dev(gpriv);
priv = usbhsg_gpriv_to_priv(gpriv);
@@ -786,18 +803,25 @@ add_fail:
static int usbhsg_gadget_stop(struct usb_gadget_driver *driver)
{
- struct usbhsg_gpriv *gpriv = the_controller;
+ struct usbhsg_gpriv *gpriv;
struct usbhs_priv *priv;
- struct device *dev = usbhsg_gpriv_to_dev(gpriv);
-
- if (!gpriv)
- return -ENODEV;
+ struct device *dev;
if (!driver ||
- !driver->unbind ||
- driver != gpriv->driver)
+ !driver->unbind)
return -EINVAL;
+ /*
+ * find controller
+ */
+ usbhsg_for_each_controller(gpriv) {
+ if (gpriv->driver == driver)
+ goto find_matching_controller;
+ }
+ return -ENODEV;
+
+find_matching_controller:
+
dev = usbhsg_gpriv_to_dev(gpriv);
priv = usbhsg_gpriv_to_priv(gpriv);
@@ -919,7 +943,7 @@ int __devinit usbhs_mod_gadget_probe(struct usbhs_priv *priv)
}
}
- the_controller = gpriv;
+ usbhsg_controller_register(gpriv);
ret = usb_add_gadget_udc(dev, &gpriv->gadget);
if (ret)
@@ -943,6 +967,9 @@ void __devexit usbhs_mod_gadget_remove(struct usbhs_priv *priv)
struct usbhsg_gpriv *gpriv = usbhsg_priv_to_gpriv(priv);
usb_del_gadget_udc(&gpriv->gadget);
+
+ usbhsg_controller_unregister(gpriv);
+
kfree(gpriv->uep);
kfree(gpriv);
}