gadget驱动框架(三)

usb_udc与usb_gadget_driver的绑定

usb_udc与usb_gadget_driver,在注册的时候分别被添加到udc_list和gadget_driver_pending_list中,无论这两者先后顺序如何,都将会动态的去识别及匹配到具体设备中,绑定过程如下:

源码:drivers/usb/gadget/udc/core.c

/* ------------------------------------------------------------------------- */

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->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函数,实体为:composite_driver_template.bind
//具体实现在drivers/usb/gadget/composite.c的composite_bind
ret = driver->bind(udc->gadget, driver);
if (ret)
goto err1; //调用usb_gadget的udc_start函数,需要udc驱动者实现
//主要功能是启动udc等
//源码:drivers/usb/gadget/udc/s3c2410_udc.c的s3c2410_udc_start
ret = usb_gadget_udc_start(udc);
if (ret) {
driver->unbind(udc->gadget);
goto err1;
} //调用usb_gadget的pullup函数,上拉或者下拉DP
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;
}

usb_udc_connect_control

源码:drivers/usb/gadget/udc/core.c

static void usb_udc_connect_control(struct usb_udc *udc)
{
//该变量在usb_add_gadget_udc_release创建usb_udc时置为true,
if (udc->vbus)
usb_gadget_connect(udc->gadget);
else
usb_gadget_disconnect(udc->gadget);
} /**
* usb_gadget_connect - software-controlled connect to USB host
* @gadget:the peripheral being connected
*
* Enables the D+ (or potentially D-) pullup. The host will start
* enumerating this gadget when the pullup is active and a VBUS session
* is active (the link is powered). This pullup is always enabled unless
* usb_gadget_disconnect() has been used to disable it.
*
* Returns zero on success, else negative errno.
*/
int usb_gadget_connect(struct usb_gadget *gadget)
{
int ret = 0; if (!gadget->ops->pullup) {
ret = -EOPNOTSUPP;
goto out;
} if (gadget->deactivated) {
/*
* If gadget is deactivated we only save new state.
* Gadget will be connected automatically after activation.
*/
gadget->connected = true;
goto out;
} //调用usb_gadget的udc_start函数,需要udc驱动者实现
//功能:上拉DP,让host检测到设备的插入
//源码:drivers/usb/gadget/udc/s3c2410_udc.c的s3c2410_udc_pullup
ret = gadget->ops->pullup(gadget, 1);
if (!ret)
gadget->connected = 1; out:
trace_usb_gadget_connect(gadget, ret); return ret;
} /**
* usb_gadget_disconnect - software-controlled disconnect from USB host
* @gadget:the peripheral being disconnected
*
* Disables the D+ (or potentially D-) pullup, which the host may see
* as a disconnect (when a VBUS session is active). Not all systems
* support software pullup controls.
*
* Returns zero on success, else negative errno.
*/
int usb_gadget_disconnect(struct usb_gadget *gadget)
{
int ret = 0; if (!gadget->ops->pullup) {
ret = -EOPNOTSUPP;
goto out;
} if (gadget->deactivated) {
/*
* If gadget is deactivated we only save new state.
* Gadget will stay disconnected after activation.
*/
gadget->connected = false;
goto out;
} //调用usb_gadget的udc_start函数,需要udc驱动者实现
//功能:下拉DP,让host检测到设备的拔出
//源码:drivers/usb/gadget/udc/s3c2410_udc.c的s3c2410_udc_pullup
ret = gadget->ops->pullup(gadget, 0);
if (!ret)
gadget->connected = 0; out:
trace_usb_gadget_disconnect(gadget, ret); return ret;
}

usb_gadget_driver的bind与ubind

主要功能是创建usb_composite_dev,及调用usb_composite_driver->bind函数

源码:drivers/usb/gadget/composite.c

static int composite_bind(struct usb_gadget *gadget,
struct usb_gadget_driver *gdriver)
{
struct usb_composite_dev *cdev;
struct usb_composite_driver *composite = to_cdriver(gdriver);
int status = -ENOMEM; //创建usb_composite_dev
cdev = kzalloc(sizeof *cdev, GFP_KERNEL);
if (!cdev)
return status; spin_lock_init(&cdev->lock);
cdev->gadget = gadget;
set_gadget_data(gadget, cdev);
//初始化usb_composite_dev的configs链表
INIT_LIST_HEAD(&cdev->configs);
//初始化usb_composite_dev的gstrings链表
INIT_LIST_HEAD(&cdev->gstrings); //初始化usb_composite_dev.req等
status = composite_dev_prepare(composite, cdev);
if (status)
goto fail; /* composite gadget needs to assign strings for whole device (like
* serial number), register function drivers, potentially update
* power state and consumption, etc
*/
//回调usb_composite_driver的bind函数,
//实例为gsrial_driver.gsbind,
//源码:drivers/usb/gadget/legacy/serial.c
//主要功能为:初始化设备描述符、字符串描述符等
status = composite->bind(cdev);
if (status < 0)
goto fail; if (cdev->use_os_string) {
status = composite_os_desc_req_prepare(cdev, gadget->ep0);
if (status)
goto fail;
} update_unchanged_dev_desc(&cdev->desc, composite->dev); /* has userspace failed to provide a serial number? */
if (composite->needs_serial && !cdev->desc.iSerialNumber)
WARNING(cdev, "userspace failed to provide iSerialNumber\n"); INFO(cdev, "%s ready\n", composite->name);
return 0; fail:
__composite_unbind(gadget, false);
return status;
} static void composite_unbind(struct usb_gadget *gadget)
{
__composite_unbind(gadget, true);
} static void __composite_unbind(struct usb_gadget *gadget, bool unbind_driver)
{
struct usb_composite_dev *cdev = get_gadget_data(gadget);
struct usb_gadget_strings *gstr = cdev->driver->strings[0];
struct usb_string *dev_str = gstr->strings; /* composite_disconnect() must already have been called
* by the underlying peripheral controller driver!
* so there's no i/o concurrency that could affect the
* state protected by cdev->lock.
*/
WARN_ON(cdev->config); while (!list_empty(&cdev->configs)) {
struct usb_configuration *c;
c = list_first_entry(&cdev->configs,
struct usb_configuration, list);
remove_config(cdev, c);
}
if (cdev->driver->unbind && unbind_driver)
cdev->driver->unbind(cdev); composite_dev_cleanup(cdev); if (dev_str[USB_GADGET_MANUFACTURER_IDX].s == cdev->def_manufacturer)
dev_str[USB_GADGET_MANUFACTURER_IDX].s = ""; kfree(cdev->def_manufacturer);
kfree(cdev);
set_gadget_data(gadget, NULL);
}

usb_composite_driver的bind与ubind

源码:

static int gs_bind(struct usb_composite_dev *cdev)
{
int status; /* Allocate string descriptor numbers ... note that string
* contents can be overridden by the composite_dev glue.
*/ status = usb_string_ids_tab(cdev, strings_dev);
if (status < 0)
goto fail;
device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id;
device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id;
status = strings_dev[STRING_DESCRIPTION_IDX].id;
serial_config_driver.iConfiguration = status; //otg设备的话,则需要做otg描述符的初始化,本次使用的非otg,暂不分析
if (gadget_is_otg(cdev->gadget)) {
if (!otg_desc[0]) {
struct usb_descriptor_header *usb_desc; usb_desc = usb_otg_descriptor_alloc(cdev->gadget);
if (!usb_desc) {
status = -ENOMEM;
goto fail;
}
usb_otg_descriptor_init(cdev->gadget, usb_desc);
otg_desc[0] = usb_desc;
otg_desc[1] = NULL;
}
serial_config_driver.descriptors = otg_desc;
serial_config_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
} /* register our configuration */
if (use_acm) {//acm function,kernel默认将use_acm置为true
status = serial_register_ports(cdev, &serial_config_driver,
"acm");
usb_ep_autoconfig_reset(cdev->gadget);
} else if (use_obex)//obex function,kernel默认将use_acm置为false
status = serial_register_ports(cdev, &serial_config_driver,
"obex");
else {//gser function
status = serial_register_ports(cdev, &serial_config_driver,
"gser");
}
if (status < 0)
goto fail1; usb_composite_overwrite_options(cdev, &coverwrite);
INFO(cdev, "%s\n", GS_VERSION_NAME); return 0;
fail1:
kfree(otg_desc[0]);
otg_desc[0] = NULL;
fail:
return status;
} static int gs_unbind(struct usb_composite_dev *cdev)
{
int i; for (i = 0; i < n_ports; i++) {
usb_put_function(f_serial[i]);
usb_put_function_instance(fi_serial[i]);
} kfree(otg_desc[0]);
otg_desc[0] = NULL; return 0;
}

serial_register_ports的function的bind

static int serial_register_ports(struct usb_composite_dev *cdev,
struct usb_configuration *c, const char *f_name)
{
int i;
int ret; //通过bConfigurationValue判断当前config,是否在cdev->configs链表中
//在,则报错;不在,则添加到链表中
ret = usb_add_config_only(cdev, c);
if (ret)
goto out; for (i = 0; i < n_ports; i++) { //根据f_name匹配相关的usb_function_instance
//源码:drivers/usb/gadget/functions.c
fi_serial[i] = usb_get_function_instance(f_name);
if (IS_ERR(fi_serial[i])) {
ret = PTR_ERR(fi_serial[i]);
goto fail;
} //调用usb_function_instance的alloc_func申请usb_function
//源码:drivers/usb/gadget/function/f_acm.c
f_serial[i] = usb_get_function(fi_serial[i]);
if (IS_ERR(f_serial[i])) {
ret = PTR_ERR(f_serial[i]);
goto err_get_func;
} //将申请到的usb_function添加到config->functions链表中
//源码:drivers/usb/gadget/composite.c
ret = usb_add_function(c, f_serial[i]);
if (ret)
goto err_add_func;
} return 0; err_add_func:
usb_put_function(f_serial[i]);
err_get_func:
usb_put_function_instance(fi_serial[i]); fail:
i--;
while (i >= 0) {
usb_remove_function(c, f_serial[i]);
usb_put_function(f_serial[i]);
usb_put_function_instance(fi_serial[i]);
i--;
}
out:
return ret;
} static struct usb_function_instance *try_get_usb_function_instance(const char *name)
{
struct usb_function_driver *fd;
struct usb_function_instance *fi; fi = ERR_PTR(-ENOENT);
mutex_lock(&func_lock);
//name="acm",遍历func_list,查找"acm"所对应的usb_function_driver
list_for_each_entry(fd, &func_list, list) { if (strcmp(name, fd->name))
continue; if (!try_module_get(fd->mod)) {
fi = ERR_PTR(-EBUSY);
break;
}
//调用usb_function_driver.alloc_inst申请usb_function_instance
fi = fd->alloc_inst();
if (IS_ERR(fi))
module_put(fd->mod);
else
fi->fd = fd;
break;
}
mutex_unlock(&func_lock);
return fi;
} struct usb_function_instance *usb_get_function_instance(const char *name)
{
struct usb_function_instance *fi;
int ret;
//name="acm",通过该name获取usb_function_instance
fi = try_get_usb_function_instance(name);
if (!IS_ERR(fi))
return fi;
ret = PTR_ERR(fi);
if (ret != -ENOENT)
return fi;
ret = request_module("usbfunc:%s", name);
if (ret < 0)
return ERR_PTR(ret);
return try_get_usb_function_instance(name);
} struct usb_function *usb_get_function(struct usb_function_instance *fi)
{
struct usb_function *f;
//调用usb_function_instance的alloc_func申请usb_function
f = fi->fd->alloc_func(fi);
if (IS_ERR(f))
return f;
f->fi = fi;
return f;
}
EXPORT_SYMBOL_GPL(usb_get_function);

usb_configuration与usb_functionn的bind

/**
* usb_add_function() - add a function to a configuration
* @config: the configuration
* @function: the function being added
* Context: single threaded during gadget setup
*
* After initialization, each configuration must have one or more
* functions added to it. Adding a function involves calling its @bind()
* method to allocate resources such as interface and string identifiers
* and endpoints.
*
* This function returns the value of the function's bind(), which is
* zero for success else a negative errno value.
*/
int usb_add_function(struct usb_configuration *config,
struct usb_function *function)
{
int value = -EINVAL; DBG(config->cdev, "adding '%s'/%p to config '%s'/%p\n",
function->name, function,
config->label, config); if (!function->set_alt || !function->disable)
goto done; function->config = config;
//将function添加到config->functions链表中
list_add_tail(&function->list, &config->functions); if (function->bind_deactivated) {
value = usb_function_deactivate(function);
if (value)
goto done;
} /* REVISIT *require* function->bind? */
if (function->bind) {
value = function->bind(config, function);
if (value < 0) {
list_del(&function->list);
function->config = NULL;
}
} else
value = 0; /* We allow configurations that don't work at both speeds.
* If we run into a lowspeed Linux system, treat it the same
* as full speed ... it's the function drivers that will need
* to avoid bulk and ISO transfers.
*/
if (!config->fullspeed && function->fs_descriptors)
config->fullspeed = true;
if (!config->highspeed && function->hs_descriptors)
config->highspeed = true;
if (!config->superspeed && function->ss_descriptors)
config->superspeed = true;
if (!config->superspeed_plus && function->ssp_descriptors)
config->superspeed_plus = true; done:
if (value)
DBG(config->cdev, "adding '%s'/%p --> %d\n",
function->name, function, value);
return value;
}

小结

到此已分析完usb_udc、usb_gadget_driver的绑定过程,及usb_function的匹配过程。。下一节将详细介绍usb_function的注册过程及相关函数的分析。另外一个方面,udc控制器已将DP上拉,udc endpoint0已使能,静待插入host完成枚举

USB gadget驱动框架(三)的更多相关文章

  1. USB摄像头驱动框架分析(五)

    一.USB摄像头驱动框架如下所示:1.构造一个usb_driver2.设置   probe:        2.1. 分配video_device:video_device_alloc        ...

  2. USB gadget 驱动 printer.c 分析

    1. modprobe g_printer idVendor=0x0525 idProduct=0xa4a8 modprobe后面也可以加模块参数 2. prn_example从stdout获取数据然 ...

  3. USB摄像头驱动框架分析

    usb摄像头驱动程序,里面涉及硬件的操作.比如说,想设置亮度的时候,需要把亮度的参数发给硬件.去得到真正视频数据的时候,需要访问硬件得到数据.usb摄像头驱动程序框架与虚拟摄像头驱动程序的框架是一样的 ...

  4. I2C驱动框架(三)

    参考:I2C子系统之platform_device初始化——smdk2440_machine_init() I2C驱动框架还应用了另一种总线-设备-驱动模型,平台设备总线platform_bus_ty ...

  5. Linux USB ECM Gadget 驱动介绍

    ​1 USB ECM介绍 USB ECM,属于USB-IF定义的CDC(Communication Device Class)下的一个子类:Ethernet Networking Control Mo ...

  6. Linux下USB驱动框架分析【转】

    转自:http://blog.csdn.net/brucexu1978/article/details/17583407 版权声明:本文为博主原创文章,未经博主允许不得转载. http://www.c ...

  7. Linux usb子系统(一) _写一个usb鼠标驱动

    USB总线是一种典型的热插拔的总线标准,由于其优异的性能几乎成为了当下大小设备中的标配. USB的驱动可以分为3类:SoC的USB控制器的驱动,主机端USB设备的驱动,设备上的USB Gadget驱动 ...

  8. I2C驱动框架(四)

    参考:I2C子系统之platform_driver初始化——I2C_adap_s3c_init() 在完成platform_device的添加之后,i2c子系统将进行platform_driver的注 ...

  9. linux usb总线驱动(一)

    目录 linux usb总线驱动框架 USB 介绍 传输类型 控制器接口 2440接口 基本流程 alloc_dev choose_address hub_port_init usb_get_devi ...

  10. Linux 串口、usb转串口驱动分析(2-2) 【转】

    转自:http://blog.chinaunix.net/xmlrpc.php?r=blog/article&uid=26807463&id=4186852 Linux 串口.usb转 ...

随机推荐

  1. docker centos8 java8 mysql8 部署springboot项目

    docker centos8 java8 mysql8 部署springboot项目 一,用idea将springboot项目打成jar包 二,将打的jar包用xshell的rz上传到docker的c ...

  2. 15、SpringMVC之常用组件及执行流程

    15.1.常用组件 15.1.1. DispatcherServlet DispatcherServlet 是前端控制器,由框架提供,不需要工程师开发: 作用:统一处理请求和响应,整个流程控制的中心, ...

  3. 【Android】构建Android12项目报错

    报错信息: Installed Build Tools revision 31.0.0 is corrupted. Remove and install again using the SDK Man ...

  4. 词云图大师(WordCloudMaster)上线Web端!

    我们非常激动地宣布,词云图大师(WordCloudMaster)现已正式上线Web端!这一全新版本为用户带来了更多的便捷和功能,让创建和分享词云变得更加轻松.无论是企业.教育机构还是个人用户,都可以通 ...

  5. rest_framework与django配合使用

    rest_framework与django配合使用 rest_framework与django配合使用   一.构建表单,在这里我们先构建五个表单,分别是 author book publish us ...

  6. Java常用类——包装类 小白版个人推荐

    包装类及自动装箱/拆箱 包装类是将Java中的八种基本数据类型封装成的类,所有数据类型都能很方便地与对应的包装类相互转换,以解决应用中要求使用数据类型,而不能使用基本数据类型的情况. int a = ...

  7. Polly服务熔断

    //自定义异常 public class MyException : Exception { public MyException(string? message) : base(message) { ...

  8. Adobe Photoshop cc2022 Mac中文破解版下载安装

    PS2024 for Mac,我这个版本是Mac版25.2,大小4.03G,支持intel/M1/M2/M3芯片,最低系统需求:13.4以上,不限速下载地址还是放在最后. 然后安装总共有三个步骤,尤其 ...

  9. Apple Silicon 芯片 Mac 在 x86_64 模式下启动 Kettle

    苹果于 2020 年推出了自家设计的基于 ARM 架构的 M1 芯片,在日常生活的大部分使用过程中,M1 的体验很好.然而,依然存在一小部分软件无法兼容 ARM 架构,需要我们模拟 x86 的架构来运 ...

  10. JWT(JSON WEB TOKEN)是玩具吗

    JWT当然不是玩具,理解其设计意图,和适用场景自然会发现存在的就是有价值的 JWT: JSON Web Token 起源和定义 JWT(JSON Web Token)是由 IETF(Internet ...