2.4 模块使用计数<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
模块在被使用时,是不允许被卸载的。2.4内核中,模块自身通过MOD_INC_USE_COUNT、MOD_DEC_USE_COUNT宏来管理自己被使用的计数。2.6内核提供了更健壮、灵活的模块计数管理接口try_module_get(&module)及module_put(&module)取代2.4中的模块使用计数管理宏;模块的使用计数不必由自身管理,而且在管理模块使用计数时考虑到SMP与PREEMPT机制的影响。
int try_module_get(struct module *module):用于增加模块使用计数;若返回为0,表示调用失败,希望使用的模块没有被加载或正在被卸载中。
void module_put(struct module *module):减少模块使用计数。
try_module_get 与module_put的引入与使用与2.6内核下的设备模型密切相关。模块是用来管理硬件设备的,2.6 内核为不同类型的设备定义了struct module *owner 域,用来指向管理此设备的模块。如字符设备的定义:
struct cdev {
        struct kobject kobj;
        struct module *owner;
        struct file_operations *ops;
        struct list_head list;
        dev_t dev;
        unsigned int count;
};
从设备使用的角度出发,当需要打开、开始使用某个设备时,使用try_module_get(dev->owner)去增加管理此设备的owner模块的使用计数;当关闭、不再使用此设备时,使用module_put(dev->owner)减少对管理此设备的owner模块的使用计数。这样,当设备在使用时,管理此设备的模块就不能被卸载;只有设备不再使用时模块才能被卸载。
2.6内核下,对于为具体设备写驱动的开发人员而言,基本无需使用try_module_get与module_put,因为此时开发人员所写的驱动通常为支持某具体设备的owner模块,对此设备owner模块的计数管理由内核里更底层的代码如总线驱动或是此类设备共用的核心模块来实现,从而简化了设备驱动开发。
<?xml:namespace prefix = v ns = "urn:schemas-microsoft-com:vml" />
回页首
2.5 模块输出的内核符号
2.4 内核下,缺省情况时模块中的非静态全局变量及函数在模块加载后会输出到内核空间。
2.6 内核下,缺省情况时模块中的非静态全局变量及函数在模块加载后不会输出到内核空间,需要显式调用宏EXPORT_SYMBOL才能输出。所以在2.6 内核的模块下,EXPORT_NO_SYMBOLS宏的调用没有意义,是空操作。在同时支持2.4与2.6内核的设备驱动中,可以通过以下代码段来输出模块的内核符号

清单6: 同时支持2.4与2.6的输出内核符号代码段
#include <linux/module.h>
#ifndef LINUX26
EXPORT_NO_SYMBOLS;
#endif 
EXPORT_SYMBOL(var);
EXPORT_SYMBOL(func);
需要注意的是如需在2.4内核下使用 EXPORT_SYMBOL,必须在 CFLAGS中定义 EXPORT_SYMTAB,否则编译将会失败。
从良好的代码风格角度出发,模块中不需要输出到内核空间且不需为模块中其它文件所用的全局变量及函数最好显式申明为static类型,需要输出的内核符号以模块名为前缀。
模块加载后,2.4内核下可通过 /proc/ksyms、 2.6 内核下可通过/proc/kallsyms查看模块输出的内核符号
回页首
2.6 模块的命令行输入参数
在装载内核模块时,用户可以向模块传递一些参数,如`modprobe modname var=value`,否则,var将使用模块内定义的缺省值。
2.4内核下,linux/module.h中定义有宏MODULE_PARM(var,type) 用于向模块传递命令行参数。var为接受参数值的变量名,type为采取如下格式的字符串[min[-max]]{b,h,i,l,s}。min及max用于表示当参数为数组类型时,允许输入的数组元素的个数范围;b:byte;h:short;i:int;l:long;s:string。
2.6内核下,宏MODULE_PARM(var,type)不再被支持。在头文件linux/moduleparam.h里定义了如下宏:
module_param(name, type, perm)
module_param_array(name, type, nump, perm)
type 类型可以是byte、short,、ushort、 int、 uint、long、ulong、charp, bool or invbool, 不再采用2.4内核中的字符串形式,而且在模块编译时会将此处申明的type与变量定义的类型进行比较,判断是否一致。
perm表示此参数在sysfs文件系统中所对应的文件节点的属性。2.6内核使用sysfs文件系统,这是一个建立在内存中比proc更强大的文件系统。sysfs文件系统可以动态、实时,有组织层次地反应当前系统中的硬件、驱动等状态。当perm为0时,表示此参数不存在sysfs文件系统下对应的文件节点。模块被加载后,在/sys/module/ 目录下将出现以此模块名命名的目录。如果此模块存在perm不为0的命令行参数,在此模块的目录下将出现parameters目录,包含一系列以参数名命名的文件节点,这些文件的权限值等于perm,文件的内容为参数的值。
nump 为保存输入的数组元素个数的变量的指针。当不需保存实际输入的数组元素个数时,可以设为NULL。从2.6.0至2.6.10 版本,须将变量名赋给nump;从2.6.10 版本开始,须将变量的引用赋给nump,这更易为开发人员理解。加载模块时,使用逗号分隔输入的数组元素。

清单7: 适用于2.4与2.6内核的模块输入参数模板
#include <linux/module.h>
#ifdef LINUX26
#include <linux/moduleparam.h>
#endif
int debug = 0;
char *mode = "800x600";
int tuner[4] = {1, 1, 1, 1};
#ifdef LINUX26
int tuner_c = 1; 
#endif
#ifdef LINUX26
MODULE_PARM(debug, "i");
MODULE_PARM(mode, "s");
MODULE_PARM(tuner,"1-4i");
#else
module_param(debug, int, 0644);
module_param(mode, charp, 0644);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10)
module_param_array(tuner, int, &tuner_c, 0644);
#else
module_param_array(tuner, int, tuner_c, 0644);
#endif
#endif
模块编译生成后,加载模块时可以输入:`modprobe my_module mode=1024x768 debug=1 tuner=22,33`。
在linux/moduleparam.h还定义有:
module_param_array_named(name, array, type, nump, perm)             
module_param_call(name, set, get, arg, perm) 
module_param_named(name, value, type, perm)
读者可以参阅linux/moduleparam.h查看这些宏的详细描述,有一点需注意,在2.6内核里,module_param这一系列宏使用的都是小写名字。
2.7 模块的许可证声明
从2.4.10版本内核开始,模块必须通过MODULE_LICENSE宏声明此模块的许可证,否则在加载此模块时,会收到内核被污染"kernel tainted" 的警告。从linux/module.h文件中可以看到,被内核接受的有意义的许可证有 "GPL","GPL v2","GPL and additional rights","Dual BSD/GPL","Dual MPL/GPL","Proprietary"。
在同时支持2.4与2.6内核的设备驱动中,模块可按如下方式声明自己的许可证。

清单8: 适用于2.4与2.6内核的模块许可证声明模板
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,10)
MODULE_LICENSE("GPL");
#endif
2.8 小结
此外,2.6内核里还有一些模块机制的改变,不常为驱动开发人员用到。如加载内核模块的接口request_module在2.4 下为request_module(const char * module_name);在2.6内核下为request_module(const char *fmt, ...)。在2.6 内核下,驱动开发人员可以通过调用
request_module("msp3400");
request_module("char-major-%d-%d", MAJOR(dev), MINOR(dev));
这种更灵活的方式加载其它内核模块。
2.6内核在linux/module.h中还提供了MODULE_ALIAS(alias)宏,模块可以通过调用此宏为自己定义一或若干个别称。而在2.4内核下,用户只能在/etc/modules.conf中为模块定义别称。
通过以上比较可以看到,从2.4到2.6内核,可装载模块管理机制的改变使设备驱动的开发变得更加简洁、灵活、健壮。

转载于:https://blog.51cto.com/zyg0227/270376

从 2.4 到 2.6:Linux 内核可装载模块机制的改变对设备驱动的影响(二)相关推荐

  1. 从 2.4 到 2.6:Linux 内核可装载模块机制的改变对设备驱动的影响(一)

    从 2.4 到 2.6:Linux 内核可装载模 块机制的改变对设备驱动的影响 <?xml:namespace prefix = o ns = "urn:schemas-microso ...

  2. linux 内核可装载模块 版本检查机制

    为保持 Linux 内核的稳定与可持续发展,内核在发展过程中引进了可装载模块这一特性.内核可装载模块就是可在内核运行时加载到内核的一组代码.通常 , 我们会在两个版本不同的内核上装载同一模块失败,即使 ...

  3. linux块设备驱动编写,Linux内核学习笔记 -49 工程实践-编写块设备驱动的基础

    块设备可以随机存储.字符设备,比如键盘,只能按照输入顺序存取,不可随机,打乱输入的字节流. 文件系统层,包括常见的文件系统,以及虚拟文件系统层VFS,字符设备可以直接用应用程序打开.块设备不会在应用程 ...

  4. linux内核可装载模块(lkm)传参机制 module_param()/module_param_string()

    对于如何向模块传递参数,Linux kernel 提供了一个简单的框架.其允许驱动程序声明参数,并且用户在系统启动或模块装载时为参数指定相应值,在驱动程序里,参数的用法如同全局变量. 使用下面的宏时需 ...

  5. linux kernel and user space通信机制,Linux内核与用户空间通信机制研究.pdf

    ISSN 1009-3044 E-mail:info@CCCC.net.CR ComputerKnowledgeandTechnology电脑知识与技术 http://www.dnzs.net.cn ...

  6. 【Linux 内核】宏内核与微内核架构 ( 操作系统需要满足的要素 | 宏内核 | 微内核 | Linux 内核动态加载机制 )

    文章目录 一.操作系统需要满足的要素 二.宏内核 三.微内核 四.Linux 内核动态加载机制 一.操作系统需要满足的要素 电脑上运行的 操作系统 , 是一个 软件 ; 设备管理 : 操作系统需要 为 ...

  7. Linux内核中的platform机制

    Linux内核中的platform机制 从Linux 2.6起引入了一套新的驱动管理和注册机制:platform_device和platform_driver.Linux中大部分的设备驱动,都可以使用 ...

  8. 自学Linux 2—Linux 的系统架构之 Linux 内核的主要模块和 Linux 的文件结构

    Linux 的系统架构 Linux 系统从应用角度来看,分为内核空间和用户空间两个部分.        内核空间是 Linux 操作系统的主要部分,但是仅有内核的操作系统是不能完成用户任务的.丰富并且 ...

  9. Linux内核如何装载和启动一个可执行程序-----实验7

    2015108 李泽源 Linux内核如何装载和启动一个可执行程序 理解编译链接的过程和ELF可执行文件格式,详细内容参考本周第一节: 编程使用exec*库函数加载一个可执行文件,动态链接分为可执行程 ...

  10. linux 信号优先级,linux内核中的信号机制

    linux内核中的信号机制--信号处理 Kernel version:2.6.14 CPU architecture:ARM920T Author:ce123(http://blog.csdn.net ...

最新文章

  1. three.js(六) 地形法向量生成
  2. 怎样才能使二级网页窗口最大化
  3. 如何理解Excel数组公式{=sum(1/countif(B8:K9,B8:K9))}
  4. 写一个判断素数的函数,在主函数输入一个整数,输出是否是素数的消息。
  5. how is crmd_product_i inserted to db
  6. C#全能数据库操作类及调用示例
  7. 揭秘 | 小米最新款12PRO智能动态刷新率技术原理
  8. oracle19c连接MySQL_oracle19c的安装和使用navicat连接oracle数据库
  9. Docker中快速安装Mysql
  10. ubuntu查看oracle客户端,ubuntu 9.04 下安装 oracle 客户端oracle-xe-client
  11. POJ 3254 Corn Fields [DP]
  12. github连接出现Bad file number问题
  13. macOS Monterey兼容哪些Mac电脑?
  14. 什么吃掉了你的执行力?在浮躁中求解
  15. MATLAB对ply文件格式的读取和显示
  16. mysql查询计算机系信息_mysql——查询练习
  17. 淘东电商项目(14) -公众号获取注册码功能
  18. python画图柱状图修改相邻两个柱之间的间隔
  19. Web3策展生态解读:谁是互联网文明的策展人?
  20. matlab 1.封装LPF 巴特沃斯低通滤波器

热门文章

  1. 码支付如何对接网站_做“刷脸支付”怎么推广?怎么办理刷脸支付POS机?
  2. python一维数组聚类
  3. Android Listview设置每条信息的间距
  4. 【安装包】gcc编译器
  5. MySQL优化(二)
  6. 遇到Io阻塞时会切换任务之【爬虫版】
  7. shell编程的for和while循环
  8. mongo 监听指定语句
  9. 【OpenCV入门教程之二】 一览众山小:OpenCV 2.4.8 or OpenCV 2.4.9组件结构全解析(转)...
  10. Swift - 通过url地址打开web页面