字符设备驱动框架解析

news2024/11/16 13:39:00

一、字符设备驱动框架解析

设备的操作函数如果比喻是桩的话(性质类似于设备操作函数的函数,在一些场合被称为桩函数),则:

驱动实现设备操作函数 ----------- 做桩

insmod调用的init函数主要作用 --------- 钉桩

rmmod调用的exitt函数主要作用 --------- 拔桩

应用层通过系统调用函数间接调用这些设备操作函数 ------- 用桩

1.1 两个操作函数中常用的结构体说明

内核中记录文件元信息的结构体
struct inode
{
	//....
	dev_t  i_rdev;//设备号
	struct cdev  *i_cdev;//如果是字符设备才有此成员,指向对应设备驱动程序中的加入系统的struct cdev对象
	//....
}
/*
	1. 内核中每个该结构体对象对应着一个实际文件,一对一
	2. open一个文件时如果内核中该文件对应的inode对象已存在则不再创建,不存在才创建
	3. 内核中用此类型对象关联到对此文件的操作函数集(对设备而言就是关联到具体驱动代码)
*/
读写文件内容过程中用到的一些控制性数据组合而成的对象------文件操作引擎(文件操控器)
struct file
{
	//...
	mode_t f_mode;//不同用户的操作权限,驱动一般不用
	loff_t f_pos;//position 数据位置指示器,需要控制数据开始读写位置的设备有用
	unsignedint f_flags;//open时的第二个参数flags存放在此,驱动中常用
	structfile_operations*f_op;//open时从struct inode中i_cdev的对应成员获得地址,驱动开发中用来协助理解工作原理,内核中使用
	void*private_data;//本次打开文件的私有数据,驱动中常来在几个操作函数间传递共用数据
	structdentry*f_dentry;//驱动中一般不用,除非需要访问对应文件的inode,用法flip->f_dentry->d_inode
    int refcnt;//引用计数,保存着该对象地址的位置个数,close时发现refcnt为0才会销毁该struct file对象
	//...
};
/*
	1. open函数被调用成功一次,则创建一个该对象,因此可以认为一个该类型的对象对应一次指定文件的操作
	2. open同一个文件多次,每次open都会创建一个该类型的对象
	3. 文件描述符数组中存放的地址指向该类型的对象
	4. 每个文件描述符都对应一个struct file对象的地址
*/

1.2 字符设备驱动程序框架分析

驱动实现端:

在这里插入图片描述

驱动使用端:

在这里插入图片描述

syscall_open函数实现的伪代码:

int syscall_open(const char *filename,int flag)
{
    dev_t devno;
    struct inode *pnode = NULL;
    struct cdev *pcdev = NULL;
    struct file *pfile = NULL;
    int fd = -1;
    
    /*根据filename在内核中查找该文件对应的struct inode对象地址
        找到则pnode指向该对象
        未找到则创建新的struct inode对象,pnode指向该对象,并从文件系统中读取文件的元信息到该对象*/
    if(/*未找到对应的struct inode对象*/)
    {/*根据文件种类决定如何进行下面的操作,如果是字符设备则执行如下操作*/
    
    	/*从pnode指向对象中得到设备号*/
	    devno = pnode->i_rdev;
    
    	/*用devno在字符设备链表查找对应节点,并将该节点的地址赋值给pcdev*/
    
    	/*pcdev赋值给pnode的i_cdev成员*/
    	pnode->i_cdev = pcdev;
    }
    
    /*创建struct file对象,并将该对象的地址赋值给pfile*/
    
    pfile->f_op = pnode->i_cdev->ops;
    pfile->f_flags = flag;
    
    /*调用驱动程序的open函数*/
    pfile->f_op->open(pnode,pfile,flag);
    
    /*将struct file对象地址填入进程的描述符数组,得到对应位置的下标赋值给fd*/
    
    return fd;
}

syscall_read函数实现的伪代码

int syscall_read(int fd,void *pbuf,int size)
{
    struct file *pfile = NULL;
    struct file_operations *fops = NULL;
    int cnt;
    
    /*将fd作为下标,在进程的描述符数组中获得struct file对象的地址赋值给pfile*/
    
    /*从struct file对象的f_op成员中得到操作函数集对象地址赋值给fops*/
    
    /*从操作函数集对象的read成员得到该设备对应的驱动程序中read函数,并调用之*/
    cnt = fops->read(pfile,pbuf,size,&pfile->f_pos);
    
    。。。。
    return cnt;
}

1.3 参考原理图

在这里插入图片描述
在这里插入图片描述

1.4 常用操作函数说明

int (*open) (struct inode *, struct file *);	//打开设备
/*
	指向函数一般用来对设备进行硬件上的初始化,对于一些简单的设备该函数只需要return 0,对应open系统调用,是open系统调用函数实现过程中调用的函数,
*/

int (*release) (struct inode *, struct file *);	//关闭设备
/*
	,指向函数一般用来对设备进行硬件上的关闭操作,对于一些简单的设备该函数只需要return 0,对应close系统调用,是close系统调用函数实现过程中调用的函数
*/

ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);	//读设备
/*
	指向函数用来将设备产生的数据读到用户空间,对应read系统调用,是read系统调用函数实现过程中调用的函数
*/

ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);    //写设备
/*
	指向函数用来将用户空间的数据写进设备,对应write系统调用,是write系统调用函数实现过程中调用的函数
*/

loff_t (*llseek) (struct file *, loff_t, int);		//数据操作位置的定位
/*
	指向函数用来获取或设置设备数据的开始操作位置(位置指示器),对应lseek系统调用,是lseek系统调用函数实现过程中调用的函数
*/


long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);//读写设备参数,读设备状态、控制设备
/*
	指向函数用来获取、设置设备一些属性或设备的工作方式等非数据读写操作,对应ioctl系统调用,是ioctl系统调用函数实现过程中调用的函数
*/

unsigned int (*poll) (struct file *, struct poll_table_struct *);//POLL机制,实现对设备的多路复用方式的访问
/*
	指向函数用来协助多路复用机制完成对本设备可读、可写数据的监控,对应select、poll、epoll_wait系统调用,是select、poll、epoll_wait系统调用函数实现过程中调用的函数
*/
  
int (*fasync) (int, struct file *, int); //信号驱动
/*
	指向函数用来创建信号驱动机制的引擎,对应fcntl系统调用的FASYNC标记设置,是fcntl系统调用函数FASYNC标记设置过程中调用的函数
*/

小结

  1. 使用open函数的第一个参数也就是文件的名称在内核中的struct inode链表里面找是否有对应的节点,没有就创建,有的话且是设备文件的话就把对应的设备号去struct cdev哈希链表中去找有没有对应的描述该设备的对象,没有就创建插入到该链表,然后将该节点的地址赋值给struct inode中的struct cdev * 这个成员。
  2. 每open一个文件都会创建一个struct file的对象(文件操作引擎),该对象里面的file_operations * 成员从struct cdev里得到,这样就拿到了对应文件的操作函数集的地址(struct file_operations结构体的地址),每个进程都会有一个struct file*类型的数组,该数组的下标就是所有的文件描述符。
  3. 接着的read、write函数就可以直接从struct file(文件操作引擎)中调用到相关的操作函数集里的相应的函数。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/947541.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

LinearAlgebraMIT_11_MatrixSpace/Rank==1‘sMatrix/SmallWorldGraph

x.1 矩阵空间 向量空间定义:满足加法和数乘的封闭性。就类似向量空间一样,也存在着矩阵空间的定义。举个例子,例如所有的3x3的矩阵构成的矩阵空间M,它的纬度就是9,如[1, 0, …], [0, 1, …]。对于M中所有对称矩阵组成…

Ansible学习笔记3

ansible模块: ansible是基于模块来工作的,本身没有批量部署的能力,真正具有批量部署的是ansible所运行的模块,ansible只是提供一个框架。 ansible支持的模块非常多,我们并不需要把每个模块记住,而只需要熟…

Ubuntu20以上高版本如何安装低版本GCC

安装了Ubuntu 20.04之后,通过命令行 sudo apt-get install build-essential安装gcc,再通过命令行 gcc -v可查看gcc版本为gcc13 如果想用低版本的gcc,比如gcc4.8,尝试输入命令 sudo apt-get install gcc-4.8会提示找不到gcc4.8的…

胡歌深夜发文:我对不起好多人

胡歌的微博又上了热搜。 8月29日01:18分,胡歌微博发文称:“我尽量保持冷静,我对不起好多人,我希望对得起这短暂的一生”,并配了一张自己胡子拉碴的图,右眼的伤疤清晰可见。 不少网友留言称“哥你又喝多了吗…

基于Java+SpringBoot+Vue前后端分离教师工作量管理系统设计和实现

博主介绍:✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 🍅文末获取源码联系🍅 👇🏻 精彩专…

希尔排序(JAVA实例代码)

目录 希尔排序 一、概念及其介绍 二、适用说明 三、过程图示 四、Java 实例代码 ShellSort.java 文件代码: 希尔排序 一、概念及其介绍 希尔排序(Shell Sort)是插入排序的一种,它是针对直接插入排序算法的改进。 希尔排序又称缩小增量排序&#…

【2023年11月第四版教材】《第9章-范围管理》(第二部分)

《第9章-范围管理》(第二部分) 4 规划范围管理4.1 范围管理计划★★★ (21下29)4.2 需求管理计划★★★ (22上27) 5 收集需求5.1 数据收集★★★5.2 决策★★★5.3 数据表现★★★5.4 人际关系与团队技能★…

【pyqt5界面化开发-6】抽屉布局界面的开发

目录 0x01 前言: 一、封装的主窗口类 第一步:封装窗口类 第二步:添加抽屉界面 第三步:添加抽屉界面的相关布局 第四步:每一个抽屉界面的点击触发 二、封装的抽屉类 三、程序入口程序 四、完整代码 0x01 前言&…

Windows端口占用处理

端口被占用时,大部分是后台服务持续运行使用了某个端口。这样会导致我们使用了相同端口的新程序无法正常启动,我们需要找到端口被占用的应用程序,方法比较简单,如下以3000端口被占用为例: 1、打开windows的cmd命令行窗…

数据结构与算法基础-学习-30-插入排序之直接插入排序、二分插入排序、希尔排序

一、排序概念 将一组杂乱无章的数据按一定规律顺次排列起来。 将无序序列排成一个有序序列(由小到大或由大到小)的运算。 二、排序方法分类 1、按数据存储介质 名称描述内部排序数据量不大、数据在内存,无需内外交换存交换存储。外部排序…

LNMT的多机部署和双机热备

目录 一、环境 二、配置tomcat 三、配置nfs共享 四、配置nginx 1、两台都需要折磨配置 2、在http下面插入这两条信息 五、配置keepalived 1、安装 2、重新启动一下keepalived查看IP 六、验证双机热备 1、查看调度器备的IP,ip漂移说明keepalived生效 2、访…

Python切换输入法的实战代码

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…

MySQL一行记录是如何存储的?

目录 MySQL的数据存放在哪个文件? 表空间文件的结构是怎么样的? 1、行(row) 2、页(page) 3、区(extent) 4、段(segment) InnoDB 行格式有哪些&#xf…

简述SpringMVC

一、典型的Servlet JSP JavaBean UserServlet看作业务逻辑处理(Controller)User看作模型(Model)user.jsp看作渲染(View) 二、高级MVC 由DispatcherServlet对请求统一处理 三、SpringMVC MVC与Spr…

雪花算法实现原理和精度失效问题

一、雪花算法的实现原理 雪花算法是一个全局唯一算法,它主要出现在像分库分表场景中作为业务主键、 或者作为一些像订单号这类的 id 生成器。 所以单纯就全局唯一性质来说,有很多的实现方式,比如 UUID , Redis 的原子递增 &#…

春秋云镜 CVE-2018-3191

春秋云镜 CVE-2018-3191 Weblogic WLS Core Components 反序列化命令执行漏洞 靶标介绍 Oracle Fusion Middleware 的 Oracle WebLogic Server 组件中的漏洞(子组件:WLS Core Components)。受影响的受支持版本包括 10.3.6.0、12.1.3.0 和 1…

基于Java+SpringBoot+Vue前后端分离工作流程管理系统设计和实现

博主介绍:✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 🍅文末获取源码联系🍅 👇🏻 精彩专…

QT6为工程添加资源文件,并在ui界面引用

以添加图片资源为例 右键工程名字(不是最上面的名字),点击添加现有文件 这种方式虽然添加到了工程中,但不能在UI设计界面完成引用。主要原因可能是未把文件放入到项目资源文件中,以下面一种方式可以看出区别。 点击添…

clickhouse 系列2:clickhouse 离线安装

1.下载rpm包 Altinity/clickhouse - Packages packagecloud 使用wget下载到本地目录 wget --content-disposition https://packagecloud.io/Altinity/clickhouse/packages/el/7/clickhouse-common-static-20.8.3.18-1.el7.x86_64.rpm/download.rpm wget

博流RISC-V芯片JTAG debug配置与运行

文章目录 1、Windows下安装与配置2、Linux下安装与配置3、芯片默认 JTAG PIN 列表4、命令行运行JTAG5、Eclipse下使用JTAG 1、Windows下安装与配置 CKLink 驱动安装 Windows版驱动下载地址: https://occ-oss-prod.oss-cn-hangzhou.aliyuncs.com/resource//1666331…