2. Linux设备模型基础

Linux设备模型是内核为统一管理硬件而抽象出的一套对象关系框架。它把“设备”“驱动”“总线”“类”“子系统”等概念组织成可枚举、可匹配、可挂载、可观察的结构,并通过sysfs、devtmpfs、udev把内核内部状态暴露给用户空间。理解这五类对象与三个用户空间接口的关系,是掌握设备生命周期与资源管理的第一步。

一、核心对象:设备、驱动、总线、类、子系统

在Linux设备模型中,设备(device)表示一个具体的硬件实例或逻辑功能节点,例如一块网卡、一个GPIO控制器、一个USB接口。设备对象通常由struct device描述,它记录父设备、所属总线、驱动绑定状态、电源管理信息等。

驱动(driver)是操作设备的代码集合,通常由struct device_driver描述。驱动并不直接“拥有”设备,而是向总线注册自己,声明能匹配哪些设备。匹配成功后,总线调用驱动的probe函数,设备进入“已绑定”状态。

总线(bus)是设备与驱动之间的匹配中介,例如platform、PCI、USB、I2C、SPI。总线负责枚举设备、维护设备链表和驱动链表,并在新设备或新驱动加入时触发匹配。总线是设备模型中的“红娘”,没有总线,设备与驱动无法自动建立关系。

类(class)是从功能角度对设备的高层抽象,例如net、tty、block、input。类不关心设备挂在哪条总线上,只关心它对外提供什么能力。类的主要作用是让用户空间按功能找到设备,并统一创建/dev节点或sysfs属性。

子系统(subsystem)是更宽泛的顶层组织单位,通常对应/sys/class/、/sys/bus/、/sys/devices/等目录下的一个分支。子系统可以包含总线、类、设备、驱动等多种对象,是内核维护设备层次结构的容器。

二、sysfs、devtmpfs、udev的分工

sysfs是内核导出的虚拟文件系统,挂载在/sys。它把设备模型中的kobject以目录和文件形式呈现,用户可以通过读写属性文件查看或调整设备状态。sysfs是“内核对象视图”,不是设备节点本身。

devtmpfs是内核早期挂载在/dev的虚拟文件系统,由内核在设备注册时自动创建对应的设备节点。它解决了“根文件系统尚未挂载时也需要设备节点”的问题,例如启动阶段需要访问/dev/console、/dev/null。

udev是用户空间的设备管理器,运行在systemd-udevd中。它监听内核通过netlink发送的uevent,根据规则文件在/dev下创建符号链接、修改权限、执行脚本。udev不替代devtmpfs,而是在devtmpfs提供的节点基础上做动态策略管理。

一句话区分:sysfs看“设备模型长什么样”,devtmpfs保证“节点先能用”,udev决定“节点最终叫什么、归谁、触发什么动作”。

Linux设备模型:内核对象与用户空间接口关系 内核空间 总线 bus platform / PCI / USB / I2C 设备 device struct device 驱动 driver struct device_driver 类 class net / tty / block 枚举 匹配 子系统 subsystem /sys/class/ /sys/bus/ /sys/devices/ kobject 导出 用户空间 sysfs 挂载点 /sys 查看设备模型与属性 只读/读写属性文件 devtmpfs 挂载点 /dev 内核自动创建设备节点 启动早期即可用 udev systemd-udevd 监听 uevent,应用规则 符号链接/权限/脚本 基础节点 uevent sysfs 呈现模型 · devtmpfs 保证节点 · udev 执行策略

三、从设备注册到/dev节点出现的完整链路

以一条platform设备为例,典型流程如下:

  1. 内核启动或模块加载时,platform总线枚举设备树或ACPI中的设备,创建struct device并注册到总线设备链表。
  2. 驱动向总线注册struct device_driver,总线调用match函数比较设备与驱动的compatible、id_table等字段。
  3. 匹配成功后,总线调用驱动的probe函数,驱动初始化硬件、申请资源、注册字符设备或网络设备。
  4. 设备注册时,内核在sysfs中创建对应目录和属性文件,同时通过devtmpfs在/dev下创建设备节点。
  5. 内核发送uevent,udev接收后根据/etc/udev/rules.d/中的规则创建符号链接、设置权限或执行辅助脚本。
# 查看某设备在sysfs中的位置
ls -l /sys/bus/platform/devices/
# 查看设备与驱动的绑定关系
ls -l /sys/bus/platform/drivers/*/
# 查看devtmpfs中的节点
ls -l /dev/ttyS0
# 查看udev规则
udevadm info -a -n /dev/ttyS0
# 监控uevent
udevadm monitor --kernel --udev

四、案例:串口设备从注册到可用

假设SoC的UART控制器在设备树中描述为serial@10000000,compatible为vendor,uart。内核启动时,platform总线根据设备树创建platform_device,串口驱动注册platform_driver。匹配成功后,驱动probe,申请寄存器地址、中断号,注册tty设备。此时sysfs中出现/sys/devices/platform/serial@10000000/,devtmpfs中创建/dev/ttyS0,udev根据规则可能创建/dev/serial/by-id/...符号链接。用户空间程序打开/dev/ttyS0即可通信。

五、常见误区与复盘

误区 正确理解
sysfs就是/dev sysfs是内核对象视图,/dev是设备节点目录,两者用途不同。
udev负责创建设备节点 devtmpfs先创建基础节点,udev在其上做策略管理;无devtmpfs时udev才负责创建。
设备与驱动直接绑定 必须经过总线匹配,总线是设备与驱动之间的必要中介。
类就是总线 类按功能分类,总线按物理/逻辑连接分类,二者维度不同。
子系统只包含设备 子系统可包含总线、类、设备、驱动等多种kobject。

排障时建议按“总线是否匹配 → 驱动probe是否成功 → sysfs是否有节点 → devtmpfs是否有设备文件 → udev规则是否生效”的顺序逐层检查,能快速定位设备不可用的原因。

掌握设备、驱动、总线、类、子系统五类对象,以及sysfs、devtmpfs、udev三者的分工,就建立了Linux设备模型的整体地图。后续无论是编写驱动、调试设备树,还是排查/dev节点异常,都可以回到这张地图上定位问题所在。