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>
This commit is contained in:
		
					parent
					
						
							
								0062f6e56f
							
						
					
				
			
			
				commit
				
					
						4c49a5f0ef
					
				
			
		
					 2 changed files with 53 additions and 21 deletions
				
			
		| 
						 | 
					@ -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;
 | 
				
			||||||
	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:
 | 
					 | 
				
			||||||
	dev_dbg(&udc->dev, "registering UDC driver [%s]\n",
 | 
						dev_dbg(&udc->dev, "registering UDC driver [%s]\n",
 | 
				
			||||||
			driver->function);
 | 
								driver->function);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -352,18 +336,64 @@ found:
 | 
				
			||||||
		ret = usb_gadget_start(udc->gadget, driver, driver->bind);
 | 
							ret = usb_gadget_start(udc->gadget, driver, driver->bind);
 | 
				
			||||||
		if (ret)
 | 
							if (ret)
 | 
				
			||||||
			goto err1;
 | 
								goto err1;
 | 
				
			||||||
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE);
 | 
						kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE);
 | 
				
			||||||
	mutex_unlock(&udc_lock);
 | 
					 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
 | 
					 | 
				
			||||||
err1:
 | 
					err1:
 | 
				
			||||||
	dev_err(&udc->dev, "failed to start %s: %d\n",
 | 
						dev_err(&udc->dev, "failed to start %s: %d\n",
 | 
				
			||||||
			udc->driver->function, ret);
 | 
								udc->driver->function, ret);
 | 
				
			||||||
	udc->driver = NULL;
 | 
						udc->driver = NULL;
 | 
				
			||||||
	udc->dev.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);
 | 
						mutex_unlock(&udc_lock);
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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 int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget);
 | 
				
			||||||
extern void usb_del_gadget_udc(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);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*-------------------------------------------------------------------------*/
 | 
					/*-------------------------------------------------------------------------*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue