usb: renesas_usbhs: support multi driver

Some SuperH/board has multi USBHS on it.
This patch supports multi register for renesas_usbhs

Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
Kuninori Morimoto 2011-07-03 17:42:35 -07:00 committed by Greg Kroah-Hartman
parent 4ef85e0f69
commit 3b87218829

View File

@ -44,6 +44,7 @@ struct usbhsg_uep {
struct usbhsg_gpriv { struct usbhsg_gpriv {
struct usb_gadget gadget; struct usb_gadget gadget;
struct usbhs_mod mod; struct usbhs_mod mod;
struct list_head link;
struct usbhsg_uep *uep; struct usbhsg_uep *uep;
int uep_size; int uep_size;
@ -113,6 +114,16 @@ struct usbhsg_recip_handle {
#define usbhsg_status_clr(gp, b) (gp->status &= ~b) #define usbhsg_status_clr(gp, b) (gp->status &= ~b)
#define usbhsg_status_has(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 * queue push/pop
*/ */
@ -732,11 +743,10 @@ static int usbhsg_try_stop(struct usbhs_priv *priv, u32 status)
* linux usb function * linux usb function
* *
*/ */
struct usbhsg_gpriv *the_controller;
static int usbhsg_gadget_start(struct usb_gadget_driver *driver, static int usbhsg_gadget_start(struct usb_gadget_driver *driver,
int (*bind)(struct usb_gadget *)) int (*bind)(struct usb_gadget *))
{ {
struct usbhsg_gpriv *gpriv = the_controller; struct usbhsg_gpriv *gpriv;
struct usbhs_priv *priv; struct usbhs_priv *priv;
struct device *dev; struct device *dev;
int ret; int ret;
@ -746,10 +756,17 @@ static int usbhsg_gadget_start(struct usb_gadget_driver *driver,
!driver->setup || !driver->setup ||
driver->speed != USB_SPEED_HIGH) driver->speed != USB_SPEED_HIGH)
return -EINVAL; return -EINVAL;
if (!gpriv)
return -ENODEV; /*
if (gpriv->driver) * find unused controller
return -EBUSY; */
usbhsg_for_each_controller(gpriv) {
if (!gpriv->driver)
goto find_unused_controller;
}
return -ENODEV;
find_unused_controller:
dev = usbhsg_gpriv_to_dev(gpriv); dev = usbhsg_gpriv_to_dev(gpriv);
priv = usbhsg_gpriv_to_priv(gpriv); priv = usbhsg_gpriv_to_priv(gpriv);
@ -786,18 +803,25 @@ static int usbhsg_gadget_start(struct usb_gadget_driver *driver,
static int usbhsg_gadget_stop(struct usb_gadget_driver *driver) 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 usbhs_priv *priv;
struct device *dev = usbhsg_gpriv_to_dev(gpriv); struct device *dev;
if (!gpriv)
return -ENODEV;
if (!driver || if (!driver ||
!driver->unbind || !driver->unbind)
driver != gpriv->driver)
return -EINVAL; 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); dev = usbhsg_gpriv_to_dev(gpriv);
priv = usbhsg_gpriv_to_priv(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); ret = usb_add_gadget_udc(dev, &gpriv->gadget);
if (ret) 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); struct usbhsg_gpriv *gpriv = usbhsg_priv_to_gpriv(priv);
usb_del_gadget_udc(&gpriv->gadget); usb_del_gadget_udc(&gpriv->gadget);
usbhsg_controller_unregister(gpriv);
kfree(gpriv->uep); kfree(gpriv->uep);
kfree(gpriv); kfree(gpriv);
} }