Composite 框架、EP0 与描述符管理

Composite 框架、EP0 与描述符管理

1. 对象模型

libcomposite 把一个 USB 设备组织为三级:

1
2
3
usb_composite_dev (cdev)        整个设备:设备描述符、strings、EP0
-> usb_configuration 一个配置:bConfigurationValue、MaxPower
-> usb_function 一个功能:接口/端点描述符、数据面
  • 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
2
3
4
5
6
7
8
9
10
11
12
13
usb_composite_probe()                     composite.c:2568
-> composite_driver_template
-> usb_gadget_register_driver_owner()
-> gadget_bind_driver()
-> composite_bind() composite.c:2425
-> composite_dev_prepare() composite.c:2308
-> 分配 EP0 req (cdev->req)
-> usb_ep_autoconfig_reset()
-> composite->bind(cdev)
-> usb_add_config() composite.c:1072
-> config->bind
-> usb_add_function() composite.c:314
-> function->bind (分配接口号/端点/描述符)

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
2
3
4
5
6
7
8
9
10
composite_setup()                         composite.c:1745
标准请求:
GET_DESCRIPTOR -> 组装 device/config/string/BOS 描述符
config 走 config_buf() composite.c:567
SET_CONFIGURATION -> set_config() composite.c:915
GET_CONFIGURATION / SET_INTERFACE / GET_INTERFACE / GET_STATUS
类/厂商请求:
按 wIndex 接口号或端点找到 usb_function
-> f->setup() (如 UVC/UAC2/HID 的 class request)
无人处理 -> EP0 stall

响应数据经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 行):

  1. wValue找到usb_configuration
  2. 对每个 function 调f->set_alt(f, intf, 0)
  3. function 在set_altusb_ep_enable()并 queue 初始请求;
  4. usb_gadget_vbus_draw()按 MaxPower 上报取电;
  5. 设备进入 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 层汇合。

文章互动

阅读 --

留言

0 条留言

正在加载留言…