Linux设备驱动开发第一天的hello程序是这样的
hello.c文件:
#include
#include
MODULE_LICENSE("GPL");
MODULE_AUTHOR("09bqluo");
MODULE_DESCRIPTION("Hello World Module");
MODULE_ALIAS("a simplest module");
static int __init hello_init()
{
printk(KERN_EMERG"Hello World!\n");
return
0;
}
static void __exit hello_exit()
{
printk("<6>hello exit\n");
}
module_init(hello_init);
module_exit(hello_exit);
。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
MODULE_LICENSE("GPL"); 许可证申明
MODULE_AUTHOR("09bqluo"); 作者申明(可选)
MODULE_DESCRIPTION("Hello World
Module"); 模块描述(可选)
MODULE_ALIAS("a simplest module"); 模块别名(可选)
这个模块定义了两个函数, 一个在模块加载到内核时被调用( hello_init )以及一个在模块被去除时被调用(
hello_exit ). moudle_init 和 module_exit 这几行使用了特别的内核宏来指出这两个函数的角色.
另一个特别的宏 (MODULE_LICENSE) 是用来告知内核, 该模块带有一个自由的许可证; 没有这样的说明,
在模块加载时内核会抱怨.
printk 函数在 Linux 内核中定义并且对模块可用; 它与标准 C 库函数 printf 的行为相似.
内核需要它自己的打印函数, 因为它靠自己运行, 没有 C 库的帮助. 模块能够调用 printk 是因为, 在 insmod
加载了它之后, 模块被连接到内核并且可存取内核的公用符号 (函数和变量, 下一节详述). 字串 KERN_ALERT
是消息的优先级.
linux/kernel.h中定义了8种记录级别,按优先级别递减的顺序分别是:
Makefile文件:
ifneq ($(KERNELRELEASE),)
obj-m := hello.o
else
KDIR :=
/lib/modules/2.6.27.5-117.fc10.i686/build //注意要按自己的虚拟机的路径来
all:
make -C $(KDIR) M=$(PWD) modules
clean:
rm -f *.ko *.o *.mod.o *.mod.c *.symvers
endif
。。。。。。。。。。。。。。。。。。。。。。。。。。。。
obj-m := hello.o
上面的安排( 它利用了由 GNU make 提供的扩展语法 )表明有一个模块要从目标文件
hello.o 建立. 在从目标文件建立后结果模块命名为 hello.ko.
反之, 如果你有一个模块名为 module.ko, 是来自 2 个源文件( 姑且称之为, file1.c 和 file2.c
), 正确的书写应当是: obj-m := module.o
module-objs := file1.o file2.o
这个 makefile 在一次典型的建立中要被读 2 次. 当从命令行中调用这个 makefile , 它注意到
KERNELRELEASE 变量没有设置. 它利用这样一个事实来定位内核源码目录, 即已安装模块目录中的符号连接指回内核建立树.
如果你实际上没有运行你在为其而建立的内核, 你可以在命令行提供一个 KERNELDIR= 选项, 设置 KERNELDIR 环境变量,
或者重写 makefile 中设置 KERNELDIR 的那一行. 一旦发现内核源码树, makefile 调用 default:
目标, 来运行第 2 个 make 命令( 在 makefile 里参数化成 $(MAKE))象前面描述过的一样来调用内核建立系统.
在第 2 次读, makefile 设置 obj-m, 并且内核的 makefile
文件完成实际的建立模块工作。也就是第一次先执行else下面的程序,第二次再利用.o文件生成.ko文件(也就是else前面的)。
M=$(PWD)表示在当前目录找源代码
clean:
rm -f *.ko *.o *.mod.o *.mod.c
*.symvers 表示的用make clean命令后删掉的文件后缀
另外,说下modprobe 工具. modprobe, 如同 insmod, 加载一个模块到内核.
它的不同在于它会查看要加载的模块, 看是否它引用了当前内核没有定义的符号. 如果发现有, modprobe
在定义相关符号的当前模块搜索路径中寻找其他模块. 当 modprobe 找到这些模块( 要加载模块需要的 ), 它也把它们加载到内核.
如果你在这种情况下代替以使用 insmod , 命令会失败, 在系统日志文件中留下一条 " unresolved symbols
"消息.