原文网址:http://www.apkbus.com/android-98520-1-1.html
前面几节都是将Linux驱动编译成模块,然后动态装载进行测试。动态装载驱动模块不会随着Android系统的启动而自动装载,因此Android系统每次启动都必须使用insmod或modprobe命令装载Linux驱动模块。
对于嵌入式系统(包括嵌入式Android、嵌入式Linux等)一般都采用将Linux驱动编译进内核的方式。这样做虽然没有动态装载灵活,但Linux驱动会随着Android的启动而自动装载。一般在开发过程中为了测试和调试方便,会将Linux驱动以模块形式装载到Linux内核中。当Linux驱动通过最终测试后,会将Linux驱动编译进Linux内核再进行测试。
本节将介绍如何将word_count驱动编译进Linux内核,并分别在Android模拟器和S3C6410开发板上测试word_count驱动。
Linux内核源代码被设计成可装卸式结构。也就是说只需要修改配置文件,就可以使某个Linux驱动编译成模块(.ko文件),或编译进Linux内核,当然,也可以将该Linux驱动从Linux内核去除。核心的配置文件如下。
q .config:该文件位于Linux内核源代码的顶层目录,为隐藏文件。该文件用于配置Linux内核中的模块。在.config文件中可以对Linux驱动进行三方面的配置:编译成驱动模块(.ko文件)、编译进内核和从Linux内核去除。可以手工修改.config文件,也可以使用make menuconfig命令用菜单方式来设置.config文件。
q Kconfig:每一个想要连接进Linux内核的模块目录都有该文件。该文件主要用于定义make menuconfig命令显示的菜单(包括菜单项名称、帮助信息、选项类型、模块依赖等信息),除此之外,Kconfig文件还可以导入位于其他目录的Kconfig文件。make命令通过Kconfig文件的递归引用,可以找到Linux内核中的所有Kconfig文件,从而建立一个完整的配置菜单。
q Makefile:一般与Kconfig文件同时出现。每有一个Kconfig文件,就必要有一个Makefile文件。该文件用于指定如何编译Makefile文件所在目录的源代码。
现在还使用word_count驱动的例子来详细说明如何将一个Linux驱动加入Linux内核源代码树中。由于word_count驱动属于字符驱动,所以可以使用如下的步骤将word_count驱动加入Linux内核源代码树。
第1步:将word_count.c文件放入Linux内核源代码
将word_count.c文件放到<Linux内核目录>/drivers/char目录中。
第2步:修改Kconfig文件
打开/root/kernel/goldfish/drivers/char/Kconfig文件,找到endmenu,并在endmenu前面添加如下代码。
config WORD_COUNT
bool "word_count driver"
help
This is a word count driver. It can get a word count from /dev/wordcount
其中,config后面的字符串将作为Shell变量名的后半部分,前半部分是CONFIG_。也就是说,每一个具体的模块都会对应一个Shell变量来保存该模块的3个编译行为(生成.ko文件、编译进Linux内核或从Linux内核中去除)。word_count驱动模块的变量是CONFIG_WORD_COUNT。该变量的值会保存在.config文件中。
bool表示word_count驱动只能进行两项设置(被编译进内核与从Linux内核中去除),后面会介绍如何设置菜单项的三项设置。bool后面的字符串就是菜单项的文本。help用于设置菜单项的帮助信息。
第3步:修改Makefile文件
打开/root/kernel/goldfish/drivers/char/Makefile文件。该文件大多都是如图6-21所示的内容,随便找个位置插入如下内容。
<ignore_js_op>
▲图6-21 在Makefile文件中添加word_count驱动模块
obj-$(CONFIG_WORD_COUNT) += word_count.o
通过第2步的设置产生了一个CONFIG_WORD_COUNT变量,而在第3步中obj-后使用了该变量,而不是使用固定的值(y或m)。make命令在编译Linux内核时会将该变量替换成相应的值。
第4步:设置.config文件
.config文件可以通过手工配置,也可以通过make menuconfig命令在菜单中配置。在这里我们采用菜单配置的方法。现在进入Linux内核顶层目录(/root/kernel/goldfish)。然后执行make menuconfig命令显示配置菜单,并进入“Device Drivers”>“Character devices”子菜单,找到“word_count_driver”菜单项,按空格键将“word_count_driver”菜单项前设置成星号(*),如图6-22所示。然后退出配置界面并保存所做的修改。
按“h”键可以显示word_count驱动的帮助信息,如图6-23所示。
<ignore_js_op>
▲图6-22 配置word_count驱动模块
<ignore_js_op>
▲图6-23 word_count驱动的帮助信息
在配置完.config文件后,读者可以打开.config文件,并找到CONFIG_WORD_COUNT,会发现该变量的值已被设成“y”。
第5步:编译Linux内核
进入/root/kernel/goldfish目录,执行下面的命令编译Linux内核。
# make
如果读者以前编译过当前的Linux内核,并不需要担心编译的时间过长,因为make足够智能,它只会编译最新修改的模块及其依赖的模块。
当成功编译Linux内核后,读者可以到/root/kernel/goldfish/arch/arm/boot目录找到zImage文件,并使用Android模拟器运行这个内核。读者会发现,在/dev目录中有一个wordcount设备文件,而我们并没有运行build.sh脚本文件安装word_count驱动。这是因为Android模拟器在装载zImage内核文件时已自动装载了word_count驱动。不过在使用前面的例子测试word_count驱动时仍然需要执行下面的命令设置/dev/wordcount设备文件的访问权限。
# adb shell chmod 777 /dev/wordcount
如果读者不想将word_count.c复制到/root/kernel/goldfish/drivers/char目录,可以使用下面的命令在/root/kernel/goldfish/drivers/char目录建立一个符号链接。
# ln -s /root/drivers/ch06/word_count /root/kernel/ goldfish/drivers/ char/word_ count
将word_count目录加入Linux内核源代码树的步骤如下(在进行下面的步骤之前需要将上面步骤所做的设置注释掉)。
第1步:建立新的Kconfig文件
在word_count目录中建立一个Kconfig文件,并输入如下内容:
config WORD_COUNT
tristate "word_count driver"
default y
help
This is a word count driver. It can get a word count from /dev/wordcount
其中tristate表示三态类型(编译进内核、编译成模块,从Linux内核移除)。如果使用tristate代替bool,菜单项前面就变成尖括号。按“y”键,尖括号中显示星号(*),表示编译进内核。按“M”键,尖括号中显示M,表示编译成模块。按“N”键,尖括号在符号消失,表示word_count驱动被忽略。如果不断按“空格”键,这3种状态会循环切换。
default用来设置默认值。如果使用tristate,default可以设置y、m和n三个值,分别对应编译进内核、编译成模块和从Linux内核中移除。当模块第一次设置时会处于default设置的默认状态。
注意如果使用tristate,必须按照6.4.2节的方法打开“Enable loadable module support”选项,否则无法将驱动设为编译成模块状态(M状态),菜单项前面仍然是一对中括号。
第2步:修改Makefile文件
word_count目录中的Makefile文件目前的内容如下:
obj-m := word_count.o
在Makefile文件中已经将编译类型设为Linux驱动模块(obj-m表示编译成.ko文件)。但现在要将word_count驱动加入Linux内核源代码树中,因此需要使用CONFIG_WORD_COUNT变量来代替m,所以Makefile文件的内容需要按如下内容修改。
obj-$(CONFIG_WORD_COUNT) := word_count.o
修改Makefile文件后,如果还想使用前面几节的脚本文件测试word_count驱动,需要将.config文件中CONFIG_WORD_COUNT变量值设为m,如果.config文件中没有该变量,就添加一个CONFIG_WORD_COUNT变量。当然,也可以使用make menuconfig命令设置。
为了可以单独编译word_count驱动,也可以和Linux内核一同编译,我们可以采用如下形式重新编写Makefile文件。当CONFIG_WORD_COUNT变量未定义时,说明没有与Linux内核一同编译。
# 与Linux内核一同编译
ifdef CONFIG_WORD_COUNT
obj-$(CONFIG_WORD_COUNT) := word_count.o
else
# 单独编译
obj-m := word_count.o
endif
第3步:修改上层目录的Kconfig文件
为了能找到word_count目录中的Kconfig文件,需要在drivers/char/Kconfig文件中引用word_count目录中的Kconfig文件。现在打开/root/kernel/goldfish/drivers/char/Kconfig文件,在“endmenu”之前添加如下一行代码。
source "drivers/char/word_count/Kconfig"
第4步:修改上层目录的Makefile文件
在drivers/char/Makefile文件中添加如下一行,以便使make命令可以找到word_count目录中的Makefile文件。
obj-$(CONFIG_WORD_COUNT) += word_count/
接下来的工作就和前面介绍的五步中的第4步和第5步一样了。在进入如图6-24所示的设置界面时,可以按“M”键将word_count驱动模块编译成.ko文件。
<ignore_js_op>
▲图6-24 设置word_count驱动模块的编译类型
注意当修改Linux内核设置后重新编译内核,以前使用该Linux内核编译的Linux驱动模块可能由于格式错误无法安装,因此,在重新编译Linux内核后,需要重新编译Linux驱动模块。
如果想将word_count驱动模块编译进其他内核也可采用与上面类似的做法。