USB Gadget 关键调用链与函数索引
按当前 RK3588 Linux 6.1 源码整理,行号可能随厂商树变动,以函数名为稳定入口。RK3588 的硬件 UDC 是drivers/usb/dwc3/gadget.c(DWC3 gadget 模式);drivers/usb/gadget/udc/目录下除core.c外的 SoC UDC 驱动均与 RK3588 无关。
1. 分层与文件归属
1 2 3 4 5 6
| 用户态 ConfigFS (/sys/kernel/config/usb_gadget/) -> configfs.c 组装 gadget、写 UDC 触发绑定 -> composite.c Chapter 9、config/function 生命周期 -> functions.c Function 注册表(usb_get_function_instance) -> udc/core.c UDC 类、gadget bus、usb_ep_*/usb_gadget_* API -> dwc3/gadget.c RK3588 真实 UDC(udc_start/pullup/queue)
|
2. UDC 上线(boot)
1 2 3 4 5 6 7 8 9 10 11
| DTS usbdrd3_0 ("rockchip,rk3588-dwc3","rockchip,rk3399-dwc3") -> dwc3-of-simple.c 匹配 rk3399-dwc3 fallback -> of_platform_populate 子节点 "snps,dwc3" -> dwc3_probe() dwc3/core.c:1976 -> dwc3_core_init_mode() dwc3/core.c:1504 dr_mode=peripheral -> dwc3_gadget_init() dr_mode=otg -> dwc3_drd_init() 角色切到 DEVICE 后再 gadget_init -> dwc3_gadget_init() dwc3/gadget.c:4697 -> usb_initialize_gadget() udc/core.c:1355 -> usb_add_gadget() udc/core.c:1378 -> /sys/class/udc/fc000000.usb(取 parent 设备名)
|
UDC 类初始化:usb_udc_init()(udc/core.c,subsys_initcall)创建udc class 和gadget bus。
3. ConfigFS 组装与绑定
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| mkdir usb_gadget/g1 mkdir functions/uac2.usb0 -> function_make() configfs.c:623 -> usb_get_function_instance() mkdir configs/c.1 ln -s functions/... configs/ -> config_usb_cfg_link() configfs.c:448 echo fc000000.usb > UDC -> gadget_dev_desc_UDC_store() configfs.c:293 -> usb_gadget_register_driver_owner() udc/core.c:1666 -> gadget bus match(按 udc_name) -> gadget_bind_driver() udc/core.c:1578 -> configfs_composite_bind() configfs.c:1319 -> composite_dev_prepare()(分配 ep0 req) -> 遍历 config 调 usb_add_function() composite.c:314 -> f->bind()(内部 usb_ep_autoconfig 认领端点) -> usb_gadget_udc_start_locked() -> dwc3_gadget_start() dwc3/gadget.c:3008 -> pullup -> dwc3_gadget_pullup() dwc3/gadget.c:2786
|
注意:ConfigFS 的usb_composite_driver.bind是空操作,真正绑定逻辑在configfs_composite_bind(作为 gadget_driver.bind,见configfs.c:1718)。启用USB_CONFIGFS_UEVENT时 setup 入口是android_setup()(configfs.c:1547),并通过android_usb class 发 CONNECTED/CONFIGURED uevent。
4. 枚举(EP0/Chapter 9)
1 2 3 4 5 6 7 8
| Host SETUP -> DWC3 IRQ -> driver->setup -> composite_setup() composite.c:1745 GET_DESCRIPTOR 填 cdev->req->buf SET_CONFIGURATION -> set_config() composite.c:915 -> 每个 f->set_alt(f, intf, 0) SET_INTERFACE -> f->set_alt() 类/厂商请求 -> f->setup() -> composite_ep0_queue() -> usb_ep_queue(ep0)
|
状态机:bus reset 时usb_gadget_udc_reset()(udc/core.c:1186)置DEFAULT;SET_ADDRESS/SET_CONFIG 在dwc3/ep0.c中推进到ADDRESS/CONFIGURED;/sys/class/udc/<name>/state可读当前状态。
5. 数据面
1 2 3 4 5 6 7 8 9 10 11 12
| Function set_alt: config_ep_by_speed() composite.c:292 按速度选描述符 usb_ep_enable() 批量 usb_ep_queue() udc/core.c:288
完成(IRQ): UDC -> usb_gadget_giveback_request() udc/core.c:989 -> req->complete()(原子上下文,通常立即重新入队)
取消/停流: usb_ep_dequeue() udc/core.c:326 完成态 -ECONNRESET usb_ep_disable() udc/core.c:156 未决请求 -ESHUTDOWN
|
请求分配:usb_ep_alloc_request()或u_f.c的alloc_ep_req()。complete 回调不可睡眠,也不可递归造成入队死锁。
6. 断开与解绑
1 2 3 4 5 6 7 8 9 10 11 12 13
| 拔线/软断开: usb_gadget_disconnect() udc/core.c -> pullup(0) -> composite_disconnect() composite.c:2204 -> reset_config() -> 每个 f->disable()
echo none > UDC: unregister_gadget -> gadget_unbind_driver() udc/core.c:1633 -> disconnect -> driver->unbind -> configfs_composite_unbind() configfs.c:1519 -> purge_configs_funcs()(f->unbind) -> composite_dev_cleanup() -> udc_stop
|
顺序不变量:先 pullup(0)/disable 停流,再 unbind 释放描述符与端点,最后 udc_stop。
7. 关键锁
| 锁 |
位置 |
保护 |
udc_lock |
udc/core.c |
udc_list、driver 绑定 |
usb_udc.connect_lock |
udc/core.c |
started/connected/pullup |
cdev->lock(spinlock) |
composite |
delayed_status、config 切换 |
gadget_info.lock/spinlock |
configfs.c |
组装、setup 与 unbind 竞态 |
| UDC 内部 spinlock |
dwc3 等 |
端点队列/硬件 |
8. RK3588 配置速查
三份 Rockchip defconfig 均启用USB_DWC3、USB_GADGET、USB_CONFIGFS(+UEVENT)、ACM/MASS_STORAGE/F_FS;差异:主配置多F_UVC,cpcem 多F_UAC1/F_UAC2/F_HID。udc/目录 SoC UDC 与USB_DUMMY_HCD均未启用。
DTS 角色:usbdrd_dwc3_0@fc000000默认dr_mode="otg"(gadget 口);usbhost_dwc3_0与 RK3588 完整版的 DRD1 默认 host。OTG 口需 Type-C role-switch 处于 device 角色,/sys/class/udc/下才有可绑定的 UDC。
运维三步:
1 2 3
| ls /sys/class/udc/ echo fc000000.usb > $G/UDC cat /sys/class/udc/fc000000.usb/state
|
正在加载留言…