"); //-->
以 LInux 的方式看待设备可区分为 3 种基本设备类型.可分类成字符模块, 块模块和网络模块.
因为内核编程没有库连接到模块中, 源文件不应当包含通常的头文件,驱动模块运行在内核空间,运行时不能依赖于任何函数库和模块连接,所以在写驱动时所调用的函数只能是作为内核一部分的函数。
要十分注意驱动程序的并发处理。
驱动模块和应用程序的一个重要不同是:应用程序退出时可不管资源释放或者其他的清除工作,但模块的退出函数必须仔细撤销初始化函数所作的一切,否则,在系统重新引导之前某些东西就会残留在系统中。
内核只有一个非常小的堆栈,你的函数必须与这个内核空间调用链共享这个堆栈.如果需要大的结构, 在调用时应当采用动态分配.
你查看内核 API 时, 你会遇到以双下划线(__)开始的函数名. 这通常是一个低层的接口组件, 双下划线告诉程序员:" 如果你调用这个函数, 确信你知道你在做什么."
内核代码不能做浮点算术.
Linux使用超级中断应当执行以下两条命令安装:
apt-get install minicom apt-get install lrzsz #x|y|zmod |
如果你编写一个模块想用来在多个内核版本上工作, 可能只能使用宏定义和 #ifdef 来使代码正确建立. 在这样情况下, 你要利用在 linux/version.h 中发现的定义(UTS_RELEASE、LINUX_VERSION_CODE、KERNEL_VERSION)
因此, 几乎所有模块代码都有下面内容:
#include <linux/module.h> #include <linux/init.h> |
所有模块代码都应该指定所使用的许可证:
MODULE_LICENSE("Dual BSD/GPL"); |
此外还有可选的其他描述性定义:
MODULE_AUTHOR(""); |
上述MODULE_声明习惯上放在文件最后。
初始化和关闭如下:
static int __init initialization_function(void) Initialization code here / static void __exit cleanup_function(void) Cleanup code here / |
不要轻言注册失败。要尽量妥善处理。
struct something item1; item2; success / |
insmod使用公共内核符号表来解析模块中未定义的符号。公共内核符号表中包含了所有的全局内核项(即函数和变量的地址),这是实现模块化驱动程序所必须的。
Linux使用模块层叠技术,我们可以将模块划分为多个层,通过简化每个层可缩短开发周期。如果一个模块需要向其他模块到处符号,则使用下面的宏:
EXPORT_SYMBOL(name); EXPORT_SYMBOL_GPL(name); |
符号必须在模块文件的全局变量部分导出,因为这两个宏将被扩展为一个特殊变量的声明,而该变量必须是全局的。
函数( __init 和 __exit )和数据 (__initdata 和 __exitdata)的标记, 只用在模块初始化或者清理时间. 为初始化所标识的项可能会在初始化完成后丢弃; 退出的项可能被丢弃如果内核没有配置模块卸载. 这些标记通过使相关的目标在可执行文件的特定的 ELF 节里被替换来工作.
“#include <linux/sched.h>” 最重要的头文件之一。包含驱动程序使用的大部分内核API的定义,包括睡眠函数以及各种变量声明。
*博客内容为网友个人发布,仅代表博主个人观点,如有侵权请联系工作人员删除。