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
相关产品推荐
相关产品推荐

