3. USB协议栈分层:物理层、协议层、设备层、功能层,以及Linux内核中对应的软件分层
USB协议栈并非单一平面结构,而是按照功能与抽象层级划分为四个层次:物理层、协议层、设备层和功能层。Linux内核的USB子系统严格对应这一分层模型,形成了从硬件控制器到设备驱动的完整软件栈。理解这种分层映射关系,是掌握URB(USB Request Block)与端点通信机制的前提。
3.1 USB协议标准分层详解
USB协议标准从底层到顶层定义了四个层次,每一层都封装了下层的细节,向上层提供标准化的服务接口。
| 层次 | 核心职责 | 关键概念 | 数据单元 |
|---|---|---|---|
| 物理层 | 电气信号传输、位编码、同步 | 差分信号D+/D-、NRZI编码、位填充 | 位(Bit) |
| 协议层 | 包格式定义、事务处理、错误检测 | 令牌包(Token)、数据包(Data)、握手包(Handshake) | 包(Packet) |
| 设备层 | 设备寻址、配置管理、端点抽象 | 设备地址、配置描述符、接口描述符、端点描述符 | 描述符(Descriptor) |
| 功能层 | 设备功能实现、数据传输语义 | 接口(Interface)、端点(Endpoint)、管道(Pipe) | 传输(Transfer) |
关键理解:物理层和协议层由USB主机控制器硬件和固件实现,设备驱动开发者通常不直接操作这两层。设备驱动的工作主要集中在设备层和功能层,通过URB与USB核心交互。
3.2 Linux内核USB软件分层
Linux内核将USB协议栈的四个层次映射为三个主要的软件层次,外加硬件层:
- 硬件层(Host Controller Hardware):对应物理层,由USB主机控制器芯片(如EHCI、xHCI)实现,负责差分信号收发、位编码、包检测等。
- HCI核心(Host Controller Interface Core):对应协议层和部分物理层抽象,包含HCD(Host Controller Driver),负责与硬件寄存器交互、DMA传输管理、中断处理。
- USB核心(USB Core):对应设备层,负责设备枚举、描述符解析、设备地址分配、URB生命周期管理、电源管理。
- 设备驱动(Device Driver):对应功能层,实现具体的设备功能逻辑,通过URB与USB核心通信,操作端点进行数据传输。
3.3 各软件层次的核心数据结构与接口
Linux内核为每一层定义了核心数据结构和操作接口,驱动开发者需要熟悉这些结构体:
| 软件层次 | 核心数据结构 | 关键接口/函数 | 所在源文件 |
|---|---|---|---|
| 设备驱动 | struct usb_driverstruct usb_device_id |
usb_register()usb_submit_urb() |
drivers/usb/core/driver.c |
| USB核心 | struct usb_devicestruct usb_host_configstruct usb_host_interface |
usb_alloc_dev()usb_new_device()usb_hcd_submit_urb() |
drivers/usb/core/hub.cdrivers/usb/core/urb.c |
| HCI核心 | struct usb_hcdstruct hc_driver |
usb_add_hcd()urb_enqueue() |
drivers/usb/core/hcd.c |
| 硬件 | 寄存器映射(__iomem) |
writel() / readl() |
各HCD驱动(如ehci-hcd.c) |
3.4 分层之间的通信机制:URB的角色
URB(USB Request Block)是贯穿整个USB软件栈的核心通信载体。一个URB从设备驱动出发,依次经过USB核心、HCI核心,最终到达硬件控制器执行数据传输。
URB的跨层传递路径:
设备驱动 →
设备驱动 →
usb_submit_urb() → USB核心(usb_hcd_submit_urb()) → HCI核心(urb_enqueue()) → HCD硬件操作 → 硬件执行
URB在每一层都被赋予不同的语义:
- 设备驱动视角:URB是异步I/O请求,包含目标端点、数据缓冲区、完成回调函数。
- USB核心视角:URB是端点通信的调度单元,需要验证端点合法性、管理URB生命周期、处理电源状态。
- HCI核心视角:URB是DMA传输描述符,需要映射DMA缓冲区、构建硬件链表、处理中断完成。
3.5 分层设计的优势与驱动开发启示
| 优势 | 说明 | 对驱动开发者的意义 |
|---|---|---|
| 硬件无关性 | 设备驱动不关心主机控制器是EHCI还是xHCI | 同一驱动可在不同USB控制器上运行 |
| 接口标准化 | 各层之间通过稳定的API通信 | 驱动开发只需关注usb_submit_urb()等标准接口 |
| 可移植性 | USB核心和HCI核心屏蔽了平台差异 | 驱动代码可在ARM、x86、RISC-V等架构上复用 |
| 调试便利性 | 每层可独立调试和跟踪 | 可通过usbmon在USB核心层捕获URB流量 |
常见误区:初学者常试图在设备驱动中直接操作HCI核心或硬件寄存器,这是错误且危险的做法。正确的做法是始终通过USB核心提供的标准接口(如
usb_submit_urb()、usb_control_msg())进行通信,由内核分层机制自动完成向下传递。
3.6 分层视角下的端点通信路径
以一个典型的BULK OUT传输为例,展示数据从设备驱动到物理总线的完整分层路径:
- 设备驱动:构造URB,设置目标端点(如端点2 OUT)、数据缓冲区、传输长度,调用
usb_submit_urb()。 - USB核心:检查URB合法性(端点是否存在、方向是否正确、设备是否挂起),将URB加入端点的URB队列,调用
usb_hcd_submit_urb()。 - HCI核心:HCD驱动将URB转换为硬件传输描述符(如EHCI的qTD),映射DMA缓冲区,将描述符链入硬件调度链表。
- 硬件:主机控制器根据调度链表发起USB事务:发送OUT令牌包 → 发送数据包 → 接收握手包。
- 完成回调:硬件产生中断 → HCD处理中断 → USB核心调用URB完成回调 → 设备驱动在回调中处理结果。
3.7 本章小结
USB协议栈的四层分层(物理层→协议层→设备层→功能层)与Linux内核的软件分层(硬件→HCI核心→USB核心→设备驱动)形成精确的映射关系。理解这种分层架构,有助于驱动开发者:
- 明确自己在哪一层工作(设备驱动层),不需要越级操作下层细节。
- 理解URB作为跨层通信载体的核心地位,掌握其生命周期。
- 在调试时能够准确定位问题所在的层次,提高开发效率。