USB
USB总线系统中的设备
USB 是以主机为中心的分层星形拓扑(tiered star),从上到下依次是:主机(含根集线器)→ 集线器 → 外围设备。

USB主机
- 每条 USB 总线(一棵拓扑树)有且只有一个主机。一个 SoC 可以有多个主机控制器。A1 的三个 DWC2 控制器各注册一条总线;但不能推广为所有控制器都一对一,例如 xHCI 通常分别注册 USB 2 和 USB 3 两条逻辑总线。
- USB 2.0 的常规事务由主机调度,设备不能自行发起普通总线事务;远程唤醒等信号是另一回事。USB 3.x 还支持 ERDY 等设备通知,不能把“所有版本始终只能等待轮询”作为通用结论。
- 主机按固定周期划分时间:每 1 ms 发一个 SOF(Start of Frame)包标识一帧;High Speed 下每帧再细分为 8 个 125 µs 的微帧(microframe)。
- 负责枚举设备(分配地址、读取描述符、选择配置)、加载驱动,以及对总线上的错误进行管理和恢复。
USB Root Hub(根集线器)
- 集成在主机控制器内部,不是独立芯片,由 HCD(Host Controller Driver)在注册总线时虚拟出来。
- Linux 中设备名为
usbN(N 为总线号),接口为N-0:1.0,绑定hub驱动。 - VID:PID 固定为 Linux Foundation 的虚拟 ID:
1d6b:0001(USB 1.1)、1d6b:0002(USB 2.0)、1d6b:0003(USB 3.x)。 - 端口数等于控制器的物理端口数,见 sysfs 的
maxchild。君正A1 每个控制器只有 1 个端口。 product、manufacturer由内核填写,A1 上分别是DWC OTG Controller、Linux 4.4.94-20220517 dwc2_hsotg。
对应的启动日志:
dwc2 13680000.otg2: new USB bus registered, assigned bus number 3
hub 3-0:1.0: USB hub found
hub 3-0:1.0: 1 port detected
USB集线器(USB HUB)
- 作用类似于网络集线器,用于扩展端口。
- 检测下游端口的插拔,通过自身的中断端点上报主机;负责端口的复位、使能、供电和挂起。设备的"添加"(枚举、分配地址)由主机完成,Hub 只负责发现和上报。
- USB 2.0 Hub 下行方向是广播转发,确实像网络集线器;USB 3.x SuperSpeed 按路由定向转发,更像交换机。
- High Speed Hub 内有 TT(Transaction Translator),把 HS 事务转换成 FS/LS 事务,低速设备(键鼠)才能挂在 HS Hub 下。Hub 设备描述符的
bDeviceProtocol:0 = FS Hub,1 = HS 单 TT,2 = HS 多 TT。
USB总线设备
- 即外围设备(Function),如U盘、键鼠、4G模块、摄像头。
- 一个物理设备可以包含多个功能(Interface),称为复合设备(Composite Device)。例如 4G 模块同时提供 AT 串口、诊断口和网卡,一个功能可能由一个或多个 Interface 组成,例如 CDC 功能可同时使用控制接口与数据接口;不能把 Interface 与功能严格一一对应。
速度等级与主机控制器
| 速度 | 速率 | 引入版本 | sysfs speed | 典型设备 |
|---|---|---|---|---|
| Low Speed (LS) | 1.5 Mbps | USB 1.x | 1.5 | 键盘、鼠标 |
| Full Speed (FS) | 12 Mbps | USB 1.x | 12 | 早期U盘、USB 音频 |
| High Speed (HS) | 480 Mbps | USB 2.0 | 480 | U盘、4G模块、摄像头 |
| SuperSpeed (SS) | 5 Gbps | USB 3.0 | 5000 | USB3 移动硬盘 |
| 主机控制器 | 支持的速度 | Linux 驱动 |
|---|---|---|
| OHCI / UHCI | USB 1.1(LS/FS) | ohci-hcd / uhci-hcd |
| EHCI | USB 2.0 HS;LS/FS 设备通常交给配套的 OHCI/UHCI(companion)处理 | ehci-hcd |
| xHCI | USB 3.x,一个控制器支持所有速度 | xhci-hcd |
| DWC2 | Synopsys DesignWare HS OTG,自身支持 LS/FS/HS,嵌入式 SoC 常见 | dwc2 |
君正A1 有 3 个 DWC2 控制器(13600000.otg0、13640000.otg1、13680000.otg2),所以有 3 条总线,都是 USB 2.0。
USB描述符
描述符层次
设备通过描述符告诉主机"我是谁、有什么功能、怎么通信":
Device(设备描述符) 一个设备一个:USB 版本、VID/PID、EP0 最大包长
└── Configuration(配置描述符) 通常只有 1 个:供电方式、最大电流
├── Interface 0(接口描述符) 接口可独立或与其他接口组成一个功能,驱动可关联多个接口
│ ├── Endpoint 0x81(IN)
│ └── Endpoint 0x02(OUT)
└── Interface 1 ... 复合设备有多个接口
- sysfs 命名
<bus>-<port_path>:<config>.<interface>中的config、interface就是这里的bConfigurationValue和bInterfaceNumber。 - 端点 0(EP0)每个设备都有,是双向的控制端点,用于枚举和标准请求,不出现在配置描述符里。
- 端点地址 bit7 表示方向:1 = IN(设备→主机),0 = OUT(主机→设备);低 4 位是端点号。
0x81= EP1 IN,0x02= EP2 OUT。 - Device 绑定通用驱动
usb,Interface 绑定具体的类驱动(如usb-storage、hub)。
实例:U盘的描述符
在君正A1 上读取 Kingston U盘的原始描述符(sysfs 的 descriptors 文件 = 设备描述符 + 所有配置描述符):
hexdump -C /sys/bus/usb/devices/1-1.1/descriptors
00000000 12 01 00 02 00 00 00 40 51 09 65 16 00 00 01 02 |.......@Q.e.....|
00000010 03 01 09 02 20 00 01 01 00 80 32 09 04 00 00 02 |.... .....2.....|
00000020 08 06 50 00 07 05 81 02 00 02 00 07 05 02 02 00 |..P.............|
00000030 02 00 |..|
按描述符拆开:
12 01 00 02 00 00 00 40 51 09 65 16 00 00 01 02 03 01 # 设备描述符(18 字节)
09 02 20 00 01 01 00 80 32 # 配置描述符(9 字节)
09 04 00 00 02 08 06 50 00 # 接口描述符(9 字节)
07 05 81 02 00 02 00 # 端点描述符(7 字节)
07 05 02 02 00 02 00 # 端点描述符(7 字节)
| 描述符 | 字段 | 值 | 含义 |
|---|---|---|---|
| 设备 | bcdUSB | 0x0200 | USB 2.0 |
| 设备 | bDeviceClass | 0x00 | 类别由接口描述符定义 |
| 设备 | bMaxPacketSize0 | 0x40 | EP0 最大包长 64 字节 |
| 设备 | idVendor / idProduct | 0x0951 / 0x1665 | Kingston / DataTraveler 2.0(小端存储) |
| 设备 | bNumConfigurations | 1 | 1 个配置 |
| 配置 | wTotalLength | 0x0020 | 配置 + 接口 + 端点共 32 字节 |
| 配置 | bNumInterfaces | 1 | 1 个接口 |
| 配置 | bConfigurationValue | 1 | 配置编号 1,即 1-1.1:1.0 中的 1 |
| 配置 | bmAttributes | 0x80 | 总线供电,不支持远程唤醒 |
| 配置 | bMaxPower | 0x32 | 50 × 2 mA = 100 mA |
| 接口 | bInterfaceNumber | 0 | 接口 0,即 1-1.1:1.0 中的 0 |
| 接口 | bNumEndpoints | 2 | 2 个端点(不含 EP0) |
| 接口 | bInterfaceClass / SubClass / Protocol | 0x08 / 0x06 / 0x50 | Mass Storage / SCSI 透明命令集 / Bulk-Only Transport |
| 端点 | bEndpointAddress / bmAttributes / wMaxPacketSize | 0x81 / 0x02 / 0x0200 | EP1 IN,Bulk,512 字节 |
| 端点 | bEndpointAddress / bmAttributes / wMaxPacketSize | 0x02 / 0x02 / 0x0200 | EP2 OUT,Bulk,512 字节 |
常见设备类别
| Class | 含义 | 例子 | Linux 驱动 |
|---|---|---|---|
| 0x00 | 由接口描述符定义 | 大多数设备 | — |
| 0x02 / 0x0a | CDC 通信 / CDC 数据 | 4G 模块网卡口、USB 串口 | cdc_ether、cdc_ncm、cdc_acm |
| 0x03 | HID | 键盘、鼠标 | usbhid |
| 0x08 | Mass Storage | U盘、读卡器、移动硬盘 | usb-storage、uas |
| 0x09 | Hub | Hub、Root Hub | hub |
| 0x0e | Video | UVC 摄像头 | uvcvideo |
| 0xe0 | 无线控制器 | RNDIS 网卡 | rndis_host |
| 0xff | 厂商自定义 | 4G 模块的 AT 口/诊断口 | option 等 usbserial 驱动 |
枚举流程
设备插入后,主机通过枚举识别设备并加载驱动:
- 检测插入:Hub 检测到端口连接状态变化,通过中断端点通知主机(Linux 中由 hub 驱动的
hub_event()处理)。 - 复位端口:主机复位该端口,复位过程中确定设备速度(HS 设备通过 chirp 握手升到 480 Mbps)。
- 读设备描述符:设备此时使用默认地址 0。主机先读设备描述符,主要为了拿到
bMaxPacketSize0。Linux 这一步按 64 字节请求,日志里的read/64就是它。 - 分配地址:
SET_ADDRESS分配唯一地址(1~127),即 sysfs 的devnum。每次插拔通常会递增,与端口无关。 - 读全部描述符:用新地址读完整的设备描述符(18 字节)、配置描述符(含接口、端点)和字符串描述符。
- 选择配置:
SET_CONFIGURATION选中配置(通常是 1),接口开始生效。 - 匹配驱动:内核为每个 Interface 生成 uevent,按驱动的
id_table(VID/PID 或 Class/SubClass/Protocol)匹配并调用 probe;mdev/udev 创建/dev节点。
驱动匹配用到的 MODALIAS 可以在 uevent 里看到:
cat /sys/bus/usb/devices/1-1.1:1.0/uevent
DEVTYPE=usb_interface
DRIVER=usb-storage
PRODUCT=951/1665/0
TYPE=0/0/0
INTERFACE=8/6/80
MODALIAS=usb:v0951p1665d0000dc00dsc00dp00ic08isc06ip50in00
君正A1 上插入U盘的实际日志:
[19845.669991] usb 1-1.1: new high-speed USB device number 7 using dwc2 # 复位完成,HS 设备,将分配地址 7
[19845.793363] usb-storage 1-1.1:1.0: USB Mass Storage device detected # 接口匹配到 usb-storage
[19845.810874] scsi host5: usb-storage 1-1.1:1.0 # usb-storage 注册 SCSI host
[19848.937381] scsi 5:0:0:0: Direct-Access 1.00 PQ: 0 ANSI: 4 # SCSI 扫描到 LUN
[19849.000416] sda: sda1 # 解析分区表
[19849.010995] sd 5:0:0:0: [sda] Attached SCSI removable disk # /dev/sda 可用
拔出时:
[19843.623371] usb 1-1.2: USB disconnect, device number 6
传输类型
| 类型 | 特点 | 带宽 / 时延 | 出错重传 | 典型用途 | 君正A1 实例 |
|---|---|---|---|---|---|
| Control | 每个设备必有(EP0),Setup→可选 Data→Status | 保留一部分带宽 | 是 | 枚举、标准请求、设备配置 | 所有设备的 ep_00 |
| Bulk | 大块数据,只用空闲带宽 | 不保证时延 | 是 | U盘、打印机、4G 网卡数据 | U盘 ep_81(IN) / ep_02(OUT),512 字节 |
| Interrupt | 少量数据,主机按 bInterval 周期轮询 | 保证最大时延 | 是 | 键鼠、Hub 端口状态变化 | Hub ep_81,interval 256ms |
| Isochronous | 实时数据流 | 预留带宽 | 否 | UVC 摄像头、音频 | — |
- Interrupt 传输不是真正的中断,仍然是主机周期性轮询。
- 周期性传输(Interrupt + Isochronous)最多占用 FS 帧的 90%、HS 微帧的 80%,剩余的留给 Control;Bulk 只能用剩下的空闲带宽,总线忙时会变慢。
- LS 设备只支持 Control 和 Interrupt。
- HS 下最大包长:Control 64、Bulk 512、Interrupt / Isochronous 最大 1024 字节。
查看端点:
cd /sys/bus/usb/devices
for e in 1-1.1/ep_00 1-1.1:1.0/ep_* 1-1:1.0/ep_*; do
echo "$e addr=$(cat $e/bEndpointAddress) type=$(cat $e/type) dir=$(cat $e/direction) maxp=$(cat $e/wMaxPacketSize) interval=$(cat $e/interval)"
done
# 输出
1-1.1/ep_00 addr=00 type=Control dir=both maxp=0040 interval=0ms
1-1.1:1.0/ep_02 addr=02 type=Bulk dir=out maxp=0200 interval=0ms
1-1.1:1.0/ep_81 addr=81 type=Bulk dir=in maxp=0200 interval=0ms
1-1:1.0/ep_81 addr=81 type=Interrupt dir=in maxp=0001 interval=256ms
Linux USB 驱动栈
应用层 mount /dev/sda1 /dev/ttyUSB* ethX / usbX /dev/input/eventX
│ │ │ │
子系统 文件系统 → sd → SCSI tty 网络协议栈 input
│ │ │ │
USB 类驱动 usb-storage option/usbserial cdc_ether/rndis_host/asix usbhid
└───────────────────┴─────────┬──────────┴────────────────────┘
│ URB(USB Request Block)
USB Core usbcore:设备模型、驱动匹配、hub 驱动(端口管理与枚举)
│
HCD dwc2(otg0 / otg1 / otg2)
│
硬件 DWC2 控制器 → Root Hub → Hub → 设备
- 类驱动通过 URB 向 usbcore 提交传输请求,usbcore 交给 HCD 调度到总线上。
- U盘的完整路径:dwc2 → usbcore → usb-storage → SCSI 中间层 → sd →
/dev/sda→ 文件系统。 - 君正A1 上已注册的 USB 驱动(
ls /sys/bus/usb/drivers):
| 驱动 | 用途 |
|---|---|
| usb、hub | 通用设备驱动、Hub 驱动 |
| usbfs | 用户态访问 /dev/bus/usb/*(libusb) |
| usb-storage | U盘、移动硬盘 |
| usbhid | 键盘、鼠标 |
| usbserial、option | 4G 模块的 AT 口/诊断口 → /dev/ttyUSB* |
| cdc_ether、cdc_ncm、cdc_subset、rndis_host、zaurus、net1080 | 4G 模块网卡口、USB 网络设备 |
| asix、ax88179_178a | USB 有线网卡芯片 |
当时板上没有 /lib/modules,但仅凭目录缺失不能证明所有驱动都内置,也可能从其他位置加载模块。当时驱动列表中没有 uvcvideo、qmi_wwan、uas,只能说明这些驱动尚未注册;是否可用还需检查内核配置和可加载模块。没有 uas 也不代表 UAS 移动硬盘完全不能用:设备若支持 Bulk-Only Transport,可能通过 usb-storage 工作。
Linux sysfs 中的 USB 设备
命名格式
<bus>-<port_path>:<config>.<interface>
# 例如
1-1:1.0
│ │ │ │
│ │ │ └── Interface 0
│ │ └──── Configuration 1
│ └────── 根 Hub 的 Port 1
└──────── USB Bus 1
1-0:1.0
│ │ │ │
│ │ │ └── Interface 0
│ │ └──── Configuration 1
│ └────── Root Hub 的特殊标识 0
└──────── USB Bus 1
# 这里的 0 并不是物理 USB Port 0,而是 Linux 用于表示 Root Hub 的特殊命名。
1-1.1
│ │ │
│ │ └── 下一级 Hub 的 Port 1
│ └──── 根 Hub 的 Port 1
└────── USB Bus 1
# 其中的 . 表示又经过了一级 Hub。
1-1表示整个USB设备,1-1:1.0表示USB设备的一个功能接口。- 端口路径对应物理端口,同一个口插什么设备名字都一样;换个口名字就变。程序里不要写死
1-1.2这类路径。 devnum(设备地址)每次插拔通常递增,与端口无关。
常用属性与工具
| 文件 | 位置 | 含义 | 君正A1 U盘(1-1.1) |
|---|---|---|---|
| idVendor / idProduct | 设备 | VID / PID | 0951 / 1665 |
| manufacturer / product / serial | 设备 | 字符串描述符 | Kingston / DataTraveler 2.0 |
| speed | 设备 | 实际协商速率(Mbps) | 480 |
| version | 设备 | bcdUSB | 2.00 |
| busnum / devnum | 设备 | 总线号 / 设备地址 | 1 / 7 |
| devpath | 设备 | 端口路径 | 1.1 |
| maxchild | 设备 | 下游端口数,非 Hub 为 0 | 0 |
| bMaxPower | 设备 | 当前配置的最大电流 | 100mA |
| descriptors | 设备 | 原始描述符(二进制) | 见"USB描述符" |
| bInterfaceClass / SubClass / Protocol | 接口 | 接口类别 | 08 / 06 / 50 |
| bNumEndpoints | 接口 | 端点数(不含 EP0) | 02 |
| ep_XX/ | 设备/接口 | 端点属性:type、direction、wMaxPacketSize、interval | — |
| driver | 设备/接口 | 绑定的驱动(符号链接) | usb / usb-storage |
| uevent | 设备/接口 | 热插拔环境变量,含 MODALIAS | — |
列出所有设备和接口:
cd /sys/bus/usb/devices
# 设备
for d in usb* [0-9]-[0-9]*; do
case $d in *:*) continue ;; esac # 跳过接口
echo "$d $(cat $d/idVendor):$(cat $d/idProduct) speed=$(cat $d/speed) $(cat $d/product 2>/dev/null)"
done
# 接口
for i in *:*; do
echo "$i class=$(cat $i/bInterfaceClass) driver=$(basename $(readlink $i/driver))"
done
其他工具:
lsusb:板上是 busybox 版本,只能列出Bus/Device/ID,不支持-t树形显示和厂商名称,详细信息要靠 sysfs。dmesg | grep -iE "usb|hub":查看枚举和插拔日志。/sys/kernel/debug/usb/devices:需要内核开启 debugfs 并挂载,A1 默认未挂载。
判断U盘
readlink -f /sys/block/sda/device/
# 得到
/sys/devices/platform/ahb2/13600000.otg0/usb1/1-1/1-1.1/1-1.1:1.0/host5/target5:0:0/5:0:0:0
路径逐段含义:
/sys/devices/platform/ahb2/13600000.otg0 ← DWC2 OTG 控制器(工作在 host 模式)
/usb1 ← 总线 1 的 Root Hub
/1-1 ← Root Hub 端口 1 上的 Hub
/1-1.1 ← 该 Hub 端口 1 上的设备 = U盘
/1-1.1:1.0 ← U盘的接口 0(Mass Storage,绑定 usb-storage)
/host5/target5:0:0/5:0:0:0 ← usb-storage 注册的 SCSI host / target / LUN
- 判断依据:路径里有
/usbN/说明 sda 挂在 USB 上;SATA 硬盘的路径里是ataN。
case "$(readlink -f /sys/block/sda/device)" in
*/usb[0-9]*/*) echo "sda 是 USB 存储设备" ;;
*/ata[0-9]*/*) echo "sda 是 SATA 设备" ;;
esac
- 局限:只能判断出"USB 存储设备"。U盘、USB 移动硬盘、读卡器都是 Mass Storage,路径区分不出来。
/sys/block/sda/removable(A1 上U盘为 1)也不可靠,很多移动硬盘报 0,部分U盘也报 0。需要区分时只能结合容量、VID/PID 判断。 - SCSI host 编号和 USB devnum 都属于运行时分配标识,可能被复用;不要依赖它们永久递增或用作设备的稳定身份。
君正A1的USB拓扑
2026-10-13 实测:
[root@Ingenic-uc1_1:devices]# ls /sys/bus/usb/devices
1-0:1.0 1-1.1 1-1:1.0 3-0:1.0 usb2
1-1 1-1.1:1.0 2-0:1.0 usb1 usb3
13600000.otg0 → usb1(Root Hub,1 口)
└── 1-1 USB HUB 1a86:8091(4 口,HS 多 TT)
├── 1-1.1 Kingston U盘 0951:1665(HS)
├── 1-1.2 空
├── 1-1.3 空
└── 1-1.4 空
13640000.otg1 → usb2(Root Hub,1 口,未接设备)
13680000.otg2 → usb3(Root Hub,1 口,未接设备)
| 名称 | 类型 | 含义 |
|---|---|---|
| usb1 | Root Hub | 控制器 otg0(13600000)的根 Hub,1 个端口 |
| usb2 | Root Hub | 控制器 otg1(13640000)的根 Hub,1 个端口 |
| usb3 | Root Hub | 控制器 otg2(13680000)的根 Hub,1 个端口 |
| 1-0:1.0 / 2-0:1.0 / 3-0:1.0 | Interface | 各根 Hub 的接口,绑定 hub 驱动 |
| 1-1 | Device(Hub) | usb1 端口 1 上的 4 口 Hub,1a86:8091(南京沁恒 WCH),开机即存在 |
| 1-1:1.0 | Interface | 该 Hub 的接口,绑定 hub 驱动 |
| 1-1.1 | Device | Hub 端口 1 上的 Kingston U盘 |
| 1-1.1:1.0 | Interface | U盘的 Mass Storage 接口,绑定 usb-storage 驱动 |
注意,Root Hub 比较特殊:它的 USB Device 目录叫 usb1,而不是 1-0,但其 Interface 仍使用 1-0:1.0。
开机时 1-1.1 上插的是一个低速 USB 鼠标,1-1.2 上是U盘。后来拔掉鼠标、把U盘换到端口 1,U盘的名字就从 1-1.2 变成了 1-1.1,devnum 也从 4 涨到了 7。低速鼠标能挂在 HS Hub 下,是靠 Hub 内部的 TT:
[ 3.020085] usb 1-1.1: new low-speed USB device number 3 using dwc2
[ 3.120089] usb 1-1.1: device descriptor read/64, error -32
[ 3.357370] hid-generic 0003:13EE:0001.0001: input,hidraw0: USB HID v1.00 Mouse [MOON AND ] on usb-13600000.otg0-1.1/input0
热插拔检测
相关设备对象增删时,内核可产生 uevent,通知路径包括:
- 通过
NETLINK_KOBJECT_UEVENT广播给用户态; - 启用相应 helper 配置且路径非空时,调用
/proc/sys/kernel/hotplug指定的程序;现代系统不一定启用此机制。A1 上是/sbin/mdev,且没有/etc/mdev.conf,只按默认规则在/dev下创建设备节点。
插一次U盘会依次产生 usb、scsi、block 等多个子系统的 uevent。应用一般只关心 SUBSYSTEM=block 的 add/remove,收到后再 mount/umount。
应用层监听 uevent 示例:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <linux/netlink.h>
int main(void)
{
struct sockaddr_nl addr;
memset(&addr, 0, sizeof(addr));
addr.nl_family = AF_NETLINK;
addr.nl_pid = 0; // 0 表示由内核分配
addr.nl_groups = 1; // 订阅内核 uevent 组播组
int fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
if (fd < 0 || bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
perror("netlink");
return 1;
}
char buf[4096];
for (;;) {
ssize_t len = recv(fd, buf, sizeof(buf) - 1, 0);
if (len <= 0)
continue;
buf[len] = '\0';
// 消息由多个 '\0' 分隔的字符串组成,例如:
// "add@/devices/.../block/sda/sda1" "ACTION=add" "SUBSYSTEM=block" "DEVNAME=sda1" "DEVTYPE=partition" ...
for (char *p = buf; p < buf + len; p += strlen(p) + 1)
printf("%s\n", p);
printf("\n");
}
}
拔U盘前要先 umount。A1 上出现过拔出后再插入时的告警:
FAT-fs (sda1): Volume was not properly unmounted. Some data may be corrupt. Please run fsck.
常见故障与日志
错误码
USB 日志里的错误码是负的 errno。MIPS 的 errno 数值和 x86 不同,查日志时要按平台对照:
| 错误码 | MIPS(A1) | x86 | 含义 |
|---|---|---|---|
| EPIPE | -32 | -32 | 端点 STALL,设备拒绝了该请求 |
| ETIME | -62 | -62 | 总线上等不到设备应答(部分 HCD) |
| EPROTO | -71 | -71 | 协议错误:位填充错误、应答超时等,多为信号质量或供电问题 |
| EOVERFLOW | -79 | -75 | babble,设备发送的数据超过包长 |
| EILSEQ | -88 | -84 | CRC 错误(部分 HCD) |
| ETIMEDOUT | -145 | -110 | 同步传输(如控制传输)超时 |
| ENODEV | -19 | -19 | 设备已拔出 |
| ESHUTDOWN | -143 | -108 | 设备或主机控制器已关闭 |
常见日志
| 日志 | 含义 | 常见原因 / 处理 |
|---|---|---|
device descriptor read/64, error -71(或 -32、-145) | 地址 0 阶段读描述符失败 | 偶发一次后能枚举成功可忽略(A1 开机时的低速鼠标就是 -32 后成功);反复出现查供电、线材、Hub |
device not accepting address N, error -71 | SET_ADDRESS 失败 | 多为信号质量、供电问题 |
unable to enumerate USB device | 多次重试后放弃枚举 | 设备损坏、供电不足、兼容性问题 |
USB disconnect 后紧跟 new ... USB device,反复出现 | 设备掉线重连 | 供电不足(移动硬盘最常见)、接触不良、静电 |
reset high-speed USB device number N using dwc2 | 设备无响应,被主机复位 | usb-storage 命令超时,常见于劣质U盘、供电不足 |
over-current condition | 端口过流 | 短路、负载电流超过限流 |
FAT-fs (sda1): Volume was not properly unmounted | 文件系统脏标志未清除 | 拔U盘前未 umount、写入过程中掉电 |
排查步骤
dmesg | grep -iE "usb|hub":看有没有枚举日志、报什么错。- sysfs 里有没有生成设备;
speed是否符合预期(HS 设备只跑到 12,说明降速了,查线材和 Hub)。 - 接口目录下有没有
driver链接。没有说明没匹配到驱动:检查bInterfaceClass和 VID/PID 是否在驱动的id_table里,或内核根本没编译该驱动(见"Linux USB 驱动栈"中的驱动列表)。 - 换 Hub 口、去掉 Hub 直连、外接供电,排除供电和 Hub 问题。
参考:Linux USB API。