linux驱动开发详解 linux驱动开发入门与实战( 二 )


11、在Linux6内核中,可接受的LICENSE包括GPL、GPLvGPLandadditionalrights、DualBSD/GPL、DualMPL/GPL和Proprietary 。大多数情况下,内核模块应遵循GPL兼容许可权 。Linux6内核模块最常见的是以MODULE_LICENSE(DualBSD/GPL)语句声明模块采用BSD/GPL双LICENSE 。
12、模块参数(可选)模块参数是模块被加载的时候可以被传递给它的值,它本身对应模块内部的全局变量 。模块导出符号(可选)内核模块可以导出符号(symbol,对应于函数或变量),这样其它模块可以使用本模块中的变量或函数 。模块作者等信息声明(可选)用于申明模块作者的相关信息,一般用于备注作者姓名、邮箱等 。
13、正在加载内核模块的函数模块加载函数Linux内核模块加载函数要用__initlogo声明,模块加载函数的典型形式如下:staticint__initinitialization_function(void){/*初始化代码*/}module_init(initialization_function);模块加载函数必须以module_init(函数名)的形式指定 。它返回一个整数值,如果初始化成功,它应该返回0 。初始化失败时,应该返回错误代码errno【在Linux内核中,错误代码errno是负值,在头文件linux/errno.h中定义,包含-ENODEV和-ENOMEM等符号值】 。
14、总是返回相应的错误代码是一个非常好的习惯,因为只有这样,用户程序才能使用perror等 *** 将其转换成有意义的错误消息字符串 。在Linux6内核中,可以使用request_module(constchar*fmt,…)函数加载内核模块,驱动开发者可以调用request_module(module_name);或者request_module("char-major-%d-%d",major(dev),minor(dev));这种灵活的方式加载其他内核模块 。注意:在Linux中,所有标识为__init的函数都放在该节中 。
15、init.text当它们连接时 。此外,所有__init函数还在该节中保存一个函数指针 。initcall.init在初始化过程中,内核会通过这些函数指针调用这些__init函数,初始化后释放init段(包括 。
16、初始化文本,..内核模块的卸载函数Linux内核模块加载函数要用__exitlogo声明,典型的模块卸载函数如下:staticvoid__exitcleanup_function(void){/*释放代码*/}module_exit(cleanup_function);模块卸载函数在模块卸载时执行,不返回值 。必须以module_exit(函数名)的形式指定 。一般来说,模块卸载功能必须执行与模块加载功能相反的功能,例如:若模块加载函数注册了XXX,则模块卸载函数应该注销XXX;若模块加载函数动态申请了内存,则模块卸载函数应释放该内存;若模块加载函数申请了硬件资源(中断、DMA通道、I/O端口和I/O内存等)的占用,则模块卸载函数应释放这些硬件资源;若模块加载函数开启了硬件,则卸载函数中一般要关闭之;和__init一样,__exit也可以让相应的函数在运行后自动回收内存 。
17、实际上,__init和__exit都是宏,它们的定义是:#define__init__attribute__((__section__(".init.text")))#ifdefMODULE#define__exit__attribute__((__section__(".exit.text")))#else#define__exit__attribute_used____attribute__((__section__(".exit.text")))#endif数据也可以定义为__initdata和__exitdata,它们是:#define__initdata__attribute__((__section__(".init.data")))和#define__exitdata__attribute__((__section__(".exit.data")))内核模块的参数传递我们可以用module_param(参数名,参数类型,参数读/写权限)来定义一个模块的参数 。例如,下面的代码定义了一个整数参数和一个字符指针参数:staticchar*book_name="深入浅出Linux设备驱动";staticintnum=4000;module_param(num,int,S_IRUGO);module_param(book_name,charp,S_IRUGO);在加载内核模块时,用户可以以in *** ode(或modprobe)模块名参数名=参数值的形式向模块传递参数 。否则,参数将使用模块中定义的默认值 。
18、参数可以是byte、short、ushort、int、uint、long、ulong、charp(字符指针)、bool或invbool(布尔的逆) 。模块编译时,module_param中声明的类型将与变量定义的类型进行比较,以确定是否一致 。模块加载后,以该模块名称命名的目录将出现在/sys/module/目录中 。

推荐阅读