学习Linux驱动有半年的时间了,但是临近毕业,由于各种事务的耽误,很多东西遗忘,现在写此博客以记录重新学习的历程。
首先,自然是从最简单的内核模块,Hello, world开始啦。
1 #include <linux/init.h> 2 #include <linux/module.h> 3 4 static int __init hello_init(void) 5 { 6 printk(KERN_NOTICE "Hello, world."); 7 return 0; 8 } 9 10 static void __exit hello_exit(void) 11 { 12 printk(KERN_NOTICE "Goodbye, world."); 13 } 14 15 MODULE_LICENSE("GPL"); 16 module_init(hello_init); 17 module_exit(hello_exit);
预备知识
为了能理解这个内核模块,首先需要一些准备。
#include <linux/init.h>
#include <linux/module.h>
所有的的内核模块代码中都要包含这两个头文件,它们是专门用于内核模块的。
包含init.h文件,可以指定初始化函数和清除函数;而module.h文件内含有可装载的模块需要的符号和函数定义。
初始化和清除
static int __init hello_init(void) { 语句; }
初始化函数不会被其他文件引用,因此被声明为static。但这不是强制的,因为一个模块函数要对内核其他部分可见,必须被显式地导出。
__init标记表示该函数只在初始化时使用。在模块加载以后,模块装载器会释放初始化函数占用的内存。
module_init(hello_init);
此宏是强制使用的,用来说明初始化函数的位置。
static void __exit hello_exit(void) { 语句; }
清除函数和初始化函数一致,在模块移除的时候被调用,用来注销接口和向系统返回所有资源。
若模块内嵌到内核,或内核不允许卸载此模块,被标记为 __exit 的函数将被丢弃。
module_exit(hello_exit);
此宏是强制使用的,用来说明清除函数的位置。
许可证
MODULE_LICENSE("GPL");
指定该模块代码使用的许可证。内核能识别"GPL"、"GPL v2"、"GPL and additional rights"、"Dual BSD/GPL"、 "Dual MPL/GPL"和"Proprietary"。若没有指定,则内核假定它是"Proprietary"(专有)。
内核函数
printk(KERN_NOTICE "Hello, world.");
内核是不能依赖标准C库的,自然内核相关的编程中也就不能使用 printf 函数。这时需要使用内核版本的打印函数 printk 。当模块连接到内核时,就可以访问公共符号。
KERN_NOTICE定义了这条内核消息的优先级。