2. Linux USB Gadget框架:软件架构与核心数据结构

Linux USB Gadget 框架是内核中实现设备端(Device Side)USB 功能的核心软件层。它向上为各类 Gadget 功能驱动(如 ECM、UVC、Mass Storage)提供统一的编程接口,向下通过 UDC(USB Device Controller)驱动直接操作硬件寄存器。理解其软件架构与核心数据结构,是进行硬件适配与移植的基础。

2.1 软件架构分层

整个框架采用分层设计,从底至上依次为:UDC 驱动层、Gadget 核心层、功能驱动层。各层职责清晰,通过标准 API 交互。

架构要点: UDC 驱动直接与硬件寄存器打交道,Gadget 核心层提供通用抽象,功能驱动实现具体的 USB 逻辑(如枚举、数据传输)。硬件适配主要工作在 UDC 驱动层。
Linux USB Gadget 软件架构分层图 Linux USB Gadget 软件架构分层 功能驱动层 (Function Drivers) ECM / UVC / Mass Storage / HID / ACM / RNDIS ... Gadget 核心层 (Gadget Core) usb_gadget_probe_driver / usb_ep_enable / usb_ep_queue UDC 驱动层 (UDC Driver) dwc3 / mv_udc / chipidea / atmel_usba / renesas_usbhs USB 硬件控制器 (USB Device Controller) 数据流向:Host → UDC → Core → Function

2.2 核心数据结构

Gadget 框架围绕三个核心数据结构构建:usb_gadget、usb_ep、usb_request。它们分别代表 USB 设备整体、端点(Endpoint)和传输请求(Request)。

2.2.1 usb_gadget:设备抽象

struct usb_gadget 是 USB 设备控制器的软件抽象,代表一个完整的 USB 设备实例。它包含设备状态、速度、电源管理、UDC 操作函数集等信息。

// include/linux/usb/gadget.h
struct usb_gadget {
    struct device          dev;           // 内核设备模型
    const struct usb_gadget_ops *ops;     // UDC 操作函数集
    struct usb_ep         *ep0;           // 控制端点 ep0
    enum usb_device_state  state;         // 设备状态 (USB_STATE_*)
    enum usb_device_speed  speed;         // 当前连接速度
    unsigned               is_otg:1;      // 是否支持 OTG
    unsigned               is_a_peripheral:1; // 是否作为 A 设备
    unsigned               b_hnp_enable:1; // HNP 使能
    unsigned               a_hnp_support:1;
    unsigned               a_alt_hnp_support:1;
    unsigned               quirk_ep_out_aligned_size:1; // 硬件 quirks
    // ... 其他字段
};
移植关注点: 在硬件适配时,需要实现 struct usb_gadget_ops 中的回调函数,如 udc_start、udc_stop、pullup、get_frame 等。这些回调直接操作 UDC 寄存器。

2.2.2 usb_ep:端点抽象

struct usb_ep 代表一个 USB 端点(Endpoint),包括端点号、方向、类型、最大包大小等属性。每个 UDC 驱动需要为所有可用端点创建对应的 usb_ep 实例。

// include/linux/usb/gadget.h
struct usb_ep {
    void                    *driver_data;  // 驱动私有数据
    const char              *name;         // 端点名称 (如 "ep1in")
    const struct usb_ep_ops *ops;          // 端点操作函数集
    struct list_head         ep_list;      // 链表节点
    unsigned                 maxpacket:16; // 最大包大小
    unsigned                 max_streams:16; // 批量流数量
    unsigned                 mult:2;       // 高带宽模式倍数
    unsigned                 maxburst:5;   // 突发传输长度
    unsigned                 address:8;    // 端点地址 (含方向位)
    const struct usb_endpoint_descriptor *desc; // 描述符指针
};
usb_ep_ops 关键回调函数
回调函数 功能描述 硬件适配要点
enable 使能端点,配置硬件寄存器 设置端点类型、最大包大小、FIFO 地址
disable 禁用端点,释放硬件资源 清空 FIFO,关闭中断
queue 提交传输请求到硬件 将 request 写入 DMA 或 FIFO,触发传输
dequeue 取消未完成的传输请求 从硬件队列中移除,处理竞争条件
set_halt 设置端点 STALL 条件 写端点控制寄存器的 STALL 位

2.2.3 usb_request:传输请求抽象

struct usb_request 描述一次 USB 数据传输请求,包含数据缓冲区、长度、完成回调等。它是 Gadget 框架中数据流动的基本单元。

// include/linux/usb/gadget.h
struct usb_request {
    void          *buf;           // 数据缓冲区
    unsigned       length;        // 缓冲区长度
    dma_addr_t     dma;           // DMA 地址 (若使用 DMA)
    unsigned       no_interrupt:1; // 是否不产生中断
    unsigned       zero:1;        // 是否发送零长度包
    unsigned       short_not_ok:1; // 是否不允许短包
    unsigned       stream_id:16;  // 批量流 ID
    void          *context;       // 回调上下文
    void (*complete)(struct usb_ep *ep, struct usb_request *req); // 完成回调
    struct list_head list;        // 链表节点
};
常见错误: 在 UDC 驱动中,usb_request 的 complete 回调必须在硬件传输真正完成后(中断上下文中)调用,且不能重复调用。错误的回调时机会导致数据丢失或内核崩溃。

2.3 数据结构关系图

以下 SVG 图展示了三个核心数据结构之间的关联关系,以及它们如何与 UDC 硬件交互。

USB Gadget 核心数据结构关系图 核心数据结构关系图 struct usb_gadget 设备抽象 / ops / state / speed struct usb_ep 端点抽象 / ops / maxpacket struct usb_request 传输请求 / buf / complete ep0 指针 ep_list 链表 queue / dequeue UDC 硬件寄存器 / FIFO / DMA 一个 gadget 包含多个 ep 每个 ep 管理多个 request

2.4 数据流与回调链

一次典型的 USB 数据传输流程如下:

  1. 功能驱动调用 usb_ep_queue() 提交 usb_request 到某个端点。
  2. Gadget 核心层将请求传递给 UDC 驱动的 ep->ops->queue() 回调。
  3. UDC 驱动将请求写入硬件(DMA 或 FIFO),启动传输。
  4. 硬件传输完成后触发中断,UDC 驱动在中断处理中调用 req->complete() 回调。
  5. 功能驱动在回调中处理数据,可能再次提交新请求。
性能关键路径: queue() 和 complete() 是数据路径上的热点函数。硬件适配时,应尽量减少这两个函数中的锁竞争和内存拷贝,优先使用 DMA 传输。

2.5 硬件适配接口清单

在移植 UDC 驱动时,必须实现以下核心接口:

UDC 驱动必须实现的接口清单
接口 所属结构 必须实现 说明
udc_start usb_gadget_ops 是 启动 UDC,注册中断,使能控制器
udc_stop usb_gadget_ops 是 停止 UDC,释放资源,注销中断
pullup usb_gadget_ops 是 控制 D+ 上拉电阻,实现软连接/断开
enable usb_ep_ops 是 配置端点寄存器,分配 FIFO
disable usb_ep_ops 是 禁用端点,释放 FIFO
queue usb_ep_ops 是 提交传输请求到硬件队列
dequeue usb_ep_ops 是 取消未完成的请求
set_halt usb_ep_ops 是 设置/清除端点 STALL
get_frame usb_gadget_ops 推荐 读取当前帧号,用于 ISO 传输
移植建议: 在开始编写 UDC 驱动前,先阅读内核中已有的类似控制器驱动(如 dwc3、chipidea、mv_udc),参考其 usb_gadget_ops 和 usb_ep_ops 的实现模式。大多数 UDC 硬件差异集中在端点配置和 DMA 管理上。