理解字符设备、设备模型与子系统:以 i.MX8MP 平台为例
视频教程请关注 B 站:“嵌入式 Jerry”
Linux 内核驱动开发中,很多人在接触字符设备(char device)、设备模型(device model)和各种子系统(subsystem)时,往往会感到概念混杂,边界模糊。本文将从 Linux 驱动体系架构的演化入手,结合 NXP 的 i.MX 8M Plus EVK 平台(下文简称 i.MX8MP-EVK),深入讲解这三者的关系、用途与实际代码的融合方式,帮助你彻底理解这些核心概念。
一、历史与基础概念
1.1 字符设备(Character Device)
字符设备是 Linux 设备类型之一,另一种是块设备(Block Device)。字符设备以字节为单位进行读写,接口类似于普通文件,通过 read()
、write()
、ioctl()
等系统调用进行操作。
- 常见字符设备:串口(serial)、GPIO、I2C、PWM、Watchdog 等。
- 管理结构:主要由
struct file_operations
和struct cdev
控制,最终通过register_chrdev_region()
和cdev_add()
注册到系统。
1.2 设备模型(Device Model)
Linux 为了实现设备与驱动的自动匹配、热插拔管理、sysfs 显示,设计了一套统一的设备模型架构,包括以下关键结构:
struct device
struct driver
struct bus_type
struct class
这套模型抽象了“设备是如何插到系统里的、驱动如何找到设备、如何在用户空间体现出设备结构”等问题。
设备模型的意义在于:“它是一种运行时的驱动与设备匹配与管理框架”。
1.3 子系统(Subsystem)
“子系统”是指内核中具有统一接口规范的功能模块,例如:
- I2C 子系统
- SPI 子系统
- PWM 子系统
- regulator 子系统
- input 子系统
- sound 子系统
每个子系统背后都有一个核心的框架代码,并暴露出标准接口(如 struct pwm_chip
、struct i2c_driver
等),驱动开发者按照接口标准进行设备适配即可。
子系统的意义在于:“统一了设备驱动的行为规范和上层调用方式,是设备模型的具体实现与应用场景”。
二、三者关系的准确理解
我们通过一个类比来帮助你理解三者关系:
类别 | 类比解释 | 实际作用 |
---|---|---|
字符设备 | 老式收音机,直接接电可用 | 最基本的驱动编程方式 |
设备模型 | 家庭电网管理系统 | 让每台收音机能统一开关、统一命名、自动识别 |
子系统 | 不同的电台频道系统(如 FM/AM) | 为收音机统一音频标准接口、设置方法等 |
正确理解:
- 设备模型并不是“设备驱动的替代品”,而是驱动与设备的匹配系统。
- 字符设备可裸用,也可嵌入子系统内部。
- 子系统是专用领域的模型扩展,基于设备模型构建的统一抽象。
三、实战解析:以 i.MX8MP 的 PWM 驱动为例
NXP 的 pwm-imx27
驱动是一个非常典型的子系统 + 设备模型驱动的代表。下面我们从设备树、驱动代码到字符接口逐步解析。
3.1 设备树定义(设备描述)
在 arch/arm64/boot/dts/freescale/imx8mp-evk.dts
中:
&pwm1 {pinctrl-names = "default";pinctrl-0 = <&pinctrl_pwm1>;status = "okay";
};
说明:pwm1 控制器启用,绑定了特定管脚。
3.2 驱动注册过程(platform_device + pwm_chip)
驱动源码文件:drivers/pwm/pwm-imx27.c
注册入口:
static struct platform_driver imx_pwm_driver = {.driver = {.name = "pwm-imx27",.of_match_table = pwm_imx27_dt_ids,},.probe = pwm_imx27_probe,
};
module_platform_driver(imx_pwm_driver);
核心结构:
struct pwm_imx27_chip {struct pwm_chip chip; // 属于PWM子系统的驱动注册入口...
};
pwm_chip
是子系统定义的结构体,其 ops
字段中定义了 .apply
、.get_state
等操作接口。
然后调用:
return devm_pwmchip_add(&pdev->dev, &imx->chip);
此函数实际上完成了驱动注册到子系统 + 注册 sysfs 接口 + device model 挂载等多个功能。
3.3 sysfs 与字符设备的区别
尽管 pwm-imx27
没有 register_chrdev
或 cdev_add
,但它通过子系统自动创建了 sysfs
接口,例如:
/sys/class/pwm/pwmchip0/
这意味着控制 PWM 不再依赖传统字符设备节点 /dev/pwm0
,而是通过标准 pwm
子系统提供的统一 sysfs 文件操作。
四、对比分析:没有子系统的字符设备
若驱动不走子系统,例如传统的 LED 控制驱动,则需要手动注册字符设备:
register_chrdev_region();
cdev_init();
cdev_add();
并创建 /dev/xxx
节点,再通过 open/read/write/ioctl
实现访问。
优缺点对比
特性 | 传统字符设备 | 子系统驱动(如 PWM) |
---|---|---|
注册方式 | register_chrdev + cdev | pwmchip_add 等 |
用户访问方式 | /dev/xxx | sysfs + standard API |
是否自动匹配设备 | 否 | 是 |
是否统一接口 | 否 | 是 |
开发复杂度 | 中等 | 略高(但标准) |
五、设备模型:驱动背后的系统机制
Linux 驱动之所以能做到自动识别设备、按需加载驱动,靠的就是设备模型架构。
5.1 总线(bus_type)
- platform 总线:用于板载设备(PWM、I2C、SPI)
- usb 总线:用于外设热插拔设备
- pci 总线:用于 PC 设备识别与枚举
所有子系统最终都依赖某种 bus 类型与设备模型框架。
5.2 匹配过程(match)
设备模型按照:
.of_match_table
(设备树匹配).id_table
(非设备树匹配)
来完成 device
与 driver
的自动匹配与调用 probe。
六、结语与建议
6.1 学习建议
- 新手建议从字符设备入手,理解基础接口。
- 进阶阶段要深入了解设备模型与 sysfs 接口。
- 若目标是嵌入式设备驱动,应熟练掌握子系统开发接口(如 I2C/SPI/PWM 等子系统结构)。
6.2 总结结构图
+------------------------+| 用户空间接口 |+------------------------+↑+-------------------------+| sysfs / /dev 节点 |+-------------------------+↑+----------------------------+| 子系统接口(如 PWM/SPI) |+----------------------------+↑+---------------------------+| 设备模型(device model) |+---------------------------+↑+--------------------------+| platform/PCI/... bus |+--------------------------+
附录:i.MX8MP 平台相关驱动推荐阅读
drivers/pwm/pwm-imx27.c
:PWM 控制器驱动drivers/regulator/pca9450-regulator.c
:PMIC 驱动drivers/i2c/busses/i2c-imx.c
:I2C 控制器驱动
视频教程请关注 B 站:“嵌入式 Jerry”