4. USB4路由器配置空间访问
任务说明
USB4路由器在Linux中作为PCI设备暴露,其配置空间可通过两种方式访问:setpci命令直接读写,或通过sysfs的/sys/bus/pci/devices/接口读取。本案例定位USB4路由器设备,读取其厂商ID(Vendor ID)和设备ID(Device ID),并验证两种方式结果一致。
环境与依赖
- Linux内核支持USB4/Thunderbolt(
CONFIG_USB4) pciutils包(提供setpci和lspci)- root权限(访问配置空间需要)
实现代码
#!/bin/bash
# usb4_cfgspace.sh - 访问USB4路由器配置空间,读取厂商ID和设备ID
set -euo pipefail
# 1. 定位USB4路由器:PCI class 0x0c0330 为USB4/Thunderbolt主机控制器
# USB4路由器通常表现为PCI桥设备,class为0x060400
find_usb4_routers() {
local dev
for dev in /sys/bus/pci/devices/*; do
[ -f "$dev/class" ] || continue
local cls
cls=$(cat "$dev/class" 2>/dev/null) || continue
# 0x0c0330 = USB4 host controller, 0x060400 = PCI bridge (router)
case "$cls" in
0x0c0330|0x060400)
# 进一步确认是USB4设备:检查是否有usb4相关属性
if [ -d "$dev/usb4" ] || [ -e "$dev/removable" ]; then
echo "$dev"
fi
;;
esac
done
}
# 2. 通过sysfs读取厂商ID和设备ID
read_via_sysfs() {
local dev="$1"
local vid did
vid=$(cat "$dev/vendor" 2>/dev/null) || { echo "无法读取vendor"; return 1; }
did=$(cat "$dev/device" 2>/dev/null) || { echo "无法读取device"; return 1; }
echo "sysfs: vendor=$vid device=$did"
}
# 3. 通过setpci读取厂商ID和设备ID
# 配置空间偏移:0x00 = Vendor ID (16bit), 0x02 = Device ID (16bit)
read_via_setpci() {
local bdf="$1"
local vid did
vid=$(setpci -s "$bdf" 0x00.w 2>/dev/null) || { echo "setpci读取vendor失败"; return 1; }
did=$(setpci -s "$bdf" 0x02.w 2>/dev/null) || { echo "setpci读取device失败"; return 1; }
echo "setpci: vendor=0x$vid device=0x$did"
}
# 主流程
main() {
local routers
routers=$(find_usb4_routers)
if [ -z "$routers" ]; then
echo "未找到USB4路由器设备"
exit 1
fi
local dev bdf
for dev in $routers; do
bdf=$(basename "$dev")
echo "=== USB4路由器: $bdf ==="
read_via_sysfs "$dev"
read_via_setpci "$bdf"
echo ""
done
}
main "$@"
运行方式
chmod +x usb4_cfgspace.sh
sudo ./usb4_cfgspace.sh
验证方法与通过条件
- 脚本输出每个USB4路由器的BDF地址(如
0000:00:0d.0)。 sysfs行与setpci行的vendor/device值应一致(注意格式:sysfs为0x8086,setpci输出为8086,需统一比较)。- 用
lspci -s <BDF> -n交叉验证:输出格式为<class>: <vendor>:<device>,其中vendor和device应与脚本读取值匹配。 - 若系统无USB4设备,脚本输出"未找到USB4路由器设备"并退出码1,属正常情况。
关键点
- 配置空间偏移
0x00为Vendor ID(16位),0x02为Device ID(16位),setpci的.w后缀表示16位读取。 sysfs路径/sys/bus/pci/devices/<BDF>/vendor和/device直接暴露这两个字段,无需root即可读取(但setpci需要root)。- USB4路由器可能以PCI桥(class 0x060400)形式出现,需结合
usb4目录或removable属性进一步筛选。