驱动开发硬核特训 · Day 18:深入理解字符设备驱动与子系统的协作机制(以 i.MX8MP 为例)
日期:2025年04月23日
回顾:2025年04月22日(Day 17:Linux 中的子系统概念与注册机制)
本日主题:字符设备驱动 × 子系统协作机制剖析
学习目标:理解字符设备的注册原理,掌握其与子系统间的接口关系与工作流,结合实际代码实现。
一、前言:设备模型之后,我们为什么学习字符设备驱动?
在前面的内容中,我们系统掌握了设备模型的构成和原理,包括 bus
、device
、driver
之间的匹配与生命周期关系。这一模型为 Linux 驱动提供了统一的管理方式。但这只是驱动“框架”的一环,驱动真正提供“功能”的部分往往以“字符设备”的形式呈现。
尤其是在嵌入式平台如 NXP i.MX8MP EVK 上,GPIO、I2C、PWM、摄像头等模块的访问大多通过 /dev/
下的字符设备进行,而这些字符设备的背后通常归属于某个子系统(例如:input、sound、misc、video、tty 等)。因此,今天我们要解决的是:
- 字符设备到底是什么?
- 它如何注册?如何与用户态通信?
- 它和设备模型有何关系?
- 子系统在其中扮演了什么角色?
二、字符设备驱动基础知识回顾
2.1 什么是字符设备?
字符设备(Character Device)是一种一次读取/写入一个字符流的设备接口,相对于块设备(如磁盘)而言,它没有缓冲区机制、没有对齐限制。常见的字符设备包括:
- 串口
/dev/ttyS*
- GPIO
/dev/gpiochip*
- I2C
/dev/i2c-*
- 自定义控制器设备(如
/dev/mypwm
)
它们通常通过 file_operations
结构体实现系统调用的处理,如 read
、write
、ioctl
等。
2.2 注册字符设备的方法(核心 API)
字符设备的注册过程大致分为以下几步:
-
申请设备号:
alloc_chrdev_region(&devt, 0, 1, "demo_char");
-
初始化 cdev 并添加到系统:
cdev_init(&cdev, &fops); cdev_add(&cdev, devt, 1);
-
创建设备节点:
class_create(); device_create();
-
注销字符设备(卸载时):
device_destroy(); class_destroy(); unregister_chrdev_region();
三、子系统:字符设备驱动背后的组织者
在 Linux 中,并非所有字符设备都以“裸 API”的方式注册,大量的字符设备实际上是依附于子系统框架进行注册的。
3.1 子系统为何存在?
子系统(subsystem)是为了解决如下问题而出现的:
- 提供统一的设备类与行为抽象(如 input, tty, misc)
- 简化字符设备注册流程(抽象 class、cdev、major/minor)
- 提供统一的 ioctl、poll、open 行为(如 video4linux 的 V4L2)
举例:
子系统 | 设备名 | 注册方式 |
---|---|---|
input | /dev/input/event* | input_register_device() |
misc | /dev/misc/* | misc_register() |
tty | /dev/ttyS* | tty_register_driver() |
video | /dev/video* | video_register_device() |
这些子系统往往会帮你封装掉字符设备注册流程,你只需关注“实现业务逻辑”。
3.2 子系统与字符设备的关系图
用户空间 内核空间
---------- -----------------------------------/dev/video0 ---> V4L2子系统 ----> 注册字符设备↑│platform_device / i2c_device / ...
四、实战:以 i.MX8MP 上的 LED 控制器为例讲解字符设备注册
4.1 示例背景
我们以 gpio-leds
中的一个 LED 为例,演示如何构造一个字符设备用于控制其亮灭。
设备树片段(位于 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";};
};
4.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 GPIO_NUM 80 // gpio3_16 = 32 * 2 + 16 = 80
static dev_t devt;
static struct cdev cdev;
static struct class *led_class;static ssize_t led_write(struct file *filp, const char __user *buf, size_t len, loff_t *off)
{char kbuf[4];if (copy_from_user(kbuf, buf, len))return -EFAULT;gpio_set_value(GPIO_NUM, kbuf[0] == '1' ? 1 : 0);return len;
}static struct file_operations led_fops = {.owner = THIS_MODULE,.write = led_write,
};static int __init led_dev_init(void)
{gpio_request(GPIO_NUM, "led_gpio");gpio_direction_output(GPIO_NUM, 1);alloc_chrdev_region(&devt, 0, 1, "led_char");cdev_init(&cdev, &led_fops);cdev_add(&cdev, devt, 1);led_class = class_create(THIS_MODULE, "led_class");device_create(led_class, NULL, devt, NULL, "ledchar");pr_info("ledchar device init done\n");return 0;
}static void __exit led_dev_exit(void)
{gpio_set_value(GPIO_NUM, 0);gpio_free(GPIO_NUM);device_destroy(led_class, devt);class_destroy(led_class);cdev_del(&cdev);unregister_chrdev_region(devt, 1);
}module_init(led_dev_init);
module_exit(led_dev_exit);
MODULE_LICENSE("GPL");
编译为模块,加载后可直接:
echo 1 > /dev/ledchar # 点亮
echo 0 > /dev/ledchar # 熄灭
五、为什么不能只靠设备模型或子系统?
设备模型的本质是“管理对象关系”,子系统的作用是“组织类行为”,但真正实现具体功能的,还得靠字符设备驱动这一“落地接口”。
我们可以这样理解它们三者的关系:
模块 | 角色 |
---|---|
设备模型 | 提供注册匹配机制(device/driver) |
子系统 | 封装字符设备注册流程,组织行为一致性 |
字符设备驱动 | 实现具体功能,操作底层硬件 |
六、总结
今日你学习了:
- 字符设备的基本概念与注册流程
- 子系统对字符设备的封装与简化作用
- 实际示例中字符设备如何与 GPIO 结合
- 三大模块(设备模型、子系统、字符设备驱动)间的工作边界与协作逻辑
字符设备是 Linux 驱动开发中最贴近用户层的部分,掌握这一点将为后续如 input 设备、V4L2 摄像头、tty 驱动打下基础。
七、问答环节(回顾与思考)
cdev_add()
与device_create()
有什么区别?- misc_register 和标准字符设备注册方法有什么异同?
- 为什么有的驱动不需要显式注册字符设备?
- 子系统能否单独工作,不借助设备模型?
视频教程请关注 B 站:“嵌入式 Jerry”
明日预告(Day 19):misc_register
机制与子系统封装详解 —— 带你剖析为什么字符设备能“一行搞定”。
如果你觉得今天的训练内容对你有帮助,欢迎留言交流,也欢迎转发给其他 Linux 驱动学习者。
相关文章:
驱动开发硬核特训 · Day 18:深入理解字符设备驱动与子系统的协作机制(以 i.MX8MP 为例)
日期:2025年04月23日 回顾:2025年04月22日(Day 17:Linux 中的子系统概念与注册机制) 本日主题:字符设备驱动 子系统协作机制剖析 学习目标:理解字符设备的注册原理,掌握其与子系统间…...
SQL Server 2022 常见问题解答:从安装到优化的全场景指南
SQL Server 2022 作为微软最新的数据库管理系统,在性能、安全性和云集成方面带来了多项革新。然而,用户在实际使用中仍可能遇到各类问题。本文将围绕安装配置、性能优化、备份恢复、安全设置、高可用性方案、兼容性问题及错误代码解析等核心场景…...
软件开发版本库命名规范说明
背景:近期一直再更新自己所开发的一个前端大文件上传npm库(enlarge-file-upload),为了让库的发版更加规范,于是参考了各种文档写下了这篇关于软件开发库的版本命名规范,且不仅局限于前端的版本命名规范,适用于整个软件…...
Kafka 详解
1.基本概念:Kafka 是分布式发布 - 订阅消息系统,具有高吞吐量、可扩展性等优势,支持点对点和发布订阅两种消息模式,涉及 Broker、Topic、Partition 等多种角色。 2.安装步骤:需先安装 JDK 和 Zookeeper,下…...
【Qwen2.5-VL 踩坑记录】本地 + 海外账号和国内账号的 API 调用区别(阿里云百炼平台)
API 调用 阿里云百炼平台的海内外 API 的区别: 海外版:需要进行 API 基础 URL 设置国内版:无需设置。 本人的服务器在香港,采用海外版的 API 时,需要进行如下API端点配置 / API基础URL设置 / API客户端配置…...
硬核解析:整车行驶阻力系数插值计算与滑行阻力分解方法论
引言:阻力优化的核心价值 在汽车工程领域,行驶阻力是影响动力性、经济性及排放的核心因素。根据统计,车辆行驶中约60%的燃油消耗用于克服阻力(风阻、滚阻、传动内阻等)。尤其在电动化趋势下,阻力降低1%可提…...
【网络原理】TCP提升效率机制(一):滑动窗口
目录 一. 前言 二. 滑动窗口 三. 丢包现象 1)ACK报文丢失 2)数据丢失 四. 总结 一. 前言 TCP最核心的机制就是可靠传输 ,确认应答,超时重传,连接管理这些都保证了可靠传输,得到了可靠传输,…...
移动端使用keep-alive将页面缓存和滚动缓存具体实现方法 - 详解
1. 配置组件名称 确保列表页组件设置了name选项,(组合式API额外配置): <!-- vue2写法 --> export default {name: UserList // 必须与 <keep-alive> 的 include 匹配 }<!-- vue3写法 --> defineOptions({na…...
工作记录9
1.点击按钮发送AJAX请求 <!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title&…...
Java 异常 SSLException: fatal alert: protocol_version 全解析与解决方案
在 Java 网络通信中,SSLException: fatal alert: protocol_version 是典型的 TLS/SSL 协议版本不兼容异常。本文结合 Java 官方规范、TLS 协议标准及实战经验,提供体系化解决方案,帮助开发者快速定位并解决协议版本冲突问题。 一、异常本质&…...
连锁美业管理系统「数据分析」的重要左右分析︳博弈美业系统疗愈系统分享
美业管理系统中的数据分析功能在提升运营效率、优化客户体验、增强决策科学性等方面具有重要作用。 数据分析功能将美业从“经验驱动”升级为“数据驱动”,帮助商家在客户管理、成本控制、服务创新等环节实现精细化运营,最终提升盈利能力与品牌竞争力…...
Openharmony 和 HarmonyOS 区别?
文章目录 OpenHarmony 与 HarmonyOS 的区别:开源生态与商业发行版的定位差异一、定义与定位二、技术架构对比1. OpenHarmony2. HarmonyOS 三、应用场景差异四、开发主体与生态支持五、关键区别总结六、如何选择?未来展望 OpenHarmony 与 HarmonyOS 的区别…...
26.OpenCV形态学操作
OpenCV形态学操作 形态学操作(Morphological Operations)源自二值图像处理,主要用于分析和处理图像中的结构元素,对图像进行去噪、提取边缘、分割等预处理步骤。OpenCV库中提供了丰富的形态学函数,常见的包括…...
uniapp小程序使用echarts
1、引入插件 在Dcloud插件市场下载echarts插件:插件地址 2、页面使用简单示例: <template><view class"pie-view flex-center"><view style"width: 100%; height: 600rpx"><l-echart ref"chartRef&quo…...
Vue 中 使用 Mixins 解决 多页面共用相同组件的相关问题
1. 需要解决的问题 最近在vue项目中,有多个页面需要用到同一个组件,至于是什么组件,这里不重要,重要的这个组件需要被多个文件引用,而且有组件有一些控制逻辑。 1.1代码展示 <template><div class"ap…...
Rust 学习笔记:Rust 简介
Rust 学习笔记:Rust 简介 Rust 学习笔记:Rust 简介历史与发展历程核心特性优点缺点应用领域 Rust 学习笔记:Rust 简介 Rust 是一种系统级编程语言,由 Mozilla 研究院的 Graydon Hoare 于 2006 年设计,旨在提供内存安全…...
第六节:进阶特性高频题-自定义指令实现场景
示例:v-lazy(图片懒加载)、v-permission(权限控制) 钩子函数:mounted、updated、unmounted等 一、自定义指令核心机制 指令生命周期钩子 const myDirective {// 元素插入父节点时调用(初始化…...
未曾设想的道路1
写在前面: 与其转去读博,倾向自学就业。 中国科学技术大学数学科学学院拥有一支优秀的师资团队,以下是部分教授的简介: 陈发来教授: 荣誉:2024年6月13日,在德国莱布尼茨信息科学中心召开的国际…...
Axure按钮设计分享:打造高效交互体验的六大按钮类型
在产品设计过程中,按钮作为用户与界面交互的核心元素,其设计质量直接影响用户体验与操作效率。Axure作为一款强大的原型设计工具,为设计师提供了丰富的按钮设计选项。本文将围绕基础按钮、禁用按钮、圆角按钮、动态按钮、渐变按钮和图标按钮六…...
MySQL 8.4企业版 安装和配置审计插件
在最新的MySQL 8.4.4企业版上启用审计日志功能 操作系统:Ubuntu 24.04 数据库:8.4.4-commercial for Linux on x86_64 (MySQL Enterprise Server - Commercial) 1.查看安装脚本 下面2个脚本位于mysql安装目录 share 下,一个是window一个是linux可以用…...
AI大模型学习十一:尝鲜ubuntu 25.04 桌面版私有化sealos cloud + devbox+minio,实战运行成功
一、说明 用了ubuntu 25.04,内核为GNU/Linux 6.14.0-15-generic x86_64,升级了部分image,过程曲折啊 sealos 能干啥 对集群生命周期进行管理,一键安装高可用 Kubernetes 集群,增删节点清理集群自恢复等 通过 sealos…...
idea无法下载源代码
通过idea找到用户设置文件路径 查看 setting.xml 文件,找到了以下相关的配置,注释掉这个maven-default-http-blocker的镜像,这个东西阻碍了去阿里的镜像库查找依赖,注释掉。 然后重启idea就能下载了...
【敏矽微ME32G030系列】介绍、环境搭建、工程测试
【敏矽微ME32G030系列】介绍、环境搭建、工程测试 本文介绍了敏矽微ME32G030系列单片机及开发板、包括参数特点、原理图、应用场景,以及开发环境搭建、工程测试等流程。 简介 本节介绍了开发板主控、特点、开发板原理图、板载资源等信息。 主控 开发板采用 ME3…...
Hooks的使用限制及原因
Hooks的使用限制及原因 Hooks的核心限制 只能在函数组件顶层调用 ⭐不能在条件语句、循环、嵌套函数中调用 ⭐只能在React函数组件或自定义Hooks中调用 ⭐ 为什么有这些限制? 根本原因:React依赖Hooks的调用顺序 React内部使用数组来存储每个组件的…...
【JavaScript】二十六、正则表达式
文章目录 1、正则表达式1.1 定义1.2 校验 2、元字符2.1 边界符2.2 量词2.3 字符类2.3.1 方括号[ ]2.3.2 小点.2.3.3 预定义 2.4 案例:用户名验证 3、修饰符3.1 语法3.2 案例:过滤敏感词 1、正则表达式 Regular Expression,正则表达式&#x…...
Geek强大的电脑卸载软件工具,免费下载
一款强大的卸载电脑软件工具,无需安装 免费下载...
tomcat Server 连接服务器 进展
由于机房的环境变更,所接触的问题也不一样!!!! 但后来出现以下提示: 已连接到服务器 配置错误: 部署源 springmvc:war 无效[2025-04-23 11:19:50,192] 工件 springmvc:war: 部署工件时出错。请参阅服务器日…...
Elasticsearch 集群节点下线方案
Elasticsearch 集群节点下线方案 在 Elasticsearch(ES)集群中,节点(Node)下线可能会影响数据的可用性和集群的健康状态。因此,正确的下线步骤需要确保数据不会丢失,并且不会影响查询或写入。 &…...
【模板匹配】图像处理(OpenCV)-part10
19.1模板匹配 模板匹配就是用模板图(通常是一个小图)在目标图像(通常是一个比模板图大的图片)中不断的滑动比较,通过某种比较方法来判断是否匹配成功,找到模板图所在的位置。 不会有边缘填充。 类似于卷积,…...
VMware中CentOS 7虚拟机设置固定IP(NAT模式)完整教程
前言 在VMware中为CentOS 7虚拟机配置固定IP是搭建稳定服务环境的关键步骤。本文基于用户提供的最新配置文件,详细演示如何从DHCP自动获取IP调整为固定IP(192.168.89.129),并提供修改前后的配置对比及操作验证。 一、当前配置状态…...
Ragflow、Dify、FastGPT、COZE核心差异对比与Ragflow的深度文档理解能力和全流程优化设计
一、Ragflow、Dify、FastGPT、COZE核心差异对比 以下从核心功能、目标用户、技术特性等维度对比四款工具的核心差异: 核心功能定位 • Ragflow:专注于深度文档理解的RAG引擎,擅长处理复杂格式(PDF、扫描件、表格等)的…...
飞帆控件:在编辑模式下额外加载的库
飞帆是一个自由的控件设计平台。在飞帆中,我们可以很方便地创建基于 Vue 2 组件的控件,并使用控件来搭建网页。 他山之石,可以攻玉。在创建控件中,使用 js 、css 依赖库能让我们的控件更强大。 有些时候,在编辑模式下…...
Agentic AI——当AI学会主动思考与决策,世界将如何被重塑?
一、引言:2025,Agentic AI的元年 “如果ChatGPT是AI的‘聊天时代’,那么2025年将开启AI的‘行动时代’。”——Global X Insights[1] 随着Agentic AI(自主决策型人工智能)的崛起,AI系统正从被动应答的“工具…...
68元撬动未来:明远智睿2351开发板重塑嵌入式开发生态
在嵌入式开发领域,价格与性能的矛盾始终存在:高端开发板功能强大但成本高昂,低价产品则往往受限于性能与扩展性。明远智睿2351开发板以68元(含税)的定价打破这一僵局,通过四核1.4G处理器、全功能Linux系统与…...
C# 全局 Mutex 是否需使用 `Global\` 前缀
回顾一下Mutex在Windows中的作用。Mutex是用于同步多个进程或线程的机制,确保同一时间只有一个实例访问资源。当创建Mutex时,如果命名时没有指定Global\前缀,默认可能是在会话内创建的,也就是只在当前用户会话中可见。这样的话&am…...
C# 中的 `lock` 关键字本质
C# 中的 lock 关键字本质上是基于 Monitor 类实现的线程同步机制,其核心是通过 互斥锁(Mutex) 确保代码块的原子性执行。以下是其实现本质的分步解析: 1. 语法糖的转换 当使用 lock 关键字时: lock (obj) {// 临界区…...
Java 集合:泛型、Set 集合及其实现类详解
参考资料:java入门到飞起 Java;泛型;Set 集合;TreeSet;HashSet;数据结构 一、引言 在 Java 编程中,集合框架是一个重要的组成部分,它提供了丰富的数据结构和算法来存储和操作数据。泛型与 Set…...
前端基础之《Vue(8)—内置组件》
一、Vue2.0中的内置组件 1、<slot> 插槽 2、<keep-alive> 动态组件 被keep-alive所包裹的组件: (1)不会被销毁。 (2)还会多两个生命周期钩子:activated()、deactivated()。 (3&a…...
Zookeeper是什么?基于zookeeper实现分布式锁
zookeeper听的很多,但实际在应用开发中用的不错,主要是作为中间件配合使用的,例如:Kafka。 了解zk首先需要知道它的数据结构,可以想象为树、文件夹目录。每个节点有基本的信息,例如:创建时间、…...
计算机网络 第二章:应用层(四)
2.6 视频流和内容分发网 对如何在因特网中实现流行的视频流服务进行概述。它们的实现方式是使用应用层协议和以像高速缓存那样方式运行的服务器。 2.6.1 因特网视频 在流式存储视频应用中,基础的媒体是预先录制的视频,例如电影、电视节目、录制好的体育…...
什么是数据库的DDL和DML,有什么区别?
数据库中的 DDL 和 DML 是两类不同的 SQL 语言,用于不同的数据库操作目的。以下是它们的定义、区别和具体说明: 1. DDL(Data Definition Language,数据定义语言) 作用:定义或修改数据库的结构(…...
HCIP实验二(OSPF网络配置与优化)
一.拓扑图与题目 1.R5为ISP,其上只能配置IP地址; R5与其他所有直连设备间均使用公有IP;环回地址为100.1.1.1/3 2.R4设备为企业出口路由器 3.整个0SPF环境IP基于172.16.0.0/16划分 4.所有设备均可访问R5的环回; 5.减少LSA的更新里,加快收敛࿰…...
第十六讲、isaaclab中使用任务空间(task-space)控制
0 前言 官方教程:https://isaac-sim.github.io/IsaacLab/main/source/tutorials/05_controllers/run_diff_ik.html IsaacsimIsaaclab安装:https://blog.csdn.net/m0_47719040/article/details/146389391?spm1001.2014.3001.5502 在之前的教程中我们利…...
无人船 | 图解基于PID控制的路径跟踪算法(以欠驱动无人艇Otter为例)
目录 1 PID控制的三大组成1.1 比例控制作用1.2 积分控制作用1.3 微分控制作用 2 基于欠驱动运动学的PID控制3 跟踪效果分析 1 PID控制的三大组成 PID控制律的定量表达请参考无人船 | 图解基于PID控制的路径跟踪算法(以全驱动无人艇WAMV为例),本文进一步介绍PID每个…...
【C++】13.list的模拟实现
首先,我们需要把链表管理起来,也就是把一个个节点管理起来,但是每个节点的信息我们也需要管理,例如节点的前驱指针和后驱指针,以及节点的值,所以我们这里先封装两个类来管理节点和链表。 namespace Ro {te…...
Springfox + Swagger 的完整配置及同类框架对比的详细说明
以下是 Springfox Swagger 的完整配置及同类框架对比的详细说明: 一、Springfox Swagger 配置详解 1. 添加依赖 在 pom.xml 中添加以下依赖: <!-- Springfox Swagger 2 --> <dependency><groupId>io.springfox</groupId>…...
实现支付宝沙箱环境搭建
1.介绍 在业务开发的过程中,有时会涉及到一些支付相关的功能,这个时候就需要接入第三方支付接口,而由于开发中需要不断进行测试,使用真实的账号进行支付就有些不值得,所以支付宝为我们提供了第三方SDK,供我…...
element-ui transfer 组件源码分享
transfer 穿梭框组件源码简单分享,主要从以下几个方面: 1、transfer 组件页面结构。 2、transfer 组件属性。 3、transfer 组件方法。 4、transfer 组件事件。 5、transfer slot 挂载。 一、组件页面结构。 二、组件属性。 2.1 value / v-model 绑…...
【最新版】沃德代驾源码全开源+前端uniapp
一.系统介绍 基于ThinkPHPUniapp开发的代驾软件。系统源码全开源,代驾软件的主要功能包括预约代驾、在线抢单、一键定位、在线支付、车主登记和代驾司机实名登记等。用户可以通过小程序预约代驾服务,系统会估算代驾价格并推送附近代驾司机供用户选择&…...
【无标题】spark安装部署
Spark 4种部署模式的另外2种,分别是Yarn、windows模式。 二、 实验准备工作: 1. 三台linux虚拟机 2. spark的压缩包 三、 实验步骤 Spark-yarn 1. 解压缩文件,并重命名为spark-yarn。 tar zxvf spark-3.0.0-bin-hadoop3.2.tgz mv spar…...