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

在 Linux USB Gadget 子系统中,设备角色的切换依赖于一套层次清晰、职责分明的软件架构。这套架构将物理硬件、设备逻辑、功能实现与枚举描述层层解耦,使得开发者能够像搭积木一样组合出不同的 USB 设备形态。理解 UDC、Gadget Driver、USB Function、Configuration 和 Interface 这五个核心概念,是掌握 ACM 串口驱动开发的基础。

3.1 五层架构总览

Gadget 框架采用自底向上的分层设计,每一层都封装了特定的职责。下面的 SVG 图展示了这五层之间的依赖与组合关系:

Gadget 框架五层核心架构 UDC (USB Device Controller) 硬件抽象层:处理寄存器、中断、DMA Gadget Driver (UDC Driver) 绑定 UDC 硬件,管理枚举与事件分发 USB Function (功能驱动) 实现具体协议:ACM、Mass Storage、RNDIS Configuration (配置) 组合多个 Function,定义设备供电与属性 Interface (接口) 端点集合,主机可见的逻辑单元 组合关系 • 1个 UDC 绑定 1个 Gadget Driver • 1个 Gadget Driver 可包含多个 Function • 1个 Configuration 聚合多个 Function
架构要点: 数据流从底层的 UDC 硬件中断向上传递,经过 Gadget Driver 的事件分发,最终由 Function 驱动处理具体的 USB 协议逻辑。Configuration 和 Interface 则是在枚举阶段向主机描述设备能力的关键描述符。

3.2 核心概念详解

3.2.1 UDC (USB Device Controller)

UDC 是物理 USB 设备控制器的软件抽象。它直接操作硬件寄存器,负责处理 USB 总线上的复位、挂起、唤醒等事件,以及端点(Endpoint)上的数据传输。在 Linux 内核中,UDC 由 struct usb_gadget 结构体表示,并通过 struct usb_gadget_ops 提供操作接口。

UDC 关键职责 说明
端点管理 分配、释放、配置端点 0~15(IN/OUT)
中断处理 响应 USB 总线事件(复位、SOF、连接断开)
DMA 传输 管理硬件 DMA 引擎,实现零拷贝数据路径
电源管理 处理挂起/唤醒信号,控制设备功耗状态

3.2.2 Gadget Driver

Gadget Driver 是 UDC 与上层 Function 之间的桥梁。它通过 usb_gadget_probe_driver() 注册到 UDC 核心层,负责解析主机发来的标准设备请求(如 Get Descriptor、Set Configuration),并将这些请求分发给对应的 Function 处理。每个 UDC 在同一时刻只能绑定一个 Gadget Driver。

// Gadget Driver 注册示例(伪代码)
static struct usb_gadget_driver acm_gadget_driver = {
    .function  = LIST_HEAD_INIT(acm_gadget_driver.function),
    .speed     = USB_SPEED_HIGH,
    .bind      = acm_bind,
    .unbind    = acm_unbind,
    .setup     = acm_setup,   // 处理标准请求
    .disconnect = acm_disconnect,
    .suspend   = acm_suspend,
    .resume    = acm_resume,
};

int ret = usb_gadget_probe_driver(&acm_gadget_driver);
if (ret)
    pr_err("Failed to probe ACM gadget driver: %d\n", ret);

3.2.3 USB Function

USB Function 是具体设备功能的实现单元。对于 ACM 串口来说,Function 层实现了 CDC ACM 协议,包括控制端点(用于波特率设置、线路编码)和数据端点(用于串口数据收发)。Function 通过 usb_function_register() 注册到 Gadget Driver,并可以动态绑定到不同的 Configuration。

ACM Function 核心组件:
  • 控制端点(EP0): 处理类特定请求,如 SEND_ENCAPSULATED_COMMAND、SET_LINE_CODING
  • 中断端点(IN): 上报串口状态变化(如 DSR、RI 信号)
  • 批量端点(IN/OUT): 传输实际的串口数据流

3.2.4 Configuration

Configuration 是 USB 描述符体系中的一级容器,用于向主机声明设备当前的工作模式。一个 Gadget 设备可以定义多个 Configuration(例如:一个用于高速模式,一个用于全速模式),但同一时刻只能激活一个。Configuration 决定了设备的供电方式(自供电/总线供电)和最大电流消耗。

// Configuration 描述符定义示例
static struct usb_config_descriptor acm_config = {
    .bLength             = USB_DT_CONFIG_SIZE,
    .bDescriptorType     = USB_DT_CONFIG,
    .wTotalLength        = 0, // 由框架自动计算
    .bNumInterfaces      = 2, // ACM 控制接口 + 数据接口
    .bConfigurationValue = 1,
    .iConfiguration      = 0,
    .bmAttributes        = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
    .bMaxPower           = CONFIG_USB_GADGET_VBUS_DRAW / 2,
};

3.2.5 Interface

Interface 是主机侧可见的最小逻辑单元。一个 Configuration 可以包含多个 Interface,每个 Interface 对应一组端点。在 ACM 设备中,通常包含两个 Interface:控制接口(Interface 0) 和 数据接口(Interface 1)。控制接口使用中断端点传输状态信息,数据接口使用批量端点传输串口数据。

ACM Interface 布局 端点类型 传输方向 用途
Interface 0 (控制) 中断 (IN) 设备 → 主机 串口状态通知
Interface 1 (数据) 批量 (IN) 设备 → 主机 串口数据发送
Interface 1 (数据) 批量 (OUT) 主机 → 设备 串口数据接收

3.3 层次协作流程

当主机枚举 ACM Gadget 设备时,五层架构按照以下顺序协同工作:

  1. UDC 检测到 USB 连接,触发中断,通知 Gadget Driver 进入连接状态。
  2. Gadget Driver 调用 bind(),分配端点资源,注册 Function 实例。
  3. 主机发送 Get Descriptor 请求,Gadget Driver 逐级查询 Configuration → Interface → Endpoint 描述符。
  4. 主机发送 Set Configuration,激活指定的 Configuration,对应的 Function 开始准备数据收发。
  5. Function 通过端点与主机通信,处理 ACM 协议的控制命令和数据传输。
常见陷阱: 在编写 ACM Gadget 驱动时,务必确保 Interface 的 bInterfaceClass、bInterfaceSubClass 和 bInterfaceProtocol 字段严格遵循 CDC ACM 规范(0x02、0x02、0x01)。任何字段错误都会导致主机无法正确加载 usbserial 驱动。

3.4 概念对比表

概念 内核数据结构 生命周期 与主机关联
UDC struct usb_gadget 与硬件共存亡 物理连接
Gadget Driver struct usb_gadget_driver 模块加载/卸载 枚举入口
USB Function struct usb_function 绑定/解绑 协议实现
Configuration struct usb_config_descriptor Set Configuration 模式选择
Interface struct usb_interface_descriptor 枚举时确定 功能单元