Browse Source

usb: gadget: udc-core: introduce UDC binding by name

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>
Sebastian Andrzej Siewior 12 years ago
parent
commit
4c49a5f0ef
2 changed files with 53 additions and 21 deletions
  1. 51 21
      drivers/usb/gadget/udc-core.c
  2. 2 0
      include/linux/usb/gadget.h

+ 51 - 21
drivers/usb/gadget/udc-core.c

@@ -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;
 }

+ 2 - 0
include/linux/usb/gadget.h

@@ -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);
 
 /*-------------------------------------------------------------------------*/