【字符设备驱动开发–IMX6ULL】(一)简介
【字符设备驱动开发–IMX6ULL】(一)简介
一、Linux驱动与裸机开发区别
1.裸机驱动开发回顾
1、底层,跟寄存器打交道,有些MCU提供了库。
spi.c:主机驱动(换成任何一个设备之后只需要调用此文件里面的函数即可)

**w25q.c:**设备驱动(根据具体的设备来写的驱动)

2.Linux驱动开发思维
1、Linux下驱动开发直接操作寄存器不现实。
2、根据Linux下的各种驱动框架进行开发。一定要满足框架,也就是Linux下各种驱动框架的掌握。
3、驱动最终表现就是/dev/xxx文件。打开、关闭、读写、。。。
4、现在新的内核支持设备树,这个一个.dts文件,此文件 描述了板子的设备信息。
3.Linux驱动开发分类
linux驱动分为三大类:
1、字符设备驱动,最多的。
2、块设备驱动,存储
3、网络设备驱动,
一个设备不说是一定只属于某一个类型。比如USB WIFI,SDIO WIFI,属于网络设备驱动,因为他又有USB和SDIO,因此也属于字符设备驱动。
二、字符设备开发基础
1.应用程序和驱动的交互原理
1.驱动就是获取外设、或者传感器数据,控制外设。数据会提交给应用程序。Linux驱动编译既要编写一个驱动,还要我们编写一个简单的测试应用程序,APP。
单片机下驱动和应用都是放到一个文件里面,也就是杂糅到一起。Linux下驱动和应用是完全分开的。
2.用户空间(用户态)和内核空间(内核态):
Linux操作系统内核和驱动程序运行在内核空间、应用程序运行在用户空间。
3.应用程序想要访问内核资源,怎么办,有三种方法:系统调用、异常(中断)和陷入。
应用程序不会直接调用系统调用,而是通过API函数来间接的调用系统调用,比如POSIX、API和C库等。unix类操作系统中最常用的编程接口就是POSIX。
应用 程序使用open函数 打开一个设备文件。
4.每个系统调用都有一个系统调用号。
系统调用处于内核空间,应用程序无法直接访问,因此需要“陷入“到内核,方法就是软中断。陷入内核以后还要指定系统调用号。

2.字符设备驱动开发流程
1,Linux里面一切皆文件,驱动设备表现就是一个/dev/下的文件,/dev/led。应用程序调用open函数打开设备,比如led。应用程序通过write函数向/dev/led写数据,比如写1表示打开,写0表示关闭。如果要关闭设备那么就是close函数。
2,编写驱动的 时候也需要编写驱动对应的open、close,write函数。字符设备驱动file_operations
1、驱动最终是被应用调用的,在写驱动的时候要考虑应用开发的便利性。
2、驱动是分驱动框架的,要按照驱动框架来编写,对于字符设备驱动来说,重点编写应用程序对应的open、close、read、write等函数。
三、字符设备驱动简介
字符设备是 Linux 驱动中最基本的一类设备驱动,字符设备就是一个一个字节,按照字节流进行读写操作的设备,读写数据是分先后顺序的。比如我们最常见的点灯、按键、IIC、SPI,LCD 等等都是字符设备,这些设备的驱动就叫做字符设备驱动。
在详细的学习字符设备驱动架构之前,我们先来简单的了解一下 Linux 下的应用程序是如何调用驱动程序的,Linux 应用程序对驱动程序的调用如图所示:

在 Linux 中一切皆为文件,驱动加载成功以后会在“/dev”目录下生成一个相应的文件,应用程序通过对这个名为“/dev/xxx”(xxx 是具体的驱动文件名字)的文件进行相应的操作即可实现对硬件的操作。
比如现在有个叫做/dev/led 的驱动文件,此文件是 led 灯的驱动文件。
- 1.应用程序使用 open 函数来打开文件
/dev/led - 2.使用完成以后使用 close 函数关闭
/dev/led这个文件。open和 close 就是打开和关闭 led 驱动的函数, - 3.如果要点亮或关闭 led,那么就使用 write 函数来操作,也就是向此驱动写入数据,这个数据就是要关闭还是要打开 led 的控制参数。
- 4.如果要获取led 灯的状态,就用 read 函数从驱动中读取相应的状态。
应用程序运行在用户空间,而 Linux 驱动属于内核的一部分,因此驱动运行于内核空间。当我们在用户空间想要实现对内核的操作,比如使用 open 函数打开/dev/led 这个驱动,因为用户空间不能直接对内核进行操作,因此必须使用一个叫做“系统调用”的方法来实现从用户空间“陷入”到内核空间,这样才能实现对底层驱动的操作。
open、close、write 和 read 等这些函数是由 C 库提供的,在 Linux 系统中,系统调用作为 C 库的一部分。当我们调用 open 函数的
时候流程如图所示:

其中关于 C 库以及如何通过系统调用“陷入”到内核空间这个我们不用去管,我们重点关注的是应用程序和具体的驱动,应用程序使用到的函数在具体驱动程序中都有与之对应的函数,
比如应用程序中调用了 open 这个函数,那么在驱动程序中也得有一个名为 open 的函数。每一个系统调用,在驱动中都有与之对应的一个驱动函数,在 Linux 内核文件 include/linux/fs.h 中有个叫做 file_operations 的结构体,此结构体就是 Linux 内核驱动操作函数集合,内容如下所示:
一般在1550行左右
struct file_operations {
//owner 拥有该结构体的模块的指针,一般设置为 THIS_MODULE。struct module *owner;
//llseek 函数用于修改文件当前的读写位置。loff_t (*llseek) (struct file *, loff_t, int);
//read 函数用于读取设备文件。ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
//write 函数用于向设备文件写入(发送)数据。ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);int (*iterate) (struct file *, struct dir_context *);
//poll 是个轮询函数,用于查询设备是否可以进行非阻塞的读写。unsigned int (*poll) (struct file *, struct poll_table_struct *);
//unlocked_ioctl 函数提供对于设备的控制功能,与应用程序中的 ioctl 函数对应。long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
//compat_ioctl 函数与 unlocked_ioctl 函数功能一样,区别在于在 64 位系统上,
//32 位的应用程序调用将会使用此函数。在 32 位的系统上运行 32 位的应用程序调用的是unlocked_ioctl。long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
/*mmap 函数用于将设备的内存映射到进程空间中(也就是用户空间),一般帧缓冲设备会使用此函数,
比如 LCD 驱动的显存,将帧缓冲(LCD 显存)映射到用户空间中以后应用程序就可以直接操作显存了,
这样就不用在用户空间和内核空间之间来回复制。*/int (*mmap) (struct file *, struct vm_area_struct *);
//open 函数用于打开设备文件。int (*open) (struct inode *, struct file *);int (*flush) (struct file *, fl_owner_t id);
//release 函数用于释放(关闭)设备文件,与应用程序中的 close 函数对应。int (*release) (struct inode *, struct file *);
//fasync 函数用于刷新待处理的数据,用于将缓冲区中的数据刷新到磁盘中。int (*fsync) (struct file *, loff_t, loff_t, int datasync);
//aio_fsync 函数与 fasync 函数的功能类似,只是 aio_fsync 是异步刷新待处理的数据。int (*aio_fsync) (struct kiocb *, int datasync);int (*fasync) (int, struct file *, int);int (*lock) (struct file *, int, struct file_lock *);ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);int (*check_flags)(int);int (*flock) (struct file *, int, struct file_lock *);ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);int (*setlease)(struct file *, long, struct file_lock **);long (*fallocate)(struct file *file, int mode, loff_t offset,loff_t len);int (*show_fdinfo)(struct seq_file *m, struct file *f);
};
在字符设备驱动开发中最常用的函数已经标上注释,关于其他的函数大家可以查阅相关文档。
我们在字符设备驱动开发中最主要的工作就是实现上面这些函数,不一定全部都要实现,
但是像 open、release、write、read 等都是需要实现的,当然了,具体需要实现哪些函数还是要看具体的驱动要求。
相关文章:
【字符设备驱动开发–IMX6ULL】(一)简介
【字符设备驱动开发–IMX6ULL】(一)简介 一、Linux驱动与裸机开发区别 1.裸机驱动开发回顾 1、底层,跟寄存器打交道,有些MCU提供了库。 spi.c:主机驱动(换成任何一个设备之后只需要调用此文件里面的…...
45 55跳跃游戏解题记录
先是55跳跃游戏,暴力解法会怎样?会超出时间限制,而且有很多细节要注意: func canJump(nums []int) bool {// 处理空数组情况,当nums只剩一个元素时,nums[i:]导致越界。if len(nums) 0 {return false}// 如…...
C++_STL之list篇
一、list的介绍 std::list是C标准模板库(STL)中的一个双向链表容器。与vector和deque不同,list不支持随机访问,但它在任何位置插入和删除元素都非常高效。 1.基本特性 (1)双向链表结构:每个元素都包含指向前驱和后继的指针 (2)非连续存储&…...
Go中的逃逸分析
什么是逃逸? 逃逸是指一个变量本来应该分配在栈(stack)上,但由于某些原因,最终被分配到了堆(heap)上。 类比: 栈就像一个临时的快餐盒,用来存放短期使用的数据。堆就像…...
Spring 声明式事务 万字详解(通俗易懂)
目录 Δ前言 一、声明式事务快速入门 1.为什么需要声明式事务? 2.定义: 3.应用实例: 二、声明式事务的传播机制 1.引出问题: 2.传播机制分类: 3.应用实例: 三、声明式事务的隔离机制 1.四种隔离级别&…...
MySQL 当中的锁
MySQL 当中的锁 文章目录 MySQL 当中的锁MySQL 中有哪些主要类型的锁?请简要说明MySQL 的全局锁有什么用?MySQL 的表级锁有哪些?作用是什么?元数据锁(MetaData Lock,MDL)意向锁(Inte…...
fyrox 2D和3D游戏的制作
目录 fyrox介绍 1. 核心特性 1.1 高性能渲染 1.2 跨平台支持 1.3 物理引擎集成 1.4 脚本系统 1.5 场景管理 2. 架构设计 2.1 渲染器 2.2 资源管理器 2.3 输入系统 2.4 音频引擎 2.5 网络模块 3. 使用场景 3.1 2D游戏 3.2 3D游戏 3.3 模拟与教育应用 4. 在游戏…...
[Linux]基础IO
基础IO C文件IO相关操作磁盘文件与内存文件inode(index node)硬链接与软连接硬链接软连接总结 动静态库静态库动态库总结 C文件IO相关操作 当前路径:进程运行的时候,所处的路径叫做当前路径 打开文件的时候,一定是进…...
力扣刷题-热题100题-第27题(c++、python)
21. 合并两个有序链表 - 力扣(LeetCode)https://leetcode.cn/problems/merge-two-sorted-lists/description/?envTypestudy-plan-v2&envIdtop-100-liked 常规法 创建一个新链表,遍历list1与list2,将新链表指向list1与list2…...
Vue3 其它API Teleport 传送门
Vue3 其它API Teleport 传送门 在定义一个模态框时,父组件的filter属性会影响子组件的position属性,导致模态框定位错误使用Teleport解决这个问题把模态框代码传送到body标签下...
windows下安装sublime
sublime4 alpha 4098 版本 下载 可以根据待破解的版本选择下载 https://www.sublimetext.com/dev crack alpha4098 的licence 在----- BEGIN LICENSE ----- TwitterInc 200 User License EA7E-890007 1D77F72E 390CDD93 4DCBA022 FAF60790 61AA12C0 A37081C5 D0316412 4584D…...
golang 的strconv包常用方法
目录 1. 字符串与整数的转换 2. 字符串与浮点数的转换 3. 布尔值的转换 4. 字符串的转义 5. 补充:rune 类型的使用 方法功能详解 代码示例: 1. 字符串与整数的转换 方法名称功能描述示例Atoi将字符串转换为十进制整数。strconv.Atoi("123&q…...
ComplexE的代码注释
目录 dataloader.pymodel.pyrun.py 先安装软件,配置环境,搞了一周。再看代码写注释搞了一周。中间隔了一周。再安装环境跑代码又一周。最后结果是没结果。自己电脑内存带不动。还不想配电脑,又不会用GPU服务器。哭死哭死。心态崩了。直接发吧…...
vector<int> 的用法
vector<int> 是 C 标准模板库(STL)中的一个容器,用于存储动态大小的整数序列。以下是它的主要用法: 基本操作 1. 创建和初始化 #include <vector> using namespace std;vector<int> v1; // 空vector vector<int>…...
Java高级JVM知识点记录,内存结构,垃圾回收,类文件结构,类加载器
JVM是Java高级部分,深入理解程序的运行及原理,面试中也问的比较多。 JVM是Java程序运行的虚拟机环境,实现了“一次编写,到处运行”。它负责将字节码解释或编译为机器码,管理内存和资源,并提供运行时环境&a…...
名言警句1
1、嫉妒是欲望的衍生,而欲望则是成长的驱动,说到底每个人都是为了成长,为了不居人后,在成长的过程中,我们可以让欲望枝繁叶茂,但不能让嫉妒开花结果 2、人生无法奢求更多,我们有健康的身体&…...
【STL】queue
q u e u e queue queue 是一种容器适配器,设计为先进先出( F i r s t I n F i r s t O u t , F I F O First\ In\ First\ Out,\ FIFO First In First Out, FIFO)的数据结构,有两个出口,将元素推入队列的操作称为 p u …...
QXmpp入门
QXmpp 是一个基于 Qt 的 XMPP (Jabber) 协议实现库,用于开发即时通讯(IM)、聊天应用和实时协作系统。它支持客户端和服务端开发,提供完整的 XMPP 核心功能扩展。 1. 核心功能 XMPP 核心协议支持 支持 RFC 6120 (XMPP Core) 和 RFC 6121 (XMPP IM) 基础功能:认证、在线状态…...
使用cursor为代码添加注释
1. add-comments.md英文 You are tasked with adding comments to a piece of code to make it more understandable for AI systems or human developers. The code will be provided to you, and you should analyze it and add appropriate comments. To add comments to …...
20250330-傅里叶级数专题之离散时间傅里叶变换(4/6)
4. 傅里叶级数专题之离散时间傅里叶变换 20250328-傅里叶级数专题之数学基础(0/6)-CSDN博客20250330-傅里叶级数专题之傅里叶级数(1/6)-CSDN博客20250330-傅里叶级数专题之傅里叶变换(2/6)-CSDN博客20250330-傅里叶级数专题之离散傅里叶级数(3/6)-CSDN博客20250330-傅里叶级数专…...
漏洞挖掘---迅饶科技X2Modbus网关-GetUser信息泄露漏洞
一、迅饶科技 X2Modbus 网关 迅饶科技 X2Modbus 网关是功能强大的协议转换利器。“X” 代表多种不同通信协议,能将近 200 种协议同时转为 Modbus RTU 和 TCP 服务器 。支持 PC、手机端等访问监控,可解决组态软件连接不常见控制设备难题,广泛…...
Java进阶——位运算
位运算直接操作二进制位,在处理底层数据、加密算法、图像处理等领域具有高效性能和效率。本文将深入探讨Java中的位运算。 本文目录 一、位运算简介1. 与运算2. 或运算异或运算取反运算左移运算右移运算无符号右移运算 二、位运算的实际应用1. 权限管理2. 交换两个变…...
golang strings包常用方法
方法名称功能描述示例strings.Join将字符串切片中的元素连接成一个字符串,使用指定的分隔符。strings.Join([]string{"hello", "world"}, " ")strings.HasPrefix检查字符串是否以指定的前缀开头。strings.HasPrefix("hello"…...
网络安全之前端学习(css篇2)
那么今天我们继续来学习css,预计这一章跟完后,下一章就是终章。然后就会开始js的学习。那么话不多说,我们开始吧。 字体属性 之前讲到了css可以改变字体属性,那么这里来详细讲一讲。 1.1字体颜色 之前讲到了对于字体改变颜色食…...
PS底纹教程
1.ctrlshiftU 去色 2.新建纯色层 颜色中性灰;转换为智能对象 3.纯色层打开滤镜(滤镜库); 素描下找到半调图案,数值调成大小5对比1; 再新建一层,素描下找到撕边,对比拉到1&#x…...
NX/UG二次开发—CAM获取加工操作的最低Z深度值的方法
网上已经有些大佬给出了解决方案,但是基本有两种,一种内部函数,另外一种就是导出程序的刀轨文件找坐标计算。使用内部函数进行操作,可以自己学习,不做解释。下面只是针对第二种进行说明,参考胡君老师的教程…...
解决pyinstaller GUI打包时无法打包图片问题
当我们的python GuI在开发时。经常会用到图片作为背景,但是在打包后再启动GUI后却发现:原先调试时好端端的背景图片竟然不翼而飞或者直接报错。这说明图片没有被pyinstaller一起打包…… 要解决这个问题很简单,就是更改图片的存储方式。 tk…...
蓝桥杯真题------R格式(高精度乘法,高精度加法)
对于高精度乘法和加法的同学可以学学这几个题 高精度乘法 高精度加法 文章目录 题意分析部分解全解 后言 题意 给出一个整数和一个浮点数,求2的整数次幂和这个浮点数相乘的结果最后四舍五入。、 分析 我们可以发现,n的范围是1000,2的1000次方非常大&am…...
Nginx — Nginx安装证书模块(配置HTTPS和TCPS)
一、安装和编译证书模块 [rootmaster nginx]# wget https://nginx.org/download/nginx-1.25.3.tar.gz [rootmaster nginx]# tar -zxvf nginx-1.25.3.tar.gz [rootmaster nginx]# cd nginx-1.25.3 [rootmaster nginx]# ./configure --prefix/usr/local/nginx --with-http_stub_…...
回调后门基础
回调后门概述 回调后门(Reverse Shell)是一种常见的攻击方式,攻击者通过受害主机主动连接到远程服务器(攻击者控制的机器),从而获得远程控制权限。 工作原理 受害者主机 运行一个恶意代码,尝…...
