1. dw3 core代码分析
文件:[drivers/usb/dwc3/core.c]
dwc3_probe 函数主要申请dwc3_vendor 参数内存(dwc3_vendor的dwc成员即是 struct dwc3结构体参数),对dwc3 通过设备树 以及寄存器信息对 dwc3的成员进行初始化,申请缓存,创建debugfs文件节点,配置dwc3寄存器 ,依据传输模式配置dwc3
static int dwc3_probe(struct platform_device *pdev)
{
struct dwc3_vendor *vdwc; | -
struct dwc3 *dwc;
vdwc = devm_kzalloc(dev, sizeof(*vdwc), GFP_KERNEL);
/* 申请dwc3_vendor内存 */
dwc = &vdwc->dwc; /* 获取到dwc3参数用于后续初始化 */
regs = devm_ioremap_resource(dev, &dwc_res);
dwc->regs = regs; | -
dwc->regs_size = resource_size(&dwc_res);
/* 配置寄存器地址参数 */
dwc3_get_properties(dwc);
/* 通过设备树获取信息进行 dwc3的成员初始化 例如: dr_mode,maximum_speed,max_ssp_rate
dwc3_cache_hwparams(dwc);
/* 初始化 dwc->hwparams 用于保存 DWC3_GHWPARAMS 0~9 的寄存器参数 */
ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_SIZE);
/* 申请 dwc->ev_buf 内存:dma 与 cache 的内存都在此处申请 */
ret = dwc3_get_dr_mode(dwc);
/* 根据dwc3 寄存器 hwparams0 参数对比 设备树获取的参数 dr_mode,不同则以hwparams0 寄存器参
数对dr_mode 重新配置 */
dwc3_debugfs_init(dwc);
/* 创建 dwc3 debugfs 文件节点: regdump,lsp_dump,mode */
ret = dwc3_core_init_mode(dwc);
/*根据创数模式 对 dwc3进行初始化*/
}
dwc3_core_init_mode(struct dwc3 *dwc) 函数,这模式是 :USB_DR_MODE_PERIPHERAL模式
所以 dwc3_core_init_mode 会调用 dwc3_gadget_init进行初始化
int dwc3_gadget_init(struct dwc3 *dwc)
{
irq = dwc3_gadget_get_irq(dwc);
/* 获取中断号配置 dwc->irq_gadget */
dwc->ep0_trb = dma_alloc_coherent
/* dma 申请 ep0 trb */
dwc->setup_buf = kzalloc(DWC3_EP0_SETUP_SIZE, GFP_KERNEL);
/* 申请 setup_bug 内存 */
dwc->bounce = dma_alloc_coherent(dwc->sysdev, DWC3_BOUNCE_SIZE,
&dwc->bounce_addr, GFP_KERNEL);
/* dma 申请 bounce */
dwc->gadget = kzalloc(sizeof(struct usb_gadget), GFP_KERNEL);
/* 申请 usb_gadget */
usb_initialize_gadget(dwc->dev, dwc->gadget, dwc_gadget_release);
/* 初始化 gadget->dev(device 成员),work,以及dev的父节点配置为dwc->dev */
dev = &dwc->gadget->dev;
dev->platform_data = dwc;
/* dwc3 配置为 gadget device 的 platform_data */
dwc->gadget->ops = &dwc3_gadget_ops;
/* 初始化 gadget 成员:ops */
dwc->gadget->speed = USB_SPEED_UNKNOWN;
dwc->gadget->ssp_rate = USB_SSP_GEN_UNKNOWN;
dwc->gadget->sg_supported = true;
dwc->gadget->name = "dwc3-gadget";
dwc->gadget->lpm_capable = !dwc->usb2_gadget_lpm_disable;
dwc3_gadget_init_endpoints(dwc, dwc->num_eps);
/* 初始化 dwc->gadget的 ep_list,依据 dwc->num_eps 数进行循环调用
dwc3_gadget_init_endpoint 申请 dwc3_ep内存,配置对应的 regs:寄存器地址
dirction:方向,number:端点号, pending_list,cancelled_list,started_list链表,
保存在 dwc->eps中, 依据端口号以及方向
调用不同接口函数 对 dep->endpoint (usb_endpoint)进行初始化,
端口0 :
endpoint ops:dwc3_gadget_ep0_ops, endpoint 添加进 gadget->ep0
非端口0:
endpoint ops: dwc3_gadget_ep_ops, endpoint 添加进 gadget->ep_list链表 */
ret = usb_add_gadget(dwc->gadget);
/* 申请 strut usb_udc 参数内存并对 成员dev( struct device) 初始化:类 udc_class,父设备
dwc->dev,添加 gadget 设备以及 udc 设备,并且添加进 udc_list中 */
}
框架图
流程图:
2. composite 层代码分析
这里以 ncm 为例子分析
文件: [kernel-5.10/drivers/usb/gadget/legacy/ncm.c]
设备描述符:
module_usb_composite_driver 调用 usb_composite_probe函数进行注册,主要是初始化usb_gadget_driver 以及遍历udc_list 与usb_udc进行配对
int usb_composite_probe(struct usb_composite_driver *driver)
{
driver->gadget_driver = composite_driver_template;
/* 配置 composite_driver的 gadget_driver */
gadget_driver->function = (char *) driver->name;
gadget_driver->driver.name = driver->name;
gadget_driver->max_speed = driver->max_speed;
/* 对gadget_drvier参数进行初始化 */
return usb_gadget_probe_driver(gadget_driver);
/* 遍历 udc_list 拿到每个usb_udc 与 gadget_driver 进行匹配
配对逻辑:
1. gadget_driver->udc_name不为空则遍历 udc_list 与 usb_udc的dev中kobj->name配对
2. gadget_driver->udc_name为空 拿到第一个usb_udc的driver为空的(未配对过的)进行配对
*/
}
usb_gadget_probe_driver 配对完后会调用 udc_bind_to_driver 函数,主要 配置 usb_udc参数的
usb_gadget_driver 成员以及回调 usb_gagdget_driver的bind函数,初始化启动dwc3的中断线程以及启动 dwc3 usb gadget
static int udc_bind_to_driver(struct usb_udc *udc, struct usb_gadget_driver *driver)
{
udc->driver = driver;
/* udc的driver成员 与 usb_gadget_drvier参数:driver 进行链接 */
udc->gadget->dev.driver = &driver->driver;
/* gadget->device 的driver 与 gadget_drver的driver成员进行链接 */
ret = driver->bind(udc->gadget, driver);
/* 回调 usb_gdget_driver 的bind 函数*/
ret = usb_gadget_udc_start(udc);
/* 回调 udc->gadget->ops->udc_start(udc->gadget, udc->driver)
回调函数:dwc3_gadget_start 主要启动dwc3 中断处理线程:dwc3_thread_interrupt
配置dwc的gadget_driver */
usb_udc_connect_control(udc);
/* 通过 usb_gadget_connect 回调 gadget->ops->pullup 即 dwc3_gadget_pullup
最终调用 __dwc3_gadget_start 初始化DWC3 USB gadget并启动它 */
kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE);
/* 发送内核事件 KOBJ_CHANGE 通知对象的状态发生了改变 */
}
driver->bind回调:gadget_driver的回调 即运行 composite_driver_template 的bind: composite_bind 主要申请usb_composite_dev 参数内存,把usb_composite_dev与 usb_gadget联系起来,申请 ep0 usb_requset ,回调composite_driver的bind
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);
cdev = kzalloc(sizeof *cdev, GFP_KERNEL);
/* 申请 usb_composite_dev 参数内存 */
cdev->gadget = gadget;
set_gadget_data(gadget, cdev);
/* usb_composite_dev 设置为 gadget device的私有数据 */
status = composite_dev_prepare(composite, cdev);
/* 主要回调dwc3_gadget_ep_alloc_request 申请 usb_request, usb_request的buf缓存,
配置urb 的 compelte 回调函数,配置 ep0的driver_data,配置composite_dev的driver成员:
composite_driver */
status = composite->bind(cdev);
/* 回调 composite_driver的 bind函数 */
update_unchanged_dev_desc(&cdev->desc, composite->dev);
/* composite_driver的 usb 设备描述符(usb_device_descriptor)对 composite_dev的usb
设备描述符进行初始化 */
}:
composite_driver的bind:gncm_bind 主要是 对composite_dev添加 usb_configuration,对usb_configuration添加usb_function
static int gncm_bind(struct usb_composite_dev *cdev)
{
struct usb_gadget *gadget = cdev->gadget;
struct f_ncm_opts *ncm_opts;
f_ncm_inst = usb_get_function_instance("ncm");
/* 遍历 func_list 通过 name进行配对,配对完成回调 alloc_inst() ,
初始配置组,获取usb_function_instance 内存 */
status = usb_add_config(cdev, &ncm_config_driver,
ncm_do_config);
/* 把 usb_configuration: ncm_config_driver 添加进 composite_dev的configs链表中,
回调ncm_do_config 该函数 主要功能:
1.通过 usb_get_function 函数
用f_ncm_inst 参数 回调 alloc_func 对usb_function 参数进行赋值,function的name,bind
unbind.setup等会调函数在此处进行赋值
2.调用usb_add_function 把对应的usb_function 添加进 usb_configuration中,回调function
bind函数:ncm_bind
*/
}
函数调用图:
框架图:
3. configfs 配置流程分析
结构体参数:
创建目录函数:主要在 usb_gadget目录下生成对应的目录 : UDC,configs, functions 等,以及初始化 usb_composite_driver 以及 usb_composite_dev
static struct config_group *gadgets_make(
struct config_group *group,
const char *name)
{
config_group_init_type_name(&gi->functions_group, "functions",
&functions_type);
configfs_add_default_group(&gi->functions_group, &gi->group);
config_group_init_type_name(&gi->configs_group, "configs",
&config_desc_type);
configfs_add_default_group(&gi->configs_group, &gi->group);
gi->composite.bind = configfs_do_nothing;
gi->composite.unbind = configfs_do_nothing;
/* 配置 composite_driver 的 bind,unbind 回调函数 */
composite_init_dev(&gi->cdev);
gi->cdev.desc.bLength = USB_DT_DEVICE_SIZE;
gi->cdev.desc.bDescriptorType = USB_DT_DEVICE;
gi->cdev.desc.bcdDevice = cpu_to_le16(get_default_bcdDevice());
/* 初始化 composite_dev */
gi->composite.gadget_driver = configfs_driver_template;
/* 配置 composite_driver 的 usb_gadget_driver参数 */
gi->composite.gadget_driver.function = kstrdup(name, GFP_KERNEL);
gi->composite.name = gi->composite.gadget_driver.function;
}
配置流程:
例子:
1. write /config/usb_gadget/g1/UDC "none"
调用函数:gadget_dev_desc_UDC_store 主要 关闭dwc3的数据传输 关闭 中断,disable ep0等, 代码流程如下
2. write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "ncm"
主要调用 config_desc_make 函数初始化usb_configuration:b1,创建 b.1和strings配置组, 以及调用usb_add_config_only 把 usb_configuration 添加进 usb_compsite_dev(gi->cdev)的configs 链表中
configuration 写入 “ncm”,具体的 store函数依据以下的宏定义
GS_STRINGS_RW(gadget_config_name, configuration);
3. mkdir /config/usb_gadget/g1/functions/ncm.gs7
调用:function_make 函数:主要遍历func_list 找到对应的function_instance,添加进
gi->available_func
static struct config_group *function_make( struct config_group *group,const char *name )
{
func_name = buf;
instance_name = strchr(func_name, '.');
*instance_name = '\0';
instance_name++;
/* 分割出func_name:ncm 以及 instance_name:gs7 */
fi = usb_get_function_instance(func_name);
/*遍历 func_list进行配对, 回调alloc_inst 申请 usb_function_instance,
初始化配置组 */
ret = config_item_set_name(&fi->group.cg_item, "%s", name);
/* 配置 ncm function的配置组名: ncm.gs7 */
list_add_tail(&fi->cfs_list, &gi->available_func);
/* usb_function_instance 添加进 gadget_info */
}
4. symlink /config/usb_gadget/g1/functions/ncm.gs7 /config/usb_gadget/g1/configs/b.1/f1
调用 config_usb_cfg_link函数: 遍历 gadget_info 的 available_func链表 进行配对,获取
usb_function 添加进 config_usb_cfg 的func_list链表
static int config_usb_cfg_link(
struct config_item *usb_cfg_ci,
struct config_item *usb_func_ci)
{
struct config_usb_cfg *cfg = to_config_usb_cfg(usb_cfg_ci);
struct gadget_info *gi = container_of(cdev, struct gadget_info, cdev);
list_for_each_entry(a_fi, &gi->available_func, cfs_list) {
if (a_fi == fi)
break;
}
/*遍历 available_func list 匹配对应的 usb_function_instance */
f = usb_get_function(fi);
/* 获取 usb_function */
list_add_tail(&f->list, &cfg->func_list);
/* 添加进 config_usb_cfg cfg 的 func_list */
}
5. write /config/usb_gadget/g1/UDC ${sys.usb.controller}
调用 gadget_dev_desc_UDC_store
static ssize_t gadget_dev_desc_UDC_store(struct config_item *item,
const char *page, size_t len)
{
gi->composite.gadget_driver.udc_name = name;
ret = usb_gadget_probe_driver(&gi->composite.gadget_driver);
/* 配置 udc_name 遍历 udc_list进行配对,回调 udc_bind_to_driver 对
usb_udc与 usb_gadget_driver进行绑定, 回调gadgdget_driver:
configfs_driver_template的 bind函数:configfs_composite_bind */
}
static int configfs_composite_bind(struct usb_gadget *gadget,
struct usb_gadget_driver *gdriver)
{
struct usb_composite_dev *cdev = &gi->cdev;
cdev->gadget = gadget;
ret = composite_dev_prepare(composite, cdev);
/* composite_dev与 usb_gadget 绑定,composite_dev 与composite_driver绑定,
申请 usb_request, requst 缓存 */
list_for_each_entry_safe(f, tmp, &cfg->func_list, list) {
list_del(&f->list);
ret = usb_add_function(c, f);
}
/* 遍历 function_list的usb_function 从function_list移除,
调用 usb_add_function 把 function 添加进 usb_configuration中 */
usb_ep_autoconfig_reset(cdev->gadget)
/*复位 gadget*/
}
5个步骤 组合起来 注册 config,注册 function 与 udc_list 的gadge配对 搭建框架如下图
流程图 :号码对应上面的步骤
4.小结
1 dwc3 和dwc3_ep 负责最终的数据传数
2 dwc3配置 usb_gadget 以及 usb_udc
3 usb_udc 负责usb_gadget 与usb_gadget_driver配对
4 composite 端 主要是构建 usb_configuration以及usb_function