支持作者,点击京东购买作者创作书籍《Yocto项目实战教程:高效定制嵌入式Linux系统》
延续《USB 硬件原理全解》篇章,本文将聚焦于 USB 的软件架构、协议栈实现、驱动开发流程以及主从模式下的实际驱动设计逻辑,完整梳理 Linux 中 USB 子系统的核心实现机制,帮助开发者深入理解 USB 软件层的技术全貌。
一、USB 软件架构整体概览
USB 软件在 Linux 内核中是一个独立的子系统,包含以下几个关键层次:
用户空间
├── libusb / 文件系统节点(/dev/ttyUSBx, /dev/sda)
内核空间
├── USB 类驱动(Class Driver)
├── USB Core 层(设备管理、匹配、配置)
├── 主机控制器驱动(HCD)
└── Gadget 设备控制器驱动(UDC)
二、主机模式(Host)驱动结构
2.1 主机控制器驱动(HCD)
- 管理 SoC 内部的 USB 主机控制器硬件,如 xHCI、EHCI、DWC3 等
- 驱动位于:
drivers/usb/host/
- 注册为
usb_hcd
,通过usb_create_hcd()
初始化
2.2 USB 核心层(usbcore)
-
负责:
- 设备检测与枚举
- 地址分配与端点配置
- 设备树或 ACPI 的匹配注册
- 驱动和设备匹配逻辑(VID/PID、Interface Class)
-
核心文件:
drivers/usb/core/
usb.c
: 核心入口hub.c
: 管理 USB Hub 和设备热插拔message.c
: 控制传输的封装
2.3 类驱动(Class Drivers)
常见标准类驱动包括:
驱动模块 | 说明 |
---|---|
usb-storage | U 盘、大容量存储设备 |
cdc-acm | USB 转串口设备,如 /dev/ttyACM0 |
uvcvideo | USB 摄像头 |
usbtmc | USB 测试与测量设备 |
2.4 驱动开发关键流程(主机端)
- 定义
struct usb_driver
- 填写
usb_device_id
匹配表 - 实现
probe()
与disconnect()
- 使用
usb_register_driver()
注册驱动
static struct usb_driver my_driver = {
.name = "my_usb",
.probe = my_probe,
.disconnect = my_disconnect,
.id_table = my_id_table,
};
三、设备模式(Gadget)驱动结构
3.1 USB Device Controller 驱动(UDC)
- 位于:
drivers/usb/gadget/udc/
- 如:
ci_hdrc
,dwc2
,musb
- 通过
usb_add_gadget_udc()
注册控制器实例
3.2 USB Composite Framework
-
用于构建复合 USB 设备(多功能设备)
-
定义:
usb_composite_driver
usb_function
usb_configuration
-
注册:
usb_composite_probe()
3.3 功能驱动(Function Driver)示例
功能模块 | 说明 |
---|---|
g_serial | USB Gadget 串口设备(ttyGS0) |
g_mass_storage | USB 模拟 U 盘设备 |
g_ether | USB 网络设备(usb0) |
g_multi | 多功能复合设备 |
四、URB(USB Request Block)机制
4.1 URB 概念
URB 是内核中用于 USB 传输的核心结构,封装一次传输请求。
struct urb {
void *transfer_buffer;
int transfer_buffer_length;
unsigned int pipe;
struct usb_device *dev;
void (*complete)(struct urb *urb);
};
4.2 使用流程(主机侧)
- 分配 URB:
usb_alloc_urb()
- 填写缓冲区、方向、端点
- 提交 URB:
usb_submit_urb()
- 回调处理:
complete()
处理函数
五、设备识别与驱动绑定流程
5.1 枚举流程(主机侧)
- 主机通过 hub 检测到电平变化(上拉)
- 分配设备地址、读取设备描述符
- 主机根据 Interface Class 查找匹配驱动
- 调用驱动的
probe()
完成初始化
5.2 Gadget 框架启动流程(设备侧)
usb_composite_register()
注册设备bind()
函数构建功能(如串口、存储)- UDC 通知主机设备准备就绪
六、用户态接口与调试工具
6.1 用户态访问路径
/dev/ttyUSB0
//dev/ttyACM0
:串口类设备/dev/sda1
:USB 存储/sys/class/usb_device/
:内核状态节点
6.2 调试工具
命令 | 用途 |
---|---|
lsusb | 查看 USB 设备信息 |
usb-devices | 显示内核识别的设备结构 |
usbmon | USB 抓包日志调试(modprobe usbmon ) |
strace | 跟踪 libusb 应用调用 |
七、主从模式差异总结
模块 | 主机模式(Host) | 设备模式(Device) |
---|---|---|
控制器 | HCD(xHCI、EHCI) | UDC(ci_hdrc、dwc2) |
架构 | usb_driver | usb_composite_driver |
端点控制 | 主机配置端点 | 设备实现端点响应 |
功能驱动 | 存储、摄像头、串口等 | g_mass_storage、g_ether、g_serial |
八、USB 驱动开发常见陷阱与建议
- 🚫 误用 Interface number:设备可能有多个接口,需要准确匹配 Interface
- 🚫 未检查设备状态变化:断开重连等事件要及时处理
- ✅ 使用 usbcore 提供的 API,避免直接读写控制器寄存器
- ✅ 调试阶段使用 usbmon 分析传输细节
结语
USB 软件架构是 Linux 内核中最成熟、模块化程度最高的子系统之一。通过对 Host/Gadget 模式的结构分析、驱动开发流程讲解和 URB 通信机制的梳理,本文为理解和开发 USB 相关驱动打下坚实基础。掌握 USB 栈的使用与扩展,不仅能处理常见外设接入问题,更能开发出定制化的 USB 复合设备、传输接口或固件烧录工具。