USB驱动移植适配与设备树配置实战 - 第1节

1. USB协议基础

USB(Universal Serial Bus)采用分层星型拓扑结构,由主机控制器、根集线器、集线器和设备四类节点构成。整个拓扑中只有一个主机,所有通信均由主机发起,设备不能主动向主机发送数据。

关键概念:USB 2.0 支持最多 127 个设备地址(地址 0 用于枚举),设备通过集线器级联,最多允许 7 层(含根集线器)。
USB 总线拓扑结构 USB 主机(Host) 根集线器(Root Hub) 集线器 1(Hub) 集线器 2(Hub) 设备 A(鼠标) 设备 B(键盘) 设备 C(U盘) 设备 D(摄像头) 说明:主机唯一,集线器扩展端口,设备挂载在集线器下游端口,逻辑上形成树形拓扑

1.1.1 拓扑中的角色与职责

角色 职责 典型实现
主机(Host) 调度总线事务、管理带宽、处理枚举 EHCI / xHCI 控制器
根集线器(Root Hub) 提供物理端口、检测设备连接/断开 集成在主机控制器内部
集线器(Hub) 端口扩展、中继信号、电源管理 独立芯片或集成在设备中
设备(Device) 实现具体功能(存储、HID、音视频等) U盘、鼠标、摄像头
驱动移植要点:在设备树中,USB 主机控制器节点通常位于 SoC 总线(如 axi、ahb)下,集线器和设备由内核自动枚举,不需要在设备树中静态描述。

1.2 USB传输类型

USB 定义了四种传输类型,分别对应不同的带宽、延迟和可靠性需求。驱动开发中,选择正确的传输类型直接影响设备性能和稳定性。

USB 四种传输类型对比 控制传输 Control Transfer 批量传输 Bulk Transfer 中断传输 Interrupt Transfer 同步传输 Isochronous Transfer 特性 控制 批量 中断 可靠性 高(重试+CRC) 高(重试+CRC) 低(无重试) 带宽保证 无 无 有(预留) 典型用途 枚举/配置 存储/打印 HID/键盘 端点类型 默认端点0 Bulk端点 Interrupt端点 最大包大小 64/8字节 512/1024字节 64/1024字节 延迟 中等 高(排队) 低(轮询) 注意:同步传输无重传机制,适用于音视频等容忍丢包的实时场景

1.2.1 控制传输

  • 用途:设备枚举、获取描述符、设置配置、发送类特定命令。
  • 特点:双向、可靠、带宽小,每个设备必须实现端点0。
  • 阶段:Setup 阶段 → Data 阶段(可选)→ Status 阶段。

1.2.2 批量传输

  • 用途:大块数据传输,如 U盘读写、打印机数据。
  • 特点:可靠(硬件重试+CRC),无带宽保证,空闲时抢占带宽。
  • 驱动注意:批量端点通常用于 BOT(Bulk-Only Transport)协议。

1.2.3 中断传输

  • 用途:鼠标、键盘、游戏手柄等 HID 设备。
  • 特点:保证最大延迟(轮询间隔),可靠传输。
  • 驱动注意:中断传输实际上是主机轮询,并非硬件中断。

1.2.4 同步传输

  • 用途:USB 摄像头、音频设备、实时数据采集。
  • 特点:预留带宽、固定延迟、无重传、允许少量丢包。
  • 驱动注意:同步端点需要预留带宽,驱动中需正确设置 wMaxPacketSize。
常见错误:在 USB 摄像头驱动中错误使用批量传输代替同步传输,导致帧率不稳定或丢帧严重。同步传输是实时流的唯一选择。

1.3 USB描述符体系

USB 描述符是设备向主机报告自身能力的结构化数据。主机通过枚举过程读取描述符,从而识别设备类型、配置端点、加载对应驱动。

USB 描述符层级体系 设备描述符(Device Descriptor) 配置描述符(Configuration Descriptor) 接口描述符(Interface Descriptor) 端点描述符 0 端点描述符 1 端点描述符 2 其他描述符(HID/Class/SuperSpeed) 说明:描述符层级为 设备 → 配置 → 接口 → 端点,一个设备可有多个配置, 一个配置可有多个接口,一个接口可有多个端点。HID 等类描述符附加在接口描述符之后。

1.3.1 核心描述符结构

描述符类型 bDescriptorType 主要字段 作用
设备描述符 0x01 idVendor, idProduct, bcdUSB 识别设备类型和协议版本
配置描述符 0x02 bNumInterfaces, bMaxPower 描述供电模式和接口数量
接口描述符 0x04 bInterfaceClass, bInterfaceSubClass 定义功能接口(如 HID、Mass Storage)
端点描述符 0x05 bEndpointAddress, bmAttributes, wMaxPacketSize 定义数据传输端点属性
字符串描述符 0x03 UNICODE 字符串 提供可读的厂商/产品名称

1.3.2 枚举流程中的描述符读取

  1. 复位:主机检测到设备连接,复位设备,分配地址 0。
  2. 获取设备描述符:主机发送控制传输读取前 8 字节,获取 wMaxPacketSize0。
  3. 设置地址:主机分配唯一地址(1~127)。
  4. 获取完整设备描述符:读取全部 18 字节。
  5. 获取配置描述符:读取配置描述符及所有接口、端点描述符。
  6. 选择配置:主机根据描述符信息加载驱动,发送 Set Configuration。
驱动开发关键:在 Linux 内核中,USB 核心层自动完成枚举和描述符解析。驱动开发者只需在 probe 回调中通过 struct usb_device 和 struct usb_interface 访问描述符信息,无需手动解析原始字节。

1.3.3 描述符在驱动中的访问示例

// 获取设备描述符中的 VID/PID
struct usb_device *udev = interface_to_usbdev(intf);
u16 vid = le16_to_cpu(udev->descriptor.idVendor);
u16 pid = le16_to_cpu(udev->descriptor.idProduct);

// 遍历接口的端点描述符
struct usb_host_interface *altsetting = intf->cur_altsetting;
for (int i = 0; i < altsetting->desc.bNumEndpoints; i++) {
    struct usb_endpoint_descriptor *ep = &altsetting->endpoint[i].desc;
    int ep_addr = ep->bEndpointAddress;
    int ep_type = ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
    int max_pkt = le16_to_cpu(ep->wMaxPacketSize);
    dev_info(&intf->dev, "EP 0x%02x, type %d, max %d\n",
             ep_addr, ep_type, max_pkt);
}
调试技巧:使用 lsusb -v 可以查看完整描述符树,是驱动移植时验证设备描述符是否正确的重要工具。

1.4 本章小结

  • USB 总线采用分层星型拓扑,主机唯一,设备通过集线器扩展。
  • 四种传输类型各有适用场景:控制用于枚举配置,批量用于大块数据,中断用于低延迟输入,同步用于实时流。
  • 描述符体系是设备自描述的基础,驱动通过描述符获取设备能力,完成匹配和初始化。
  • 在设备树中,USB 主机控制器节点描述硬件寄存器、中断和时钟,设备枚举由内核自动完成。