1【Linux驱动】第二章构造和运行模块设置测试系统开发环境及HelloWorld入门模块在前面中已经讲到,请参考:一,核心模块与应用程序的对比应用程序:小规模及中规模程序,从头到尾执行单个任务。核心模块:预先注册自己,以便服务于将来的某个请求。然后他的初始化函数就立即结束。退出时候,应用程序可以不释放自己申请的资源,而模块在退出之前必须仔细撤销初始化函数所做的一切。二,用户空间和内核空间模块运行在内核空间,应用程序运行在内核空间。每当应用程序执行系统调用或者被硬件中断挂起时,Unix将执行模式从用户空间切换到内核空间。应用程序在虚拟内存中布局,并具有一块很大的栈空间(保存函数调用历史以及当前活动函数中的自动变量)。内核具有非常小的栈,所以我们自己的函数必须和整个内核空间调用链一同共享这个栈。【注意】在内核API中看到有两个下划线__的函数名:接口的底层组件三,初始化和关闭staticint__initinitialization_function(void){/*初始化代码*/returnint;}module_init(initialization_function);//说明内核初始化位置,没有这个函数,则初始化函数无法调用2【注意】__init__initdata表明函数只在初始化期间使用,模块装载完成后不再使用。staticvoid__initcleanup_function(void)//没有返回值清除函数类似module_exit(cleanup_function)四,初始化过程中的错误处理1)时刻铭记,注册可能会失败,因此模块代码要始终检查返回值。2)当注册时,有些模块注册失败,则需要自行撤销已注册的设施。否则内核处于一种不稳定状态。唯一有效的解决办法:重新引导系统3)使用gotoint__my_init_function(void){interr;err=regeister_this(ptr1,skull);if(err)gotofail_this;err=regeister_that(ptr2,skull);if(err)gotofail_that;err=regeister_those(ptr3,skull);if(err)gotofail_those;return0;//成功3fail_this:returnerr;fail_those:unregeister_those(ptr3,skull);fail_that:unregeister_that(ptr3,skull);}4)初始化函数还在运行时,内核就完全可能会调用我们的模块。所以我们应在用来支持某个设施的所有内部初始化完成之前,不要注册任何设施。五,模块参数支持很多类型;1)基本类型:bool:布尔类型invbool:颠倒了值的bool类型;charp:字符指针类型,内存为用户提供的字符串分配;int:整型long:长整型short:短整型uint:无符号整型ulong:无符号长整型ushort:无符号短整型定义模块参数的方法:module_param(name,type,perm);其中,name:表示参数的名字;type:表示参数的类型;perm:表示参数的访问权限;2)数组类型:用逗号间隔的列表提供的值;声明一个数组参数:module_param_array(name,type,num,perm);其中,name:表示数组的名字;type:表示参数的类型;num:表示数组中元素数量;perm:表示参数的访问权限;3)参数的访问权限modlue_param和module_param_array中的perm用于设定该参数的访问权限;perm表示该参数在sysfs文件系统中所对应的文件节点的属性;你用该使用linux/stat.h中定义的权限值;这个值控制谁可以存取这些模块参数在sysfs文件系统中的表示;当perm为0时,表示此参数不存在sysfs文件系统下对应的文件节点;否则,模块被加载后,在/sys/module/目录下将会出现以此模块名命名的目录,带有给定的权限;4比如:#defineS_IRWXU00700#defineS_IRUSR00400#defineS_IWUSR00200#defineS_IXUSR00100#defineS_IRWXG00070#defineS_IRGRP00040#defineS_IWGRP00020#defineS_IXGRP00010#defineS_IRWXO00007#defineS_IROTH00004#defineS_IWOTH00002#defineS_IXOTH00001注意:如果一个参数被sysfs修改了,那么你的模块看到的参数值也被修改了,但是你的模块不会收到任何通知;你应当不要使模块参数可写,除非你准备好检测这个改变并因而作出反应;六,在用户空间编写驱动程序用户空间驱动程序的优点:1)可以和整个C库链接2)驱动程序不用借助外部程序(对于复杂的外设,常常需要和驱动一起发行用户提供策略的应用程序)就可以完成许多非常规的任务。3)在驱动中可以使用浮点数,在某些特殊的硬件中,可能需要使用浮点数,而linux内核并不提供浮点数的支持。如果能在用户态实现驱动,就可以轻松解决这一问题4)驱动的问题不会导致整个系统挂起,有过驱动开发经验的人一定会对调试深有感触,一些错误常常导致整个系统挂起。而用户态的驱动在调试上就要方便很多。5)用户内存可以换出6)设计良好的驱动仍然可以支持对设备的并发访问7)可以给出封闭源码的驱动程序,不必采用GPL,更为灵活用户空间驱动的最常见例子是X-server,很多USB设备的驱动也可以放到用户空间。目前,很多人尝试在用户态为PCI设备提供驱动用户空间驱动的缺点:1)中断在用户空间不可用,最新的UIO接口已经解决了这一问题2)响应时间较慢3)只能支持字符设备,无法支持块设备和网络设备4)可靠性较低,很多驱动都是闭源的,我们没法通过阅读代码解决问题5)有些硬件厂商只提供和某些linux开发版(常常早就过时了)相匹配的用户空间驱动相关阅读:【Linux驱动】第一章设备驱动程序简介【Linux驱动】驱动开发第一步----开发环境搭配