linux应用层到驱动层再到硬件图解(inline)

1 系统整体工作原理

     1.1  总体流程图

        1.1.1  这里举一个函数例子,比如内核给我们应用层提供的open/read/write等函数指针,这些函数在内核的fs.h中用file_operation(用来操作文件的所有接口)结构体封装,他们只是一个函数指针(用来挂接驱动里的函数实体),实体是具体用来操作硬件的,根据自己的需要写在驱动模块里面。

linux应用层到驱动层再到硬件图解(inline)_第1张图片

        1.1.2  列出上述重点

                (1)应用层->API->设备驱动->硬件

                (2)API:open、read、write、close等

                (3)驱动源码中提供真正的open、read、write、close等函数实体


 1.2  注册设备驱动(也就是KO模块里面需要做的事)

1.2.1 注册设备驱动需要理解的5点

              (1)为何要注册驱动

        解释: 注册了之后app调用的file_operation的函数指针才能正确的对接驱动里面的函数实体,正确的去操作对于的硬件

              (2)谁去负责注册

     解释:这部分的工作是驱动本身来注册

               (3)向谁注册

     解释:向内核注册

               (4)注册函数从哪里来

     解释:是内核提供的注册函数,驱动只要调用这个函数去注册即可

               (5)注册前怎样?注册后怎样?注册产生什么结果?

     解释:比如字符驱动,注册之后内核就会给我们提供一个设备号,以文件的形式打来来操作,一切皆是文件的思想,这是内核VFS虚拟文件系统为了操作方便定义出来的一套软件。


1.2.2 注册设备驱动的函数register_chrdev详解(#include )

(1)作用,驱动向内核注册自己的file_operations

(2)inline 

        解释1:加上inline在链接时,会将函数体破坏只取这个函数里面的内容,将其直接链接进去,这样减少了函数的调用层级,减小时间上的开销。一般是函数里面只有一句代码,主要是为了保证函数的封装性(方便阅读代码),比如__init定义的一个函数,我们再次将它封装去掉__。

        解释:本来只是为了效率,使用它,他还产生了另一个作用,封装好后的函数体,就可以放在h文件里面了,方便模块化,函数体本来一般不放在h文件,因为和变量定义,函数声明不一样,链接时会出现重复包含同一个函数体的错误。


1.2.3 内核如何管理设备驱动

(1)内核中有一个数组用来存储注册的字符设备驱动

        解释:内核提供一个数组,定义了255个元素,所有只能注册255个不同类型设备驱动(同一类的可以有次设备号,比如几个LED驱动)

(2)register_chrdev内部将我们要注册的驱动的信息(主要是 )存储在数组中相应的位置

(3)cat /proc/devices查看内核中已经注册过的字符设备驱动(和块设备驱动)

流程图如下:

linux应用层到驱动层再到硬件图解(inline)_第2张图片



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读写函数来操作寄存器,以实现最大程度可移植性。








        












你可能感兴趣的:(linux应用层到驱动层再到硬件图解(inline))