Composite 框架、EP0 与描述符管理
1. 对象模型
libcomposite 把一个 USB 设备组织为三级:
1 | usb_composite_dev (cdev) 整个设备:设备描述符、strings、EP0 |
usb_composite_driver:一个 gadget 方案(VID/PID、strings、bind 回调);usb_function_driver:function 类型注册表项(functions.c管理,按名字如”acm”、”mass_storage”查找);usb_function_instance:一个 function 的配置实例(ConfigFS 目录对应物);usb_function:实例绑定到某配置后的运行对象。
2. 注册与 bind 主链
1 | usb_composite_probe() composite.c:2568 |
Function bind 中常用:
usb_interface_id():composite.c:479,分配接口号;usb_string_id():1351 行,分配字符串 ID;usb_ep_autoconfig():分配端点;usb_assign_descriptors():登记 FS/HS/SS 描述符组。
卸载走composite_unbind()(2265 行)→ __composite_unbind()(2233 行),逆序释放 configuration/function 和 EP0 请求。
3. EP0 Setup 分发
UDC 收到 SETUP 包后调用 gadget driver 的setup回调,即:
1 | composite_setup() composite.c:1745 |
响应数据经cdev->req在 EP0 queue,完成回调composite_setup_complete()(1540 行)。若 function 需要延迟状态阶段(如 UVC 等待用户态应答),setup 返回USB_GADGET_DELAYED_STATUS,之后调用usb_composite_setup_continue()(2612 行)恢复。
4. SET_CONFIGURATION 与 SET_INTERFACE
set_config()(915 行):
- 依
wValue找到usb_configuration; - 对每个 function 调
f->set_alt(f, intf, 0); - function 在
set_alt中usb_ep_enable()并 queue 初始请求; usb_gadget_vbus_draw()按 MaxPower 上报取电;- 设备进入 CONFIGURED 状态。
SET_INTERFACE 直接分发到对应 function 的set_alt;带 isochronous 端点的 function(UAC/UVC)用 alt 0/1 表示流关闭/开启,是音视频启停的真正入口。
5. 描述符三速组织
Function 为 FS/HS/SS 各准备一组描述符,包长与间隔字段不同(bulk 64/512/1024;isoc/int 的 bInterval 语义也不同)。config_buf()按当前协商速度选择对应组拼接返回。SS 还需usb_ss_ep_comp_descriptor描述 burst/streams。仅提供 HS 描述符的 function 在 SS 链路上会 bind 失败或降级,这是 DWC3 SuperSpeed 口上常见问题。
6. Disconnect / Suspend / Resume
| 事件 | 入口 | 动作 |
|---|---|---|
| 断开/复位 | composite_disconnect() composite.c:2204 |
调各 function disable,回到未配置状态 |
| 挂起 | composite_suspend() 2476 行 |
分发f->suspend,降 VBUS 电流 |
| 恢复 | composite_resume() 2500 行 |
分发f->resume,恢复取电 |
Function 的disable必须停止端点并容忍随后所有请求以-ESHUTDOWN完成;拔线可在任意传输中途发生。
7. 锁与并发要点
- EP0 setup 由 UDC 中断上下文串行发起,function
setup回调不得睡眠(延迟状态机制用于需要等待的场景); cdev->lock(spinlock)保护配置切换与 EP0 请求状态;- disconnect 与数据面 completion 并发,function 私有状态需要自己的锁;
- bind/unbind 受 gadget driver 绑定流程串行化,但与用户态 ConfigFS 操作交互时要注意实例仍被引用的情况。
8. 与 ConfigFS 的关系
Legacy gadget 在内核里静态调用usb_composite_probe();ConfigFS 则动态构造等价物:configfs.c自己实现usb_gadget_driver(bind=configfs_composite_bind),把用户在 configfs 中创建的目录/符号链接翻译为usb_add_config()/usb_add_function()调用。两条路径最终在 composite 层汇合。
正在加载留言…