使用udevadm(modinfo)查找linux下设备对应的驱动

    制作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。
    如同windows以设备的venderID/deviceID来匹配驱动(驱动也会有个兼容列表,列举了该驱动可以兼容的设备),linux也是通过这样的方式匹配设备和驱动。上面ls的结果中我们看到了eth0匹配到pcnet32驱动,我们来看下这个设备的vid/pid信息,udevadm也输出了设备的vid/pid(subsystem-vid/subsystem-pid如果有的话):

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)

最后,在看看我虚拟机上sda设备的驱动:

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)

有了这些信息后,就可以在制作initramfs时包含必要的驱动以减小initramfs的空间。

附注:

有时候/sys/class下可能会遇到模棱两可的设备,这时,可以到/sys/bus目录下最终定位设备~






你可能感兴趣的:(linux内核,LiveCD)