diff options
Diffstat (limited to 'drivers/usb')
-rw-r--r-- | drivers/usb/renesas_usbhs/mod_gadget.c | 55 |
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); } |