高级驱动———驱动详解

本文详细探讨了Linux内核如何自动匹配设备驱动,包括字符设备的注册、内核处理流程、设备文件创建以及应用层与驱动层的交互。重点解释了input_dev_list和input_handler_list链表的匹配机制,connect函数的作用,以及应用层调用read时驱动层执行文件操作的原理。同时,介绍了设备节点的创建、file_operations结构体在文件操作中的关键角色。
摘要由CSDN通过智能技术生成

虽然我们知道了当我们写一个设备的模块时候,只要指定是字符输入设备,当你模块装载的时候,内核就会自动匹配input.ko event.ko模块,让这个设备模块完成驱动。
内核帮我们完成了这些事情
2,申请设备号 register_chrdev_region (与内核相关)
3,注册字符设备驱动 cdev_alloc cdev_init cdev_add (与内核相关)
4,利用udev/mdev机制创建设备文件(节点) class_create, device_create (与内核相关)
5,构建 file_operation结构 (与内核相关)
6,实现操作硬件方法 xxx_open,xxx_read,xxxx_write…(与硬件相关)
那我们肯定要了解,内核是怎么做这些事情的。
然后还有就是一些疑问?
1)就是它是怎么匹配的——————(之前猜的是总线,但是不是,就是两个链表,那具体是怎么实现的呢?看名字?)
2)我一直不理解,为什么应用层调一个read 那驱动层就会执行read的文件操作??虽然是通过文件描述符肯定有有一些联系?
但是怎么联系的呢?总不能是我应用层read了这个文件,然后我内核就知道o,你要read啊,那我就调read。内核肯定没怎么智能

————————————————————————————————————————————————————
首先看一个驱动的在运行的时候做的事情的顺序。
就是我把我的设备模块写好,装载进去的时候内核是执行那些步骤然后完成驱动的。
在这里插入图片描述

第一步:
把设备模块装载在内核中
第二步:
装载完成之后,在核心层就会,注册设备号(系统自动给你分配主次设备号)这里还有一个file_operation
然后还是在核心层创建类,这个类和c++中的类不是一样 的,这个类也是一个sys下的一个目录该目录下包含所有注册在
kernel里面的设备类型 我们的设备会出现在 /sys/class/input/这个目录里面。

然后我们要对硬件信息进行初始化(这个步骤是我们自己完成的,不是内核做的)

第三步:
把设备注册到input_dev_list这个链表里面去,
然后我们的input_handler_list 里面在内核运行的时候就已经把内核中有的调用层handler加进去了。
俩个链表就会进行匹配。怎么匹配的后面会讲。
第四步:
匹配完成之后handle层就会调用connet这个函数去创建我们的设备节点
然后实现file_operation
connect和怎么实现file_operation后面也会讲。

具体代码可以去看kernel下面的drives下面的input.c 和evdev.c这俩个就是核心层和调用层的源代码。

————————————————————————————————————————————————
一、input_dev_list 和 input_handler_list是怎么匹配的。
在这里插入图片描述
首先,无论你是input_dev_list 还是input_handler_list,这俩个链表中哪一个链表注册进新的节点,都会去遍历一遍对方的链表。
遍历如果发现条件相同就会进行匹配。那什么是条件呢?比如我dev的evbit 的值是一个条件 keybit的值也是一个条件等等。
然后我要handel指定去驱动evbit的值是按键的。那么就会和dev的evbit 的值是按键的设备匹配。
然后我们看一下event下匹配事件
在这里插入图片描述
这里event的id_table只有一个1,是什么意识?就是恒匹配的意思。
只要你属于输入设备,我都可以把你看成一个event一个事件,我的handler都可以和你一起组成一个完整的驱动。
其实之前没有引入event的时候,我们会把驱动模块进行区分,比如分mouse模块 joystatic模块,,这样我mouse只能和evbit的条件是mouse的设备进行匹配,引入event之后可以把所有的设备都可以看成一个事件,所以事件里面包含鼠标,
但是你去看drives下面的目录,就会发现不止有evdev.c 还有mouse.c 这就是,没有引入evdev之前的mouse

————————————————————————————————————————————
一、connect函数的作用
connect属于 evdev_handler里面的一个函数接口

static struct input_handler evdev_handler = {
	.event		= evdev_event,
	.events		= evdev_events,
	.connect	= evdev_connect,
	.disconnect	= evdev_disconnect,
	.legacy_minors	= true,
	.minor		= EVDEV_MINOR_BASE,
	.name		= "evdev",

connect:
首先:
1)会创建一个evdev的结构体,并初始化
在这里插入图片描述
evdev里面有一个叫dev的成员 //这个dev只要是用来创建设备节点的。
这个dev会调用一个set_dev_name的函数去创建一个设备节点
和我们之前用的device_create函数差不多。
而创建的dev设备节点点里面又包含了,handler和decvice的指针呢个,这就类似于:
在这里插入图片描述
这里可能有点乱了,我们再从另一个角度来看
———————————————————————————————————————————
在这里插入图片描述
这是核心层里面的
首先:input_dev_list和input_handler_list这是来个要匹配的链表,链表里面由很多相同的结构体组成。
如果我们的input_dev要和input_handle匹配,就会调用connect去创建设备节点。
这个设备节点就是我们这里的evdev对象。它下面有一个Input_handle的结构体,这个结构体里面会有指向handler和DEV的指针。
这样这三方就联系起来了
—————————————————————————————————————————————————
二、接下来我们看一下
为什么应用层调一个read 那驱动层就会执行read的文件操作
首先,我们会调用open函数去打开dev/。。。这个设备文件。就会返回一个文件描述符。
那这个文件描述符——我们对文件描述都哦比较熟悉了,比如我们打开一个文件返回的文件描述符应该就会是3但是这个三只是应该下标,
它还会有一个结构体,里面存放这很多文件的信息。

这个结构体叫struct file {};
我们之前的驱动中fiel_opreation里面的read,write等函数里面的参数就是要填一个struct file
在这里插入图片描述
我们看一下这个结构体里面有什么?

struct file {
	union {
		struct llist_node	fu_llist;
		struct rcu_head 	fu_rcuhead;
	} f_u;
	struct path		f_path;
#define f_dentry	f_path.dentry
	struct inode		*f_inode;	/* cached value */
	const struct file_operations	*f_op;

	/*
	 * Protects f_ep_links, f_flags.
	 * Must not be taken from IRQ context.
	 */
	spinlock_t		f_lock;
	atomic_long_t		f_count;
	unsigned int 		f_flags;
	fmode_t			f_mode;
	struct mutex		f_pos_lock;
	loff_t			f_pos;
	struct fown_struct	f_owner;
	const struct cred	*f_cred;
	struct file_ra_state	f_ra;
	..............

我们只列了一部分:
可以看到里面有一个:
const struct file_operations *f_op;
这不就是我们经常用的文件操作结构体吗???
我们看一下是怎么通过这个文件操作结构体来实现的这些操作。
在这里插入图片描述
当我们打开一个文件的时候,就会创建一个文件结构体,这个文件结构体就会存储 flags等信息。
当我们对这个文件描述符进行文件io的操作的时候,就会进行系统调用。
会遍历VFS(虚拟文件系统)的一个cdev链表,然后根据主次设备号匹配这个链表;
这些CDEV链表是从哪里来的呢?就是我们在驱动层调用regeaust_chrdev申请设备号的函数的时候,创建的一个cdev
在这里插入图片描述
这是我们以前的没有引入高级驱动的方法的时候自己申请的设备号,现在内核会自己申请了,它也调用了这个函数

那我们来看一下,它传的参数 &my_fope :这个就是一个file_operation 所以这个cdev里面不止存放着主次设备号,还有file_operation的指针。
在这里插入图片描述
当系统调用read去遍历VFS层的cdev的时候就会去遍历主次设备号,一旦找到一样的就会拿到ile_operation的指针
然后就会把cdev的file_operation给到 file结构体里的f_ops结构体里面去。
然后调用对应的操作。

————————————————————————————————————————————————————
三、数据上报的详解
在这里插入图片描述
connect下面的evdev对象下面还会有一个client用于存放要上报的数据
在open的时候会创建这个缓冲区

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值