RK DWC3 gadget模块 分析

2023-10-07 08:40
文章标签 分析 模块 gadget rk dwc3

本文主要是介绍RK DWC3 gadget模块 分析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

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_ratedwc3_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,bindunbind.setup等会调函数在此处进行赋值2.调用usb_add_function 把对应的usb_function 添加进 usb_configuration中,回调functionbind函数: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

这篇关于RK DWC3 gadget模块 分析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/157249

相关文章

python: 多模块(.py)中全局变量的导入

文章目录 global关键字可变类型和不可变类型数据的内存地址单模块(单个py文件)的全局变量示例总结 多模块(多个py文件)的全局变量from x import x导入全局变量示例 import x导入全局变量示例 总结 global关键字 global 的作用范围是模块(.py)级别: 当你在一个模块(文件)中使用 global 声明变量时,这个变量只在该模块的全局命名空

性能分析之MySQL索引实战案例

文章目录 一、前言二、准备三、MySQL索引优化四、MySQL 索引知识回顾五、总结 一、前言 在上一讲性能工具之 JProfiler 简单登录案例分析实战中已经发现SQL没有建立索引问题,本文将一起从代码层去分析为什么没有建立索引? 开源ERP项目地址:https://gitee.com/jishenghua/JSH_ERP 二、准备 打开IDEA找到登录请求资源路径位置

深入探索协同过滤:从原理到推荐模块案例

文章目录 前言一、协同过滤1. 基于用户的协同过滤(UserCF)2. 基于物品的协同过滤(ItemCF)3. 相似度计算方法 二、相似度计算方法1. 欧氏距离2. 皮尔逊相关系数3. 杰卡德相似系数4. 余弦相似度 三、推荐模块案例1.基于文章的协同过滤推荐功能2.基于用户的协同过滤推荐功能 前言     在信息过载的时代,推荐系统成为连接用户与内容的桥梁。本文聚焦于

SWAP作物生长模型安装教程、数据制备、敏感性分析、气候变化影响、R模型敏感性分析与贝叶斯优化、Fortran源代码分析、气候数据降尺度与变化影响分析

查看原文>>>全流程SWAP农业模型数据制备、敏感性分析及气候变化影响实践技术应用 SWAP模型是由荷兰瓦赫宁根大学开发的先进农作物模型,它综合考虑了土壤-水分-大气以及植被间的相互作用;是一种描述作物生长过程的一种机理性作物生长模型。它不但运用Richard方程,使其能够精确的模拟土壤中水分的运动,而且耦合了WOFOST作物模型使作物的生长描述更为科学。 本文让更多的科研人员和农业工作者

MOLE 2.5 分析分子通道和孔隙

软件介绍 生物大分子通道和孔隙在生物学中发挥着重要作用,例如在分子识别和酶底物特异性方面。 我们介绍了一种名为 MOLE 2.5 的高级软件工具,该工具旨在分析分子通道和孔隙。 与其他可用软件工具的基准测试表明,MOLE 2.5 相比更快、更强大、功能更丰富。作为一项新功能,MOLE 2.5 可以估算已识别通道的物理化学性质。 软件下载 https://pan.quark.cn/s/57

衡石分析平台使用手册-单机安装及启动

单机安装及启动​ 本文讲述如何在单机环境下进行 HENGSHI SENSE 安装的操作过程。 在安装前请确认网络环境,如果是隔离环境,无法连接互联网时,请先按照 离线环境安装依赖的指导进行依赖包的安装,然后按照本文的指导继续操作。如果网络环境可以连接互联网,请直接按照本文的指导进行安装。 准备工作​ 请参考安装环境文档准备安装环境。 配置用户与安装目录。 在操作前请检查您是否有 sud

线性因子模型 - 独立分量分析(ICA)篇

序言 线性因子模型是数据分析与机器学习中的一类重要模型,它们通过引入潜变量( latent variables \text{latent variables} latent variables)来更好地表征数据。其中,独立分量分析( ICA \text{ICA} ICA)作为线性因子模型的一种,以其独特的视角和广泛的应用领域而备受关注。 ICA \text{ICA} ICA旨在将观察到的复杂信号

【软考】希尔排序算法分析

目录 1. c代码2. 运行截图3. 运行解析 1. c代码 #include <stdio.h>#include <stdlib.h> void shellSort(int data[], int n){// 划分的数组,例如8个数则为[4, 2, 1]int *delta;int k;// i控制delta的轮次int i;// 临时变量,换值int temp;in

三相直流无刷电机(BLDC)控制算法实现:BLDC有感启动算法思路分析

一枚从事路径规划算法、运动控制算法、BLDC/FOC电机控制算法、工控、物联网工程师,爱吃土豆。如有需要技术交流或者需要方案帮助、需求:以下为联系方式—V 方案1:通过霍尔传感器IO中断触发换相 1.1 整体执行思路 霍尔传感器U、V、W三相通过IO+EXIT中断的方式进行霍尔传感器数据的读取。将IO口配置为上升沿+下降沿中断触发的方式。当霍尔传感器信号发生发生信号的变化就会触发中断在中断

kubelet组件的启动流程源码分析

概述 摘要: 本文将总结kubelet的作用以及原理,在有一定基础认识的前提下,通过阅读kubelet源码,对kubelet组件的启动流程进行分析。 正文 kubelet的作用 这里对kubelet的作用做一个简单总结。 节点管理 节点的注册 节点状态更新 容器管理(pod生命周期管理) 监听apiserver的容器事件 容器的创建、删除(CRI) 容器的网络的创建与删除