驱动模块的编译与安装

驱动模块的编译与安装

模块可以被选择“模块化编译”或“静态编译”
1. 分离式模块化编译:需要在内核运行时动态加载(也能实现开机加载 );非常适合驱动的开发与调试
2. 静态编译:链接入内核镜像,默认被加载;适合开发完成后在产品中使用
3. 统一式模块化编译:和内核一起编译,并统一输出到文件系统,在内核启动时统一开机加载 ;有利于实现开机加速

1.分离式模块化编译与安装

  • 所谓分离式模块化编译,就是不和内核一起编译的意思,非常适合驱动的开发与调试
  • 首先必须要获得开发板上内核的“该次编译源码目录”,因为模块化编译依赖于开发板上内核的“那一次编译”,如果内核与模块化编译不是“同一次编译”的,那么模块安装时将发生错误
  • 进入“该次编译源码目录”,可以在drivers目录下创建一个文件夹,以后可以在此文件夹下工作;文件夹内需要有模块源码(假设名字为module_test.c)与Makefile
  • 这是一个典型的驱动模块Makefile,它是非常模式化的,要改动的地方很少
#指定“该次编译源码目录”
KERN_DIR = xxxx/kernel

#obj-m表示将module_test.o编译成单独的模块
obj-m   += module_test.o

#下面这句真正开始编译
all:
    make -C $(KERN_DIR) M=`pwd` modules 

#提供复制功能,将.ko文件复制到nfs根文件系统中
cp:
    cp -f *.ko /xxxx

.PHONY: clean   
clean:
    make -C $(KERN_DIR) M=`pwd` modules clean
  • 这个Makefile只是一个索引,真正的编译是在内核源码树中完成的;make -C $(KERN_DIR) M=‘pwd’ modules 这句代码的本质其实是 make modules,中间的都是参数,-C代表进入到指定的源码目录下进行编译,M=’pwd’代表将编译完的.ko文件放回到当前目录下,得到的这个.ko文件即是模块
  • 如果我们的驱动文件包含多个.c文件呢?只需要将Makefile中的obj-m += module_test.o 改为如下即可,得到的还是一个module_test.ko
obj-m := module_test.o
modulename-objs := file1.o file2.o
  • 得到了module_test.ko之后,先通过modinfo module_test.ko 来查看模块的信息,尤其要检查vermagic这个参数,确保和kernel版本要一致vermagic: 2.6.35.7 preempt mod_unload ARMv7,然后将module_test.ko放到开发板的rootfs中
  • 开启开发板,然后在控制台中使用以下命令即可操作驱动模块
    • insmod:安装模块,如insmod module_test.ko
    • lsmod:显示当前系统已经安装的模块
    • rmmod:卸载模块,如rmmod module_test
    • demsg:显示内核所有的打印信息,当看不到模块打印信息时可以使用
  • 设置开机自动加载模块,根据手动构建rootfs及文件功能分析可知,在rootfs的rcS最后添加insmod /home/module_test.ko 即可实现开机自动加载模块

2.静态编译

内核代码静态编译的原理详见:kernel配置阶段宏观分析。所以得出结论,我们要在内核中添加新东西必须在对应的子Kconfig中添加新选项、子Makefile中添加新目标,然后使用make menuconfig设置子Kconfig中添加新选项为Y(将该选项的变量导入.config),最后编译的时候子Makefile便会根据.config中的变量值来选择如何编译。我们这里以leds-s5pv210.c这个驱动为例

  • 首先要将驱动的源码放到合适的目录中去(drivers/leds目录下),何谓“合适的目录”?比如我们写了一个基于普通字符设备驱动的led驱动,那么就应把它放在drivers/char目录下;如果我们写了一个基于框架的led驱动,那么就应把它放在drivers/leds目录下。如此安放,就符合了内核的目录结构
  • 打开该目录下的字Kconfig,根据 kernel中的Kconfig详尽分析,同时仿照同类驱动的写法,把我们的驱动文件添加进去。其中,depends on可以去掉,不用依赖其他东西
#之前还有很多,这里省略掉了
...
config LEDS_88PM860X
    tristate "LED Support for Marvell 88PM860x PMIC"
    depends on MFD_88PM860X
    help
      This option enables support for on-chip LED drivers found on Marvell
      Semiconductor 88PM8606 PMIC.

#我们依样画葫芦,添加一个
config LEDS_S5PV210
    tristate "LED Support for S5PV210(X210)"
    help
      This option enables support for on-chip LED drivers found on SM.

  • 打开该目录下的子Makefile,发现里面有很多的目标,我们仿照同类驱动写法,把我们的驱动文件也添加进去。值得注意的是,括号里的名称要和Kconfig中对应
#之前还有很多,这里省略掉了
...
obj-$(CONFIG_LEDS_INTEL_SS4200)        += leds-ss4200.o
obj-$(CONFIG_LEDS_LT3593)      += leds-lt3593.o
obj-$(CONFIG_LEDS_ADP5520)     += leds-adp5520.o
obj-$(CONFIG_LEDS_DELL_NETBOOKS)   += dell-led.o
obj-$(CONFIG_LEDS_MC13783)     += leds-mc13783.o

#我们依样画葫芦,添加一个
obj-$(CONFIG_LEDS_S5PV210)     += leds-s5pv210.o
  • 如果我们的驱动文件包含多个.c文件呢?只需要将Makefile中的obj-$(CONFIG_LEDS_S5PV210) += 后面把需要的.o文件续上去即可
  • 进入配置阶段。先make distclean一下,接着make xxx_defconfig生成.config,然后使用make menuconfig 来设置子Kconfig中刚刚添加的新选项为Y
  • 最后编译即可得到含有驱动的zImage
  • 特别要注意的一点,有时候驱动和驱动是互相冲突的,如果发现驱动不工作或没反应,可能是开发板上本来就有相同功能的驱动。比如在这里发现led驱动完全没效果,打开menuconfig 一看,发现里面还使能了一个默认的开发板商写的led驱动,把它关掉再重新编译就好了

3.统一式模块化编译

统一式模块化编译的操作和静态编译极为类似,操作几乎相同,只是在make menuconfig 时来设置添加新选项为M即可

  • 当内核编译完时,我们可以使用make modules_install将所有的ko文件导出到_install文件夹内,然后我们可以将_install/lib/modules/xxxxx复制到文件系统的/lib/modules/xxxxx内,这样系统开机的时候便能统一加载所有的模块了
  • 那模块是如何被开机加载的呢?主要是通过开机启动的脚本/etc/init.d/modutils.sh来实现的,主要工作是去/lib/modules/xxxxx内加载所有的模块
  • 不难看出,统一式模块化编译可以提高系统的启动时间,将一部分不重要的工作挪到了开机后进行

4.设备及设备文件的查看

cat /proc/devices

可以查看已经安装的设备和设备号

ls /dev

可以查看已经生成的设备文件

你可能感兴趣的:(【Linux内核与驱动】)