1. USB Gadget子系统概述

USB Gadget 子系统是 Linux 内核中用于让嵌入式设备(如开发板、手机、IoT 网关)模拟成 USB 外设(如 U 盘、串口、网卡、音频设备)的核心框架。它位于内核的 drivers/usb/gadget/ 目录下,与主机侧的 USB 驱动栈(Host Stack)对称存在,但设计目标完全不同:主机栈负责枚举和管理外设,而 Gadget 栈负责被枚举并提供功能。

核心定位:Gadget 子系统是嵌入式 Linux 设备“变身”为 USB 外设的软件基础设施,它把硬件无关的功能逻辑与硬件相关的 UDC 驱动解耦,使得同一套功能代码可以在不同 SoC 上复用。

1.1 在 Linux 内核中的位置

USB Gadget 子系统处于内核 USB 子系统的“设备端”分支,与主机端(Host)并列。其代码层次关系如下表所示:

层级 目录/文件 职责
用户空间接口 configfs/、functionfs/ 通过 ConfigFS 或 FunctionFS 动态配置 Gadget 功能
Gadget Function 层 functions/ 实现具体 USB 功能(Mass Storage、Serial、ECM、RNDIS 等)
Gadget API 层 udc-core.c、composite.c 提供统一的 UDC 操作接口和复合设备管理
UDC 驱动层 udc/ 直接操作 USB 设备控制器硬件(DWC2、DWC3、Chipidea 等)

从内核源码树视角看,Gadget 子系统与主机栈共享 drivers/usb/ 根目录,但拥有独立的 Kconfig 和 Makefile 体系:

drivers/usb/
├── host/          # 主机侧驱动(EHCI、OHCI、xHCI)
├── gadget/        # 设备侧驱动(Gadget 子系统)
│   ├── udc/       # UDC 硬件驱动
│   ├── function/  # Gadget Function 实现
│   ├── configfs.c # ConfigFS 接口
│   ├── composite.c# 复合设备框架
│   └── u_fs.h     # FunctionFS 接口
├── core/          # USB 核心(urb、hub、端点分配等)
└── common/        # 通用工具函数

1.2 核心组件详解

Gadget 子系统由三大核心组件构成:UDC(USB Device Controller)驱动、Gadget Function 和 ConfigFS。三者之间的关系可以用下面的 SVG 架构图清晰展示:

USB Gadget 子系统核心组件架构 用户空间 应用程序 / libusb / 脚本 ConfigFS 配置接口 /sys/kernel/config/usb_gadget/ Gadget Function 层 Mass Storage | Serial | ECM/RNDIS | Audio | HID FunctionFS 用户态功能 Composite 复合设备框架 绑定 Function → 配置 → 字符串描述符 UDC 驱动层 DWC2 | DWC3 | Chipidea | MUSB | 自定义 SoC UDC 数据流方向:用户空间 → ConfigFS → Function → Composite → UDC → USB 线缆 → 主机

1.2.1 UDC(USB Device Controller)驱动

UDC 驱动是 Gadget 子系统的硬件抽象层,直接与 SoC 内部的 USB 设备控制器寄存器交互。它负责:

  • 端点管理:分配、配置和释放 USB 端点(Endpoint 0 控制端点 + 若干数据端点)。
  • DMA 传输:发起和完成 USB 数据包的 DMA 传输。
  • 中断处理:处理 USB 总线事件(复位、挂起、恢复、端点中断)。
  • 连接状态:通过 VBUS 检测或软件控制,管理 D+ / D- 上拉电阻的使能。
移植要点:UDC 驱动是移植工作的核心。不同 SoC 的 UDC 寄存器布局、DMA 引擎、中断机制差异巨大。常见的 UDC 驱动包括 dwc2(Synopsys)、dwc3(Synopsys)、chipidea(NXP)、musb(TI)等。移植时通常需要修改设备树(Device Tree)中的 UDC 节点,并确保时钟、电源、复位信号正确配置。

1.2.2 Gadget Function

Gadget Function 是功能逻辑的实现单元,每个 Function 对应一种 USB 设备类。内核提供了丰富的内置 Function:

Function 名称 内核模块 模拟的设备类型 典型应用
Mass Storage usb_f_mass_storage.ko U 盘 / 读卡器 文件传输、系统安装盘
Serial / ACM usb_f_acm.ko USB 虚拟串口 调试终端、AT 指令
ECM / RNDIS usb_f_ecm.ko / usb_f_rndis.ko USB 以太网适配器 网络共享、ADB
Audio usb_f_uac1.ko / usb_f_uac2.ko USB 声卡 音频播放/录制
HID usb_f_hid.ko 键盘 / 鼠标 / 游戏手柄 人机交互设备
FunctionFS usb_f_fs.ko 用户自定义功能 私有协议、高速数据采集

每个 Function 都实现了 struct usb_function 接口,包含 bind()、unbind()、set_alt()、disable() 等回调。多个 Function 可以组合成一个复合设备(Composite Device),例如同时提供 Mass Storage + Serial + ECM 三个功能。

1.2.3 ConfigFS

ConfigFS(Configuration Filesystem)是 Gadget 子系统的用户空间配置接口,挂载在 /sys/kernel/config/usb_gadget/ 下。它允许用户在运行时动态创建、配置和启动 Gadget 设备,无需重新编译内核或编写内核模块。

ConfigFS 的典型配置流程如下:

  1. 创建 Gadget 目录:mkdir /sys/kernel/config/usb_gadget/g1
  2. 设置 VID/PID:写入 idVendor 和 idProduct 文件
  3. 创建配置(Configuration):mkdir configs/c.1
  4. 创建功能(Function):mkdir functions/mass_storage.usb0
  5. 绑定功能到配置:ln -s functions/mass_storage.usb0 configs/c.1
  6. 绑定 UDC:将 UDC 名称写入 UDC 文件,启动枚举
注意事项:ConfigFS 要求内核开启 CONFIG_USB_CONFIGFS 和对应的 Function 模块。在嵌入式系统中,如果使用 Buildroot 或 Yocto,需要确保内核配置中包含 CONFIGFS_FS=y 和 CONFIG_USB_GADGET=y。另外,ConfigFS 的路径和文件权限需要正确设置,否则用户空间脚本无法正常操作。

1.3 三组件协作流程

当用户通过 ConfigFS 配置好 Gadget 并绑定 UDC 后,三个组件的协作流程如下面的 SVG 时序图所示:

Gadget 三组件协作流程(从配置到枚举) ConfigFS Gadget Function UDC 驱动 ① 用户创建目录、写入 VID/PID ② 创建 Function 并链接到配置 ③ 写入 UDC 名称,触发枚举 ④ UDC 驱动初始化端点、上拉 D+ ⑤ 主机发送 SETUP 请求,UDC 中断上报 ⑥ Composite 回调 Function 获取描述符 枚举完成后,主机识别到复合设备,加载对应类驱动,开始数据传输

1.4 小结

USB Gadget 子系统通过UDC 驱动屏蔽硬件差异,通过Gadget Function 提供标准化的 USB 功能实现,通过 ConfigFS 提供灵活的用户空间配置能力。三者的分层设计使得嵌入式 Linux 设备可以轻松模拟成多种 USB 外设,且功能组合和切换完全在运行时完成,无需重新烧录固件。