3. Gadget框架核心概念:UDC驱动、Gadget驱动、USB Function、USB Configuration、USB Interface
Linux USB Gadget 框架采用分层的软件架构,将复杂的 USB 设备角色实现抽象为五个核心概念。理解这些概念及其相互关系,是掌握 Gadget 驱动开发的基础。本章将从底层硬件抽象到上层功能描述,逐一剖析这五个核心要素。
3.1 核心概念全景图
下图展示了 Gadget 框架中五个核心概念之间的层次关系与数据流路径:
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 端点数
};
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 复合设备(串口 + 网卡)为例,展示五个核心概念在具体实现中的协作关系:
3.8 工程实践建议
- 优先使用现有 Function:Linux 内核已内置丰富的 Function 驱动(Serial、Ethernet、Mass Storage、HID、Audio、Video 等),通过 ConfigFS 即可组合使用,无需重复造轮子。
- UDC 驱动选择:根据硬件平台选择对应的 UDC 驱动(如 dwc2 用于 Raspberry Pi、chipidea 用于 i.MX 系列、musb 用于 TI 平台)。
- 调试手段:使用
lsusb -v查看设备描述符树,确认 Configuration、Interface、Endpoint 的层次关系是否正确。 - 性能考量:多 Configuration 会增加枚举时间,建议仅在需要切换工作模式时使用;Alternate Setting 切换比 Configuration 切换更快,优先使用。