4. Linux USB Gadget 框架核心数据结构详解

USB Gadget 框架的核心在于三个相互关联的数据结构:usb_gadget(控制器抽象)、usb_ep(端点抽象)和 usb_request(请求抽象)。它们是驱动开发者与硬件交互的基石,理解其内部字段与生命周期是进行批量传输性能优化的前提。

4.1 usb_gadget:控制器实例

usb_gadget 结构体代表一个 USB 设备控制器(UDC)实例。它封装了硬件能力、电源状态、连接状态以及指向端点列表的指针。每个 UDC 驱动在 probe 阶段都会分配并注册一个 usb_gadget 对象。

关键字段速览: 在批量传输优化中,max_speed 决定了是否启用 SuperSpeed(SS)或 SuperSpeedPlus(SSP)的批量端点;sg_supported 标志位直接关联到是否可以使用分散/聚集 I/O 来减少内存拷贝。
字段 类型 说明 优化关注点
ops struct usb_gadget_ops * 控制器操作函数表(如 pullup、vbus_session) 函数指针调用频率影响延迟
ep0 struct usb_ep * 端点 0(控制端点)的引用 控制传输与批量传输共享同一 UDC 总线
ep_list struct list_head 所有可用端点的双向链表头 遍历速度影响端点匹配效率
max_speed enum usb_device_speed 控制器支持的最高速度 决定批量端点最大包大小(HS: 512B, SS: 1024B)
sg_supported unsigned 是否支持 Scatter/Gather DMA 开启后可减少 usb_request 提交次数
quirk_ep_out_aligned_size unsigned OUT 端点是否需要对齐缓冲区 未对齐时需额外 memcpy,降低吞吐
优化提示: 在批量传输场景中,优先检查 gadget->sg_supported。若为真,则使用 usb_ep_queue 提交 sg_table 而非单缓冲区,可显著降低 CPU 占用。
usb_gadget 结构体核心布局 usb_gadget ops (函数表) ep0 (端点0) ep_list (链表头) max_speed (速度) sg_supported (标志) 批量传输优化关键 sg_supported → 启用 SG max_speed → 决定 wMaxPacketSize ep_list → 遍历匹配端点

4.2 usb_ep:端点抽象

usb_ep 是对硬件端点的软件抽象。每个端点都有方向(IN/OUT)、类型(批量/中断/等时)、最大包大小和当前状态。Gadget 函数驱动通过 usb_ep_autoconfig 从 ep_list 中匹配可用端点。

常见误区: 批量端点必须配置为 USB_EP_BULK 类型。若误配为中断类型,主机会以轮询方式处理,导致批量吞吐骤降。此外,maxpacket 必须与主机协商的 wMaxPacketSize 一致,否则传输会卡死在数据阶段。
字段 说明 批量传输影响
name 端点名称(如 "ep1in-bulk") 调试和匹配时使用
ops 端点操作函数表(queue、dequeue、enable 等) queue 函数是提交请求的唯一入口
maxpacket 端点支持的最大包大小(字节) HS: 512, SS: 1024;决定单次传输数据量
maxburst SuperSpeed 下的突发传输次数 SS 批量端点可设置为 1~16,提升吞吐
address 端点地址(方向 + 编号) 主机通过该地址寻址端点
caps 端点能力掩码(type_bulk、dir_in 等) 用于自动匹配,避免手动指定
usb_ep 端点匹配与配置流程 usb_ep_autoconfig 遍历 ep_list 匹配 caps 掩码 配置 maxpacket 配置 maxburst (SS) usb_ep_enable 批量端点必须设置 caps.type_bulk = 1,否则 autoconfig 会跳过该端点

4.3 usb_request:I/O 请求单元

usb_request 是数据传输的最小工作单元。函数驱动分配请求、填充缓冲区,然后通过 usb_ep_queue 提交给 UDC 硬件。完成时,complete 回调被触发。批量传输性能优化的核心就在于如何高效地管理这些请求的生命周期。

struct usb_request {
    void            *buf;           // 数据缓冲区指针
    unsigned        length;         // 缓冲区长度(字节)
    dma_addr_t      dma;            // DMA 地址(若使用 DMA)
    unsigned        sg_nents;       // 分散/聚集表项数
    struct scatterlist *sg;         // 分散/聚集表指针
    unsigned        num_sgs;        // SG 表项数量
    unsigned        stream_id;      // 批量流 ID(USB 3.0 批量流)
    void            (*complete)(struct usb_ep *ep,
                                struct usb_request *req); // 完成回调
    void            *context;       // 回调上下文
    int             status;         // 传输状态(0 成功,负值错误码)
    unsigned        actual;         // 实际传输字节数
    unsigned        no_interrupt;   // 是否禁止完成中断
    unsigned        zero;           // 是否发送 ZLP(零长度包)
    unsigned        short_not_ok;   // 是否不允许短包
    struct list_head list;          // 用于挂入请求队列
};
字段 批量优化作用 推荐设置
buf / dma 缓冲区管理方式(CPU 地址 vs DMA 地址) 优先使用 dma 字段,避免 bounce buffer
sg / num_sgs 分散/聚集 I/O,一次提交多个不连续缓冲区 设置 sg_nents 并确保 sg_supported 为真
stream_id 批量流协议,允许多个数据流共享同一端点 仅在 USB 3.0 且双方支持时使用
no_interrupt 控制是否在请求完成时触发中断 批量高吞吐场景设为 1,减少中断压力
zero 当数据长度为端点最大包整数倍时,是否追加 ZLP 批量 OUT 通常设为 1,防止主机挂起
short_not_ok 是否拒绝短包(接收时) 批量接收通常设为 0,允许短包
性能关键路径: 批量传输中,usb_ep_queue 调用会触发 UDC 驱动的 DMA 描述符编程。若每个请求只提交 512 字节,中断频率会极高。建议将请求缓冲区大小设为 maxpacket * maxburst * N(N 为 4~8),并配合 no_interrupt=1,可降低 60% 以上的中断开销。
usb_request 生命周期与批量传输队列 请求池 提交队列 UDC 硬件 complete 回调 请求回收至池中,准备下一次提交 批量传输优化策略 1. 预分配请求池,避免运行时 kmalloc 2. 使用 no_interrupt=1 批量提交,减少中断 3. 利用 SG 表一次提交多个缓冲区,提升 DMA 效率

4.4 三者协作关系

在 Gadget 函数驱动中,这三个结构体通过以下方式协作:

  1. 初始化阶段: 通过 gadget->ep_list 遍历,使用 usb_ep_autoconfig 匹配 usb_ep,并调用 usb_ep_enable 激活端点。
  2. 传输阶段: 分配 usb_request,填充 buf 和 length,调用 usb_ep_queue 提交到 UDC。
  3. 完成阶段: UDC 硬件完成传输后,调用 usb_request->complete 回调,驱动在回调中检查 status 和 actual,然后回收请求。
优化总结: 批量传输性能优化的本质是减少 usb_ep_queue 的调用次数和中断频率。通过增大单次请求的数据量(利用 maxburst 和 sg)、关闭不必要的中断(no_interrupt)、以及预分配请求池,可以在 Gadget 框架下实现接近硬件极限的批量吞吐。