ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

【notes8】usb

2026/8/12 20:34:00 拓冰建站 浏览量
【notes8】usb 文章目录1.硬件接口2.枚举和断开过程usb调试PC-USBUSB-SMD1.硬件接口USB口用于打印机第四个是硬盘OTGOn The Go安上即可用如下是typec接口usb2.0协议只关心红色的框。2.枚举和断开过程USB2.0协议中枚举过程一个高速 USB 设备刚插上时先假装自己是全速设备然后通过一段暗号Chirp和主机确认彼此都支持高速后再切换到真正的高速模式。1.设备连接主机检测到D有高电平粉线主机并输出总线复位信号期间设备D-拉高0.8v绿线产生K信号表明高速或全速身份。2.K信号后主机发生KJ序列表明高速主机或全速主机身份。3.后面就是高速波形完成通讯。// USB设备枚举一般会经过插入、供电、初始化、分配地址配置【获取设备描述符、获取配置描述符、获取字符串描述符】和配置设备。usb调试高通平台作为usb device和pc机进行连接pc通过usb发送数据如AT数据控制 Modem 的命令语言at_usb0 可以理解成Linux 看到/dev/ttyUSB0。如果PC发送AT命令到达了AP说明USB正常。还要排查SMD转发到MPSS侧。PC-USB如下上位机是windows才能用下面工具。USB-SMDusbmon工具上位机是linux场景Bus 001Device 004Vendor ID 05e3Product ID 0749对上面usbmon_log文件解析ububtuapt-get install vusb-analyzerhost侧有低速高速等控制器查看插入pc windows侧插入的设备描述符配置描述符端口描述符等如下比如键盘先表示自己是输入类设备PIDVID等包含多套配置如键盘功能键盘上小红点功能Sysfs/sys/devices/ 等“展示现状”。它主要是内核用来向用户空间暴露已存在的设备信息和属性如 CPU 频率、电源状态。你可以写文件去修改参数但不能在 Sysfs 里创建一个不存在的设备。 ConfigFS/sys/kernel/config/“从零构建”。它允许用户在目录里新建文件夹mkdir 来实例化一个新的内核对象。当你删除这个文件夹rmdir时这个对象就被销毁了。当你往 /sys/kernel/config/usb_gadget/g1/UDC 里写入一个 UDC 名称如 DWC3时内核背后发生了什么。你已经用 ConfigFS 把一个“USB 设备”配置好了最后执行 echo DWC3 UDC相当于把这个虚拟 USB 设备正式插到 DWC3 这个 USB 控制器上让主机能够发现它。举个最容易理解的例子假设你的 BMC 板子有一个 DWC3 USB Device 控制器你想让板子插到 PC 后PC 把它识别成一个 U 盘USB 网卡 的复合设备。 前面你可能已经做了类似配置 mkdir/sys/kernel/config/usb_gadget/g1 cd/sys/kernel/config/usb_gadget/g1 echo0x1234idVendor echo0x5678idProduct # 创建 USB 网卡 mkdir functions/ecm.usb0 # 创建 U 盘 mkdir functions/mass_storage.0# 创建配置 mkdir configs/c.1ln-s functions/ecm.usb0 configs/c.1/ln-s functions/mass_storage.0configs/c.1/到这里其实可以理解成 “USB 设备的简历已经写好了但还没有正式上岗。” 也就是说你已经告诉 Linux 我要伪装成一个 USB 设备 里面有 USB 网卡 USB U盘 但是 PC 此时可能还看不到它。 最后执行 echo DWC3/sys/kernel/config/usb_gadget/g1/UDC 这才是图里重点描述的过程。echo DWC3 UDC 到底是什么感觉可以类比成USB Gadget 配置↓“我已经设计好了一个USB设备”↓echo DWC3 UDC↓“现在把这个USB设备接到DWC3硬件控制器上”↓DWC3 开始工作↓PC叮咚发现新USB设备这里有两个完全不同的角色。Gadget“我要表现成什么 USB 设备”比如U盘网卡串口HID键盘摄像头而 UDCUSB Device Controller 是“真正负责往 USB 线上发数据的硬件控制器是谁”比如DWC3所以echo DWC3 UDC实际上就是把 g1 这个 GadgetDWC3 这个硬件 USB Device Controller↓绑定起来图片最上面echo DWC3 /sys/kernel/config/usb_gadget/g1/UDC然后进入gadget_dev_desc_UDC_store()这个函数其实很好理解因为 UDC 是一个 sysfs/configfs 属性。你执行echo DWC3 UDC本质就是用户往 UDC 文件写入字符串 “DWC3”内核于是调用它对应的store()也就是gadget_dev_desc_UDC_store()你可以把它理解成UDC_store(“DWC3”){// 用户说// 我要绑定 DWC3}然后进入 usb_gadget_probe_driver()图中接下来是usb_gadget_probe_driver()这一步可以理解为“现在有一个 Gadget Driver 想找一个 UDC 控制器上班。”内核手里实际上有两个东西。一个是 Gadget DriverComposite Gadget Driver它描述这个USB设备怎么工作另一个是 UDCDWC3 Controller它负责USB硬件收发可以想象成招聘员工USB Gadget Driver岗位DWC3 UDCusb_gadget_probe_driver()↓帮它们撮合图中下面的 list_for_each_entry这一步特别重要。Linux 里面可能有不止一个 UDC。比如系统中可能存在DWC3_0DWC3_1MUSBChipIdea内核会维护一个类似udc_list你可以脑补成UDC 控制器名单[0] DWC3[1] DWC3.1[2] MUSB然后list_for_each_entry(…)就是一个个找过去看哪个 UDC 是我要的。类似for (每一个 UDC) {if (这个UDC名字 DWC3) { 找到了; break; }}所以图中写的遍历合适的端点更准确地理解这里这一层的话是在遍历/查找合适的 UDC。找到之后DWC3↓UDC Core找到 DWC3 后udc_bind_to_driver()接下来udc_bind_to_driver()名字其实已经非常直白了UDC bind to driver就是把 DWC3 控制器和 Gadget Driver 正式绑定。类似DWC3 控制器USB Gadget Driver↓绑定可以类比 Linux platform driverdevicedriver↓probeUSB Gadget 这里类似UDCgadget driver↓bind然后调用 driver-bind图片右边driver-bind这里就是典型的 C 函数指针。大概可以脑补成struct usb_gadget_driver driver {.bind composite_bind,};因此driver-bind(…)实际调用composite_bind(…)这就是为什么图右边写着driver - bind↓composite_bindcomposite_bind() 是干嘛的这里的 Composite 指的是 USB Composite DeviceUSB 复合设备。比如你的设备同时具有USB 网卡USB 串口USB U盘那么USB Device │ ┌───────┼───────┐ ↓ ↓ ↓ 网卡 串口 U盘这种就是 Composite Device。所以composite_bind()可以理解成把你前面 ConfigFS 创建好的这些 Function 真正组织成一个 USB 设备。例如g1│├── mass_storage│├── ecm│└── acm开始进行初始化。图下面的 Endpoint 是什么这又是 USB Gadget 很重要的概念。例如你做一个 USB U盘数据总得有地方进出吧。USB 不是直接PC ↔ U盘程序而是PC↓USB Endpoint↓UDC↓Gadget Function例如 U 盘可能需要Bulk OUT EndpointPC → BMCBulk IN EndpointBMC → PC比如ep1outep1inDWC3 控制器可能提供ep0ep1inep1outep2inep2out…而 Gadget Function 会提出需求mass_storage我要一个 Bulk IN我要一个 Bulk OUTECM网卡我要 Bulk IN我要 Bulk OUT我要 Interrupt IN于是内核就开始给这些 Function 分配合适的 Endpoint。可以把它理解成酒店分房间DWC3提供房间1Bulk IN房间2Bulk OUT房间3Interrupt IN房间4Bulk IN…↓ 分配USB U盘Bulk IN → ep1inBulk OUT → ep1outUSB 网卡Bulk IN → ep2inBulk OUT → ep2out因此图中struct usb_gadget|±— Endpoint±— Endpoint±— Endpoint表示的是UDC 驱动向 Gadget Core 暴露了这个硬件控制器所拥有的 Endpoint 能力。把整张图变成一个生活化例子可以把它想成 公司招聘 开店。你已经准备了一家店USB Gadget g1店里准备卖咖啡 USB网卡面包 USB U盘但现在还只是装修好了菜单写好了员工培训好了并没有营业。你执行echo DWC3 UDC相当于“把这家店挂到 DWC3 这个实体门店上正式营业。”于是gadget_dev_desc_UDC_store()接到你的申请我要使用 DWC3↓usb_gadget_probe_driver()开始寻找系统里有没有 DWC3↓list_for_each_entry()翻 UDC 名单MUSB不是DWC2不是DWC3是它↓udc_bind_to_driver()让USB Gadget Driver↕DWC3正式绑定。↓调用driver-bind()实际就是composite_bind()↓开始给 USB Function 安排 EndpointU盘ep1inep1out网卡ep2inep2outep3in↓DWC3 开始监听 USB 总线。这时候你把 BMC 接到 PCPC││ USB↓DWC3│↓Linux USB Gadget│├── U盘└── 网卡PC 开始枚举GET_DESCRIPTORSET_ADDRESSGET_CONFIGURATIONSET_CONFIGURATION最终 PC 就看到发现 USB Mass Storage发现 USB Ethernet所以你记住这 4 层就够了这张图第一次看很容易被各种函数名搞晕其实核心就是① ConfigFS“我要做成什么USB设备”↓② Gadget / Composite Driver“USB设备的软件逻辑”↓③ UDC Core“帮 Gadget 找 USB 控制器”↓④ DWC3 UDC Driver“真正操作USB硬件”最终路径echo DWC3 UDC↓gadget_dev_desc_UDC_store()↓usb_gadget_probe_driver()↓从 udc_list 找 DWC3↓udc_bind_to_driver()↓driver-bind()↓composite_bind()↓Function / Endpoint 初始化↓DWC3 启动↓PC 开始枚举这个 USB 设备最关键的一点是echo DWC3 UDC 并不是“创建 USB Gadget”而是把之前已经配置好的 Gadget 绑定到真正的 DWC3 USB Device Controller 上。这就很像设备树里“描述硬件”和驱动真正 probe 起来的区别——前面是在准备绑定 UDC 后才是真正让这套 Gadget 开始对外工作。