为什么 Udev 为单个 USB 设备加载两个内核模块?

为什么 Udev 为单个 USB 设备加载两个内核模块?

我有一个RTL8153基于 USB 以太网适配器,cdc_ether默认使用该驱动程序。

我想使用该r8152驱动程序,可以通过创建自定义 udev 规则来加载该驱动程序,如 Realtek 的 Linux 驱动程序源中所示。

但这里有一个令人困惑的部分,当我插入适配器时,cdc_etherr8152模块都会被加载。我的问题是,

  1. 为什么?
  2. 如何找到负责加载的 udev 规则cdc_ether
  3. 我怎样才能停止加载该模块?因为在这种情况下不需要加载两个模块。

Udev规则的一行

ACTION=="add", DRIVER=="r8152", ATTR{idVendor}=="2357", ATTR{idProduct}=="0601", ATTR{bConfigurationValue}!="$env{REALTEK_NIC_MODE}", ATTR{bConfigurationValue}="$env{REALTEK_NIC_MODE}"

DRIVER==部分不是必需的。

答案1

ACTION=="add", DRIVER=="r8152", ATTR{idVendor}=="2357", ATTR{idProduct}=="0601", ATTR{bConfigurationValue}!="$env{REALTEK_NIC_MODE}", ATTR{bConfigurationValue}="$env{REALTEK_NIC_MODE}"

该 udev 规则的含义如下:“当将idVendor值为 2357 和idProduct值为 0601 的设备(由驱动程序“r8152”管理)添加到系统时,如果它bConfigurationValue不是环境变量中定义的任何值REALTEK_NIC_MODE,请将其设置bConfigurationValue为那个值。”

换句话说,此 udev 规则不会加载 r8152 驱动程序,而是在必要时将设备切换到该驱动程序的正确模式。

当添加一个新设备时,Linux 内核基本上modprobe使用设备的硬件 ID(以及其他一些东西)来运行,这些设备 ID 编码在它请求的模块的“名称”中。然后将该“名称”modprobe与作为模块别名嵌入到每个模块中的通配符字符串进行比较。该depmod命令收集这些别名并将其存储起来/lib/modules/<kernel version>/modules.alias[.bin]以便快速搜索。您可以使用该命令查看嵌入到内核模块中的别名字符串modinfo

对于您的 USB 以太网适配器,“名称”类似于usb:v2357p0601d....不幸的是,该cdc_ether模块有一个与之匹配的通配符别名。

中定义的任何别名/etc/modprobe.d将优先于嵌入模块本身的别名。因此,您可以指定一个与您的以太网适配器匹配的别名,并导致r8152加载模块。

尝试将其添加为/etc/modprobe.d/usbnic.conf

alias usb:v2357p0601d*dc*dsc*dp*ic*isc*ip*in* r8152

然后以 root 身份运行depmod -a,拔下 USB 以太网适配器,卸载r8152cdc_ether模块,重新插入以太网适配器,看看会发生什么。如果只加载r8152模块,那就好。

如果cdc_ether仍然被加载,则别名可能需要更具体(即其中的一个或多个星号需要替换为实际值,无论它们是什么),以便使该别名最具体,从而“最佳”匹配。

更新:这是模块别名格式的描述:http://people.skolelinux.org/pere/blog/Modalias_strings___a_practical_way_to_map__stuff__to_hardware.html

答案2

最近的内核中有一个针对此问题的补丁:https://lkml.org/lkml/2017/9/25/711

相关内容