1. USB Gadget 概述
USB Gadget 是嵌入式 Linux 系统中实现设备端 USB 功能的核心框架。它允许运行 Linux 的硬件(如开发板、手机、嵌入式设备)通过 USB 接口模拟出多种标准 USB 设备角色,例如 U 盘、串口、网卡或 MIDI 设备。理解 Gadget 框架是进行驱动调试和枚举失败定位的基础。
1.1 USB Gadget 框架介绍
Linux USB Gadget 框架采用分层的软件架构,从上到下依次为:Gadget Function 层、UDC (USB Device Controller) 核心层 和 UDC 驱动层。这种分层设计使得功能实现与硬件控制器解耦,便于移植和扩展。
调试要点: 枚举失败时,首先确认 UDC 驱动层是否成功绑定硬件。检查
/sys/kernel/debug/usb/ 下的设备状态,或使用 ls /sys/class/udc/ 查看是否有 UDC 设备节点。
1.2 Gadget 与 Host 的区别
在 USB 体系中,Host(主机) 和 Gadget(设备) 的角色有本质区别。理解这些差异有助于在调试时快速定位问题属于主机侧还是设备侧。
| 对比维度 | USB Host(主机) | USB Gadget(设备) |
|---|---|---|
| 典型硬件 | PC、笔记本、树莓派(Type-A 口) | 嵌入式开发板、手机(Type-B / OTG 口) |
| 软件栈 | HCD (Host Controller Driver) + USB Core + Class Driver | UDC Driver + Gadget Core + Function Driver |
| 总线控制权 | 负责发起所有传输、调度、枚举 | 被动响应主机请求,不能主动发起传输 |
| 枚举角色 | 发送复位信号、获取描述符、配置设备 | 响应主机请求,返回描述符,配置端点 |
| 电源角色 | 提供 VBUS 电源(通常为 5V) | 由 VBUS 供电或自供电 |
| 常见问题 | 驱动缺失、xHCI 控制器故障、电源不足 | UDC 未注册、描述符错误、端点配置失败 |
关键概念: 在 OTG (On-The-Go) 模式下,同一硬件端口可以在 Host 和 Gadget 角色之间切换。调试时务必确认当前端口的工作模式,使用
cat /sys/kernel/debug/usb/otg_state 查看状态。
1.3 常见 Gadget 功能
Linux USB Gadget 框架支持多种标准 USB 设备类。以下是嵌入式开发中最常用的四种功能:
- U 盘 (Mass Storage Class) — 将嵌入式设备模拟为 USB 大容量存储设备,用于文件传输、固件升级。
- 串口 (Communication Device Class - ACM) — 模拟 USB 虚拟串口,用于控制台访问、日志输出、AT 命令交互。
- 网卡 (Ethernet Control Model / RNDIS) — 模拟 USB 以太网适配器,实现设备与主机之间的网络通信。
- MIDI (Audio Class - MIDI) — 模拟 USB MIDI 设备,用于音乐制作、合成器控制、音频信号处理。
1.4 Gadget 功能对比与选择
在实际项目中,选择哪种 Gadget 功能取决于应用需求。下表从传输速率、实时性、配置复杂度三个维度进行对比:
| Gadget 功能 | USB 类协议 | 典型传输速率 | 实时性 | 配置复杂度 | 典型应用 |
|---|---|---|---|---|---|
| U 盘 | Mass Storage (BOT / UAS) | 20~400 MB/s | 低 | 低 | 文件拷贝、系统升级 |
| 串口 | CDC ACM | 115200 bps ~ 12 Mbps | 中 | 低 | 调试控制台、AT 指令 |
| 网卡 | CDC ECM / RNDIS | 10~1000 Mbps | 中 | 中 | 网络共享、远程登录 |
| MIDI | Audio Class 1.0 / 2.0 | 31.25 Kbps (MIDI 1.0) | 高 | 高 | 电子乐器、音序器 |
常见误区: 不要将 Gadget 功能与 USB 转串口芯片(如 FT232、CP2102)混淆。Gadget 是软件模拟的 USB 设备,而 USB 转串口芯片是硬件桥接器。调试时,主机侧看到的设备描述符和 VID/PID 完全不同。
1.5 Gadget 功能加载示例
在 Linux 内核中,Gadget 功能通常以内核模块形式加载。以下是通过 ConfigFS 配置一个 USB 串口 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
echo 0x1d6b > idVendor # Linux Foundation
echo 0x0104 > idProduct # Gadget Serial
# 4. 创建英文字符串
mkdir strings/0x409
echo "MyBoard" > strings/0x409/manufacturer
echo "USB Serial Gadget" > strings/0x409/product
# 5. 创建配置
mkdir configs/c.1
mkdir configs/c.1/strings/0x409
echo "Serial Config" > configs/c.1/strings/0x409/configuration
# 6. 绑定串口功能
mkdir functions/acm.usb0
ln -s functions/acm.usb0 configs/c.1
# 7. 绑定 UDC 控制器
echo musb-hdrc.0 > UDC # 根据实际 UDC 名称调整
调试技巧: 如果
echo ... > UDC 失败,检查 dmesg 中是否有 "can't bind" 或 "UDC core: gadget not registered" 错误。常见原因是 UDC 驱动未加载或硬件未初始化。