Linux设备驱动学习0构造和运行程序

整理文档很辛苦,赏杯茶钱您下走!

免费阅读已结束,点击下载阅读编辑剩下 ...

阅读已结束,您可以下载文档离线阅读编辑

资源描述

序言:想学习linux设备驱动,看到TekkamanNinja的学习笔记大为惊叹,同时也非常感谢这位大哥的无私奉献精神,这才是真正的开源精神,我打算沿着TekkamanNinja的脚步,走完我的linux设备驱动程序之旅,我相信在整理与实践过程中会学到更多的东西。本笔记一面是参考TekkamanNinja的学习程整理,一面是按照自己的实际情况学习编写,如有侵犯您的权益,请联系QQ:307921462Email:yflying7@gmail.com我的学习思路是:先看《linux设备驱动程序(第三版)》,然后看TekkamanNinja博客上的笔记,接着自己试着写驱动程序和应用程序,再对比自己和TekkamanNinja的程序思想上和算法上的差距,昀后再综合二者写完整程序。CQUPT-07-谷飞扬于老家陋室二〇一〇年二月二日Linux设备驱动程序学习[0]—构造和运行程序第一个例程:hello.c/**Name:hello.c*Function:testmodules*Author:gufeiyang*From:LDD3*Time:2010-2-1homeyunnan*/#includelinux/init.h#includelinux/module.hMODULE_LICENSE(“DualBSD/GPL”);staticinthello_init(void){printk(KERN_ALERT“Hello,world,Iamgufeiyang!\n”);return0;}staticvoidhello_exit(void){printk(KERN_ALERT“Goodbye,cruelworld,YYwillbeback!\n”);}module_init(hello_init);module_exit(hello_exit);参照《linux设备驱动程序》编写Makefile#IfKERNELRELEASEisdefined,we’vebeeninvokedfromthe#kernelbuildsystemandcanuseitslanguage.FILENAME=hello.oifneq($(KERNELRELEASE),)obj-m:=$(FILENAME)#Otherwisewewerecalleddirectlyfromthecommand#line;invokethekernelbuildsystem.ElseKERNELDIR?=/root/kernel/linux-2.6.25.8/PWD:=$(shellpwd)default:$(MAKE)–C$(KERNELDIR)M=$(PWD)modules@rm–vf*.o*.order*.symvers*.mod.**~@cp–vf*.ko/nfsEndif通过NFS在板子上即可看到[root@gfy-S3C2440/tmp]#insmodhello.koHello,world,Iamgufeiyang![root@gfy-S3C2440/tmp]#rmmodhello.koGoodbye,cruelworld,YYwillbeback![root@gfy-S3C2440/tmp]#lsmodNottaintedhello15040–Live0xbf000000[root@gfy-S3C2440/tmp]#心得:1、模块只可以调用内核导出的那些函数,不能调用libc之类的函数库;2、模块运行在内核空间,应用程序应用在用户空间;3、缺乏对浮点数的支持;4、驱动模块和应用程序的一个重要不同是:应用程序退出时可不管资源释放或者其他的清除工作,但模块的退出函数必须仔细撤销初始化函数所作的一切,否则,在系统重新引导之前某些东西就会残留在系统中;5、处理器的多种工作模式(级别)其实就是为了操作系统的用户空间和内核空间设计的。在Unix类的操作系统中只用到了两个级别:昀高和昀低级别;6、要注意驱动程序的并发处理;7、内核API中具有双下划线(__)的函数,通常是接口的底层组件,应慎用;8、Makefile文件分析ifneq($(KERNELRELEASE),)判断是否在内核根目录下,也就是判断该Makefile是否在内核目录树中,从内核顶层的Makefile可以看到KERNELRELEASE的定义为#ReadKERNELRELEASEfrominclude/config/kernel.release(ifitexists)KERNELRELEASE=$(shellcatinclude/config/kernel.release2/dev/null在看看include/config/kernel.release里面是什么东西[root@localhostlinux-2.6.25.8]#catinclude/config/kernel.release2.6.25.8include/config/kernel.release里面放的是该内核的版本号,也就是说如果存在include/config/kernel.release这个文件,就把内核版本号给KERNELRELEASE。如果版本号就从内核目录树编译。Obj-m:=hello.o代表了我们要构造的模块名为hell.ko,make会在该目录下自动找到hell.c文件进行编译。如果hello.o是由其他的源文件生成(比如file1.c和file2.c)的,则在下面加上(注意红色字体的对应关系):hello-objs:=file1.ofile2.o…...$(MAKE)–C$(KERNELDIR)M=$(PWD)modules其中–C$(KERNELDIR)指定了内核源代码的位置,其中保存有内核的顶层makefile文件。M=$(PWD)指定了模块源代码的位置modules目标指向obj-m变量中设定的模块。说明:在一个典型的构造过程中,Makefile将被调用2次,第一次是构造内核目录树,#IfKERNELRELEASEisdefined,we’vebeeninvokedfromthe#kernelbuildsystemandcanuseitslanguage.FILENAME=helloifneq($(KERNELRELEASE),)obj-m:=$(FILENAME).o#Otherwisewewerecalleddirectlyfromthecommand#line;invokethekernelbuildsystem.ElseKERNELDIR?=/root/kernel/linux-2.6.25.8/到此即可找到内核目录树,此时KERNELRELEASE已被定义第二次调用时发现KERNELRELEASE已被定义,那么才定义obj-m:=$(FILENAME).o这个模块,然后才执行$(MAKE)–C$(KERNELDIR)M=$(PWD)modules第一次看的时候发现个问题,如果Makefile只调用一次,那么未定义KERNELRELEASE的时候obj-m:=$(FILENAME).o这个模块就不能增加,后来仔细阅读了LDD3才发现一个典型的构造Makefile需要被调用2次。这才解决了疑问。9、insmod使用公共内核符号表来解析模块中未定义的符号。公共内核符号表中包含了所有的全局内核项(即函数和变量的地址),这是实现模块化驱动程序所必须的;10、Linux使用模块层叠技术,我们可以将模块划分为多个层,通过简化每个层可缩短开发周期。如果一个模块需要向其他模块导出符号,则使用下面的宏:EXPORT_SYMBOL(name);EXPORT_SYMBOL_GPL(name);符号必须在模块文件的全局变量部分导出,因为这两个宏将被扩展为一个特殊变量的声明,而该变量必须是全局的;11、所有模块代码中都包含一下两个头文件:#includelinux/init.h#includelinux/module.h12、所有模块代码都应该指定所使用的许可证:MODULE_LICENSE(“DualBSD/GPL”);此外还有可选的其他描述性定义:MODULE_AUTHOR(“”);声明谁编写了模块MODULE_DESCRIPTION(“”);一个人可读的关于模块做什么的声明MODULE_VERSION(“”);一个代码修订版本号MODULE_ALIAS(“”);模块为人所知的另一个名子MODULE_DEVICE_TABLE(“”);来告知用户空间,模块支持那些设备上述MODULE_声明习惯上放在文件昀后13、初始化和关闭初始化staticint__initinitialization_function(void){/*Initializationcodehere*/}module_init(initialization_function);清除函数staticvoid__exitcleanup_function(void){/*Cleanupcodehere*/}module_exit(cleanup_function);这里首次接触在模块内使用staticvoid__exitcleanup_function(void),说明static的一种用法:1)在模块内,一个被声明为静态的函数只可被这一模块内的其他函数调用。那就是,这个函数被限制在声明他的模块的本地范围内使用;另外两种用法;2)在函数体,一个被声明为静态的变量在这一函数被调用过程中维持其值不变。3)在模块内(但在函数体外),一个被声明为静态的变量能够被模块内所用函数访问,但不能被模块外其他函数访问。他是个本地的全局变量。14、错误恢复有时用goto语句处理是昀好的.我们通常不愿使用goto,但是在我们的观念里,这是一个它有用的地方.在错误情形下小心使用goto可以去掉大量的复杂,过度对齐的,“结构形”的逻辑.因此,在内核里,goto是处理错误经常用到;以下是《linux设备驱动程序3》给出的关于错误处理的框架;structsomething*item1;structsomethingelse*item2;intstuff_ok;voidmy_cleanup(void){if(item1)release_thing(item1);if(item2)release_thing2(item2);if(stuff_ok)unregister_stuff();return;}int__initmy_init(void){interr=-ENOMEM;item1=allocate_thing(arguments);item2=allocate_thing2(arguments2);if(!item2||!item2)gotofail;err=register_stuff(item1,item2);if(!err)stuff_ok=1;elsegotofail;return0;/*success*/fail:my_cleanup();returnerr;}15、模块参数:内核允许对驱动程序指定参数,而这些参数可在装载驱动程序模块时改变。以下是我的实验程序:/**Name:hello.c*Function:testmodules*Author:gufeiyang*From:LDD3*Time:2010-2-1homeyunnan*/#includelinux/init.h#includelinux/module.hstaticchar*whom=“world”;staticinthowmany=4;staticchararray[]={‘a’,’b’,’c’,’d’};module_param(howmany,int,S_IRUGO);module_param(whom,charp,S_IRUGO);module_param_array(array,charp,4,S_IRUGO);staticinthello_init(void){i

1 / 62
下载文档,编辑使用

©2015-2020 m.777doc.com 三七文档.

备案号:鲁ICP备2024069028号-1 客服联系 QQ:2149211541

×
保存成功