返回列表 发帖

[站长原创] Linux设备驱动程序开发 - Linux内核模块驱动程序的编写

[站长原创] Linux设备驱动程序开发 - Linux内核模块驱动程序的编写

嵌入式开发联盟www.mcuos.com

Osboy站长原创

QQ:82475491

Mcuos.com@gmail.com


何为linux内核驱动模块加载?


我们在写驱动程序的时候,大家都知道可以静态的使用make menuconfig配置相应的驱动程序,然后编译内核统一生成内核文件中包含很多的驱动程序代码。这叫驱动的静态编译。


而相反的Linux提供了一种机制,可以动态的加载内核驱动程序,就是说,当内核启动的时候并没有包含这个驱动模块,当要用到这个驱动的时候,我们可以通过一种命令直接加载相应的驱动程序,这样内核文件的size就变的很小,我们可以把相对较大的驱动编译成ko形式的模块形式,存储到flash或者sd卡中,做到用的时候加载,不用的时候卸载,这就大大节省了内存空间。


典型的应用就是,内核某个驱动厂家不希望透露给别人驱动源代码,他们一般的做法就是编译自己的驱动为ko形式的动态模块,直接把这个给客户,要客户直接insmod xxx.ko然后使用就可以了。不过这个并不符合GPL开发代码的需求吧,不过用的挺广泛这种做法。


一个Linux内核模块驱动程序主要包括以下几个方面:



(1)模块加载函数:module_init(xxx)


当通过insmod命令加载驱动ko模块的时候,这个函数xxx会被第一个执行,进行一些驱动的初始化工作。


(2)模块卸载函数:module_exit(yyy)


当通过rmmod命令卸载驱动ko模块的时候,这个函数yyy会被第一个执行,进行一些驱动的卸载删除工作。


(3)许可证声明


描述内核模块的许可权限,没有这个声明内核会产生一个抱怨。例如MODULE_LICENSE("GPL");,内核模块应遵循GPL兼容许可权。


一个简单的内核模块驱动程序:

由osboy徒弟liuzhedash提供:

  1.   1 #include <linux/module.h>
  2.   2 #include <linux/init.h>
  3.   3 static int __init test_init(void)
  4.   4 {
  5.   5     pinrtk("hello world!\n");
  6.   6     return 0;
  7.   7 }
  8.   8
  9.   9 static void __exit test_exit(void)
  10. 10 {
  11. 11     printk("good bye!\n");
  12. 12 }
  13. 13 module_init(test_init);
  14. 14 module_exit(test_exit);
  15. 15 MODULE_LICENSE("GPL");
  16. 16 MODULE_AUTHOR("Roland Lau");
  17. 17 MODULE_VERSION("1.0");
复制代码


几个注意事项:
static int __init 中的__init, 注意__init不要写成__int,是错误的,出现此类错误的原因之一是你没有理解static int __init  test_init()函数的意思,这里的static int 是申请的一个整型函数,返回值为整型,_init是表示在程序执行完之后会释放掉这个函数所占的内存,也就说,这个初始化函数在模块加载的时候只执行一次,之后在驱动使用过程中不会再重复加载,所以就没有必要为其保留函数内存空间了。


static void __exit中的__exit和__init类似,都是要释放函数内存空间的。
内核实现这个机制的原理,就是把需要释放空间的函数都统一放到一个内存段中,比如这个__init就是被定义为:
#define __init          __section(.init.text) __cold notrace
这句话的意思就是把所有声明为__init的函数都放到init.text这个段中,如果不清楚linux内核段的概念的话请参考下面osboy写的帖子:


移植内核必备知识-内核的链接脚本文件vmlinux.lds.S的探讨:http://mcuos.com/thread-8170-1-1.html
分享到: QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友

学习了
__init和__exit 是一种标记

TOP

返回列表
网页右侧QQ悬浮滚动在线客服
网页右侧QQ悬浮滚动在线客服