2. USB Gadget框架概述
USB Gadget子系统是Linux内核中用于实现设备端(Device Side)USB功能的软件框架。与主机侧(Host Side)的USB主机控制器驱动(HCD)不同,Gadget子系统允许嵌入式设备模拟成各种USB外设,如U盘、串口、网卡、音频设备等。理解其整体架构是进行Gadget驱动开发的第一步。
2.1 子系统三层架构总览
USB Gadget子系统从下到上主要分为三层:UDC驱动层(底层)、Gadget核心层(中间层)、功能驱动层(上层)。ConfigFS接口则作为用户空间与内核空间交互的桥梁,主要用于上层功能的动态组合与配置。
2.2 UDC驱动层(底层)
UDC(USB Device Controller)驱动层是Gadget子系统中最接近硬件的部分。它直接与SoC或外挂芯片中的USB设备控制器硬件交互,负责处理USB总线上的物理信号、包传输、中断管理以及DMA操作。
| UDC驱动名称 | 对应控制器 | 常见平台 | 特点 |
|---|---|---|---|
| dwc2.ko | DesignWare Cores DWC2 | Raspberry Pi、Allwinner、Rockchip | 支持OTG,驱动代码成熟 |
| dwc3.ko | DesignWare Cores DWC3 | 高通、TI、Xilinx、Intel | 支持USB 3.0 SuperSpeed,性能高 |
| chipidea.ko | NXP ChipIdea | i.MX系列、LPC系列 | 集成度高,常用于工业控制 |
| musb.ko | Mentor Graphics MUSB | OMAP、DaVinci、Blackfin | 双角色控制器,历史悠久 |
| at91_udc.ko | Microchip AT91 UDC | AT91SAM系列 | 专用于AT91 ARM SoC |
UDC驱动需要实现的核心回调函数包括:udc_start()、udc_stop()、ep_enable()、ep_disable()、ep_queue()、ep_dequeue() 等。这些函数通过 usb_gadget_ops 结构体注册到核心层。
// UDC驱动必须实现的操作集结构体(位于 include/linux/usb/gadget.h)
struct usb_gadget_ops {
int (*get_frame)(struct usb_gadget *);
int (*wakeup)(struct usb_gadget *);
int (*set_selfpowered)(struct usb_gadget *, int value);
int (*vbus_session)(struct usb_gadget *, int is_active);
int (*vbus_draw)(struct usb_gadget *, unsigned int mA);
int (*pullup)(struct usb_gadget *, int is_on);
int (*ioctl)(struct usb_gadget *, unsigned int code, unsigned long param);
int (*udc_start)(struct usb_gadget *, struct usb_gadget_driver *);
int (*udc_stop)(struct usb_gadget *);
};
2.3 Gadget功能驱动层(上层)
功能驱动层是开发者最常接触的部分。每个功能驱动实现一种具体的USB设备类协议,例如串口(CDC ACM)、以太网(RNDIS/ECM)、大容量存储(MSC)、音频(UAC)或HID设备。
功能驱动通过Gadget核心层提供的API与UDC驱动交互。它负责构建USB描述符(设备描述符、配置描述符、接口描述符、端点描述符)、处理控制传输(Setup包)、管理批量/中断/等时传输的数据流。
内核中预置了多个标准功能驱动,可以直接通过配置启用:
- g_serial.ko — USB虚拟串口(CDC ACM),主机端显示为COM端口
- g_ether.ko — USB虚拟以太网(CDC ECM/RNDIS),主机端显示为网卡
- g_mass_storage.ko — USB大容量存储设备,将文件或块设备模拟为U盘
- g_audio.ko — USB音频设备(UAC),实现双向音频流
- g_hid.ko — USB HID设备,可模拟键盘、鼠标、游戏手柄
- g_multi.ko — 复合设备,同时包含多个功能(如串口+网卡+存储)
2.4 ConfigFS接口
ConfigFS(Configuration File System)是Linux内核提供的一种基于文件系统的配置机制,挂载在 /sys/kernel/config/ 目录下。在USB Gadget子系统中,ConfigFS允许用户在用户空间通过创建目录、写入文件的方式动态构建USB设备配置,而无需编写内核代码或重新编译内核模块。
使用ConfigFS配置Gadget的基本流程如下:
- 创建Gadget实例:
mkdir /sys/kernel/config/usb_gadget/g1 - 设置VID/PID: 写入
idVendor和idProduct文件 - 创建配置:
mkdir configs/c.1,设置配置属性(如MaxPower) - 创建功能实例:
mkdir functions/acm.usb0 - 绑定功能到配置: 创建符号链接
ln -s functions/acm.usb0 configs/c.1 - 绑定UDC: 将Gadget实例的UDC文件写入对应的UDC控制器名称(如
echo "musb-hdrc.0" > UDC)
# 一个完整的ConfigFS配置示例:创建USB虚拟串口
# 1. 挂载ConfigFS(如果未挂载)
mount -t configfs none /sys/kernel/config
# 2. 创建Gadget实例
mkdir /sys/kernel/config/usb_gadget/g_serial_demo
cd /sys/kernel/config/usb_gadget/g_serial_demo
# 3. 设置USB标准描述符
echo 0x1d6b > idVendor # Linux Foundation
echo 0x0104 > idProduct # Multifunction Composite Gadget
echo 0x0100 > bcdDevice # v1.0.0
echo 0x0200 > bcdUSB # USB 2.0
# 4. 创建字符串描述符(英文)
mkdir strings/0x409
echo "MyCompany" > strings/0x409/manufacturer
echo "VirtualSerialPort" > strings/0x409/product
echo "1234567890" > strings/0x409/serialnumber
# 5. 创建配置
mkdir configs/c.1
mkdir configs/c.1/strings/0x409
echo "ACM Serial Config" > configs/c.1/strings/0x409/configuration
echo 120 > configs/c.1/MaxPower # 120mA
# 6. 创建ACM功能并绑定
mkdir functions/acm.usb0
ln -s functions/acm.usb0 configs/c.1/
# 7. 绑定UDC控制器(假设控制器名称为 musb-hdrc.0)
echo "musb-hdrc.0" > UDC
2.5 各层协作关系总结
下表总结了USB Gadget子系统中各层的职责、核心数据结构以及开发者需要关注的程度:
| 层次 | 核心职责 | 关键数据结构/接口 | 开发者关注度 |
|---|---|---|---|
| UDC驱动层 | 硬件寄存器操作、中断处理、DMA传输 | usb_gadget_ops、usb_ep |
低(除非移植新硬件) |
| Gadget核心层 | UDC与功能驱动的桥梁、端点管理、请求调度 | usb_gadget_driver、usb_request |
中(理解API即可) |
| 功能驱动层 | USB类协议实现、描述符构建、数据收发 | usb_function、usb_function_instance |
高(开发重点) |
| ConfigFS接口 | 用户空间动态配置、功能组合、UDC绑定 | 文件系统操作(mkdir/echo/ln) | 高(日常使用) |