1 系统整体工作原理
1.1 总体流程图
1.1.1 这里举一个函数例子,比如内核给我们应用层提供的open/read/write等函数指针,这些函数在内核的fs.h中用file_operation(用来操作文件的所有接口)结构体封装,他们只是一个函数指针(用来挂接驱动里的函数实体),实体是具体用来操作硬件的,根据自己的需要写在驱动模块里面。
1.1.2 列出上述重点
(1)应用层->API->设备驱动->硬件
(2)API:open、read、write、close等
(3)驱动源码中提供真正的open、read、write、close等函数实体
1.2 注册设备驱动(也就是KO模块里面需要做的事)
1.2.1 注册设备驱动需要理解的5点
(1)为何要注册驱动
(2)谁去负责注册解释: 注册了之后app调用的file_operation的函数指针才能正确的对接驱动里面的函数实体,正确的去操作对于的硬件
(3)向谁注册解释:这部分的工作是驱动本身来注册
(4)注册函数从哪里来解释:向内核注册
(5)注册前怎样?注册后怎样?注册产生什么结果?解释:是内核提供的注册函数,驱动只要调用这个函数去注册即可
解释:比如字符驱动,注册之后内核就会给我们提供一个设备号,以文件的形式打来来操作,一切皆是文件的思想,这是内核VFS虚拟文件系统为了操作方便定义出来的一套软件。
1.2.2 注册设备驱动的函数register_chrdev详解(#include <linux/fs.h>)
(1)作用,驱动向内核注册自己的file_operations
(2)inline
解释1:加上inline在链接时,会将函数体破坏只取这个函数里面的内容,将其直接链接进去,这样减少了函数的调用层级,减小时间上的开销。一般是函数里面只有一句代码,主要是为了保证函数的封装性(方便阅读代码),比如__init定义的一个函数,我们再次将它封装去掉__。
解释:本来只是为了效率,使用它,他还产生了另一个作用,封装好后的函数体,就可以放在h文件里面了,方便模块化,函数体本来一般不放在h文件,因为和变量定义,函数声明不一样,链接时会出现重复包含同一个函数体的错误。
1.2.3 内核如何管理设备驱动
(1)内核中有一个数组用来存储注册的字符设备驱动
解释:内核提供一个数组,定义了255个元素,所有只能注册255个不同类型设备驱动(同一类的可以有次设备号,比如几个LED驱动)
(2)register_chrdev内部将我们要注册的驱动的信息(主要是 )存储在数组中相应的位置(3)cat /proc/devices查看内核中已经注册过的字符设备驱动(和块设备驱动)
流程图如下:
1.2.4 应用层如何调用驱动
1、驱动设备文件的创建(1)何为设备文件
(2)设备文件的关键信息是:设备号 = 主设备号 + 次设备号,使用ls -l去查看设备文件,就可以得到这个设备文件对应的主次设备号。
(3)使用mknod创建设备文件:mknod /dev/xxx c 主设备号 次设备号
1.2.5 驱动如何操作硬件
1、还是那个硬件(1)硬件物理原理不变
(2)硬件操作接口(寄存器)不变
(3)硬件操作代码不变
2、哪里不同了?
(1)寄存器地址不同。原来是直接用物理地址,现在需要用该物理地址在内核虚拟地址空间相对应的虚拟地址。寄存器的物理地址是CPU设计时决定的,从datasheet中查找到的。
(2)编程方法不同。裸机中习惯直接用函数指针操作寄存器地址,而kernel中习惯用封装好的io读写函数来操作寄存器,以实现最大程度可移植性。