You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Ubuntu 20.04下编程识别物理USB端口的技术方案咨询

确定Linux(Ubuntu 20.04)下物理USB端口的编程识别方法

需求背景

我需要编写一款PC应用,用于批量克隆USB块设备:将SD卡镜像烧录到10张通过USB读卡器连接的SD卡中。核心需求是精确识别物理USB端口,无论端口是否连接设备:

  • 烧录异常时,标记对应物理端口的故障SD卡,方便用户丢弃;
  • 烧录完成后,告知用户每个物理端口对应的SD卡写入的唯一ID(计划在物理端口旁贴标签,映射到应用GUI的“插槽”)。

之前我认为无法实现——常规方法只能获取依赖插入顺序的设备路径,而非物理端口位置。后来发现Windows平台可通过打开底层USB root hub并发送IOCTL命令实现,想确认该思路在Linux下是否可行,或有无其他方案。

已尝试的方法(均无法满足需求)

1. lsusb -t命令

插入读卡器时,标记#######的行出现;移除后消失,但插入其他物理端口时这些行仍会出现,无法区分物理端口:

$ lsusb -t

/:  Bus 04.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/4p, 5000M
    |__ Port 4: Dev 2, If 0, Class=Hub, Driver=hub/7p, 5000M
/:  Bus 03.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/4p, 480M
    |__ Port 1: Dev 2, If 0, Class=Hub, Driver=hub/7p, 12M
        |__ Port 1: Dev 4, If 0, Class=Human Interface Device, Driver=usbhid, 12M
    |__ Port 2: Dev 3, If 0, Class=Hub, Driver=hub/7p, 480M                         #######
        |__ Port 1: Dev 30, If 0, Class=Mass Storage, Driver=usb-storage, 480M      #######
    |__ Port 3: Dev 5, If 0, Class=Hub, Driver=hub/7p, 12M
    |__ Port 4: Dev 6, If 0, Class=Hub, Driver=hub/7p, 480M
/:  Bus 02.Port 1: Dev 1, Class=root_hub, Driver=uhci_hcd/2p, 12M
    |__ Port 1: Dev 4, If 0, Class=Wireless, Driver=btusb, 12M
    |__ Port 1: Dev 4, If 1, Class=Wireless, Driver=btusb, 12M
    |__ Port 2: Dev 3, If 0, Class=Hub, Driver=hub/7p, 12M
/:  Bus 01.Port 1: Dev 1, Class=root_hub, Driver=ehci-pci/6p, 480M

2. /sys/bus/usb/devices目录

同样,标记#######的行随读卡器插拔出现/消失,但更换物理端口后仍会生成类似路径,无法对应物理位置:

$ ls /sys/bus/usb/devices

1-0:1.0 -> ../../../devices/pci0000:00/0000:00:11.0/0000:02:03.0/usb1/1-0:1.0
2-0:1.0 -> ../../../devices/pci0000:00/0000:00:11.0/0000:02:00.0/usb2/2-0:1.0
2-1 -> ../../../devices/pci0000:00/0000:00:11.0/0000:02:00.0/usb2/2-1
2-1:1.0 -> ../../../devices/pci0000:00/0000:00:11.0/0000:02:00.0/usb2/2-1/2-1:1.0
2-1:1.1 -> ../../../devices/pci0000:00/0000:00:11.0/0000:02:00.0/usb2/2-1/2-1:1.1
2-2 -> ../../../devices/pci0000:00/0000:00:11.0/0000:02:00.0/usb2/2-2
2-2:1.0 -> ../../../devices/pci0000:00/0000:00:11.0/0000:02:00.0/usb2/2-2/2-2:1.0
3-0:1.0 -> ../../../devices/pci0000:00/0000:00:15.0/0000:03:00.0/usb3/3-0:1.0
3-1 -> ../../../devices/pci0000:00/0000:00:15.0/0000:03:00.0/usb3/3-1
3-1.1 -> ../../../devices/pci0000:00/0000:00:15.0/0000:03:00.0/usb3/3-1/3-1.1
3-1.1:1.0 -> ../../../devices/pci0000:00/0000:00:15.0/0000:03:00.0/usb3/3-1/3-1.1/3-1.1:1.0
3-1:1.0 -> ../../../devices/pci0000:00/0000:00:15.0/0000:03:00.0/usb3/3-1/3-1:1.0
3-2 -> ../../../devices/pci0000:00/0000:00:15.0/0000:03:00.0/usb3/3-2
3-2.1 -> ../../../devices/pci0000:00/0000:00:15.0/0000:03:00.0/usb3/3-2/3-2.1                   #######
3-2.1:1.0 -> ../../../devices/pci0000:00/0000:00:15.0/0000:03:00.0/usb3/3-2/3-2.1/3-2.1:1.0     #######
3-2:1.0 -> ../../../devices/pci0000:00/0000:00:15.0/0000:03:00.0/usb3/3-2/3-2:1.0
3-3 -> ../../../devices/pci0000:00/0000:00:15.0/0000:03:00.0/usb3/3-3
3-3:1.0 -> ../../../devices/pci0000:00/0000:00:15.0/0000:03:00.0/usb3/3-3/3-3:1.0
3-4 -> ../../../devices/pci0000:00/0000:00:15.0/0000:03:00.0/usb3/3-4
3-4:1.0 -> ../../../devices/pci0000:00/0000:00:15.0/0000:03:00.0/usb3/3-4/3-4:1.0
4-0:1.0 -> ../../../devices/pci0000:00/0000:00:15.0/0000:03:00.0/usb4/4-0:1.0
4-4 -> ../../../devices/pci0000:00/0000:00:15.0/0000:03:00.0/usb4/4-4
4-4:1.0 -> ../../../devices/pci0000:00/0000:00:15.0/0000:03:00.0/usb4/4-4/4-4:1.0
usb1 -> ../../../devices/pci0000:00/0000:00:11.0/0000:02:03.0/usb1
usb2 -> ../../../devices/pci0000:00/0000:00:11.0/0000:02:00.0/usb2
usb3 -> ../../../devices/pci0000:00/0000:00:15.0/0000:03:00.0/usb3
usb4 -> ../../../devices/pci0000:00/0000:00:15.0/0000:03:00.0/usb4

3. lsusb.py脚本

切换读卡器到不同物理端口时,输出内容无变化,标记“3-2”和“3-2.1”的行仅随设备插拔出现/消失,无法对应物理端口:

$ python3 lsusb.py 
 WARNING: Failure to read usb.ids
usb1              1d6b:0002 09 1IF  [USB 2.00,   480 Mbps,   0mA] (ehci_hcd 0000:02:03.0) hub
usb2              1d6b:0001 09 1IF  [USB 1.10,    12 Mbps,   0mA] (uhci_hcd 0000:02:00.0) hub
  2-1               0e0f:0008 e0 2IFs [USB 2.00,    12 Mbps,   0mA] (VMware Virtual Bluetooth Adapter 000650268328)
  2-2               0e0f:0002 09 1IF  [USB 1.10,    12 Mbps,   0mA] (VMware, Inc. VMware Virtual USB Hub) hub
usb3              1d6b:0002 09 1IF  [USB 2.00,   480 Mbps,   0mA] (xhci-hcd 0000:03:00.0) hub
  3-1               0e0f:0002 09 1IF  [USB 1.10,    12 Mbps,   0mA] (VMware, Inc. VMware Virtual USB Hub) hub
    3-1.1             0e0f:0003 00 1IF  [USB 1.10,    12 Mbps,   0mA] (VMware VMware Virtual USB Mouse)
  3-2               0e0f:0002 09 1IF  [USB 2.00,   480 Mbps,   0mA] (VMware, Inc. VMware Virtual USB Hub) hub
    3-2.1             058f:6366 00 1IF  [USB 2.00,   480 Mbps, 100mA] (Generic Mass Storage Device 058F63666433)
  3-3               0e0f:0002 09 1IF  [USB 1.10,    12 Mbps,   0mA] (VMware, Inc. VMware Virtual USB Hub) hub
  3-4               0e0f:0002 09 1IF  [USB 2.00,   480 Mbps,   0mA] (VMware, Inc. VMware Virtual USB Hub) hub
usb4              1d6b:0003 09 1IF  [USB 3.00,  5000 Mbps,   0mA] (xhci-hcd 0000:03:00.0) hub
  4-4               0e0f:0002 09 1IF  [USB 3.10,  5000 Mbps,   0mA] (VMware, Inc. VMware Virtual USB Hub) hub

Linux下的可行方案

1. 利用sysfs中的端口物理标识

对于xHCI控制器,每个物理端口在sysfs中有唯一的port目录,包含location属性,对应主板上的物理端口位置。例如:

# 查看root hub的端口目录
ls /sys/devices/pci0000:00/0000:00:15.0/0000:03:00.0/usb3/3-*

# 读取端口的物理位置信息
cat /sys/devices/pci0000:00/0000:00:15.0/0000:03:00.0/usb3/3-2/location

该location值由硬件提供,与设备插拔无关,可唯一标识物理端口。

2. 直接与USB hub通信(类似Windows的IOCTL思路)

Linux下可通过libusb库发送USB控制请求,直接查询hub的端口状态和物理标识:

  • 打开对应的root hub设备;
  • 发送USB_REQ_GET_PORT_STATUS请求获取端口状态;
  • 对于支持的hub,可通过自定义请求读取端口的物理位置信息。

3. udev规则辅助

编写udev规则,在设备插入时记录物理端口的唯一标识(如sysfs中的location或path属性),并关联到设备节点,应用程序可通过读取udev数据库获取对应关系。

关键注意事项

  • 部分旧款USB控制器(如EHCI/UHCI)可能不提供location属性,需优先使用xHCI控制器;
  • 若使用外接USB hub,需区分hub本身的物理端口与上游root hub的端口,需遍历USB拓扑结构获取完整物理路径。

内容的提问来源于stack exchange,提问作者EEALNT

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 03:10:54