📅 日期:2025-04-27
📚 技术平台:嵌入式Jerry(B站)
1. 为什么要有子系统?(深度版)
在 Linux 内核发展早期,设备管理较为混乱,每种设备(如网卡、硬盘、LED)各自为政,驱动开发非常困难,系统维护复杂、扩展困难。
1.1 难点总结
- 接口不统一:每类设备定义自己的操作方式
- 用户访问混乱:无法通过统一路径管理设备
- 内核膨胀严重:各种 if-else、switch-case 代码横行
1.2 子系统带来的变化
✅ 为每一类功能设备定义 统一接口规范;
✅ 在 /sys/class/
下暴露出 统一访问路径;
✅ 驱动开发者只需遵循子系统接口,避免重复设计;
✅ 设备热插拔、动态加载、统一管理变得简单。
2. 子系统本质是什么?
一句通俗的话:
子系统是内核根据设备功能,把一大堆设备分类管理的机制。
技术上:
- 基于 kobject/kset/ktype 的设备模型机制
- 在 sysfs 文件系统中形成 class 目录
- 提供标准的注册/注销流程
2.1 子系统 VS 设备模型
项目 | 设备模型 (device model) | 子系统 (subsystem) |
---|---|---|
定义 | Linux 内核通用框架 | 特定类型设备的组织分类 |
基础 | kobject/kset/ktype | 基于设备模型构建 |
目的 | 支撑总线/驱动/设备统一管理 | 便于管理一类设备 |
示例 | platform bus, device | net, block, regulator |
3. 子系统的基本结构和机制
一个子系统通常包括:
- Class:对应 sysfs 的
/sys/class/
,逻辑分组 - Device:每个实例(一个 LED、一个 BUCK)对应一个 device
- Driver:驱动设备,通常与特定 bus 匹配
结构图理解:
class_create() -> 创建类 (Class)
device_create() -> 创建设备 (Device)用户空间访问:
/sys/class/<class>/<device>/
4. 子系统创建与使用详细流程
4.1 创建子系统
内核代码核心步骤:
// 1. 创建一个 Class(子系统)
struct class *my_class;my_class = class_create(THIS_MODULE, "mychar_class");
if (IS_ERR(my_class))return PTR_ERR(my_class);
对应生成 /sys/class/mychar_class/
4.2 注册设备到子系统
// 2. 在子系统下挂一个设备
struct device *dev;dev = device_create(my_class, NULL, devt, NULL, "mychar");
if (IS_ERR(dev))return PTR_ERR(dev);
对应生成 /sys/class/mychar_class/mychar
节点。
同时,udev等工具可自动生成 /dev/mychar
设备文件。
4.3 销毁流程
// 卸载时销毁
device_destroy(my_class, devt);
class_destroy(my_class);
确保模块退出时资源清理,防止内核内存泄漏。
5. 详细实例:基于 i.MX8MP EVK 控制 LED
5.1 设备树节点
imx8mp-evk.dts
中已有:
gpio-leds {compatible = "gpio-leds";pinctrl-names = "default";pinctrl-0 = <&pinctrl_gpio_led>;status {label = "yellow:status";gpios = <&gpio3 16 GPIO_ACTIVE_HIGH>;default-state = "on";};
};
说明:
- GPIO3_16 = 32 * 2 + 16 = 80号 GPIO
- 默认状态点亮
5.2 驱动代码示例(增加丰富注释版)
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/gpio.h>
#include <linux/uaccess.h>
#include <linux/cdev.h>
#include <linux/device.h>#define LED_GPIO 80 // gpio3_16static dev_t devt;
static struct cdev led_cdev;
static struct class *led_class;
static struct device *led_device;// 写接口,实现开关LED
static ssize_t led_write(struct file *filp, const char __user *buf, size_t len, loff_t *off)
{char kbuf[4] = {0};if (copy_from_user(kbuf, buf, len))return -EFAULT;if (kbuf[0] == '1')gpio_set_value(LED_GPIO, 1); // 点亮elsegpio_set_value(LED_GPIO, 0); // 熄灭return len;
}// 文件操作结构
static struct file_operations led_fops = {.owner = THIS_MODULE,.write = led_write,
};static int __init led_init(void)
{int ret;// 申请GPIOret = gpio_request(LED_GPIO, "led_gpio");if (ret)return ret;gpio_direction_output(LED_GPIO, 1);// 分配设备号alloc_chrdev_region(&devt, 0, 1, "ledchar");cdev_init(&led_cdev, &led_fops);cdev_add(&led_cdev, devt, 1);// 创建子系统(class)led_class = class_create(THIS_MODULE, "led_class");led_device = device_create(led_class, NULL, devt, NULL, "ledchar");pr_info("ledchar device initialized\n");return 0;
}static void __exit led_exit(void)
{gpio_set_value(LED_GPIO, 0);gpio_free(LED_GPIO);device_destroy(led_class, devt);class_destroy(led_class);cdev_del(&led_cdev);unregister_chrdev_region(devt, 1);pr_info("ledchar device removed\n");
}module_init(led_init);
module_exit(led_exit);
MODULE_LICENSE("GPL");
5.3 加载模块效果
# 加载模块
insmod ledchar.ko# 查看/sys目录
ls /sys/class/led_class/ledchar/# 控制LED
echo 1 > /dev/ledchar
echo 0 > /dev/ledchar
✅ 通过字符设备 /dev/ledchar
写操作,控制真正硬件上的 GPIO 灯亮灭。
✅ 同时在 /sys/class/led_class/ledchar/
中可查看设备属性。
6. 深度讲解:子系统、字符设备、设备模型关系总结
类型 | 作用 | 示例 | 本质 |
---|---|---|---|
字符设备 (cdev) | 提供read/write/ioctl接口 | /dev/ledchar | 用来读写硬件 |
子系统 (class) | 统一组织管理设备 | /sys/class/led_class/ | 便于分类管理 |
设备模型 (device model) | 内核统一抽象 | bus/device/driver | 子系统基于它 |
7. 为什么字符设备要挂子系统?
- 如果直接裸 cdev:仅
/dev
有节点,sysfs 中无管理 - 如果挂到子系统:
- 有
/dev
节点 - 有
/sys/class
路径 - 更易于热插拔、用户空间管理
- 可以扩展 attribute 节点(如调节亮度)
- 有
所以,规范写法:
字符设备 + 子系统结合,才是完整专业驱动。
8. 小结与今日提炼
✅ 子系统统一管理同类设备,提升 Linux 内核规范性。
✅ 子系统本质上是设备模型的一个应用。
✅ 字符设备可直接使用,也可以挂到子系统,推荐挂载管理。
✅ 电源子系统(regulator)、LED子系统、网卡子系统都是应用范例。
9. 后续学习计划(已升级)
阶段 | 主题 | 备注 |
---|---|---|
✅ 阶段一 | 设备模型 + 字符设备 | 已完成 |
✅ 阶段二 | 子系统概念与应用 | 今日完成 |
🔜 阶段三 | 电源子系统(regulator)深度学习 | 明日开始 |
10. 技术交流
💬 更多 Linux 驱动开发教学,请关注 B 站:【嵌入式Jerry】