2. Linux USB驱动框架:USB核心层、HCD、UDC与Gadget框架分层
USB驱动体系是Linux内核中最为复杂的子系统之一,其分层设计兼顾了主机侧与设备侧的双向通信需求。理解USB驱动框架的分层结构,是掌握设备树绑定与PHY配置的前提。本章将从全局视角剖析USB核心层、主机控制器驱动(HCD)、设备控制器驱动(UDC)以及Gadget框架的职责与协作关系。
2.1 USB驱动整体分层架构
Linux USB驱动体系采用树形分层设计,以USB核心层为枢纽,向上对接各类USB设备驱动(如存储、HID、网络),向下通过HCD或UDC桥接硬件控制器。Gadget框架则在内核中模拟设备侧行为,使嵌入式设备能够作为USB外设工作。
核心概念: USB驱动框架的对称性——主机侧通过HCD管理总线,设备侧通过UDC暴露功能,而Gadget框架在设备侧实现了与主机侧“类驱动”对应的功能抽象。
2.2 USB核心层(usbcore)
USB核心层是驱动框架的中枢神经系统,它不直接操作硬件,而是提供一套标准化的数据结构和接口,使主机侧与设备侧的驱动开发得以解耦。核心层以内核模块usbcore.ko形式存在,主要职责包括:
- 总线管理: 注册USB总线类型,维护USB设备与接口的枚举、配置、热插拔。
- URB(USB Request Block)管理: 提供URB分配、提交、取消、完成回调机制,是主机侧数据传输的基本单元。
- 设备模型抽象: 定义
usb_device、usb_interface、usb_driver等核心数据结构。 - 协议处理: 实现标准设备请求(如Get Descriptor、Set Configuration)的默认处理路径。
| 数据结构 | 作用域 | 核心字段/用途 |
|---|---|---|
usb_device | 主机侧 | 代表一个物理USB设备,包含设备描述符、配置列表、端点信息 |
usb_interface | 主机侧 | 代表设备中的一个功能接口,是驱动绑定的基本单位 |
usb_driver | 主机侧 | USB设备驱动结构体,通过id_table匹配接口 |
urb | 主机侧 | USB请求块,包含传输类型、端点、数据缓冲区、完成函数 |
usb_gadget | 设备侧 | 代表设备侧的USB控制器抽象,包含端点列表和操作函数 |
usb_request | 设备侧 | 设备侧的数据传输请求,对应主机侧的URB |
开发提示: 在设备树中配置USB控制器时,核心层并不直接解析设备树属性。设备树信息由HCD或UDC驱动读取,再通过核心层提供的注册接口(如
usb_add_hcd())将硬件能力上报给核心层。
2.3 HCD(主机控制器驱动)
HCD是主机侧最接近硬件的软件层,直接管理USB主机控制器寄存器,负责:
- 根Hub模拟: 实现虚拟根Hub,处理端口状态变化(连接/断开/复位)。
- 传输管理: 将核心层下发的URB转换为控制器硬件可执行的传输描述符(如TRB、TD)。
- 中断处理: 响应控制器中断,完成数据传输并回调URB完成函数。
- 电源管理: 控制端口供电、挂起/唤醒、PHY时钟门控。
Linux内核支持多种主机控制器标准,其驱动实现差异显著:
| 标准 | 速度 | 驱动文件 | 特点 |
|---|---|---|---|
| OHCI (Open HCI) | USB 1.1 (全速/低速) | ohci-hcd.c | 寄存器接口简单,中断处理开销较大 |
| EHCI (Enhanced HCI) | USB 2.0 (高速) | ehci-hcd.c | 支持高速传输,通常与OHCI/UHCI配合实现速率降级 |
| xHCI (eXtensible HCI) | USB 3.0/3.1/3.2 | xhci-hcd.c | 统一处理所有速度,支持Streaming、LPM,结构最复杂 |
设备树绑定注意: xHCI控制器在设备树中通常需要配置
usb3-lpm-capable、snps,dis-u2-freeclk-exists-quirk等属性。错误的PHY引用或时钟配置会导致HCD初始化失败,表现为“xhci-hcd: probe of xhci-hcd.0 failed with error -22”。
2.4 UDC(设备控制器驱动)
UDC是设备侧的核心驱动,负责管理USB设备控制器硬件,使嵌入式设备能够作为USB外设(如虚拟串口、U盘、网卡)被主机识别。UDC的主要职责包括:
- 端点管理: 配置和控制控制端点(Endpoint 0)及功能端点(IN/OUT)。
- 请求处理: 接收Gadget框架下发的
usb_request,将其转换为控制器DMA或FIFO操作。 - 事件处理: 响应控制器中断(如SETUP包到达、传输完成、总线复位)。
- 连接状态管理: 通过VBUS检测或软件控制实现连接/断开模拟。
常见的UDC驱动实现包括:
- DWC2: 广泛用于STM32、Allwinner、Rockchip等平台,支持OTG模式,驱动文件
dwc2.c。 - DWC3: 高通、TI、Intel等高端SoC使用,支持USB 3.0/2.0,驱动文件
dwc3.c。 - Chipidea: NXP i.MX系列常用,驱动文件
ci_hdrc_imx.c。 - Fotg210: Faraday控制器,用于部分嵌入式平台。
2.5 Gadget框架
Gadget框架是Linux设备侧USB驱动的灵魂,它允许嵌入式设备通过UDC模拟任意USB设备类型。Gadget框架分为三层:
- Gadget功能驱动(Function Driver): 实现具体的USB设备功能,如串口(
g_serial)、大容量存储(g_mass_storage)、以太网(g_ether)、音频(g_audio)。 - Gadget核心层(udc-core): 管理UDC设备的注册与绑定,提供
usb_gadget_probe_driver()接口,负责将功能驱动与UDC实例配对。 - 配置层(ConfigFS / Legacy): 提供用户空间配置接口,ConfigFS方式允许在运行时动态组合多个功能(如同时模拟串口+U盘)。
实战要点: 在嵌入式Linux中,Gadget功能驱动的选择直接影响设备树中UDC节点的配置。例如,使用
g_mass_storage时,需要确保UDC支持Bulk传输且端点数量足够;使用g_ether时,需关注MAC地址的生成策略(设备树中可通过local-mac-address属性指定)。
2.6 分层协作实例:主机识别Gadget设备
以下流程展示了一个完整的USB通信链路,从主机侧应用层到设备侧硬件:
| 步骤 | 主机侧 | 设备侧 |
|---|---|---|
| 1 | 主机控制器检测端口电平变化 | UDC使能上拉电阻,通知主机连接 |
| 2 | HCD复位端口,开始枚举 | UDC响应复位,将端点0设为控制端点 |
| 3 | 核心层发送Get Descriptor请求 | Gadget功能驱动构建设备描述符,通过UDC返回 |
| 4 | 核心层分配地址,发送Set Address | UDC接收地址,更新控制器寄存器 |
| 5 | 核心层获取配置描述符 | Gadget核心层组合配置/接口/端点描述符 |
| 6 | 核心层选择配置(Set Configuration) | UDC激活非控制端点,功能驱动准备数据传输 |
| 7 | 类驱动绑定接口,开始数据通信 | 功能驱动通过UDC提交/接收usb_request |
2.7 设备树视角的分层映射
设备树描述的是硬件拓扑,与USB驱动分层存在明确的映射关系:
- 控制器节点: 对应HCD或UDC实例,包含
compatible、reg、interrupts、phys等属性。 - PHY节点: 对应USB PHY硬件,通过
phy-handle或phys属性引用,由PHY框架管理。 - 时钟与电源: 通过
clocks、power-domains属性关联,影响HCD/UDC的初始化时序。 - Gadget配置: 部分平台在设备树中通过
dr_mode(host/peripheral/otg)指定控制器工作模式。