在类unix操作系统中,驱动加载方式一般分为:静态加载和动态加载。静态加载就是把驱动程序直接编译到内核里,系统启动后直接被调用。静态加载的缺点是调试起来比较麻烦,每次修改一个地方都要重新编译下载内核,效率较低。动态加载利用了LINUX的module特性,可以在系统启动后用insmod命令把驱动程序(.ko文件)添加上去,在不需要的时候用rmmod命令来卸载。下面我们通过蜂鸣器驱动实例分别对其进行详述。
1.1.1 静态加载
第一步:在kernel/drivers/char目录下新建目录beep,在beep目录下创建Kconfig,Makefile以及x4412-beep.c三个文件。
第二步:编辑Makefile内容如下:
编辑Kconfig内容如下:
再编辑x4412-beep.c文件,其部分源码如下:
第三步:在kernel/drivers/char/Kconfig
中添加如下语句:
第四步:在kernel/drivers/char/Makefile
中添加如下语句:
第五步:配置menuconfig,编译内核。menuconfig配置界面如下:
编译完内核后,在kernel/drivers/char/beep
目录下将会生成目标文件x4412-beep.o
,它会被打包到内核映像zImage
中。
1.1.1 动态加载
在前面的静态加载实验中,我们在menuconfig中尝试配置X4412 beep driver,发现只能选中或不选中,这是由beep目录下面的Kconfig文件决定的。我们发现,X4412 beep driver被声明的参数为bool。我们只需要将bool改为tristate,就可以配置成模块了。bool表示布尔类型,只允许选中或不选中;tristate为三态类型,允许选中,不选中以及编译成模块。修改后的配置界面如下:
保存配置之后再编译内核,这时我们发现,在kernel/drivers/char/beep目录下将会生成模块文件x4412-beep.ko。
将新生成的内核映像zImage烧写到开发板,进入/sys/devices/platform目录,我们发现已经没有x4412-beep目录了,有图为证:
linux设备驱动的动态加载可以使用insmod或modprobe两种方式,insmod一次只能加载一个特定的驱动,且需要驱动的绝对路径,而modprobe则可以一次性将有依赖关系的驱动全部加载到内核,不需要驱动的具体地址。但需要将驱动拷贝到/lib/modules/$(uname -r)/目录下,下面我们以前面的蜂鸣器驱动为例,分别介绍两种加载方法。
1. 使用insmod加载驱动
将前面生成的x4412-beep.ko文件拷贝到SD卡或U盘,并mount到/mnt目录:
这时我们在任意目录下即可执行如下指令加载驱动了:
我们可以看到打印信息“x4412 beep driver”,它就是蜂鸣器驱动的module_init加载的函数执行的打印信息,表明驱动已经正常运行。
可以使用lsmod命令查看已经加载的KO文件:
我们可以进一步验证驱动是否加载,可以看到/sys/devices/platform目录下是否有x4412-beep目录生成:
可以执行指令测试蜂鸣器是否鸣叫:
如果还不信,使用如下指令卸载驱动后,然后再执行上面的测试指令查看结果。
2. 使用modprobe加载驱动
前面我们提到,modprobe并不需要指定到具体的KO文件目录,我们不仿测试下:
这里提示找不到/lib/modules目录,和前面介绍的一样,它需要在指定目录下加载KO,那我们不仿新建该目录,再执行上面的指令测试:
这里提示找不到3.0.15-9tripod目录,它对应linux内核的名称,可以使用uname–r指令查询。我们继续新建目录,继续测试:
这时,提示找不到modules.dep文件。我们不需要手动创建该文件,使用depmod指令即可自动生成。很有可能默认情况下根文件系统不支持该指令,执行时会提示如下信息:
我们可以通过配置busybox来添加这个功能。但是我们制作的根文件系统,是用buildroot自动完成的,busybox也随之自动生成,我们还能随心所欲的添加其他功能吗?答案是肯定的。
进入buildroot的menuconfig菜单,进入Target packages选项,发现第一栏有关于busybox的配置选项,如下图所示:
可见,我们只需要配置完busybox
后,保存到这里就可以了。有两种方法可以实现,第一种就是在busybox
的编译目录配置完成后,用busybox
当前目录的配置文件.config
替换掉package/busybox/busybox.config
文件。第二种就是配置完busybox
后,直接在buildroot
的配置选项中导入这个配置文件。
busybox
的编译目录在output/build/busybox-1.22.1
下,这里output
是编译之后才会释放的文件,手工配置busybox
后,配置文件也会保存在这个目录下,因此不推荐用第二种方法,它不便于源码维护。下面介绍第一种方法。
进入output/build/busybox-1.22.1
目录,执行make menuconfig
,进入Linux Module Utilities
菜单,如下图所示:
选中insmod,rmmod,lsmod,modprobe,depmod,保存退出,然后将当前目录下的.config文件覆盖掉package\busybox\busybox.config文件,之后在buildroot根目录下执行make指令重新编译,busybox将会自动更新,并最终打包到映像文件rootfs.ext4中。
将开发板更新最新的文件系统后,我们就可以使用depmod
指令了。在没有执行该指令时,在/lib/modules/ 3.0.15-9tripod
下是没有任何文件的,执行depmod
命令后,该目录下将会生成三个文件:
我们再尝试执行modprobe指令加载驱动:
这里提示在modules.dep文件中没有发现我们加载的ko文件,我们尝试查看一下modules.dep的内容:
可见,里面的内容为空。实际上,depmod指令会自动分析/lib/modules/$(uname -r)目录下的可加载模块,并按照固定的格式填入modules.dep中。因此,我们可以先将需要加载的ko文件拷贝到对应的目录,再执行depmod指令。
可以看到,在modules.dep中已经存在有我们需要加载的ko文件名了。注意,不要手工的去编辑modules.dep文件!再执行modprobe指令,即可加载模块了。