答案1
PCI/PCIe总线具有硬件自动配置功能,因此Linux内核包含一个PCI总线驱动程序,可以读取所有PCI/PCIe设备的硬件ID。通过lspci -nn
,您可以自己查看这些 ID。
如果此时还没有为硬件加载驱动程序,内核将生成驱动程序模块加载请求,相当于:
modprobe pci:v0000<PCI vendor ID>d000<PCI device ID>sv<subvendor ID>sd<subdevice ID>bc<base class ID>sc<subclass ID>i<programming interface ID>
驱动模块应该包括相应的 情态信息,用于modprobe
查找匹配模块。如果运行modprobe -c | grep pci:
,您将看到所有当前安装的驱动程序模块的 modalias 行。
加载驱动程序后(和/或如果有任何内核级 PCI(e) 热插拔事件,在支持热插拔的硬件中),驱动程序将查找驱动程序了解的硬件。如果驱动程序找到可以运行的设备,通常会触发 udev 热插拔事件来自动创建必要的设备文件。
如果默认值不适合您的用例,您可以使用 udev 规则修改设备文件的路径、名称、所有权和权限,和/或运行任意脚本操作。在大多数情况下,手动mknod
应该是不必要的,并且由于 Linux 自内核版本 2.6 以来一直使用非持久性/dev
设备文件系统,因此任何手动命令的效果mknod
都将在下次重新启动时丢失。
司机可能一旦检测到设备,就采取进一步的步骤来询问/初始化设备,或者驱动程序可以简单地设置与设备节点相对应的内核端基础设施并等待来自用户空间的输入。
如果驱动程序没有找到任何相关硬件,它将保持加载在内存中,等待内核级热插拔事件,这些事件可能会告诉它再次寻找设备。
但 PCI(e) UART 卡很可能会被检测为只是一个串行端口设备(即设备/dev/ttyS*
)。由于串行端口技术非常古老,因此没有可靠的方法可以探测串行端口以识别连接到端口的内容;有一些检测方案,但在 Linux 中,这些通常在用户空间中实现,例如gpsd
GPS 接收器设备和ModemManager
3G/4G 无线调制解调器。这些服务将查找串行端口,检查端口握手线的状态,如果看起来有连接(即串行端口的传入 DSR 线处于活动状态),它们将查找传入数据和/或发送一些标准查询字符串。
例如,ModemManager 可能会发送AT
到一个新的串行端口:如果设备响应OK
,则另一端的设备似乎能够理解经典的 Hayes AT 命令,因此它可能是某种调制解调器;然后ModemManager将发送进一步的命令以更准确地识别它。
这种主动探测很可能会干扰 UART 设备的某些使用。如有必要,您可以使用 udev 规则告诉 ModemManager 它应该完全忽略特定的 UART 设备。
例如,我有一个带有 PCIe 串口卡的系统:
# lspci -nn
...
04:00.0 Serial controller [0700]: Oxford Semiconductor Ltd OXPCIe952 Dual 16C950 UART [1415:c158]
...
它有两个端口,udevadm info -q all -a -n /dev/ttyS<number>
在我的所有/dev/ttyS*
设备上运行可以让我识别它们。第一个端口具有 udev 属性ATTR{line}=="1"
,第二个端口具有ATTR{line}=="2"
.
我现在可以将我的特殊串行设备连接到该卡的端口 #1,并将这样的 udev 规则写入文件中/etc/udev/rules.d/99-my-uart-device.rules
:
SUBSYSTEM=="tty", DRIVERS=="serial", ATTRS{vendor}=="0x1415", ATTRS{device}=="0xc158", ATTRS{line}=="1", ALIAS="my_serial_device", ENV{ID_MM_DEVICE_IGNORE}="1"
此规则将导致创建一个别名(符号链接),/dev/my_serial_device
以始终引用该串行端口卡的端口 #1,无论可能向系统添加什么其他类似 UART 的设备以及检测到它们的顺序如何它还会告诉ModemManager不要探测这个端口(该ENV{ID_MM_DEVICE_IGNORE}="1"
部分)。
我现在可以设置一个应用程序来代替/dev/my_serial_device
例如,/dev/ttyS1
并相信它将始终使用正确的物理串行端口与设备进行通信。
串口卡由 PCIe 插槽供电,因此它会始终与计算机一起通电并被检测到。连接到端口的设备可以保持断电状态,直到启动使用该设备的应用程序之前。