usb: renesas_usbhs: support multi driver
authorKuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Mon, 4 Jul 2011 00:42:35 +0000 (17:42 -0700)
committerGreg Kroah-Hartman <gregkh@suse.de>
Fri, 8 Jul 2011 22:08:19 +0000 (15:08 -0700)
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>
drivers/usb/renesas_usbhs/mod_gadget.c

index cc3ad63..ba79dbf 100644 (file)
@@ -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);
 }