目录
[(1) /sys/bus/pci](#(1) /sys/bus/pci)
[(2) /sys/bus/pci/devices](#(2) /sys/bus/pci/devices)
[(3) /sys/bus/usb](#(3) /sys/bus/usb)
[(4) /sys/bus/usb/devices](#(4) /sys/bus/usb/devices)
一、lspci和lsusb作用和原理
1.作用
lspci和lsusb作用就是 "输出系统枚举到的pci/pcie和usb设备"
对于lspci,开头的三个数字分别是 总线号:设备号:功能号,后面的是ID映射。下面的示例表明系统枚举到了15个pci/pcie设备,共有3条pci总线。
对于lsusb,Bus是总线号,Device是设备号,ID是厂商号和产品号,后面的ID映射。下面的示例表明系统枚举到了5个USB设备,共有2条USB总线。
bash
zbc@zhouzheng:~$ lspci
00:00.0 Host bridge: Intel Corporation 10th Gen Core Processor Host Bridge/DRAM Registers (rev 05)
00:01.0 PCI bridge: Intel Corporation 6th-10th Gen Core Processor PCIe Controller (x16) (rev 05)
00:14.0 USB controller: Intel Corporation Comet Lake PCH-V USB Controller
00:14.2 Signal processing controller: Intel Corporation Comet Lake PCH-V Thermal Subsystem
00:16.0 Communication controller: Intel Corporation Comet Lake PCH-V HECI Controller
00:17.0 SATA controller: Intel Corporation 400 Series Chipset Family SATA AHCI Controller
00:1b.0 PCI bridge: Intel Corporation Comet Lake PCI Express Root Port #21 (rev f0)
00:1f.0 ISA bridge: Intel Corporation B460 Chipset LPC/eSPI Controller
00:1f.2 Memory controller: Intel Corporation Cannon Lake PCH Power Management Controller
00:1f.3 Audio device: Intel Corporation Comet Lake PCH-V cAVS
00:1f.4 SMBus: Intel Corporation Comet Lake PCH-V SMBus Host Controller
00:1f.6 Ethernet controller: Intel Corporation Ethernet Connection (12) I219-V
01:00.0 VGA compatible controller: Advanced Micro Devices, Inc. [AMD/ATI] Oland [Radeon HD 8570 / R5 430 OEM / R7 240/340 / Radeon 520 OEM] (rev 87)
01:00.1 Audio device: Advanced Micro Devices, Inc. [AMD/ATI] Oland/Hainan/Cape Verde/Pitcairn HDMI Audio [Radeon HD 7000 Series]
02:00.0 Non-Volatile memory controller: Phison Electronics Corporation PS5013 E13 NVMe Controller (rev 01)
zbc@zhouzheng:~$ lsusb
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 044: ID 1c4f:0002 SiGma Micro Keyboard TRACER Gamma Ivory
Bus 001 Device 004: ID 05e3:0608 Genesys Logic, Inc. Hub
Bus 001 Device 002: ID 12d1:10a2 Huawei Technologies Co., Ltd.
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
2.原理
lspci和lsusb并非直接去扫描设备,而是由内核去扫描这些设备,并将所有枚举到的设备信息存储到指定文件下,枚举到pci设备将其信息存储到 /sys/bus/pci 目录下,枚举到usb设备将其信息存储到 /sys/bus/usb 目录下。
lspci去 /sys/bus/pci/devices 路径下读取设备,lsusb去 /sys/bus/usb/devices 路径下读取设备。主要是读取设备ID(vendorID和deviceID),再通过 /usr/share/misc/pci.ids 和 /usr/share/misc/usb.ids 去查找设备描述,最后输出。
接下来将探讨 /sys/bus/pci 和 /sys/bus/usb 目录下究竟有哪些文件,存储什么设备信息:
(1) /sys/bus/pci
- devices:存储系统枚举到的所有pci设备,每个pci设备都有自己的目录,本质是个软链接(指向 /sys/devices 目录下对应的目录,后续讨论),目录名就是pci设备地址
- drivers:存储所有pci设备已加载的驱动,每个驱动都有自己的目录,目录名就是驱动名称
- slots:存储所有支持热插拔的pci设备
- drivers_autoprobe:自动加载驱动开关,默认为1,表示内核检测到新的硬件设备后会自动去匹配已安装的驱动程序并加载,如果设置为0则不会自动匹配驱动
- drivers_probe:手动加载驱动开关,只写文件,如果某个pci设备加载驱动失败了或者未加载驱动,向这个文件中写入指定pci设备的设备地址(包括域),内核就会重新去匹配这个设备的驱动
- rescan:重新扫描开关,只写文件,向文件中写入1(echo 1 | sudo tee /sys/bus/pci/rescan),内核会重新扫描所有硬件设备
- uevent:用户空间事件,只写文件。向该文件中写入udev规则,内核收到后会将udev规则通过Netlink广播给udev,由udev完成指令。常规的流程是,当内核检测到设备时,通过Netlink广播消息"有一个新设备到来,ID是 xxxx:xxxx",这个消息就是uevent,udev收到消息后再去匹配并加载驱动。如果udev启动比较晚,没有接收到广播消息,那么系统启动脚本会自动向uevent文件中写入指令,让内核重新发送广播,因此,正常它不需要用户来操作,都是自动化的。(注意,/sys/bus/pci/devices 目录下的每个设备都有自己的uevent,/sys/bus/pci/uevent 是属于PCI总线子系统的,仅仅是为了统一性增加的这个文件,实际上并不需要使用,仅使用各个设备的uevent即可)
bash
zbc@zhouzheng:~$ ls -l /sys/bus/pci/
总用量 0
drwxr-xr-x 2 root root 0 2月 2 16:28 devices
drwxr-xr-x 24 root root 0 2月 2 16:28 drivers
-rw-r--r-- 1 root root 4096 2月 2 16:28 drivers_autoprobe
--w------- 1 root root 4096 2月 2 16:28 drivers_probe
--w--w---- 1 root root 4096 2月 2 16:28 rescan
-rw-r--r-- 1 root root 4096 2月 2 16:28 resource_alignment
drwxr-xr-x 2 root root 0 2月 2 16:28 slots
--w------- 1 root root 4096 1月 14 11:02 uevent
(2) /sys/bus/pci/devices
/sys/bus/pci/devices 目录下存放的其实是软链接,指向的是 /sys/devices/pci0000:00,即0号PCI域的0号总线。所有pci总线都指向0号总线,因为这是其他的总线都是挂在0号总线上的。真实路径/sys/devices/pci0000:00按照层级结构存放所有pci设备目录,桥接器设备目录下存放着新总线上的设备目录。
接下来以 0000:00:1f.6 设备(有线网卡)为例,分析设备目录下存储着哪些数据:
- 设备身份信息
- vendor:芯片厂商号
- device:芯片设备号
- subsystem_vendor:板卡厂商号
- subsystem_device:板卡设备号
- class:设备类型号(16进制,以0x020000为例,高8位是大类,0x02表示网络控制器,中8位是子类,0x00表示以太网控制器,低8位是标准接口,0x00表示标准的以太网接口)
- revision:修订版本号
- modalias:设备模块别名,本质就是将vendor、device、subsystem_vendor、subsystem_device和class拼接在一起(pci:v00008086d00000D55sv00001849sd00000D55bc02sc00i00)。内核通过netlink广播发出的数据就是这个,udev设备管理器也是通过这个来匹配驱动的。
- 硬件交互接口
- config:存储设备寄存器中的数据,二进制数据,使用hexdump -C config 查看,内核会直接去读取设备芯片内部的寄存器。
- resource:存储设备申请的内存地址范围和I/O端口
- resource0:是该PCI设备的BAR0物理地址空间的虚拟映射,直接暴露用于控制设备行为、查询实时状态及管理 DMA 传输的片上功能寄存器组的数据。使用mmap技术将这个文件映射到用户空间内存,向这个内存中写数据,相当于直接向设备的寄存器中写数据。
- 控制开关
- enable:启用/禁用设备,1表示启用,0表示禁用
- remove:只写文件,写入1表示移除该设备,但仅仅是逻辑上的移除。需要到该设备的上一层桥接器rescan才能重新识别到该设备
- reset:重置设备,写入1则该设备将清除所有寄存器数据,重新加载固件,重新建立物理链路(PCI、PHY)
- driver_override:强制绑定驱动。该文件默认值为 (null),写入指定驱动名称,例如 echo "指定驱动" | sudo tee /sys/bus/pci/devices/0000:00:1f.6/driver_override,那么该设备以后将只能加载指定的驱动,但是当前正在运行的驱动并不会主动卸载。接下来还需要echo "0000:00:1f.6" | sudo tee /sys/bus/pci/dirvers/"已加载的驱动"/ubind 卸载旧驱动,再 echo "0000:00:1f.6" | sudo tee /sys/bus/pci/drivers_probe 重新加载这个设备的驱动。
- 软链接
- driver:指向当前设备使用的驱动目录
- subsystem:指向设备所属的总线类型
- firmnode:执行ACPI表中定义的节点,说明该设备是固化在主板上的,并非插拔式设备
- 目录
- net:网络入口,该设备是一个以太网控制器
- msi_irqs:存放中断向量信息
- power:电源管理
- ptp:高精度时钟
bash
zbc@zhouzheng:~$ ls -l /sys/bus/pci/devices/
总用量 0
lrwxrwxrwx 1 root root 0 2月 2 16:52 0000:00:00.0 -> ../../../devices/pci0000:00/0000:00:00.0
lrwxrwxrwx 1 root root 0 2月 2 16:52 0000:00:01.0 -> ../../../devices/pci0000:00/0000:00:01.0
lrwxrwxrwx 1 root root 0 2月 2 16:52 0000:00:14.0 -> ../../../devices/pci0000:00/0000:00:14.0
lrwxrwxrwx 1 root root 0 2月 2 16:52 0000:00:14.2 -> ../../../devices/pci0000:00/0000:00:14.2
lrwxrwxrwx 1 root root 0 2月 2 16:52 0000:00:16.0 -> ../../../devices/pci0000:00/0000:00:16.0
lrwxrwxrwx 1 root root 0 2月 2 16:52 0000:00:17.0 -> ../../../devices/pci0000:00/0000:00:17.0
lrwxrwxrwx 1 root root 0 2月 2 16:52 0000:00:1b.0 -> ../../../devices/pci0000:00/0000:00:1b.0
lrwxrwxrwx 1 root root 0 2月 2 16:52 0000:00:1f.0 -> ../../../devices/pci0000:00/0000:00:1f.0
lrwxrwxrwx 1 root root 0 2月 2 16:52 0000:00:1f.2 -> ../../../devices/pci0000:00/0000:00:1f.2
lrwxrwxrwx 1 root root 0 2月 2 16:52 0000:00:1f.3 -> ../../../devices/pci0000:00/0000:00:1f.3
lrwxrwxrwx 1 root root 0 2月 2 16:52 0000:00:1f.4 -> ../../../devices/pci0000:00/0000:00:1f.4
lrwxrwxrwx 1 root root 0 2月 2 16:52 0000:00:1f.6 -> ../../../devices/pci0000:00/0000:00:1f.6
lrwxrwxrwx 1 root root 0 2月 2 16:52 0000:01:00.0 -> ../../../devices/pci0000:00/0000:00:01.0/0000:01:00.0
lrwxrwxrwx 1 root root 0 2月 2 16:52 0000:01:00.1 -> ../../../devices/pci0000:00/0000:00:01.0/0000:01:00.1
lrwxrwxrwx 1 root root 0 2月 2 16:52 0000:02:00.0 -> ../../../devices/pci0000:00/0000:00:1b.0/0000:02:00.0
bash
zbc@zhouzheng:~$ ls -l /sys/bus/pci/devices/0000:00:1f.6/
总用量 0
-r--r--r-- 1 root root 4096 2月 3 18:11 ari_enabled
-rw-r--r-- 1 root root 4096 2月 3 18:11 broken_parity_status
-r--r--r-- 1 root root 4096 2月 4 13:17 class
-rw-r--r-- 1 root root 256 1月 14 11:02 config
-r--r--r-- 1 root root 4096 2月 3 18:11 consistent_dma_mask_bits
-rw-r--r-- 1 root root 4096 2月 3 18:11 d3cold_allowed
-r--r--r-- 1 root root 4096 2月 4 13:17 device
-r--r--r-- 1 root root 4096 2月 3 18:11 dma_mask_bits
lrwxrwxrwx 1 root root 0 1月 28 22:29 driver -> ../../../bus/pci/drivers/e1000e
-rw-r--r-- 1 root root 4096 2月 3 18:11 driver_override
-rw-r--r-- 1 root root 4096 2月 3 18:11 enable
lrwxrwxrwx 1 root root 0 2月 3 18:11 firmware_node -> ../../LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:4c
-r--r--r-- 1 root root 4096 2月 3 18:11 index
-r--r--r-- 1 root root 4096 2月 4 13:17 irq
-r--r--r-- 1 root root 4096 2月 4 13:17 label
-r--r--r-- 1 root root 4096 2月 3 18:11 local_cpulist
-r--r--r-- 1 root root 4096 2月 3 18:11 local_cpus
-r--r--r-- 1 root root 4096 1月 28 22:29 modalias
-rw-r--r-- 1 root root 4096 2月 3 18:11 msi_bus
drwxr-xr-x 2 root root 0 2月 4 13:17 msi_irqs
drwxr-xr-x 3 root root 0 1月 28 19:18 net
-rw-r--r-- 1 root root 4096 1月 29 11:36 numa_node
drwxr-xr-x 2 root root 0 2月 2 09:32 power
drwxr-xr-x 3 root root 0 2月 4 13:17 ptp
--w--w---- 1 root root 4096 2月 3 18:11 remove
--w--w---- 1 root root 4096 2月 3 18:11 rescan
--w------- 1 root root 4096 2月 3 18:11 reset
-r--r--r-- 1 root root 4096 2月 4 13:17 resource
-rw------- 1 root root 131072 2月 3 18:11 resource0
-r--r--r-- 1 root root 4096 2月 3 18:11 revision
lrwxrwxrwx 1 root root 0 1月 29 11:34 subsystem -> ../../../bus/pci
-r--r--r-- 1 root root 4096 2月 4 13:17 subsystem_device
-r--r--r-- 1 root root 4096 2月 4 13:17 subsystem_vendor
-rw-r--r-- 1 root root 4096 1月 14 11:02 uevent
-r--r--r-- 1 root root 4096 2月 4 13:17 vendor
(3) /sys/bus/usb
- devices:存储所有系统枚举到的usb设备,每个usb设备都有自己的目录,目录名是"总线号-端口号",这些目录本质是一个软链接,指向 /sys/devices/ 下的对应目录
- drivers:存储所有usb设备已加载的驱动,每个驱动有自己的目录,目录名就是驱动名
- drivers_autoprobe:自动加载驱动开关,读写文件,默认为1,表示系统枚举到usb设备会自动加载驱动,如果写入0,则不会自动加载驱动
- drivers_probe:手动加载驱动开关,只写文件,写入指定usb设备ID,例如"1-1:1.0",内核会为该设备重新匹配并加载驱动
- uevent:用户空间事件,只写文件,向其中写入udev规则,内核接收到后会通过Netlink广播给udev设备管理器,由udev设备管理器执行指令。
bash
zbc@zhouzheng:~$ ls -l /sys/bus/usb
总用量 0
drwxr-xr-x 2 root root 0 2月 5 10:05 devices
drwxr-xr-x 10 root root 0 2月 4 18:00 drivers
-rw-r--r-- 1 root root 4096 2月 4 18:00 drivers_autoprobe
--w------- 1 root root 4096 2月 4 18:00 drivers_probe
--w------- 1 root root 4096 1月 14 11:02 uevent
(4) /sys/bus/usb/devices
/sys/bus/usb/devices 目录下存放的都是软链接,指向 /sys/devices/pci0000:00 目录下的各个子目录,因为USB控制器本身也是挂在PCI总线的,所以也指向pci0000:00这个目录。
接下来以USB设备 1-5 为例,分析usb设备目录下存放着的内容:
- 接口目录
- 1-5:1.0:证明usb设备1-5是一个复合设备,拥有多个功能。这里的 1-5:1.0 分别表示 总线号-端口号:配置号:功能号
- 1-5:1.1:同上
- 设备身份信息
- idVendor:厂商ID
- idProduct:产品ID
- manufacturer:厂商名称(人类可读字符串)
- product:产品名称(人类可读字符串)
- bcdDevice:设备固件版本号
- version:支持的USB协议(例如2.00表示USB2.0,1.10表示USB1.1)
- 连接状态
- speed:当前通信速率,1.5表示低速,12表示全速,480表示高速,5000表示超高速
- busnum:所属总线号
- devnum:设备号,由内核临时分配,每次插拔都会变化
- devpath:物理拓扑路径,如果插在额外的hub集线器,那么就是端口号,如果插在额外的集线器上就是 父端口号.子端口号
- port:软链接,指向真实的物理端口
- driver:软链接,指向当前正在使用的驱动
- 控制开关
- authorized:设备锁,默认为1,如果设置为0,表示禁止该设备与驱动通信
- power:电源配置
- remove:只写文件,写入1表示逻辑上移除该usb设备
- uevent:用户空间事件
- 配置
- bDeviceClass:设备类代码
- bNumInterfaces:设备接口数量,接口数量大于1就表明这个设备是一个复合设备
- bMaxPower:设备申请的最大电流
- configuration:设备配置的字符串描述
- descriptors:二进制文件,存储设备的所有原始描述符数据
bash
zbc@zhouzheng:~$ ls -l /sys/bus/usb/devices/
总用量 0
lrwxrwxrwx 1 root root 0 2月 2 16:55 1-0:1.0 -> ../../../devices/pci0000:00/0000:00:14.0/usb1/1-0:1.0
lrwxrwxrwx 1 root root 0 2月 2 16:55 1-1 -> ../../../devices/pci0000:00/0000:00:14.0/usb1/1-1
lrwxrwxrwx 1 root root 0 2月 2 16:55 1-10 -> ../../../devices/pci0000:00/0000:00:14.0/usb1/1-10
lrwxrwxrwx 1 root root 0 2月 2 16:55 1-10:1.0 -> ../../../devices/pci0000:00/0000:00:14.0/usb1/1-10/1-10:1.0
lrwxrwxrwx 1 root root 0 2月 2 16:55 1-1:1.0 -> ../../../devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1:1.0
lrwxrwxrwx 1 root root 0 2月 2 16:55 1-5 -> ../../../devices/pci0000:00/0000:00:14.0/usb1/1-5
lrwxrwxrwx 1 root root 0 2月 2 16:55 1-5:1.0 -> ../../../devices/pci0000:00/0000:00:14.0/usb1/1-5/1-5:1.0
lrwxrwxrwx 1 root root 0 2月 2 16:55 1-5:1.1 -> ../../../devices/pci0000:00/0000:00:14.0/usb1/1-5/1-5:1.1
lrwxrwxrwx 1 root root 0 2月 2 16:55 2-0:1.0 -> ../../../devices/pci0000:00/0000:00:14.0/usb2/2-0:1.0
lrwxrwxrwx 1 root root 0 2月 2 16:55 usb1 -> ../../../devices/pci0000:00/0000:00:14.0/usb1
lrwxrwxrwx 1 root root 0 2月 2 16:55 usb2 -> ../../../devices/pci0000:00/0000:00:14.0/usb2
bash
zbc@zhouzheng:~$ ls -l /sys/bus/usb/devices/1-5/
总用量 0
drwxr-xr-x 5 root root 0 1月 30 13:12 1-5:1.0
drwxr-xr-x 5 root root 0 1月 30 13:12 1-5:1.1
-rw-r--r-- 1 root root 4096 2月 5 11:08 authorized
-rw-r--r-- 1 root root 4096 2月 5 11:08 avoid_reset_quirk
-r--r--r-- 1 root root 4096 2月 5 09:55 bcdDevice
-rw-r--r-- 1 root root 4096 2月 5 10:51 bConfigurationValue
-r--r--r-- 1 root root 4096 2月 5 09:55 bDeviceClass
-r--r--r-- 1 root root 4096 2月 5 09:55 bDeviceProtocol
-r--r--r-- 1 root root 4096 2月 5 09:55 bDeviceSubClass
-r--r--r-- 1 root root 4096 2月 5 10:51 bmAttributes
-r--r--r-- 1 root root 4096 2月 5 10:51 bMaxPacketSize0
-r--r--r-- 1 root root 4096 2月 5 10:51 bMaxPower
-r--r--r-- 1 root root 4096 2月 5 10:51 bNumConfigurations
-r--r--r-- 1 root root 4096 2月 5 09:55 bNumInterfaces
-r--r--r-- 1 root root 4096 2月 5 06:25 busnum
-r--r--r-- 1 root root 4096 2月 5 10:51 configuration
-r--r--r-- 1 root root 65553 2月 5 06:25 descriptors
-r--r--r-- 1 root root 4096 2月 5 11:08 dev
-r--r--r-- 1 root root 4096 2月 5 06:25 devnum
-r--r--r-- 1 root root 4096 2月 5 11:08 devpath
lrwxrwxrwx 1 root root 0 2月 5 10:51 driver -> ../../../../../bus/usb/drivers/usb
drwxr-xr-x 3 root root 0 2月 5 11:08 ep_00
-r--r--r-- 1 root root 4096 2月 5 09:55 idProduct
-r--r--r-- 1 root root 4096 2月 5 09:55 idVendor
-r--r--r-- 1 root root 4096 2月 5 11:08 ltm_capable
-r--r--r-- 1 root root 4096 2月 5 09:55 manufacturer
-r--r--r-- 1 root root 4096 2月 5 10:51 maxchild
lrwxrwxrwx 1 root root 0 2月 5 11:08 port -> ../1-0:1.0/usb1-port5
drwxr-xr-x 2 root root 0 2月 5 11:08 power
-r--r--r-- 1 root root 4096 2月 5 09:55 product
-r--r--r-- 1 root root 4096 2月 5 11:08 quirks
-r--r--r-- 1 root root 4096 2月 5 11:08 removable
--w------- 1 root root 4096 2月 5 11:08 remove
-r--r--r-- 1 root root 4096 2月 5 11:08 rx_lanes
-r--r--r-- 1 root root 4096 2月 5 06:25 speed
lrwxrwxrwx 1 root root 0 1月 30 13:12 subsystem -> ../../../../../bus/usb
-r--r--r-- 1 root root 4096 2月 5 11:08 tx_lanes
-rw-r--r-- 1 root root 4096 1月 30 13:12 uevent
-r--r--r-- 1 root root 4096 2月 5 11:08 urbnum
-r--r--r-- 1 root root 4096 2月 5 10:51 version
二、PCI总线和USB总线的理解
1.PCI总线
PCI总线本质就是印刷在主板上的铜线,从CPU内部引出,连接着主板上的pci物理插槽,以及许多嵌入在主板上的芯片,例如USB控制器芯片、网卡芯片。
2.USB总线
USB总线本质也是印刷在主板上的铜线,从USB控制器内部的根集线器引出,连接到物理的usb插槽。
三、PCI设备和USB设备的枚举原理
1.PCI设备枚举
PCI设备硬件上会留有寄存器,用于存储设备的厂商号、设备号以及设备类型等信息。当系统启动时,扫描PCI总线上的每一个位置是否有设备,如果检查到设备就读取设备的信息,并将设备信息注册到sysfs虚拟系统中,内核再通过Netlink广播发送数据(本质是设备的modalias),设备管理器udev收到广播后,拿着设备的modalias去匹配系统中已安装的驱动,本质是去 /lib/modules/$(uname -r)/modules.alias文件中查找,匹配成功则加载驱动。如果扫描到桥接器,则会进入新的总线中继续扫描,重复之前的操作,本质就是深度优先搜索。
2.USB设备枚举
USB端口中有上拉电阻和下拉电阻,当有USB设备插入时,USB控制器中的根集线器感受到电平变化,就知道有新的USB设备到来,通知USB控制器。随后USB控制器复位这个USB端口,让USB设备初始化,处于地址0。接下来内核查找USB总线上空闲的位置,为USB设备分配设备号,例如为5,那么这个USB设备就处于地址5,接下来USB设备只需要响应地址5即可。然后USB控制器就读取这个USB设备的信息,并注册到sysfs虚拟系统中,并通过Netlink广播发送数据,即modalias,设备管理器udev收到modalias后就去匹配并加载驱动。和PCI设备不同的是,USB设备绑定驱动是按照接口来的,不同的USB设备接口绑定不同的驱动,如果一个USB设备有多个接口,就会绑定多个驱动。