3. Gadget框架核心概念:UDC驱动、Gadget驱动、USB Function、USB Configuration、USB Interface

Linux USB Gadget 框架采用分层的软件架构,将复杂的 USB 设备角色实现抽象为五个核心概念。理解这些概念及其相互关系,是掌握 Gadget 驱动开发的基础。本章将从底层硬件抽象到上层功能描述,逐一剖析这五个核心要素。

3.1 核心概念全景图

下图展示了 Gadget 框架中五个核心概念之间的层次关系与数据流路径:

Gadget框架核心概念层次结构 Gadget 框架核心概念层次结构 UDC 驱动 (USB Device Controller Driver) 硬件抽象层:直接操作 USB 控制器寄存器,处理中断与 DMA Gadget 驱动 (Gadget Driver) 中间层:绑定 UDC 与 Function,管理枚举与配置切换 USB Configuration (配置) 描述设备的一种工作模式,包含一个或多个 Interface USB Interface (接口) 按功能划分的逻辑单元,每个 Interface 包含一个或多个 Endpoint USB Function (功能) 层次关系说明 1个UDC绑定1个Gadget 1个Gadget含N个Config 1个Config含M个Interface
关键理解:这五个概念从下到上构成了一个"硬件→抽象→功能描述"的完整链路。UDC 驱动是唯一与硬件相关的部分,而 USB Function 则是最终呈现给主机侧的功能实体。

3.2 UDC 驱动 (USB Device Controller Driver)

UDC 驱动是 Gadget 框架中最接近硬件的层,直接与 SoC 或外挂 USB 控制器硬件交互。它负责处理底层寄存器操作、中断服务、DMA 传输以及端点(Endpoint)管理。

3.2.1 UDC 驱动的职责

  • 硬件初始化:上电复位、时钟使能、中断配置、端点 FIFO 分配。
  • 端点管理:提供端点注册、使能/禁用、传输请求提交(usb_request)接口。
  • 中断处理:处理 SETUP 包、传输完成、总线复位、挂起/唤醒等中断事件。
  • DMA 传输:如果硬件支持,实现 DMA 通道管理与描述符链。
  • VBUS 检测:监测 USB 总线连接/断开状态。

3.2.2 核心数据结构

// include/linux/usb/gadget.h
struct usb_gadget_ops {
    int     (*get_frame)(struct usb_gadget *);
    int     (*wakeup)(struct usb_gadget *);
    int     (*set_selfpowered)(struct usb_gadget *, int);
    int     (*vbus_session)(struct usb_gadget *, int);
    int     (*vbus_draw)(struct usb_gadget *, unsigned mA);
    int     (*pullup)(struct usb_gadget *, int);
    int     (*ioctl)(struct usb_gadget *, unsigned, unsigned long);
};

struct usb_gadget {
    struct device              dev;
    const struct usb_gadget_ops *ops;
    struct usb_ep              *ep0;       // 控制端点 0
    struct list_head           ep_list;    // 可用端点列表
    enum usb_speed             speed;      // 当前连接速度
    unsigned                   is_otg:1;
    unsigned                   is_a_peripheral:1;
    unsigned                   out_epnum;  // 已分配的 OUT 端点数
    unsigned                   in_epnum;   // 已分配的 IN 端点数
};
工程要点:编写 UDC 驱动时,必须实现 usb_gadget_ops 中的所有回调函数。其中 pullup 回调控制 D+ 线上的上拉电阻,是主机识别设备的关键操作。

3.3 Gadget 驱动 (Gadget Driver)

Gadget 驱动是框架的"胶水层",它不直接操作硬件,而是通过 UDC 驱动提供的 API 来管理 USB 枚举过程和配置切换。一个 Gadget 驱动对应一个 UDC 实例。

3.3.1 Gadget 驱动的核心作用

功能 说明
绑定 UDC 通过 usb_gadget_probe_driver() 将 Gadget 驱动注册到 UDC 上
处理 SETUP 包 解析标准请求(Get Descriptor、Set Configuration 等)并响应
配置管理 维护 Configuration 列表,根据主机选择的配置激活对应的 Function
事件回调 将 UDC 上报的断开、挂起、复位等事件传递给上层 Function

3.3.2 注册与绑定流程

// 典型的 Gadget 驱动注册流程
static struct usb_gadget_driver my_gadget_driver = {
    .function   = "My USB Device",
    .speed      = USB_SPEED_HIGH,
    .bind       = my_gadget_bind,
    .unbind     = my_gadget_unbind,
    .setup      = my_gadget_setup,
    .disconnect = my_gadget_disconnect,
    .suspend    = my_gadget_suspend,
    .resume     = my_gadget_resume,
};

int __init my_init(void) {
    return usb_gadget_probe_driver(&my_gadget_driver);
}

3.4 USB Configuration (配置)

USB Configuration 描述设备的一种工作模式。一个物理设备可以支持多个 Configuration,但同一时刻只能有一个 Configuration 处于激活状态。主机通过 Set Configuration 请求选择配置。

3.4.1 Configuration 的属性

  • bConfigurationValue:配置编号(1~255),主机用此值选择配置。
  • bmAttributes:配置特性,如自供电、远程唤醒等。
  • bMaxPower:该配置下设备从总线获取的最大电流(单位 2mA)。
  • 接口集合:每个 Configuration 包含一个或多个 Interface。

3.4.2 多配置应用场景

场景 Configuration 1 Configuration 2
USB 音频设备 高带宽模式(96kHz/24bit) 低功耗模式(44.1kHz/16bit)
复合设备 仅串口功能 串口 + 网卡 + 大容量存储
电池敏感设备 全功能(500mA) 受限功能(100mA)

3.5 USB Interface (接口)

USB Interface 是 USB 规范中按功能划分的逻辑单元。每个 Interface 代表一个独立的功能入口,拥有自己的端点集合和类特定描述符。主机通过 Set Interface 请求可以在同一个 Configuration 下切换 Interface 的备用设置(Alternate Setting)。

3.5.1 Interface 的组成

// 一个典型的 Interface 描述符结构
struct usb_interface_descriptor {
    __u8  bLength;            // 描述符长度,固定为 9
    __u8  bDescriptorType;    // 描述符类型,USB_DT_INTERFACE = 4
    __u8  bInterfaceNumber;   // 接口编号(从 0 开始)
    __u8  bAlternateSetting;  // 备用设置编号
    __u8  bNumEndpoints;      // 端点数量(不包括端点 0)
    __u8  bInterfaceClass;    // 类代码
    __u8  bInterfaceSubClass; // 子类代码
    __u8  bInterfaceProtocol; // 协议代码
    __u8  iInterface;         // 字符串描述符索引
} __attribute__ ((packed));

3.5.2 Alternate Setting 的作用

Alternate Setting 允许同一个 Interface 在不同时刻使用不同的端点配置。典型应用场景:

  • 音频设备:Alternate Setting 0 不占用带宽,Alternate Setting 1 激活等时端点。
  • 视频设备:不同备用设置对应不同的帧率或分辨率。
  • HID 设备:切换报告描述符的格式。

3.6 USB Function (功能)

USB Function 是 Gadget 框架中最高层的抽象,它封装了一个完整的 USB 功能实现。在 Linux 内核中,Function 通常由 usb_function 结构体表示,并包含一个或多个 Interface。

3.6.1 常见的内置 Function

Function 名称 内核模块 模拟的设备类型
Serial (ACM) u_serial.ko / g_serial.ko USB 虚拟串口
Ethernet (RNDIS/ECM) u_ether.ko / g_ether.ko USB 虚拟网卡
Mass Storage u_ms.ko / g_mass_storage.ko U 盘 / 光盘
HID u_hid.ko / g_hid.ko 键盘 / 鼠标 / 游戏手柄
Audio (UAC1/UAC2) u_audio.ko / g_audio.ko USB 麦克风 / 扬声器
Video (UVC) uvc.ko / g_webcam.ko USB 摄像头

3.6.2 Function 与 Interface 的映射关系

一个 Function 可能包含多个 Interface。例如 USB 音频设备(UAC2)需要三个 Interface:

// UAC2 Function 的 Interface 布局
Interface 0: 音频控制 (AudioControl)
  - 端点: 无(使用默认端点 0)
Interface 1: 音频数据输出 (AudioStreaming OUT)
  - 端点: EP1 OUT (等时)
Interface 2: 音频数据输入 (AudioStreaming IN)
  - 端点: EP2 IN (等时)

3.7 五者关系总结

下图以 USB 复合设备(串口 + 网卡)为例,展示五个核心概念在具体实现中的协作关系:

复合设备实例:五层协作关系 复合设备实例:串口 + 网卡的五层协作 UDC 驱动 (dwc2 / chipidea / musb ...) Gadget 驱动 (g_serial + g_ether 复合) Configuration (bConfigurationValue = 1, bMaxPower = 250mA) Interface 0: 串口 (ACM) EP1 IN (中断) + EP2 OUT (批量) Interface 1: 网卡 (ECM) EP3 IN (批量) + EP4 OUT (批量) Function: Serial (ACM) Function: Ethernet (ECM)
常见误区:初学者容易混淆 USB Interface 和 USB Function。Interface 是 USB 规范中的描述符概念,而 Function 是 Linux 内核中的软件抽象。一个 Function 内部可以包含多个 Interface,但一个 Interface 不能跨多个 Function。

3.8 工程实践建议

  1. 优先使用现有 Function:Linux 内核已内置丰富的 Function 驱动(Serial、Ethernet、Mass Storage、HID、Audio、Video 等),通过 ConfigFS 即可组合使用,无需重复造轮子。
  2. UDC 驱动选择:根据硬件平台选择对应的 UDC 驱动(如 dwc2 用于 Raspberry Pi、chipidea 用于 i.MX 系列、musb 用于 TI 平台)。
  3. 调试手段:使用 lsusb -v 查看设备描述符树,确认 Configuration、Interface、Endpoint 的层次关系是否正确。
  4. 性能考量:多 Configuration 会增加枚举时间,建议仅在需要切换工作模式时使用;Alternate Setting 切换比 Configuration 切换更快,优先使用。