我该如何找出内核加载了哪个RTC模块?

3

在使用从Ubuntu OS 16.04获取的配置文件编译我的内核时,我注意到我正在编译大量RTC驱动程序,基本上是每个可能的驱动程序:

... snip ...
CC [M]  drivers/rtc/rtc-bq4802.o
CC [M]  drivers/rtc/rtc-da9052.o 
CC [M]  drivers/rtc/rtc-da9055.o
... more of those ...
...

我想知道是否可以摆脱那些很多的驱动程序,所以我开始寻找如何做到:

  1. 在查看lsmod时,我没有看到RTC驱动程序
  2. lshw也没有帮助
  3. lspci -v也没有提供太多信息。

更低级别的检查显示设备存在:

$ ls -l /dev/rtc
lrwxrwxrwx 1 root root 4 Dec 18 09:54 /dev/rtc -> rtc0

最接近获取更多信息的是在/sys/class/rtc/目录中:
$ sudo cat /sys/class/rtc/rtc0/device/rtc/rtc0/name 
rtc_cmos

这是否意味着,我的内核只使用了 rtc_cmos 驱动程序?

  • 这是否意味着我不需要所有其他驱动程序?
  • 这是否意味着我的笔记本电脑使用了兼容CMOS的硬件?
  • 另外,为什么 modinfo rtc_cmos 没有返回任何内容?
2个回答

8

我知道OP已经得到了关于狭窄问题的正确答案,但是我认为更符合SO精神的是将答案概括,因此我发帖希望它对回答概括性问题有所帮助:如何查找/dev/xyz使用的驱动程序?

选项1:浏览/sys文件系统

假设您已经挂载了sysfs(通常在/sys上;但我还没有找到一个不这样做的发行版),为什么不问内核呢?

1. 找出设备类型(字符/块)和节点号

$ ls -l /dev/rtc0
crw------- 1 root root 249, 0 2019-04-01 15:22:29 /dev/rtc0
^                       ^   ^
+-> character device    +---+-> Major and minor node numbers.

第二步,将数字替换到/sys/dev路径中,如下所示(char 表示字符设备,block表示块设备)。

$ cat /sys/dev/char/249:0/name
rtc_cmos 00:00

这是连接到节点的内核模块的名称。无论模块是链接到内核还是通过modprobe加载,它都起同样的作用。(而00:00不是RTC时钟中的时间。据我所知,它是父驱动程序或总线上其“功能”的设备地址;但请不要相信我,我只是隐约记得)。
附带说明,请放心探索此文件系统。它可被非root用户读取(除了安全敏感的部分,大多数可用root读取),完全可安全阅读,并且您可以在其中找到许多硬件和低级软件配置信息。与/proc的大部分内容不同,/sys的大部分内容是可写的,并且由程序用于更改运行中的内核和设备参数。例如,sysctl完全通过这个目录实现。但我跑题了。

选项2:使用udevadm查找/sys

如果您有可用的udevadm,请向它询问关于设备的所有已知信息(该程序接受设备的/dev/sys路径):

$ udevadm info -a /dev/rtc0

[...snip intro text...]

  looking at device '/devices/pnp0/00:00/rtc/rtc0':
    KERNEL=="rtc0"
    SUBSYSTEM=="rtc"
    DRIVER==""
    ATTR{date}=="2019-06-27"
    ATTR{hctosys}=="1"
    ATTR{max_user_freq}=="64"
    ATTR{name}=="rtc_cmos 00:00"
    ATTR{since_epoch}=="1561605536"
    ATTR{time}=="03:18:56"
    ATTR{wakealarm}==""

  looking at parent device '/devices/pnp0/00:00':
    KERNELS=="00:00"
    SUBSYSTEMS=="pnp"
    DRIVERS=="rtc_cmos"   <== THIS
    ATTRS{id}=="PNP0b00"
    ATTRS{nvram}==""
    ATTRS{options}==""

  looking at parent device '/devices/pnp0':
    KERNELS=="pnp0"
    SUBSYSTEMS==""
    DRIVERS==""
info 命令告诉 udevadm 输出设备的全部信息,-a 选项则用于沿着父级驱动程序/总线链向上获取信息。下面可以看到父设备 /devices/pnp0/00:00 使用了驱动程序 rtc_cmos,并在由另一个设备 pnp0 创建的总线上被发现/激活,该设备是即插即用总线枚举器。

顺便提一下,udevadm 打印的名称也是 sysfs 中的路径,即您可以通过在 sysfs 挂载点 /sys 前缀来在普通文件空间中查看它们。
$ ls -l /sys/devices/pnp0/00:00/rtc/rtc0
$ ls -l /sys/dev/char/249:0/

这两个命令将生成相同的输出。

有一个注意点,与“普通”文件系统不同,sysfs硬链接目录,因此不要尝试在其中进行任何递归搜索(例如“find . /sys”或“ls -R /sys”)--这些程序将在文件系统上无限循环后崩溃。

那么,/sys/class/rtc/rtc0/device/rtc/rtc0怎么样?

正如您所注意到的,从sysfs根目录到设备参数节点有多个路径。哪一个才是真正的诺依曼机器?

  • 并非每个设备都通过/dev文件系统(或任何其他文件系统)具有接口(与/dev没有任何特殊之处--它只是一个tempfs;/dev/rtc0是特殊的文件)。您无法通过路径/sys/dev/*找到这些设备。

  • 并非每个设备都是子系统的一部分,这也是可选的。您无法通过/sys/class*发现这些设备。因此,这也是一个有用但可选的链接。请注意,此节点不同:它必须公开特定于子系统的参数。在我们的情况下,所有RTC时钟都公开了一组rtcsubsystem通用的已知设置。

  • 现在,/sys/devices/pnp0/00:00/rtc/rtc0是到设备sysfs节点的主要、规范路径。它始终对应于其在系统总线和驱动程序层次结构中的拓扑位置:这是设备rtc的实例rtc0,在总线pnp0上的地址为00:00。它并不总是对应于其物理连接;在我们的情况下,pnp0是一个虚拟总线,它不连接设备到物理总线和桥接器,只发现和枚举它们。这是udev用来唯一标识设备的规范名称(当然,去掉/sys前缀--它只是一个挂载点)。

  • 最后,内核模块不必在sysfs中公开任何内容。仅需从用户空间发现内核模块即可。但如果它确实这样做了,那么该模块将决定公开什么,而它的父级和祖先将决定它在devices根下的sysfs中的位置


4
这意味着我不需要其他所有驱动程序吗? 这是否意味着我的笔记本电脑使用兼容CMOS的硬件?
是的,如果您只关心RTC,则只需要rtc_cmos。 如果您的PC足够新,则rtc-efi可能是一个有效的替代方案。
此外,为什么modinfo rtc_cmos没有返回任何内容?
因为该驱动程序可能已经被静态编译到内核中,而不是作为模块。请检查您的配置中是否存在CONFIG_RTC_DRV_CMOS=y。

是的!$ grep CMOS /usr/src/linux/.config CONFIG_GENERIC_CMOS_UPDATE=y CONFIG_RTC_DRV_CMOS=y - oz123
rtc-efi是efi模块的一部分吗?我看到CONFIG_EFI=y,但是在grep CONFIG_RTC /usr/src/linux/.config | grep -i EFI中没有找到任何相关内容。 - oz123
实际上,自从https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=7efe665903d0d963b0ebf4cab25cc3ae32c62600以来,x86上已经被禁用了。 - Alexandre Belloni
好的,谢谢您告诉我。那就意味着我的内核正在使用GENERIC_CMOS驱动程序。我重新编译了我的内核并取消了其他驱动程序的标记,目前计算机正在按预期工作。 - oz123

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接