gadget之udc
简介
udc全称为(usb device conctrl),usb设备控制器,其为某soc的usb device的控制器,将usb device的功能抽象,转换成一个个可实现的实例。相关源码如下:
//udc的核心层代码
drivers/usb/gadget/core.c
//某udc控制器的代码,具体需要编写udc驱动者实现
drivers/usb/gadget/fotg210-udc.c
drivers/usb/gadget/s3c2410_udc.c
struct usb_udc
/**
* struct usb_udc - describes one usb device controller
* @driver - the gadget driver pointer. For use by the class code
* @dev - the child device to the actual controller
* @gadget - the gadget. For use by the class code
* @list - for use by the udc class driver
* @vbus - for udcs who care about vbus status, this value is real vbus status;
* for udcs who do not care about vbus status, this value is always true
*
* This represents the internal data structure which is used by the UDC-class
* to hold information about udc driver and gadget together.
*/
struct usb_udc {
struct usb_gadget_driver *driver;
struct usb_gadget *gadget;
struct device dev;
struct list_head list;
bool vbus;
};
usb_udc初始化及创建:
/**
* usb_add_gadget_udc - adds a new gadget to the udc class driver list
* @parent: the parent device to this udc. Usually the controller
* driver's device.
* @gadget: the gadget to be added to the list
*
* Returns zero on success, negative errno otherwise.
*/
int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget)
{
return usb_add_gadget_udc_release(parent, gadget, NULL);
}
EXPORT_SYMBOL_GPL(usb_add_gadget_udc);
/**
* usb_add_gadget_udc_release - adds a new gadget to the udc class driver list
* @parent: the parent device to this udc. Usually the controller driver's
* device.
* @gadget: the gadget to be added to the list.
* @release: a gadget release function.
*
* Returns zero on success, negative errno otherwise.
* Calls the gadget release function in the latter case.
*/
int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget,
void (*release)(struct device *dev))
{
struct usb_udc *udc;
int ret = -ENOMEM;
dev_set_name(&gadget->dev, "gadget");
INIT_WORK(&gadget->work, usb_gadget_state_work);
gadget->dev.parent = parent;
if (release)
gadget->dev.release = release;
else
gadget->dev.release = usb_udc_nop_release;
device_initialize(&gadget->dev);
//创建一个udc设备
udc = kzalloc(sizeof(*udc), GFP_KERNEL);
if (!udc)
goto err_put_gadget;
//初始化udc相关成员
device_initialize(&udc->dev);
udc->dev.release = usb_udc_release;
udc->dev.class = udc_class;
udc->dev.groups = usb_udc_attr_groups;
udc->dev.parent = parent;
ret = dev_set_name(&udc->dev, "%s", kobject_name(&parent->kobj));
if (ret)
goto err_put_udc;
ret = device_add(&gadget->dev);
if (ret)
goto err_put_udc;
//udc 与 usb_gadget绑定
udc->gadget = gadget;
gadget->udc = udc;
mutex_lock(&udc_lock);
list_add_tail(&udc->list, &udc_list);//将udc设备添加到udc_list链表中
ret = device_add(&udc->dev);
if (ret)
goto err_unlist_udc;
usb_gadget_set_state(gadget, USB_STATE_NOTATTACHED);
udc->vbus = true;
/* pick up one of pending gadget drivers */
ret = check_pending_gadget_drivers(udc);
if (ret)
goto err_del_udc;
mutex_unlock(&udc_lock);
return 0;
err_del_udc:
device_del(&udc->dev);
err_unlist_udc:
list_del(&udc->list);
mutex_unlock(&udc_lock);
device_del(&gadget->dev);
err_put_udc:
put_device(&udc->dev);
err_put_gadget:
put_device(&gadget->dev);
return ret;
}
/* should be called with udc_lock held */
static int check_pending_gadget_drivers(struct usb_udc *udc)
{
struct usb_gadget_driver *driver;
int ret = 0;
//遍历gadget_driver_pending_list链表,如有usb_gadget_driver注册,则将其与udc设备绑定
list_for_each_entry(driver, &gadget_driver_pending_list, pending)
if (!driver->udc_name || strcmp(driver->udc_name,
dev_name(&udc->dev)) == 0) {
ret = udc_bind_to_driver(udc, driver);
if (ret != -EPROBE_DEFER)
list_del_init(&driver->pending);
break;
}
return ret;
}
usb_udc与usb_gadget_driver绑定
/* ------------------------------------------------------------------------- */
static int udc_bind_to_driver(struct usb_udc *udc, struct usb_gadget_driver *driver)
{
int ret;
dev_dbg(&udc->dev, "registering UDC driver [%s]\n",
driver->function);
//udc与usb_gadget_driver绑定
udc->driver = driver;
udc->dev.driver = &driver->driver;
udc->gadget->dev.driver = &driver->driver;
usb_gadget_udc_set_speed(udc, driver->max_speed);
//调用usb_gadget_driver.bind,详见gadget之usb_gadget
//源码为:drivers/usb/gadget/composite.c
ret = driver->bind(udc->gadget, driver);
if (ret)
goto err1;
//回调usb_gadget的udc_start函数,启动udc控制器
//该功能需udc控制器驱动实现
ret = usb_gadget_udc_start(udc);
if (ret) {
driver->unbind(udc->gadget);
goto err1;
}
//源码见:drivers/usb/gadget/udc/core.c
//会回调到usb_gadget的pillup函数,配置上拉,连接到host
//该功能需udc控制器驱动实现
usb_udc_connect_control(udc);
kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE);
return 0;
err1:
if (ret != -EISNAM)
dev_err(&udc->dev, "failed to start %s: %d\n",
udc->driver->function, ret);
udc->driver = NULL;
udc->dev.driver = NULL;
udc->gadget->dev.driver = NULL;
return ret;
}