理解 Linux USB sysfs
七月 03, 2026 #linux #usblsusb 输出解读
以一个 QEMU 虚拟机的输出为例:
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 001 Device 002: ID 0627:0001 Adomax Technology Co., Ltd QEMU Tablet
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
每行格式为 Bus XXX Device YYY: ID vvvv:pppp VendorName ProductName:
| 字段 | 含义 |
|---|---|
Bus 001 | USB 总线编号 |
Device 001 | 该总线上的设备编号(按枚举顺序分配) |
ID 1d6b:0002 | VID (Vendor ID,由 USB-IF 分配) + PID (Product ID,厂商自定义) |
Linux Foundation ... | 从 /usr/share/hwdata/usb.ids 查表得到的人类可读名称 |
以上三行表示两台设备:
1d6b:0002— USB 2.0 根集线器(xHCI 控制器在 USB 2.0 侧的抽象)0627:0001— QEMU 虚拟 USB Tablet(模拟触控/鼠标输入)1d6b:0003— USB 3.0 根集线器(同一控制器在 USB 3.0 侧的抽象)
lsusb -tv 树状拓扑
-t 显示层级拓扑,-v 显示详细信息:
/: Bus 001.Port 001: Dev 001, Class=root_hub, Driver=xhci_hcd/15p, 480M
ID 1d6b:0002 Linux Foundation 2.0 root hub
|__ Port 001: Dev 002, If 0, Class=Human Interface Device, Driver=usbhid, 480M
ID 0627:0001 Adomax Technology Co., Ltd QEMU Tablet
/: Bus 002.Port 001: Dev 001, Class=root_hub, Driver=xhci_hcd/15p, 5000M
ID 1d6b:0003 Linux Foundation 3.0 root hub
| 字段 | 含义 |
|---|---|
/ | USB 拓扑的根节点 |
Bus 001, Bus 002 | 分别对应 USB 2.0 总线和 USB 3.0 总线 |
Port 001, Port ... | 物理端口号 |
Dev N | 设备编号 |
Class=root_hub | 设备类别(根集线器 / HID 等) |
Driver=xhci_hcd/15p | 绑定驱动和下游端口数(15 个端口) |
480M | 链路速率 480 Mbps (USB 2.0 High-Speed) |
5000M | 链路速率 5 Gbps (USB 3.0 SuperSpeed) |
|__ | 缩进表示子设备,连接在本集线器的某个端口上 |
If 0 | Interface 0(一个设备可同时暴露多个接口) |
Class=Human Interface Device | 接口类别为 HID(键盘/鼠标/触控类) |
Driver=usbhid | 绑定驱动 |
sysfs 路径命名规则
设备在 /sys/bus/usb/devices/ 中的路径名由三部分构成:
<总线>-<端口路径>:<配置>.<接口>
bus-part(总线部分)
| 示例 | 含义 |
|---|---|
usb1 | USB Bus 1 的虚拟根设备(唯一不带端口路径的特例) |
usb2 | USB Bus 2 的虚拟根设备 |
port-path(端口路径部分)
端口路径从根集线器向下逐级编号,用 - 分隔第一个端口与总线,后续层级都用 .。
| 示例 | 含义 |
|---|---|
1-0 | Bus 1 上的根集线器本身(port 0 仅为占位符,非真实端口) |
1-1 | Bus 1 根集线器的 Port 1 |
1-2 | Bus 1 根集线器的 Port 2 |
1-1.2 | Bus 1 → 根 Port 1 上的下游集线器 → 该集线器的 Port 2 |
1-1.2.3 | 再延伸一级:Port 2 下级集线器的 Port 3 |
3-2.1.4 | Bus 3 → Port 2 → 集线器 Port 1 → 集线器 Port 4 |
规则概括: - 只出现一次,作为总线号与端口链的分隔符;0 仅用于根集线器作为设备自身被引用时。
config.interface(配置与接口部分)
USB 设备层次为:Device → Configuration → Interface → Endpoint。
| 示例 | 含义 |
|---|---|
1-1 | 设备级别(无配置/接口信息) |
1-1:1.0 | 设备,配置 1,接口 0 |
1-1:1.1 | 同一设备的配置 1 下的接口 1(复合设备可多接口) |
1-1:2.0 | 同一设备的配置 2 下的接口 0(多配置设备) |
1-0:1.0 | 根集线器作为设备,配置 1,接口 0 |
综合示例
在 /sys/bus/usb/devices/ 中的一个多层拓扑可能长这样:
usb1 ← Bus 1 根设备
1-0:1.0 ← Bus 1 根集线器接口
1-1 ← 根 Port 1 上的设备
1-1:1.0 ← 该设备,配置 1 接口 0
1-1:1.1 ← 该设备,配置 1 接口 1(复合设备)
1-1.2 ← 该设备是个下游集线器,其 Port 2 上的设备
1-1.2:1.0
1-1.2.3 ← 下游集线器 Port 3 上的设备
1-1.2.3:1.0
usb2 ← Bus 2 根设备
2-0:1.0
2-1 ← Bus 2 根 Port 1
2-1:1.0
端点(Endpoint)
端点是 USB 通信的最终收发单元,位于整个层次的最底层:
Device → Configuration → Interface → Endpoint
EP0:设备级的控制端点
EP0 属于设备,不属于任何接口。 每个 USB 设备强制拥有 EP0,在配置和接口建立之前就已存在。EP0 是双向控制端点,用于:
- 获取设备/配置/接口/端点描述符
- 设置地址(
SET_ADDRESS) - 选择配置(
SET_CONFIGURATION) - 厂商自定义的控制命令
任何接口都不能声明或占用 EP0。
端点资源与分配
USB 端点地址由 4 位端点号 + 1 位方向组成,规范限制每个设备最多 16 个端点号(EP0 ~ EP15):
端点地址字节: [D7 = 方向: 1=IN, 0=OUT] [D3..D0 = 端点号]
EP1 OUT = 0x01 EP1 IN = 0x81
EP2 OUT = 0x02 EP2 IN = 0x82
扣除强制占用的 EP0,剩余 15 个端点号(EP1 ~ EP15),每个号可分配 IN 和 OUT 两个方向,因此单方向计最多 30 个端点(不含 EP0)。
端点号是设备级资源:一个端点号在给定配置内只能被一个接口独占,不能跨接口共用。
设备端点池:EP1 IN, EP1 OUT, EP2 IN, EP2 OUT, ..., EP15 IN, EP15 OUT
│ │
│ Interface 0 │ Interface 1
└───────────────────┴──────────────────────
各自领走端点,同一个端点号不会出现在两个接口里
注意 EP1 IN 和 EP1 OUT 虽然共用端点号 1,但是两个独立的端点,各占端点池的一个位置。
一个接口可以独占所有剩余端点(如一个复杂的 UVC 摄像头用掉 6~8 个),也可以多个接口分摊。总之是瓜分,不是共享。
端点类型
| 类型 | 用途 | 典型场景 |
|---|---|---|
| Control | 设备配置/命令 | EP0(设备级) |
| Interrupt | 低延迟、小数据量 | HID 键盘/鼠标 |
| Bulk | 大数据量、无延迟保证 | Mass Storage、串口 |
| Isochronous | 固定带宽、允许丢包 | 摄像头、音频 |
常见接口的端点使用
| 设备类型 | 接口数 | 端点 |
|---|---|---|
| HID 键盘 | 1 | 1 IN interrupt |
| HID 鼠标+键盘 | 2 | 2 IN interrupt(各 1 个) |
| Mass Storage(U 盘) | 1 | 1 IN bulk + 1 OUT bulk |
| CDC ACM(串口) | 2 | 1 IN bulk + 1 OUT bulk + 1 IN interrupt(通知) |
| UVC 摄像头 | 2~3 | 1 isochronous IN + alternate settings 的多组 isochronous 端点 |
多配置(Multiple Configurations)
USB 规范允许一个设备有多个配置(Configuration),但同一时刻只有一个配置生效,且互相排斥。
什么时候用多配置
| 场景 | 配置 1 | 配置 2 |
|---|---|---|
| 低功耗模式 | 全功能(键盘+鼠标),耗电高 | 仅键盘,耗电低 |
| 固件升级 | 正常工作模式 | DFU (Device Firmware Upgrade) |
| 多用途 | CDC ECM(网卡) | 其他功能 |
| 兼容性 | USB 3.0 全速 | 降级 USB 2.0 |
实际上,99.9% 的设备只有一个配置。
配置的选择与切换
设备插入后,内核自动遍历所有配置描述符,并默认激活配置 1。可以通过 sysfs 手动切换:
# 查看当前激活的配置
cat /sys/bus/usb/devices/1-1/bConfigurationValue
# → 1
# 查看设备支持几个配置
cat /sys/bus/usb/devices/1-1/bNumConfigurations
# → 2
# 切换到配置 2
echo 2 | sudo tee /sys/bus/usb/devices/1-1/bConfigurationValue
切换配置时内核会解绑旧配置下所有接口的驱动,重建新接口,再重新匹配驱动。
切换配置 ≠ 固件重枚举
更常见的场景是 usb_modeswitch 之类的工具,它不是切换配置,而是让设备固件在电气层面断开再重连,以新的 VID/PID 重新枚举:
插入设备 → 识别为 Mass Storage (PID=1001)
↓ usb_modeswitch 发送 SCSI/vendor 命令
设备断开 USB 连接
↓ 设备固件切换内部模式
设备重新上拉 D+ → 识别为 Modem/网卡 (PID=1002)
| 配置切换 | 固件重枚举 | |
|---|---|---|
| VID/PID | 不变 | 可不同 |
| 机制 | SetConfiguration() | 电气断开再重连 |
| 对主机而言 | 同一设备 | 两个独立的插入事件 |
xHCI 双总线架构
xHCI 控制器内部有两个独立的根集线器——USB 2.0 和 USB 3.0 各一个。一个物理端口从同一个插座同时引出两组引脚:
xHCI 控制器
┌─────────────┐
│ │
USB 2.0 总线 │ ┌───────┐ │ USB 3.0 总线
(Bus 1, 480M) │ │ 芯片 │ │ (Bus 2, 5000M)
↑ │ └───────┘ │ ↑
│ │ │ │
└────────────┼─────────────┼──────────┘
物理端口 (同一个物理插座)
┌───┴───┐
D+/D- SSTX+/SSRX+
(USB 2.0) (USB 3.0)
设备路由
| 插入设备类型 | 使用引脚 | 枚举到 |
|---|---|---|
| USB 3.0/3.x (SuperSpeed) | SSTX/SSRX | Bus 2 (USB 3.0 总线) |
| USB 2.0 (High/Full/Low Speed) | D+/D- | Bus 1 (USB 2.0 总线) |
因此 1-1 和 2-1 会同时出现在 sysfs 中——它们是同一个物理端口的 USB 2.0 影子和 USB 3.0 影子,设备实际只出现在其中一条总线上,取决于插入设备的速度层级。
职责划分
| 层 | 职责 |
|---|---|
| 物理层 | D+/D- 和 SSTX/SSRX 是两组独立差分信号线 |
| xHCI 控制器硬件 | 内部两个根集线器,根据检测到的信号自动路由到对应总线 |
xhci_hcd 驱动 | 为两个根集线器分别创建 usb1/usb2,管理端口映射和设备枚举 |
| USB 核心 (usbcore) | 抽象层,统一设备模型与 sysfs 接口 |
| 设备驱动 (usbhid 等) | 不感知上述细节,只看到绑定到自己接口上的设备 |
为什么根集线器是 1-0 而非 1-0.1
根集线器的端口路径命名中,-0 是占位符——根集线器没有上游端口可以编号,所以用 0 表示它作为设备本身。
但引用根集线器上的端口时,路径直接从该端口号开始,根集线器本身不在路径中出现:
| 期望的写法(错误) | 实际写法 | 原因 |
|---|---|---|
1-0.1 | 1-1 | - 之后直接是端口链,根集线器默认为起点 |
1-0.1.2 | 1-1.2 | 同上,起点不编号 |
| 引用根集线器本身 | 1-0 | 这是唯一出现 0 的地方 |
下游集线器不需要 0,因为它们的设备路径已以自身端口号结束,不存在 N-M.n.0 这种写法。
速查表
| sysfs 路径 | 含义 |
|---|---|
usbN | 虚拟根设备,Bus N |
N-0:1.0 | Bus N 根集线器,配置 1,接口 0 |
N-M | Bus N 根集线器 Port M 上的设备 |
N-M:1.0 | 同上,配置 1,接口 0 |
N-M.N | Bus N → Port M 下游集线器 → Port N |
N-M.N:1.0 | 同上,配置 1,接口 0 |
N-M.N.O | 三层集线器嵌套 |
N-M:1.1 | 同一配置下的第 2 个接口(复合设备) |
N-M:2.0 | 第 2 个配置的第 1 个接口(罕见) |