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 占用。
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 等) |
用于自动匹配,避免手动指定 |
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% 以上的中断开销。
4.4 三者协作关系
在 Gadget 函数驱动中,这三个结构体通过以下方式协作:
- 初始化阶段: 通过
gadget->ep_list遍历,使用usb_ep_autoconfig匹配usb_ep,并调用usb_ep_enable激活端点。 - 传输阶段: 分配
usb_request,填充buf和length,调用usb_ep_queue提交到 UDC。 - 完成阶段: UDC 硬件完成传输后,调用
usb_request->complete回调,驱动在回调中检查status和actual,然后回收请求。
优化总结: 批量传输性能优化的本质是减少
usb_ep_queue 的调用次数和中断频率。通过增大单次请求的数据量(利用 maxburst 和 sg)、关闭不必要的中断(no_interrupt)、以及预分配请求池,可以在 Gadget 框架下实现接近硬件极限的批量吞吐。