一、字符设备驱动调用过程的一些理解:

    设备驱动文件(也就是设备驱动程序源代码ap3216c.c)在内核中注册成功后,会生成一个设备文件,设备文件的名称就是设备驱动文件中定义的设备名称(.name字段的值 = ap3216c),设备文件注册成功后,在./dev.目录下就可以看到这个驱动文件ap3216c。

    在应用程序中通过open函数打开一个文件,打开的文件就是设备文件./dev./ap3216c,一旦打开文件成功,就会创建struct file结构体的对象,创建struct inode结构体的对象,然后通过设备号把把两个对象绑定,实现关联;

    那么节点结构体struct inode和文件结构体struct file的关系是什么呢? 在Linux系统中,针对某种设备,设备文件只有一个。同一个类型的设备共用一个设备驱动文件,此时驱动文件只有一个,抽象为设备cdev对象也只有一个。但是多个设备怎么共用这个设备驱动文件呢,通过inode对象,每个设备对应一个inode,inode指向cdev,调用cdev管理的ops函数接口,实现对设备的操作。设备文件可以多次打开,就像Windows一样,你可以同时打开一个记事本文件。每次打开设备驱动文件,就会分配一个file结构体对象,对应的就是一块内存空间。所以,关系就是:file对象通过inode对象根据设备号找到cdev对象。

    一个字符设备或块设备都有一个主设备号和一个次设备号。一个字符设备或块设备都有一个主设备号和一个次设备号。主设备号用来标识与设备文件相连的驱动程序,用来反映设备类型。次设备号被驱动程序用来辨别操作的是哪个设备,用来区分同类型的设备。一个驱动文件对应同一种类型的设备,所以,主设备号一般分配一个,对应一种类型的设备。次设备号有多个,对应同类型下的多个设备。每一个外部设备,都有主设备号+此设备号,并且是唯一的(有点类似身份证ID),通过主设备号和次设备号确定字符设备的唯一性;

    字符设备结构体struct cdev的作用:一般在字符设备驱动文件中把字符设备抽象为字符结构体,实例化结构体对象。这个字符结构体里面封装了,设备号,fops函数集等主要信息。然后在字符设备驱动程序中,根据这个设备结构体对象,对设备进行初始化,添加,删除,以及实现fops函数,作为接口,供系统调用,为APP应用程序服务。同时,当设备驱动文件向Linux系统注册成功后,一般会在目录/dev/......生成设备文件。好,那么我们顺便可以总结下,在字符设备驱动文件中主要的工作有哪些?(1)定义一个自己的设备结构体,比如struct xxx_dev,结构体中必然包含struct cdev结构体,然后定义一个对象struct  xxx_dev  mydev ;(2)定义一个struct file_operations xxx_ops对象,填充(初始化)主要的成员,比如.read = xxx_read,.write = xxx_write,.open = xxx_open,然后实现这些函数(xxx_read(),xxx_write(),xxx_open()).注意,这里填充的成员,就是设备驱动文件的VFS接口,供系统调用,应用程序就是通过系统调用调用VFS的这些接口,实现对设备的操作;(3)初始化设备结构体mydev ,目的大概就是申请设备号,把fops关联;(4)向Linux内核添加设备,生产设备文件在目录/dev/......(5)删除设备;6)匹配ID定义等等;

    关于设备树:设备树是用来描述设备的硬件信息,最后会放到一个大型数组中。加载驱动模块的时候,通过总线匹配设备树中的设备信息和驱动文件。引入了设备树,只是改变了设备的描述方法,以及匹配方式。此时,对设备的初始化,添加,等工作,都是放在probe函数中执行了。

二、字符设备驱动调用过程的路径(图片):

三、简述调用过程

    要知道,应用程序是位于用户空间,驱动程序是位于内核空间,应用空间是不可以直接调用内核空间的函数,需要通过系统调用来完成。一般情况,再应用程序中执行open函数fd = open(filename, O_RDWR)、然后调用标准C库函数open,经过系统调用进入内核空间,通过一系列调用,最终会执行到 chrdev_open。int chrdev_open(struct inode * inode, struct file * filp)。执行完 chrdev_open()之后,file对象的f_op指向cdev的ops,因而之后对设备进行的read, write等操作,就会执行cdev的相应操作,即设备驱动文件中实现的各种函数。

chrdev_open()所做的事情可以概括如下:(摘录自:https://www.cnblogs.com/chen-farsight/p/6177870.html

1. 根据设备号(inode->i_rdev), 在字符设备驱动模型中查找对应的驱动程序, 这通过kobj_lookup() 来实现, kobj_lookup()会返回对应驱动程序cdev的kobject.

2. 设置inode->i_cdev , 指向找到的cdev.

3. 将inode添加到cdev->list 的链表中.

4. 使用cdev的ops 设置file对象的f_op

5. 如果ops中定义了open方法,则调用该open方法

6. 返回

 

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐