制作initramfs的过程中需要为系统搭载的设备匹配驱动,linux下搜索驱动的方法众多,不同类型的设备可能会有不同的搜索方法,很难找到一种统一的方法。我摸索了很久,试图用/sys文件系统和udevadm来匹配各类设备对应的驱动。
windows会将设备分门别类的存放:比如将USB网卡/PCI网卡归为网卡类;移动硬盘/Scsi硬盘归入存储设备类。同样的归类方式也被linux所应用,linux将设备类存放在/sys/class下
eugen@ubuntu:/sys/class$ ls
ata_device dma input power_supply scsi_disk vc
ata_link dmi leds ppdev scsi_generic virtio-ports
ata_port drm mdio_bus ppp scsi_host vtconsole
backlight extcon mem printer sound watchdog
bdi firmware misc pwm spi_host
block graphics mmc_host regulator spi_master
bluetooth hidraw net rfkill spi_transport
bsg hwmon pci_bus rtc thermal
devfreq i2c-adapter powercap scsi_device tty
linux系统/sys/class下也有网卡类目录net/和块设备类block/等。进入net/目录可以看到比较清晰的各种设备:
eugen@ubuntu:/sys/class/net$ ls
eth0 lo
再进入eth0目录,可以看到这里的文件多数是/sys/device /sys/driver目录下的软连接
eugen@ubuntu:/sys/class/net$ cd eth0
eugen@ubuntu:/sys/class/net/eth0$ ll
total 0
drwxr-xr-x 5 root root 0 Jul 18 2016 ./
drwxr-xr-x 3 root root 0 Jul 18 2016 ../
-r--r--r-- 1 root root 4096 Jul 18 2016 addr_assign_type
...
lrwxrwxrwx 1 root root 0 Jul 18 2016 device -> ../../../0000:02:01.0/
-r--r--r-- 1 root root 4096 Jul 18 2016 dev_id
...
drwxr-xr-x 2 root root 0 Feb 8 07:47 statistics/
lrwxrwxrwx 1 root root 0 Jul 18 2016 subsystem -> ../../../../../../class/net/
-rw-r--r-- 1 root root 4096 Feb 8 07:47 tx_queue_len
-r--r--r-- 1 root root 4096 Jul 18 2016 type
-rw-r--r-- 1 root root 4096 Jul 18 2016 uevent
当然,也可以直接到/sys/device目录下通过总线关系来查找设备,不过这实在是太麻烦了:
eugen@ubuntu:/sys/class/net/eth0$ ls /sys/devices/pci0000\:00/
0000:00:00.0 0000:00:15.0 0000:00:16.1 0000:00:17.2 0000:00:18.3
0000:00:01.0 0000:00:15.1 0000:00:16.2 0000:00:17.3 0000:00:18.4
0000:00:07.0 0000:00:15.2 0000:00:16.3 0000:00:17.4 0000:00:18.5
0000:00:07.1 0000:00:15.3 0000:00:16.4 0000:00:17.5 0000:00:18.6
0000:00:07.3 0000:00:15.4 0000:00:16.5 0000:00:17.6 0000:00:18.7
0000:00:07.7 0000:00:15.5 0000:00:16.6 0000:00:17.7 firmware_node
0000:00:0f.0 0000:00:15.6 0000:00:16.7 0000:00:18.0 pci_bus
0000:00:10.0 0000:00:15.7 0000:00:17.0 0000:00:18.1 power
0000:00:11.0 0000:00:16.0 0000:00:17.1 0000:00:18.2 uevent
面对这么多数字编号的文件,鬼晓得哪个是我想要搜索的网卡设备...
回到我们的设备类目录中,现在我们知道系统上搭载了哪些设备后,就可以准备搜索这个设备对应的驱动程序了,这就要借助udevadm工具了。
eugen@ubuntu:/sys/class/net/eth0$ udevadm info -a -p /sys/class/net/eth0 # -p:要查询设备在/sys下的路径,-a:设备uevent属性,info:udevadm查询功能
looking at device '/devices/pci0000:00/0000:00:11.0/0000:02:01.0/net/eth0':
KERNEL=="eth0"
SUBSYSTEM=="net"
DRIVER==""
ATTR{mtu}=="1500"
ATTR{type}=="1"
ATTR{netdev_group}=="0"
ATTR{flags}=="0x1003"
ATTR{dormant}=="0"
ATTR{addr_assign_type}=="0"
ATTR{dev_id}=="0x0"
ATTR{iflink}=="2"
ATTR{addr_len}=="6"
ATTR{address}=="00:0c:29:72:87:d8"
ATTR{operstate}=="up"
ATTR{broadcast}=="ff:ff:ff:ff:ff:ff"
ATTR{tx_queue_len}=="1000"
ATTR{ifalias}==""
ATTR{ifindex}=="2"
ATTR{link_mode}=="0"
ATTR{carrier}=="1"
looking at parent device '/devices/pci0000:00/0000:00:11.0/0000:02:01.0':
KERNELS=="0000:02:01.0"
SUBSYSTEMS=="pci"
DRIVERS=="pcnet32" #<----------设备相关的驱动模块
ATTRS{irq}=="19"
ATTRS{subsystem_vendor}=="0x1022"
ATTRS{broken_parity_status}=="0"
ATTRS{class}=="0x020000"
ATTRS{label}=="Ethernet0"
ATTRS{enabled}=="1"
ATTRS{consistent_dma_mask_bits}=="32"
ATTRS{dma_mask_bits}=="32"
ATTRS{local_cpus}=="ff"
ATTRS{device}=="0x2000"
ATTRS{msi_bus}==""
ATTRS{local_cpulist}=="0-7"
ATTRS{vendor}=="0x1022"
ATTRS{acpi_index}=="16777736"
ATTRS{subsystem_device}=="0x2000"
ATTRS{d3cold_allowed}=="0"
looking at parent device '/devices/pci0000:00/0000:00:11.0':
KERNELS=="0000:00:11.0"
SUBSYSTEMS=="pci"
DRIVERS==""
ATTRS{irq}=="0"
ATTRS{subsystem_vendor}=="0x15ad"
ATTRS{broken_parity_status}=="0"
ATTRS{class}=="0x060401"
ATTRS{enabled}=="1"
ATTRS{consistent_dma_mask_bits}=="32"
ATTRS{dma_mask_bits}=="32"
ATTRS{local_cpus}=="ff"
ATTRS{device}=="0x0790"
ATTRS{msi_bus}=="1"
ATTRS{local_cpulist}=="0-7"
ATTRS{vendor}=="0x15ad"
ATTRS{subsystem_device}=="0x0790"
ATTRS{d3cold_allowed}=="0"
looking at parent device '/devices/pci0000:00':
KERNELS=="pci0000:00"
SUBSYSTEMS==""
DRIVERS==""
在udevadm是以设备树的形式由叶节点向根节点输出,行中最前面的是设备,往后是设备所挂载的插槽或者总线,以"looking at"分割每个节点。如果节点中"DRIVERS="之后不为空,则其中的内容就是与设备相匹配的驱动。比如这里的eth0设备,它的驱动程序是pcnet32。
looking at parent device '/devices/pci0000:00/0000:00:11.0/0000:02:01.0':
KERNELS=="0000:02:01.0"
SUBSYSTEMS=="pci"
DRIVERS=="pcnet32"
...
ATTRS{subsystem_vendor}=="0x1022" #subsystem_vid
...
ATTRS{device}=="0x2000" #deviceId
...
ATTRS{vendor}=="0x1022" #vendorIr
ATTRS{subsystem_device}=="0x2000" #subsystem_device
那pcnet32这个驱动兼容列表里是否包含这个设备呢?这需要通过modinfo来查看,这个工具除了显示模块依赖信息,还包含驱动兼容列表v****代表厂商id d****代表设备id sv***代表子厂商id sd***代表子设备id:
eugen@ubuntu:/sys/class/net/eth0$ modinfo pcnet32
filename: /lib/modules/3.13.0-32-generic/kernel/drivers/net/ethernet/amd/pcnet32.ko
license: GPL
description: Driver for PCnet32 and PCnetPCI based ethercards
author: Thomas Bogendoerfer
srcversion: C4943E68861BEE404D99565
alias: pci:v00001023d00002000sv*sd*bc02sc00i*
alias: pci:v00001022d00002000sv*sd*bc*sc*i* #<------这个alias完全匹配我们的设备,因此为我们的驱动加载了pcnet32模块
alias: pci:v00001022d00002001sv*sd*bc*sc*i*
depends: mii
intree: Y
vermagic: 3.13.0-32-generic SMP mod_unload modversions 686
signer: Magrathea: Glacier signing key
sig_key: A7:FC:65:90:FC:4A:8D:85:9A:AE:BD:A2:CA:5D:D0:47:16:24:4F:A0
sig_hashalgo: sha512
parm: debug:pcnet32 debug level (int)
parm: max_interrupt_work:pcnet32 maximum events handled per interrupt (int)
parm: rx_copybreak:pcnet32 copy breakpoint for copy-only-tiny-frames (int)
parm: tx_start_pt:pcnet32 transmit start point (0-3) (int)
parm: pcnet32vlb:pcnet32 Vesa local bus (VLB) support (0/1) (int)
parm: options:pcnet32 initial option setting(s) (0-15) (array of int)
parm: full_duplex:pcnet32 full duplex setting(s) (1) (array of int)
parm: homepna:pcnet32 mode for 79C978 cards (1 for HomePNA, 0 for Ethernet, default Ethernet (array of int)
ugen@ubuntu:/sys/class/block$ udevadm info -a -p /sys/class/block/sda
looking at device '/devices/pci0000:00/0000:00:10.0/host32/target32:0:0/32:0:0:0/block/sda':
KERNEL=="sda"
SUBSYSTEM=="block"
DRIVER==""
ATTR{ro}=="0"
ATTR{size}=="41943040"
ATTR{stat}==" 29068 11872 1077742 1948848 3000 6461 247072 1304440 0 198688 3252304"
ATTR{range}=="16"
ATTR{discard_alignment}=="0"
ATTR{events}==""
ATTR{ext_range}=="256"
ATTR{events_poll_msecs}=="-1"
ATTR{alignment_offset}=="0"
ATTR{inflight}==" 0 0"
ATTR{removable}=="0"
ATTR{capability}=="50"
ATTR{events_async}==""
looking at parent device '/devices/pci0000:00/0000:00:10.0/host32/target32:0:0/32:0:0:0':
KERNELS=="32:0:0:0"
SUBSYSTEMS=="scsi"
DRIVERS=="sd"
ATTRS{rev}=="1.0 "
ATTRS{type}=="0"
ATTRS{scsi_level}=="3"
ATTRS{model}=="VMware Virtual S"
ATTRS{state}=="running"
ATTRS{queue_type}=="simple"
ATTRS{iodone_cnt}=="0x7d82"
ATTRS{iorequest_cnt}=="0x7d82"
ATTRS{queue_ramp_up_period}=="120000"
ATTRS{device_busy}=="0"
ATTRS{evt_capacity_change_reported}=="0"
ATTRS{timeout}=="180"
ATTRS{evt_media_change}=="0"
ATTRS{ioerr_cnt}=="0x9"
ATTRS{queue_depth}=="32"
ATTRS{vendor}=="VMware, "
ATTRS{evt_soft_threshold_reached}=="0"
ATTRS{device_blocked}=="0"
ATTRS{evt_mode_parameter_change_reported}=="0"
ATTRS{evt_lun_change_reported}=="0"
ATTRS{evt_inquiry_change_reported}=="0"
ATTRS{iocounterbits}=="32"
ATTRS{eh_timeout}=="10"
looking at parent device '/devices/pci0000:00/0000:00:10.0/host32/target32:0:0':
KERNELS=="target32:0:0"
SUBSYSTEMS=="scsi"
DRIVERS==""
looking at parent device '/devices/pci0000:00/0000:00:10.0/host32':
KERNELS=="host32"
SUBSYSTEMS=="scsi"
DRIVERS==""
looking at parent device '/devices/pci0000:00/0000:00:10.0':
KERNELS=="0000:00:10.0"
SUBSYSTEMS=="pci"
DRIVERS=="mptspi" #磁盘设备的驱动程序是mptspi
ATTRS{irq}=="17"
ATTRS{subsystem_vendor}=="0x15ad"
ATTRS{broken_parity_status}=="0"
ATTRS{class}=="0x010000"
ATTRS{enabled}=="1"
ATTRS{consistent_dma_mask_bits}=="32"
ATTRS{dma_mask_bits}=="32"
ATTRS{local_cpus}=="ff"
ATTRS{config}==""
ATTRS{device}=="0x0030" #deviceID
ATTRS{msi_bus}==""
ATTRS{local_cpulist}=="0-7"
ATTRS{vendor}=="0x1000" #vid
ATTRS{subsystem_device}=="0x1976"
ATTRS{d3cold_allowed}=="0"
looking at parent device '/devices/pci0000:00':
KERNELS=="pci0000:00"
SUBSYSTEMS==""
DRIVERS==""
看看mptspi的兼容列表:
eugen@ubuntu:/sys/class/block$ modinfo mptspi
filename: /lib/modules/3.13.0-32-generic/kernel/drivers/message/fusion/mptspi.ko
version: 3.04.20
license: GPL
description: Fusion MPT SPI Host driver
author: LSI Corporation
srcversion: C704B01EA98284063D3E1F6
alias: pci:v00001000d00000040sv*sd*bc*sc*i*
alias: pci:v0000117Cd00000030sv*sd*bc*sc*i*
alias: pci:v00001000d00000030sv*sd*bc*sc*i* #这个alisa可以匹配我的磁盘
depends: mptscsih,mptbase
intree: Y
vermagic: 3.13.0-32-generic SMP mod_unload modversions 686
signer: Magrathea: Glacier signing key
sig_key: A7:FC:65:90:FC:4A:8D:85:9A:AE:BD:A2:CA:5D:D0:47:16:24:4F:A0
sig_hashalgo: sha512
parm: mpt_saf_te: Force enabling SEP Processor: enable=1 (default=MPTSCSIH_SAF_TE=0) (int)
附注:
有时候/sys/class下可能会遇到模棱两可的设备,这时,可以到/sys/bus目录下最终定位设备~