安装好 gadget 驱动程序后(比如 modprobe g_zero), 它只是构造好了各类描述符。在设备的枚举过程会读取描述符。
使用 otg 线连接电脑和开发板时,电脑软件会执行如下操作:
使用控制传输,读取设备信息(设备描述符):第一次读取时,它只需要得到 8 字节数据,因为第 8 个数据表示端点 0 能传输的最大数据长度。host 分配地址给设备,然后把新地址发给设备。使用新地址,重新读取设备描述符,设备描述符长度是 18读取配置描述符:它传入的长度是 255,想一次性把当前配置描述符、它下面的接口描述符、端点描述符全部读出来。读取字符描述符。上述过程里,设备方都是接收到 host 发给 endpoint 0 的数据,然后做出回应。不同的 gadget 设备,在返回描述符给主机时,这些操作都是一样的,只是回应的数据不同而已。源码分析的起点都是某个中断函数:
imx6ull:ci_irq(drivers/usb/chipidea/core.c)stm32mp157: dwc2_hsotg_irq(drivers/usb/dwc2/gadget.c)4.1 imx6ull 的核心函数imx6ull 芯片中 usb 控制器型号是 chipidea,在linux-4.9.88driversusbchipideacore.c中注册了中断函数:
ci_hdrc_probe ret = devm_request_irq(dev, ci- >irq, ci_irq, irqf_shared, ci- >platdata- >name, ci);发生中断后,对于 endpoint 0 的数据处理流程如下:
// linux-4.9.88driversusbchipideacore.cci_irq /* handle device/host interrupt */ if (ci- >role != ci_role_end) ret = ci_role(ci)- >irq(ci); // udc_irq // linux-4.9.88driversusbchipideaudc.c udc_irq if (usbi_ui & intr) // linux-4.9.88driversusbchipideaudc.c isr_tr_complete_handler(ci); /* only handle setup packet below */ if (i == 0 && hw_test_and_clear(ci, op_endptsetupstat, bit(0))) // linux-4.9.88driversusbchipideaudc.c isr_setup_packet_handler(ci);函数isr_setup_packet_handler就是处理 endpoint 0 接收到的控制传输的关键。
4.2 stm32mp157的核心函数stm32mp157 芯片中 usb 控制器型号是 dwc2,在linux-5.4driversusbdwc2gadget.c中注册了中断函数:
dwc2_gadget_init ret = devm_request_irq(hsotg- >dev, hsotg- >irq, dwc2_hsotg_irq, irqf_shared, dev_name(hsotg- >dev), hsotg);发生中断后,函数dwc2_hsotg_irq被调用,它处理 endpoint 中断有两种方法:
使用 dma 时:调用dwc2_hsotg_epint来处理不使用 dma 时:调用dwc2_hsotg_handle_rx来处理以dwc2_hsotg_epint为例进行分析,对于 endpoint 0 的数据处理流程如下:
// linux-5.4driversusbdwc2gadget.cdwc2_hsotg_irq // 处理endpoint中断 for (ep = 0; ep num_of_eps && daint_out; ep++, daint_out > >= 1) { if (daint_out & 1) dwc2_hsotg_epint(hsotg, ep, 0); } for (ep = 0; ep num_of_eps && daint_in; ep++, daint_in > >= 1) { if (daint_in & 1) dwc2_hsotg_epint(hsotg, ep, 1); }函数dwc2_hsotg_epint中,对于 endpoint 0 的处理如下:
// linux-5.4driversusbdwc2gadget.cdwc2_hsotg_epint if (idx == 0 && !hs_ep- >req) dwc2_hsotg_enqueue_setup(hsotg);函数dwc2_hsotg_enqueue_setup被调用时,gadget 设备已经收到了 setup 令牌包,但是还没收到 data0 令牌包。dwc2_hsotg_enqueue_setup的作用是,设置、启动一个 request,核心在于设置了 request 的 complete 函数(当 settup 事务完成后这个函数被调用):
当控制传输的setup事务完成时,函数dwc2_hsotg_complete_setup被调用。
4.3 如何处理控制传输无论是 mx6ull 的函数isr_setup_packet_handler,还是 stm32m157 的函数dwc2_hsotg_complete_setup,它们都是在 gadget 设备收到setup事务后才被调用。接收完setup事务后,就可以从里面知道这个控制传输想做什么(req.brequest 是什么),然后就可以处理它了。
怎么处理呢?可以分为 3 层:
udc 驱动程序:类似设置地址的控制传输,在底层的 udc 驱动程序里就可以处理, 这类请求有: usb_req_set_addressusb_req_set_feature // 有一些请求可能需要上报改 gadget driverusb_req_clear_feature // 有一些请求可能需要上报改 gadget driverusb_req_get_status // 有一些请求可能需要上报改 gadget driver驱动程序位置 imx6ull: linux-4.9.88driversusbchipideaudc.c, 函数 isr_setup_packet_handlerstm32mp157: linux-5.4driversusbdwc2gadget.c, 函数 dwc2_hsotg_complete_setupgadget driver:涉及描述符的操作 这类请求有: usb_req_get_descriptorusb_req_set_configurationusb_req_get_configurationusb_req_set_interfaceusb_req_get_interfaceusb_req_get_status // 底层 udc 驱动无法处理的话, gadget driver 来处理usb_req_clear_feature // 底层 udc 驱动无法处理的话, gadget driver 来处理usb_req_set_feature // 底层 udc 驱动无法处理的话, gadget driver 来处理驱动程序位置 文件:driversusbgadgetcomposite.c函数:composite_setupusb_configuration 或 usb_function 的处理:这是二选一的。大部分设备使用控制传输实现标准的 usb 请求,但是也可以用控制传输来进行实现相关的请求,对于这些非标准的请求,就需要上层驱动来处理。
CVPR2019新作:一种基于视频流的自监督特征表达方法
英伟达跨界医疗AI 首先从医学及卫生保健领域入手
“你好,自然美” 自拍旗舰vivo S10系列正式发布
基于I2C总线的CMOS图像传感器接口电路设计
50个三菱PLC常见问题解答
从获取描述符的角度理解Gadget框架
RFID仓库管理解决方案助力绿色物流+智能RFID仓库落地
虹科携手预测性维护专家提供WATCHMAN 360预测性维护方案
AI预测人生轨迹到底可不可行?
2023年美国首座核动力比特币矿场将开放
LTpowerCAD设计工具的回路补偿特性的介绍
意法半导体物联网解决及方案
SERDES的引脚数量和通道优势
ROHM旗下蓝碧石半导体微控制器入门套件“SK-AD01”开始网售电容式开关系统的导入更轻松!
专家揭秘:STM32启动过程全解
e络盟播客节目《创新专家》第三集上线,HIOKI剖析电池设计问题
刀片电池的优缺点,刀片电池寿命一般多长时间
烽火通信连续三年在中国移动蝶形光缆集采项目中排名前三
戴尔易安信利用全方位存储产品组合打造现代化数据中心
家居装修APP开发方案