1. USB Gadget 基础概念

USB Gadget 是嵌入式 Linux 系统中一个极为重要的概念。简单来说,USB Gadget 允许一台嵌入式设备(如开发板、路由器、手机)通过 USB 接口模拟成各种常见的 USB 外设,例如 U 盘、网卡、串口或键盘鼠标。这使得设备在物理上作为 Host 连接 USB 外设的同时,也能在另一条 USB 线上扮演 Device 角色。

1.1 什么是 USB Gadget

在 USB 协议体系中,任何 USB 系统都包含一个 Host(主机) 和至少一个 Device(设备)。传统 PC 作为 Host,U 盘作为 Device。而 USB Gadget 技术则让嵌入式设备能够运行 Gadget 驱动程序,利用硬件中的 UDC(USB Device Controller) 模块,将自己伪装成一个标准的 USB 设备。

核心要点: USB Gadget 是运行在 Device 端的软件栈,它利用硬件 UDC 实现与 Host 的通信,并向上层应用提供标准化的设备功能接口。
常见误区: 很多人认为 Gadget 就是“把设备变成主机”,实际上 Gadget 是让设备变成“从机”(外设)。例如,手机通过 USB 线连接电脑,手机就是 Gadget,电脑是 Host。
USB Gadget 系统架构位置图 USB Gadget 在嵌入式系统中的位置 USB Host PC / 笔记本电脑 USB 主机控制器 (HC) USB 驱动程序栈 应用层 (文件管理器等) USB 总线 USB Device (Gadget) 嵌入式设备 / 开发板 UDC (USB Device Controller) Gadget 驱动框架 (Linux Kernel) Function 驱动 (Mass Storage / ECM / ACM) 用户态配置工具 (ConfigFS / GadgetFS) Gadget 角色 模拟 U 盘、网卡、 串口、HID 等外设 对 Host 透明

1.2 Gadget 与 Host 的区别

理解 Gadget 与 Host 的本质区别是排查故障的基础。两者在硬件角色、软件栈、电气特性以及通信发起方式上存在根本不同。

对比维度 USB Host USB Gadget (Device)
硬件控制器 EHCI / XHCI / OHCI / UHCI UDC (USB Device Controller)
电气角色 提供 VBUS 电源 (5V) 消耗 VBUS 电源 (或自供电)
通信发起 主动发起所有事务 (Token) 被动响应 Host 请求
软件栈 USB Core → HCD → 设备驱动 Gadget Core → UDC 驱动 → Function 驱动
枚举过程 检测设备插入 → 复位 → 分配地址 → 读取描述符 响应复位 → 接收地址 → 返回描述符
典型设备 PC、笔记本、OTG 主设备 U 盘、鼠标、键盘、手机
排查提示: 在调试 Gadget 时,如果 Host 侧无法识别设备,首先要确认硬件连接是否正确(D+/D- 是否交叉)、VBUS 是否正常供电。Gadget 侧的错误通常表现为 UDC 驱动未加载或描述符配置错误。
Host 与 Gadget 通信流程对比 Host 与 Gadget 通信流程对比 USB Host 流程 ① 检测 VBUS 上升沿 → 设备插入 ② 发送复位信号 (SE0) ③ 分配地址 → 读取设备描述符 ④ 配置设备 → 选择配置 USB Gadget 流程 ① 等待 Host 检测 (VBUS 供电) ② 检测复位 → 初始化端点 0 ③ 接收地址 → 响应描述符请求 ④ 接收配置 → 进入配置状态

1.3 常见 Gadget 类型

Linux Gadget 框架支持多种功能类型,每种类型对应不同的 USB 类规范和实际应用场景。以下是四种最常用的 Gadget 类型。

1.3.1 大容量存储 Gadget (Mass Storage Gadget)

模拟 U 盘或移动硬盘。Host 将其识别为 SCSI 磁盘设备,可以直接进行文件读写。常用于嵌入式设备的固件升级、数据导出或作为虚拟光驱。

  • 内核模块: g_mass_storage.ko 或通过 ConfigFS 配置 mass_storage.usb
  • 后端存储: 可以是物理分区 (/dev/sda1)、文件镜像 (file.bin) 或 RAM 盘
  • 典型应用: 开发板模拟 U 盘、路由器共享存储

1.3.2 以太网 Gadget (Ethernet Gadget)

模拟 USB 网卡,通常使用 CDC ECM (Ethernet Control Model) 或 RNDIS (Microsoft 私有协议) 协议。Host 侧会枚举出一个虚拟网口,实现设备与 Host 之间的网络通信。

  • 内核模块: g_ether.ko (ECM) 或 g_cdc.ko
  • IP 分配: 通常通过 DHCP 或静态 IP 配置,Host 端自动获取
  • 典型应用: 开发板共享网络、ADB 调试、IoT 设备配置

1.3.3 串口 Gadget (Serial Gadget)

模拟 USB 转串口适配器,使用 CDC ACM (Abstract Control Model) 协议。Host 侧会创建一个虚拟串口 (如 /dev/ttyACM0),用于双向数据传输。

  • 内核模块: g_serial.ko 或 g_acm_ms.ko
  • 波特率: 虚拟串口通常忽略波特率设置,仅传输数据流
  • 典型应用: 嵌入式控制台、Modem 通信、传感器数据采集

1.3.4 HID Gadget (Human Interface Device)

模拟键盘、鼠标、游戏手柄等输入设备。HID Gadget 可以发送按键事件、鼠标移动或自定义 HID 报告,用于自动化测试、远程控制或特殊输入场景。

  • 内核模块: g_hid.ko 或通过 ConfigFS 配置 hid.usb
  • 报告描述符: 需要自定义 HID Report Descriptor 定义数据格式
  • 典型应用: 自动化按键注入、KVM 切换器、特殊工业控制器
四种常见 USB Gadget 类型 常见 USB Gadget 类型与协议栈 Linux Gadget 核心框架 (UDC Core + ConfigFS) 大容量存储 Mass Storage SCSI 命令集 Bulk-Only Transport 文件镜像 / 分区 g_mass_storage.ko 以太网 Ethernet CDC ECM / RNDIS 虚拟网口 (usb0) TCP/IP 协议栈 g_ether.ko 串口 Serial CDC ACM 虚拟串口 (ttyGS0) 双向数据流 g_serial.ko HID Human Interface HID Report 协议 键盘 / 鼠标 / 手柄 自定义报告描述符 g_hid.ko 每种 Gadget 类型对应不同的 USB 类规范,Host 侧需要安装相应的类驱动程序

1.4 Gadget 配置方式演进

Linux 内核中 Gadget 的配置方式经历了从旧式模块参数到现代 ConfigFS 的演进。了解这些方式有助于阅读内核日志和定位配置问题。

配置方式 内核版本 特点 示例
Legacy Module Params 2.6.x ~ 3.x 通过模块参数加载,功能固定 modprobe g_mass_storage file=/data.img
GadgetFS 2.6.x ~ 4.x 用户态文件系统接口,灵活但复杂 挂载 gadgetfs 后手动写描述符
ConfigFS (推荐) 3.11+ 基于 sysfs 的配置,支持复合设备 通过 /sys/kernel/config/usb_gadget/ 配置
推荐实践: 现代 Linux 系统(内核 4.x 及以上)强烈建议使用 ConfigFS 方式配置 Gadget。它支持复合设备(例如同时模拟 U 盘和串口),配置过程可脚本化,且故障信息更清晰。

1.5 本章小结