usb: gadget: udc-core: introduce UDC binding by name
authorSebastian Andrzej Siewior <bigeasy@linutronix.de>
Sun, 23 Dec 2012 20:10:19 +0000 (21:10 +0100)
committerFelipe Balbi <balbi@ti.com>
Mon, 21 Jan 2013 18:52:46 +0000 (20:52 +0200)
This patch adds udc_attach_driver() which allows to bind an UDC which is
specified by name to a driver. The name of available UDCs can be
obtained from /sys/class/udc. This interface is intended for configfs
interface.

Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Signed-off-by: Felipe Balbi <balbi@ti.com>
drivers/usb/gadget/udc-core.c
include/linux/usb/gadget.h

index 4d90a800063ce93a66a2486f95bfd1273c348d7d..e7c591621a3b04d549878e048a98b85df4cd4dff 100644 (file)
@@ -311,26 +311,10 @@ EXPORT_SYMBOL_GPL(usb_del_gadget_udc);
 
 /* ------------------------------------------------------------------------- */
 
-int usb_gadget_probe_driver(struct usb_gadget_driver *driver)
+static int udc_bind_to_driver(struct usb_udc *udc, struct usb_gadget_driver *driver)
 {
-       struct usb_udc          *udc = NULL;
-       int                     ret;
-
-       if (!driver || !driver->bind || !driver->setup)
-               return -EINVAL;
+       int ret;
 
-       mutex_lock(&udc_lock);
-       list_for_each_entry(udc, &udc_list, list) {
-               /* For now we take the first one */
-               if (!udc->driver)
-                       goto found;
-       }
-
-       pr_debug("couldn't find an available UDC\n");
-       mutex_unlock(&udc_lock);
-       return -ENODEV;
-
-found:
        dev_dbg(&udc->dev, "registering UDC driver [%s]\n",
                        driver->function);
 
@@ -352,18 +336,64 @@ found:
                ret = usb_gadget_start(udc->gadget, driver, driver->bind);
                if (ret)
                        goto err1;
-
        }
 
        kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE);
-       mutex_unlock(&udc_lock);
        return 0;
-
 err1:
        dev_err(&udc->dev, "failed to start %s: %d\n",
                        udc->driver->function, ret);
        udc->driver = NULL;
        udc->dev.driver = NULL;
+       return ret;
+}
+
+int udc_attach_driver(const char *name, struct usb_gadget_driver *driver)
+{
+       struct usb_udc *udc = NULL;
+       int ret = -ENODEV;
+
+       mutex_lock(&udc_lock);
+       list_for_each_entry(udc, &udc_list, list) {
+               ret = strcmp(name, dev_name(&udc->dev));
+               if (!ret)
+                       break;
+       }
+       if (ret) {
+               ret = -ENODEV;
+               goto out;
+       }
+       if (udc->driver) {
+               ret = -EBUSY;
+               goto out;
+       }
+       ret = udc_bind_to_driver(udc, driver);
+out:
+       mutex_unlock(&udc_lock);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(udc_attach_driver);
+
+int usb_gadget_probe_driver(struct usb_gadget_driver *driver)
+{
+       struct usb_udc          *udc = NULL;
+       int                     ret;
+
+       if (!driver || !driver->bind || !driver->setup)
+               return -EINVAL;
+
+       mutex_lock(&udc_lock);
+       list_for_each_entry(udc, &udc_list, list) {
+               /* For now we take the first one */
+               if (!udc->driver)
+                       goto found;
+       }
+
+       pr_debug("couldn't find an available UDC\n");
+       mutex_unlock(&udc_lock);
+       return -ENODEV;
+found:
+       ret = udc_bind_to_driver(udc, driver);
        mutex_unlock(&udc_lock);
        return ret;
 }
index 0af6569b8cc60778c619f3a059d4b78ff49f07f4..62156701e4f109273da0ba84bba3f883afbd1a49 100644 (file)
@@ -880,6 +880,8 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver);
 
 extern int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget);
 extern void usb_del_gadget_udc(struct usb_gadget *gadget);
+extern int udc_attach_driver(const char *name,
+               struct usb_gadget_driver *driver);
 
 /*-------------------------------------------------------------------------*/