1. 课程导入

在嵌入式Linux、服务器与桌面系统中,设备驱动开发者经常面对一个看似矛盾的现象:内核里明明有成千上万个驱动,用户空间却能用极简的路径访问设备,例如 /dev/ttyS0、/sys/class/net/eth0、/dev/input/event3。这种“内核复杂、用户接口统一”的能力,正是由Linux设备模型(Linux Device Model)提供的。设备模型不是某一个单独的文件,而是一套贯穿内核的对象抽象、注册机制与用户空间视图,它把总线、设备、驱动、类、属性、电源管理等概念组织成可枚举、可匹配、可观察的结构。

本课程聚焦其中的Class(类)与设备节点管理。Class是设备模型面向用户空间的重要出口:它不关心设备挂在哪条总线上,而是按功能归类,例如 net、tty、input、block、sound。设备节点则是用户空间真正打开、读写、控制的入口,通常由 devtmpfs、udev 或 mdev 根据内核事件动态创建。理解Class与节点管理,等于掌握了“驱动如何被看见、设备如何被访问、权限如何被控制”的主线。

本节核心问题:设备模型为什么存在?Class在系统中处于什么位置?设备节点从何而来?后续30章将围绕哪些能力展开?

一、Linux设备模型的核心抽象

Linux设备模型用 kobject、kset、device、device_driver、bus_type、class 等结构描述内核对象及其关系。可以把它理解为一张动态维护的“设备关系网”:

  • kobject:最基础的对象引用计数与sysfs目录表示,是设备模型的地基。
  • bus_type:总线类型,负责设备与驱动的匹配,如 platform、i2c、spi、usb、pci。
  • device:具体设备实例,挂接在总线上,拥有资源、属性和生命周期。
  • device_driver:驱动实现,通过 probe 与设备绑定,通过 remove 解绑。
  • class:按功能划分的设备集合,向用户空间提供统一视图,如 /sys/class/net。
  • device node:用户空间设备文件,如 /dev/video0,由设备号与驱动关联。

这些对象最终都映射到 sysfs 中。sysfs不是普通文件系统,而是内核对象关系的实时投影。用户执行 ls /sys/class 看到的目录,正是Class抽象的直接体现。

二、Class与节点管理在系统中的位置

从数据流看,设备模型位于“硬件/总线”与“用户空间”之间。硬件被总线枚举后生成device;驱动匹配后注册class与属性;内核通过uevent通知用户空间;用户空间的udev/mdev根据uevent创建设备节点并设置权限。整个过程可以用下面的关系图表示:

Linux设备模型:从硬件到用户空间的主链路 硬件与总线 platform / i2c / usb 枚举与匹配 device / driver probe / remove 资源与属性 class 类抽象 net / tty / input /sys/class/* 用户空间 udev / mdev /dev 节点 sysfs:内核对象关系的实时投影 /sys/devices /sys/bus /sys/class /sys/dev uevent 事件 add / remove / change netlink 广播 设备节点管理 主次设备号 权限 / 属主 / 符号链接 应用访问 open / read / write ioctl / mmap Class 提供功能视图,uevent 驱动节点创建,/dev 提供最终访问入口

图中可见,Class并不直接创建设备节点,而是提供“功能分类视图”和uevent信息。真正让 /dev 出现节点的是用户空间设备管理器。因此,Class与节点管理是“内核抽象”与“用户空间落地”之间的桥梁。

三、方法流程:一次设备注册到节点生成

以平台设备为例,典型流程如下:

  1. 设备树或板级代码描述硬件,内核生成 platform_device。
  2. 驱动注册 platform_driver,总线匹配成功后调用 probe。
  3. 驱动申请设备号,注册 cdev 或 class_create / device_create。
  4. 内核在sysfs中生成 /sys/class/xxx/yyy,并发出uevent。
  5. udev/mdev接收uevent,读取 dev 属性中的主次设备号。
  6. 在 /dev 下创建节点,设置权限、属主和符号链接。
# 观察 class 与设备节点
ls -l /sys/class/net/
ls -l /dev/ttyS0
cat /sys/class/tty/ttyS0/dev
# 输出示例:4:64

# 查看 uevent 内容
cat /sys/class/net/eth0/uevent
# 输出示例:
# INTERFACE=eth0
# IFINDEX=2

这段命令展示了Class视图、设备号与uevent之间的对应关系。设备号 4:64 是内核内部标识,/dev/ttyS0 是用户空间入口,二者通过设备节点管理绑定。

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

假设SoC有一个UART控制器,内核启动后出现 /dev/ttyS0。背后发生的事包括:串口驱动注册 tty_driver,创建 tty_class,调用 device_create 生成 /sys/class/tty/ttyS0,并发出uevent。udev根据规则创建 /dev/ttyS0,权限通常为 crw-rw---- root dialout。应用打开该节点即可收发数据。

如果节点没有出现,排查顺序通常是:驱动是否probe成功、class是否注册、uevent是否发出、udev/mdev是否运行、规则是否匹配、权限是否被覆盖。这个排查链条正是本课程后续要反复训练的能力。

五、常见误区与复盘

误区实际情况正确做法
Class就是设备节点Class是sysfs功能视图,节点在/dev分别查看 /sys/class 与 /dev
设备号无关紧要主次设备号决定内核如何找到驱动用 cat /sys/class/.../dev 核对
udev规则一定生效规则顺序、匹配条件、权限都会影响结果用 udevadm test 验证
节点创建后权限不会变后续规则或服务可能覆盖权限检查规则优先级与默认权限

学习建议:每学一个概念,都在真实系统中找对应路径。看到 /sys/class 想Class,看到 /dev 想节点,看到 uevent 想事件传递。三者联动,设备模型就不再抽象。

六、整体知识框架与学习目标

本课程后续将围绕五条主线展开:设备模型基础对象与sysfs、Class机制与class_create/device_create、设备号与cdev、uevent与用户空间事件、udev/mdev规则与节点权限管理。最终目标是能够独立完成驱动侧Class注册、用户空间节点生成、权限配置与故障排查。

  • 理解kobject、kset、device、driver、bus、class之间的关系。
  • 掌握Class的注册、注销与sysfs属性组织。
  • 掌握设备号分配、cdev注册与设备节点生成流程。
  • 能编写和调试udev/mdev规则,控制节点权限与命名。
  • 能定位“驱动正常但节点缺失”“权限错误”“节点名不符”等典型问题。

设备模型是Linux驱动工程的骨架,Class与节点管理是骨架上的关节。掌握它们,才能在复杂系统中让设备“被内核识别、被用户空间看见、被应用正确访问”。