编写驱动我们需要内核源码,并且是目标机器的内核源码,这在编译驱动的时候会用到。编译模块需要内核代码, 并配置和编译内核代码,就算有源码,但是没经过编译,也是不能用于编译模块的。编译模 块的内核配置必须与所运行内核的编译配置一样,否则将有可能无法加载或者运行。
首先准备内核,到kernel.org下载对应版本的内核源码,或者是适配好的内核源码。将源码复制到开发主机的/usr/src目录(只要记住路径放在都行,但是推荐放在/usr/src)。
tar -xvf file 解压源码,得到源码目录
配置好后make编译
make modules
make modules_install 这两步会在/lib/modules/ 下生成对应版本的目录。
然后编写一个最简单的内核模块测试一下
程序源码driver01.c,编译驱动的Makefile
#include <linux/module.h>
#include <linux/init.h>
static int __init hello_init(void)
{
printk("Hello, I'm ready!\n");
return 0;
}
static void __exit hello_exit(void)
{
printk("I'll be leaving, bye!\n");
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");
注意这个KDIR 就是内核源码的路径,我实验的主机有自带的源码,所以没有使用下载的源码
obj-m := driver01.o
#module-objs := driver01.o
KERN_VER = $(shell uname -r)
KDIR = /lib/modules/$(KERN_VER)/build
#KDIR := /usr/src/linux-3.10/ 这个是下载的
PWD := $(shell pwd)
modules:
$(MAKE) -C $(KDIR) M=$(PWD) modules
clean:
rm -rf *.o .* .cmd *.ko *.mod.c .tmp_versions
在驱动源码目录(我放在了/home/driver)下执行make,得到目标模块driver01.ko
安装模块 insmod driver01.ko,可能会没有内容输出,使用dmesg查看,模块初始的内容已经打印出来了。
lsmod查看所有模块
使用 rmmod driver01 卸载模块,dmesg查看信息,模块被卸载。
结束
-------------------------------------------------------------------------------------------------------------------
其他:
我又用了下载的内核源码编译试了下,安装模块时提示格式错误,装不上,错误模块的信息,不知道是什么原因。
对于Makefile的理解。
obj-m += driver.o
表示将我们的module_test.o编译成一个模块。
$(MAKE) -C $(KDIR) M=$(PWD) modules
-C参数指定内核源码树目录,当执行make命令的时候会跳转到这个目录下去执行,M=`pwd`用来指定执行完make命令之后的返回当前目录。整体过程就是跳转到指定的目录下 执行 make modules,执行完之后在返回到当前的目录,并把编译好的模块复制到当前目录下;
modules肯定是一个内核源码树下的Makefile中的一个目标,这个目标定义了内核模块的编译规则,所以切不可胡乱改modules,所以得知,我们这里的Makefile只不过是一个入口,真正的
模块编译工作是在内核源码树下的Makefile中进行的,所以我们才需要在这个Makefile中指定一个入口地址(也就是内核源码树的路径)给我们的make管理器。