![如何在 Linux 上查找与设备关联的驱动程序(模块)?](https://linux22.com/image/3372/%E5%A6%82%E4%BD%95%E5%9C%A8%20Linux%20%E4%B8%8A%E6%9F%A5%E6%89%BE%E4%B8%8E%E8%AE%BE%E5%A4%87%E5%85%B3%E8%81%94%E7%9A%84%E9%A9%B1%E5%8A%A8%E7%A8%8B%E5%BA%8F%EF%BC%88%E6%A8%A1%E5%9D%97%EF%BC%89%EF%BC%9F.png)
在 Linux 上,给出:
- 一个设备,例如
/dev/sda
, - 及其主要号码和次要号码,例如
8, 0
,
我如何知道哪个模块/驱动程序正在“驱动”它?
我可以深入研究/sys
或/proc
发现这一点吗?
答案1
要从sysfs
设备文件获取此信息,首先通过查看 的输出来确定主/次编号ls -l
,例如
$ ls -l /dev/sda
brw-rw---- 1 root disk 8, 0 Apr 17 12:26 /dev/sda
告诉8, 0
我们主数是8
,次数是0
。b
列表开头的 还告诉我们它是一个块设备。其他设备可能c
在开始时就有一个 for 字符设备。
如果您随后查看/sys/dev
,您将看到有两个目录。一通电话block
,一通电话char
。这里显而易见的是,它们分别适用于块设备和字符设备。然后,每个设备都可以通过该目录中的主/次编号进行访问。如果该设备有可用的驱动程序,则可以通过读取driver
此目录或device
子目录中的链接目标来找到该驱动程序。例如,对于我来说,/dev/sda
我可以简单地执行以下操作:
$ readlink /sys/dev/block/8\:0/device/driver
../../../../../../../bus/scsi/drivers/sd
这表明该sd
驱动程序已用于该设备。如果您不确定该设备是块设备还是字符设备,在 shell 中您可以简单地将这部分替换为*
.这也同样有效:
$ readlink /sys/dev/*/8\:0/device/driver
../../../../../../../bus/scsi/drivers/sd
块设备也可以通过 或 的名称直接/sys/block
访问/sys/class/block
。例如:
$ readlink /sys/block/sda/device/driver
../../../../../../../bus/scsi/drivers/sd
请注意,各个目录的存在/sys
可能会根据内核配置而变化。此外,并非所有设备都有device
子文件夹。例如,分区设备文件(例如/dev/sda1
.在这里,您必须访问整个磁盘的设备(不幸的是没有sys
这方面的链接)。
最后一件有用的事情是列出可用的所有设备的驱动程序。为此,您可以使用 glob 来选择驱动程序链接所在的所有目录。例如:
$ ls -l /sys/dev/*/*/device/driver && ls -l /sys/dev/*/*/driver
lrwxrwxrwx 1 root root 0 Apr 17 12:27 /sys/dev/block/11:0/device/driver -> ../../../../../../../bus/scsi/drivers/sr
lrwxrwxrwx 1 root root 0 Apr 17 12:26 /sys/dev/block/8:0/device/driver -> ../../../../../../../bus/scsi/drivers/sd
lrwxrwxrwx 1 root root 0 Apr 17 12:26 /sys/dev/block/8:16/device/driver -> ../../../../../../../bus/scsi/drivers/sd
lrwxrwxrwx 1 root root 0 Apr 17 12:26 /sys/dev/block/8:32/device/driver -> ../../../../../../../../../bus/scsi/drivers/sd
lrwxrwxrwx 1 root root 0 Apr 17 20:38 /sys/dev/char/189:0/driver -> ../../../../bus/usb/drivers/usb
lrwxrwxrwx 1 root root 0 Apr 17 20:38 /sys/dev/char/189:1024/driver -> ../../../../bus/usb/drivers/usb
lrwxrwxrwx 1 root root 0 Apr 17 20:38 /sys/dev/char/189:128/driver -> ../../../../bus/usb/drivers/usb
lrwxrwxrwx 1 root root 0 Apr 17 20:38 /sys/dev/char/189:256/driver -> ../../../../bus/usb/drivers/usb
lrwxrwxrwx 1 root root 0 Apr 17 20:38 /sys/dev/char/189:384/driver -> ../../../../bus/usb/drivers/usb
lrwxrwxrwx 1 root root 0 Apr 17 12:26 /sys/dev/char/189:512/driver -> ../../../../bus/usb/drivers/usb
lrwxrwxrwx 1 root root 0 Apr 17 12:26 /sys/dev/char/189:513/driver -> ../../../../../bus/usb/drivers/usb
lrwxrwxrwx 1 root root 0 Apr 17 12:26 /sys/dev/char/189:514/driver -> ../../../../../bus/usb/drivers/usb
lrwxrwxrwx 1 root root 0 Apr 17 12:26 /sys/dev/char/189:640/driver -> ../../../../bus/usb/drivers/usb
lrwxrwxrwx 1 root root 0 Apr 17 12:26 /sys/dev/char/189:643/driver -> ../../../../../bus/usb/drivers/usb
lrwxrwxrwx 1 root root 0 Apr 17 20:38 /sys/dev/char/189:768/driver -> ../../../../bus/usb/drivers/usb
lrwxrwxrwx 1 root root 0 Apr 17 20:38 /sys/dev/char/189:896/driver -> ../../../../bus/usb/drivers/usb
lrwxrwxrwx 1 root root 0 Apr 17 12:26 /sys/dev/char/21:0/device/driver -> ../../../../../../../bus/scsi/drivers/sd
lrwxrwxrwx 1 root root 0 Apr 17 12:26 /sys/dev/char/21:1/device/driver -> ../../../../../../../bus/scsi/drivers/sd
lrwxrwxrwx 1 root root 0 Apr 17 12:27 /sys/dev/char/21:2/device/driver -> ../../../../../../../bus/scsi/drivers/sr
lrwxrwxrwx 1 root root 0 Apr 17 12:26 /sys/dev/char/21:3/device/driver -> ../../../../../../../../../bus/scsi/drivers/sd
lrwxrwxrwx 1 root root 0 Apr 17 12:26 /sys/dev/char/250:0/device/driver -> ../../../../../../../bus/hid/drivers/hid-generic
lrwxrwxrwx 1 root root 0 Apr 17 12:26 /sys/dev/char/250:1/device/driver -> ../../../../../../../bus/hid/drivers/hid-generic
lrwxrwxrwx 1 root root 0 Apr 17 12:26 /sys/dev/char/250:2/device/driver -> ../../../../../../../bus/hid/drivers/hid-generic
lrwxrwxrwx 1 root root 0 Apr 17 12:26 /sys/dev/char/252:0/device/driver -> ../../../../../../../bus/scsi/drivers/sd
lrwxrwxrwx 1 root root 0 Apr 17 12:26 /sys/dev/char/252:1/device/driver -> ../../../../../../../bus/scsi/drivers/sd
lrwxrwxrwx 1 root root 0 Apr 17 12:27 /sys/dev/char/252:2/device/driver -> ../../../../../../../bus/scsi/drivers/sr
lrwxrwxrwx 1 root root 0 Apr 17 12:26 /sys/dev/char/252:3/device/driver -> ../../../../../../../../../bus/scsi/drivers/sd
lrwxrwxrwx 1 root root 0 Apr 17 19:53 /sys/dev/char/254:0/device/driver -> ../../../bus/pnp/drivers/rtc_cmos
lrwxrwxrwx 1 root root 0 Apr 17 19:53 /sys/dev/char/29:0/device/driver -> ../../../bus/platform/drivers/simple-framebuffer
lrwxrwxrwx 1 root root 0 Apr 17 19:53 /sys/dev/char/4:64/device/driver -> ../../../bus/pnp/drivers/serial
lrwxrwxrwx 1 root root 0 Apr 17 19:53 /sys/dev/char/4:65/device/driver -> ../../../bus/platform/drivers/serial8250
lrwxrwxrwx 1 root root 0 Apr 17 19:53 /sys/dev/char/4:66/device/driver -> ../../../bus/platform/drivers/serial8250
lrwxrwxrwx 1 root root 0 Apr 17 19:53 /sys/dev/char/4:67/device/driver -> ../../../bus/platform/drivers/serial8250
lrwxrwxrwx 1 root root 0 Apr 17 12:26 /sys/dev/char/6:0/device/driver -> ../../../bus/pnp/drivers/parport_pc
lrwxrwxrwx 1 root root 0 Apr 17 12:26 /sys/dev/char/99:0/device/driver -> ../../../bus/pnp/drivers/parport_pc
最后,为了稍微偏离这个问题,我将添加另一个/sys
glob 技巧,以更广泛地了解哪些设备正在使用哪些驱动程序(尽管不一定是那些具有设备文件的驱动程序):
find /sys/bus/*/drivers/* -maxdepth 1 -lname '*devices*' -ls
更新
更仔细地观察 的输出udevadm
,它似乎通过查找规范/sys
目录(如果您取消引用上面的主要/次要目录就会得到),然后沿着目录树向上工作,打印出它找到的任何信息来工作。通过这种方式,您可以获得有关父设备及其使用的任何驱动程序的信息。
为了进行实验,我编写了下面的脚本来遍历目录树并显示每个相关级别的信息。udev
似乎在每个级别寻找可读文件,其名称和内容都合并在ATTRS
.我没有这样做,而是显示每个级别的文件内容uevent
(似乎它的存在定义了一个不同的级别而不仅仅是一个子目录)。我还显示了我找到的任何子系统链接的基本名称,这显示了设备如何适合此层次结构。udevadm
不显示相同的信息,所以这是一个很好的补充工具。PCI
如果您想要将其他工具的输出(例如lshw
更高级别的设备)匹配,则父设备信息(例如信息)也很有用。
#!/bin/bash
dev=$(readlink -m $1)
# test for block/character device
if [ -b "$dev" ]; then
mode=block
elif [ -c "$dev" ]; then
mode=char
else
echo "$dev is not a device file" >&2
exit 1
fi
# stat outputs major/minor in hex, convert to decimal
data=( $(stat -c '%t %T' $dev) ) || exit 2
major=$(( 0x${data[0]} ))
minor=$(( 0x${data[1]} ))
echo -e "Given device: $1"
echo -e "Canonical device: $dev"
echo -e "Major: $major"
echo -e "Minor: $minor\n"
# sometimes nodes have been created for devices that are not present
dir=$(readlink -f /sys/dev/$mode/$major\:$minor)
if ! [ -e "$dir" ]; then
echo "No /sys entry for $dev" >&2
exit 3
fi
# walk up the /sys hierarchy one directory at a time
# stop when there are three levels left
while [[ $dir == /*/*/* ]]; do
# it seems the directory is only of interest if there is a 'uevent' file
if [ -e "$dir/uevent" ]; then
echo "$dir:"
echo " Uevent:"
sed 's/^/ /' "$dir/uevent"
# check for subsystem link
if [ -d "$dir/subsystem" ]; then
subsystem=$(readlink -f "$dir/subsystem")
echo -e "\n Subsystem:\n ${subsystem##*/}"
fi
echo
fi
# strip a subdirectory
dir=${dir%/*}
done
答案2
您可以使用该udevadm
工具来发现这一点。
命令是udevadm info -a -n /dev/sda
,然后查看DRIVER==
参数。
# udevadm info -a -n /dev/sda | grep -oP 'DRIVERS?=="\K[^"]+'
sd
ahci
这表明实际上有 2 个驱动程序参与提供该设备,sd
并且ahci
.第一个sd
直接负责设备/dev/sda
,但它使用ahci
下面的驱动程序。
该命令的输出udevadm
如下所示,并包含其工作原理的描述。
# udevadm info -a -n /dev/sda
Udevadm info starts with the device specified by the devpath and then
walks up the chain of parent devices. It prints for every device
found, all possible attributes in the udev rules key format.
A rule to match, can be composed by the attributes of the device
and the attributes from one single parent device.
looking at device '/devices/pci0000:00/0000:00:1f.2/ata1/host0/target0:0:0/0:0:0:0/block/sda':
KERNEL=="sda"
SUBSYSTEM=="block"
DRIVER==""
ATTR{ro}=="0"
ATTR{size}=="500118192"
ATTR{stat}==" 84786 1420 3091333 40215 966488 12528 14804028 2357668 0 1146934 2396653"
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:1f.2/ata1/host0/target0:0:0/0:0:0:0':
KERNELS=="0:0:0:0"
SUBSYSTEMS=="scsi"
DRIVERS=="sd"
ATTRS{rev}=="VZJ4"
ATTRS{type}=="0"
ATTRS{scsi_level}=="6"
ATTRS{model}=="LITEONIT LMT-256"
ATTRS{state}=="running"
ATTRS{queue_type}=="simple"
ATTRS{iodone_cnt}=="0x10daad"
ATTRS{iorequest_cnt}=="0x10ead1"
ATTRS{queue_ramp_up_period}=="120000"
ATTRS{device_busy}=="0"
ATTRS{evt_capacity_change_reported}=="0"
ATTRS{timeout}=="30"
ATTRS{evt_media_change}=="0"
ATTRS{ioerr_cnt}=="0x2"
ATTRS{queue_depth}=="31"
ATTRS{vendor}=="ATA "
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:1f.2/ata1/host0/target0:0:0':
KERNELS=="target0:0:0"
SUBSYSTEMS=="scsi"
DRIVERS==""
looking at parent device '/devices/pci0000:00/0000:00:1f.2/ata1/host0':
KERNELS=="host0"
SUBSYSTEMS=="scsi"
DRIVERS==""
looking at parent device '/devices/pci0000:00/0000:00:1f.2/ata1':
KERNELS=="ata1"
SUBSYSTEMS==""
DRIVERS==""
looking at parent device '/devices/pci0000:00/0000:00:1f.2':
KERNELS=="0000:00:1f.2"
SUBSYSTEMS=="pci"
DRIVERS=="ahci"
ATTRS{irq}=="41"
ATTRS{subsystem_vendor}=="0x144d"
ATTRS{broken_parity_status}=="0"
ATTRS{class}=="0x010601"
ATTRS{enabled}=="1"
ATTRS{consistent_dma_mask_bits}=="64"
ATTRS{dma_mask_bits}=="64"
ATTRS{local_cpus}=="0f"
ATTRS{device}=="0x1e03"
ATTRS{msi_bus}==""
ATTRS{local_cpulist}=="0-3"
ATTRS{vendor}=="0x8086"
ATTRS{subsystem_device}=="0xc0d3"
ATTRS{numa_node}=="-1"
ATTRS{d3cold_allowed}=="1"
looking at parent device '/devices/pci0000:00':
KERNELS=="pci0000:00"
SUBSYSTEMS==""
DRIVERS==""
答案3
使用命令 hwinfo以及输出型号和驱动程序。如果没有驱动程序则不会显示。以磁盘为例:
# hwinfo --block | grep -Ei "驱动程序\:|型号\:" 型号:“软盘” 型号:“富士通MHZ2080B” 驱动程序:“ahci”、“sd” 型号:“隔断” 型号:“隔断” 型号:“隔断” 型号:“通用多卡” 驱动程序:“ums-realtek”、“sd” 型号:“瑞昱USB2.0-CRW” 驱动程序:“ums-realtek”
对于网卡:
# hwinfo --网卡 | grep -Ei "驱动程序\:|型号\:" 型号:“Broadcom NetXtreme BCM5764M 千兆位以太网 PCIe” 驱动程序:“tg3” 型号:“英特尔无线 WiFi Link 5100” 驱动程序:“iwlwifi”
对于 USB 设备:
# hwinfo --usb | grep -Ei "驱动程序\:|型号\:" 型号:“Linux 3.11.10-7-desktop uhci_hcd UHCI 主机控制器” 司机:“枢纽” 型号:“Linux 3.11.10-7-desktop uhci_hcd UHCI 主机控制器” 司机:“枢纽” 型号:“IDEACOM IDC 6680” 驱动程序:“usbhid” [...]
使用 hwinfo --help 找出您可以查询的其他设备类型。 hwinfo 默认安装在 SUSE Linux 上。
答案4
lshw
是一个很棒的工具,可以列出您机器中找到的硬件。在运行之前您必须先安装它。
$ yum install lshw
$ apt-get install lshw
使用yum
或apt-get
取决于您所使用的系统。然后具体列出存储硬件:
# lshw -class storage
*-storage
description: SATA controller
product: 5 Series/3400 Series Chipset 4 port SATA AHCI Controller
vendor: Intel Corporation
physical id: 1f.2
bus info: pci@0000:00:1f.2
version: 06
width: 32 bits
clock: 66MHz
capabilities: storage msi pm ahci_1.0 bus_master cap_list
configuration: driver=ahci latency=0
resources: irq:41 ioport:1830(size=8) ioport:1824(size=4) ioport:1828(size=8) ioport:1820(size=4) ioport:1800(size=32) memory:f0305000-f03057ff
您可能想要运行它以root
获取所有信息。
否则,lspci
还可以提供有关您的硬件的信息:
$ lspci -vv
00:1f.2 SATA controller: Intel Corporation 5 Series/3400 Series Chipset 4 port SATA AHCI Controller (rev 06) (prog-if 01 [AHCI 1.0])
Subsystem: Dell Device 0434
Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- DisINTx+
Status: Cap+ 66MHz+ UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
Latency: 0
Interrupt: pin B routed to IRQ 41
Region 0: I/O ports at 1830 [size=8]
Region 1: I/O ports at 1824 [size=4]
Region 2: I/O ports at 1828 [size=8]
Region 3: I/O ports at 1820 [size=4]
Region 4: I/O ports at 1800 [size=32]
Region 5: Memory at f0305000 (32-bit, non-prefetchable) [size=2K]
Capabilities: <access denied>
Kernel driver in use: ahci
要找出设备的主设备号和次设备号,只需ls
在设备上运行即可。
$ ls -l /dev/sda
brw-rw----. 1 root disk 8, 0 13 avril 10:54 /dev/sda
在此输出中,b
inbrw-rw----.
表示这是一个块设备。数字8
和0
分别是设备的主编号和次编号。