1. USB Gadget 基础概念

1.1 USB Gadget 框架简介

USB Gadget 是 Linux 内核中用于让嵌入式设备模拟 USB 外设(Peripheral)角色的软件框架。它运行在设备端(Device Side),通过硬件 USB 控制器(如 DWC2、DWC3、ChipIdea)向上层提供标准化的接口,使得开发者无需关心底层寄存器操作即可实现多种 USB 功能。

Gadget 框架的核心组件包括:

  • UDC(USB Device Controller)驱动:直接操作硬件 USB 控制器,负责收发 USB 数据包、处理中断、管理端点。
  • Gadget API:UDC 驱动向上层暴露的统一接口,包括 usb_gadget、usb_ep、usb_request 等核心结构体。
  • Function 驱动:实现具体 USB 功能(如 Ethernet、Serial、Mass Storage),通过 Gadget API 与 UDC 交互。
  • ConfigFS / Legacy Gadget:用户态配置接口,允许动态组合多个 Function 形成复合设备。
关键路径: 用户态通过 ConfigFS 配置 Gadget → 内核 Function 驱动注册端点 → UDC 驱动处理硬件传输 → Host 端枚举并加载对应驱动。
USB Gadget 软件架构分层图 USB Gadget 软件架构分层图 用户态配置层 ConfigFS (configfs) / Legacy Gadget (g_ether.ko, g_serial.ko) Function 驱动层 u_ether.ko / u_serial.ko / u_msc.ko / u_audio.ko / u_video.ko Gadget API 抽象层 usb_gadget / usb_ep / usb_request / usb_composite_dev UDC 驱动层(硬件相关) dwc2 / dwc3 / chipidea / musb / renesas_usb3

1.2 Gadget 与 Host 的区别

在 USB 体系中,Host(主机)和 Gadget(设备)的角色有本质区别。理解这些差异是排查枚举失败的基础。

对比维度 Host(主机) Gadget(设备)
硬件角色 提供 VBUS 电源,发起枚举 消耗 VBUS 电源,响应枚举
软件栈 USB 主机控制器驱动 + HCI(xHCI/EHCI/OHCI) UDC 驱动 + Gadget API + Function 驱动
端点方向 OUT 表示数据从主机到设备,IN 表示数据从设备到主机 OUT 表示数据从主机到设备,IN 表示数据从设备到主机(与 Host 对称)
枚举发起者 主动发送 SETUP 包,获取设备描述符 被动响应 SETUP 包,返回描述符
典型硬件 PC、笔记本、树莓派(Type-A 口) 嵌入式开发板、手机、IoT 设备(Type-B / Type-C / Micro-AB 口)
驱动加载方式 根据设备描述符匹配主机端驱动 Function 驱动由 Gadget 框架自身加载
排查提示: 枚举失败时,首先确认硬件连接方向是否正确。Gadget 设备必须连接到 Host 的 Type-A 口或支持 DRP(Dual Role Port)的 Type-C 口。如果 Gadget 设备连接到另一个 Gadget 设备(如两块开发板直连),枚举必然失败。
Host 与 Gadget 交互流程图 Host 与 Gadget 交互流程图 USB Host 提供 VBUS (5V) 发送 SETUP 包 加载主机端驱动 SETUP 包 USB 总线 D+ / D- 差分信号 VBUS / GND 描述符响应 USB Gadget 消耗 VBUS 响应 SETUP 包 加载 Function 驱动 枚举关键步骤 ① Host 检测 D+ 上拉电阻 → 检测到设备连接 ② Host 发送复位信号 → 设备地址为 0 ③ Host 发送 GET_DESCRIPTOR 请求 → Gadget 返回设备描述符 ④ Host 分配地址 → 配置设备 → 加载驱动

1.3 常见 Gadget 类型

Linux Gadget 框架支持多种 USB 功能类型,以下三种是最常用且故障排查频率最高的:

1.3.1 Ethernet Gadget(USB 网卡)

将嵌入式设备模拟为 USB 以太网适配器,Host 端识别为网络接口(如 usb0、enp0s20f0u1)。支持两种协议:

  • CDC ECM(Ethernet Control Model):标准协议,Linux/macOS 原生支持,Windows 需额外驱动。
  • CDC NCM(Network Control Model):更高吞吐量,适合高速传输。
  • RNDIS(Remote NDIS):Microsoft 专有协议,Windows 原生支持,Linux 需加载 rndis_host 驱动。
常见故障: Host 端枚举成功但无法获取 IP 地址。通常是因为 Gadget 端未配置 g_ether 的 MAC 地址,或 Host 端未启用 DHCP 客户端。排查时使用 dmesg 查看 Host 端是否识别到 usb0 接口。

1.3.2 Serial Gadget(USB 串口)

将嵌入式设备模拟为 USB 转串口适配器,Host 端识别为 /dev/ttyUSB0(Linux)或 COM 端口(Windows)。常见实现:

  • CDC ACM(Abstract Control Model):标准串口协议,广泛用于 Modem、GPS、工业设备。
  • Generic Serial:简单的批量传输串口,适用于自定义协议。
排查提示: 如果 Host 端枚举成功但 /dev/ttyUSB0 未出现,检查 Gadget 端是否加载了 g_serial 或 u_serial 模块,并确认 ttyGS0 设备节点已创建。

1.3.3 Mass Storage Gadget(USB 存储设备)

将嵌入式设备的存储介质(如 SD 卡、eMMC 分区、RAM 磁盘)模拟为 USB 大容量存储设备,Host 端识别为 U 盘。支持两种模式:

  • 直写模式(Direct Access):Host 直接读写底层块设备,适合文件传输。
  • 只读模式(Read-Only):防止 Host 修改 Gadget 端数据,适合固件升级或安全场景。
Gadget 类型 内核模块 Host 端识别 典型应用
Ethernet g_ether.ko / u_ether.ko usb0 / enp* 网络共享、IoT 设备管理
Serial g_serial.ko / u_serial.ko /dev/ttyUSB0 / COMx 调试控制台、Modem 通信
Mass Storage g_mass_storage.ko / u_msc.ko /dev/sd* / 可移动磁盘 文件传输、固件升级
三种常见 Gadget 类型对比图 三种常见 Gadget 类型对比图 Ethernet Gadget 模拟 USB 网卡 协议:ECM / NCM / RNDIS Host 端:usb0 网络接口 应用:网络共享、IoT 管理 Serial Gadget 模拟 USB 串口 协议:CDC ACM / Generic Host 端:/dev/ttyUSB0 应用:调试控制台、Modem Mass Storage Gadget 模拟 USB 存储设备 协议:SCSI / BBB Host 端:/dev/sd* 磁盘 应用:文件传输、固件升级 Gadget 类型选择建议 • 需要网络功能(SSH、HTTP)→ 选择 Ethernet Gadget,优先使用 CDC ECM 以获得最佳兼容性 • 需要串口调试或 Modem 通信 → 选择 Serial Gadget,CDC ACM 是跨平台最稳定的方案 • 需要文件传输或存储扩展 → 选择 Mass Storage Gadget,注意直写模式与只读模式的选择 • 复合设备需求 → 使用 ConfigFS 组合多个 Function,例如 Ethernet + Serial 同时工作

1.4 Gadget 配置示例(ConfigFS)

以下是一个使用 ConfigFS 配置 CDC ECM Ethernet Gadget 的完整流程,用于后续故障排查的参考基线:

# 1. 挂载 configfs
mount -t configfs none /sys/kernel/config

# 2. 创建 Gadget 目录
mkdir /sys/kernel/config/usb_gadget/g1
cd /sys/kernel/config/usb_gadget/g1

# 3. 设置 VID/PID(必须与 Host 驱动匹配)
echo 0x1d6b > idVendor   # Linux Foundation
echo 0x0104 > idProduct  # CDC ECM

# 4. 设置字符串描述符(可选但推荐)
mkdir strings/0x409
echo "MyBoard" > strings/0x409/manufacturer
echo "USB Ethernet" > strings/0x409/product
echo "1234567890" > strings/0x409/serialnumber

# 5. 创建配置
mkdir configs/c.1
mkdir configs/c.1/strings/0x409
echo "ECM Config" > configs/c.1/strings/0x409/configuration

# 6. 创建 Ethernet Function
mkdir functions/ecm.usb0

# 7. 绑定 Function 到配置
ln -s functions/ecm.usb0 configs/c.1/

# 8. 绑定 UDC(替换为实际 UDC 名称)
echo "musb-hdrc.0.auto" > UDC
故障排查基线: 上述配置完成后,Host 端应枚举出 usb0 接口。如果枚举失败,首先检查 /sys/kernel/config/usb_gadget/g1/UDC 是否已写入正确的 UDC 名称,以及 dmesg 中是否有 UDC 驱动报错。