请选择 进入手机版 | 继续访问电脑版
查看: 93|回复: 2

[经验分享] 基于Linux驱动的一个例程讲解

[复制链接]

签到天数: 137 天

[LV.7]化身百千

发表于 2018-10-9 11:07:38 | 显示全部楼层 |阅读模式
这篇帖子以一个具体的例子来具体说明驱动的一些知识,在这里将编写一个字符设备驱动例这个字符设备与任何具体的硬件设备无关,它的功能是将应用程序写入的数据保存在一小段内存中,当应用程序读设备时也从这块内存中获取数据。
        
        我们将这个例程命名为Kpad,源码中与设备相关的标识符的命名都加上了kpad作为前缀,这样做的好处是避免与内核定义的标识符重名。
前面的博文已经提到写驱动时  固定模式(40%) 内核相关知识(30%) 硬件知识(30%),下面为内核模块编程必须依照的一个固定模式:

                        

    下面来一行一行的解释:
        1~4行为头文件,注意:编译内核模块时头文件不是在系统头文件目录中搜索的,而是在内核源码的include目录中。第1行为模块编程需要的头文件,第2行为设备号、文件操纵接口所需的,第3行为字符设备编程接口所需的,第4行为访问用户态内存接口。

        7~11行为对模块的描述,第7行必须有,8~11为模块可选参数,即可以不写 第7行将代码的版权声明为GPL,因为GUN/Linux 内核本身是GPL版权,内核模块被认为是在内核的基础上进行的二次开发,因此必须遵循GPL版权,如果模块中没有版权声明,则加载时可能会被内核拒绝。版权声明放在内核源码中的任何位置都可以。8~11分别定义模块的作者,对模块的描述,模块版本,模块别名。

        13~15为模块的初始化函数(此处函数体没写,后面补齐),与应用程序不同,内核模块没有入口函数main,而有一个初始化函数。初始化函数只在模块加载时被调用一次。其中的__init是可选的(最好写上),它告诉编译器将此函数放在一个特殊的代码段上,当模块加载成功后,这个代码段就被释放掉以节约内存空间。

       初始化函数必须有一个int型的返回值,返回0代表成功,否则表示初始化失败,按惯例内核的函数失败时返回一个负数,代表失败的原因,称为错误码。 内核的错误码都以宏的形式定义在头文件中,这些宏定义都是正数,所以返回时要加一个负号(后文会再次提到)。

        21行是一个宏,它的作用是将所给出的函数指定的为模块的初始化函数,必须加上这一行,这样13行的函数才成功设置成初始化函数。

        17~19为模块的退出函数。退出函数只在模块被卸载时调用一次。其中的__exit是可选的(最好写上),它告诉编译器,如果模块被编译进内核,则这个函数根本不需要编译成目标代码,因为在这种情况下不存在不存在卸载操作。

         22行是一个宏,它的作用是将所给出的函数指定的为模块的退出函数,必须加上这一行,这样17行的函数才成功设置成退出函数

        注意:内核编程时,因为编译器的语法比较严格,最好加上void参数,否则可能会提示错误

        至此内核模块的模式也就写完了,就剩完善了,驱动编写时的40%的模式,这里只表现了一部分,剩下的后面会慢慢到来,嘿嘿!
   
         用一个结构体存储kpad设备的所有信息,具体如下:

        

        接着要表明这个设备所支持的文件操作,和定义这个设备:

        
        
        注意,file_operations 结构体中 赋值时是逗号,不是分号;

签到天数: 686 天

[LV.9]元老将成

发表于 2018-10-9 11:50:02 | 显示全部楼层
不错的资料
回复 支持 反对

使用道具 举报

签到天数: 686 天

[LV.9]元老将成

发表于 2018-10-9 11:50:04 | 显示全部楼层
不错的资料
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关闭

站长推荐上一条 /1 下一条

返回顶部