summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/usb/gadget/udc-core.c72
-rw-r--r--include/linux/usb/gadget.h2
2 files changed, 53 insertions, 21 deletions
diff --git a/drivers/usb/gadget/udc-core.c b/drivers/usb/gadget/udc-core.c
index 4d90a800063c..e7c591621a3b 100644
--- a/drivers/usb/gadget/udc-core.c
+++ b/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;
}
diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
index 0af6569b8cc6..62156701e4f1 100644
--- a/include/linux/usb/gadget.h
+++ b/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);
/*-------------------------------------------------------------------------*/