驱动程序添加到内核
一.概述:
在Linux内核中增加程序需要完成以下三项工作:
1.将编写的源代码复制到Linux内核源代码的相应目录
2.在目录的Kconfig文件中增加新源代码对应项目的编译配置选项
3.在目录的Makefile文件中增加对新源代码的编译条目
二.实例
1.先把驱动代码usbtmc(文件夹)赋值到/usr/src/linux-headers-2.6.32-31-generic/drivers/char下
首先你要清楚你的模块应在内核源代码树中处于何处。
1>设备驱动程序存放在内核源码树根目录drivers/的子目录下,在其内部,设备驱动文件进一步按照类别,类型等有序地组织起来。
a.字符设备存在于drivers/char/目录下
b.块设备存放在drivers/block/目录下
c.USB设备则存放在drivers/usb/目录下。
注意:
(1)此处的文件组织规则并非绝对不变,例如:USB设备也属于字符设备,也可以存放在drivers/usb/目录下。
(2)例如我们把驱动程序usbtmc存放在drivers/char/目录下,那么你要注意,在该目录下同时会存在大量的C源代码文件和许多其他目录。所有对于仅仅只有一两个源文件的设备驱动程序,可以直接存放在该目录下,但如果驱动程序包含许多源文件和其他辅助文件,那么可以创建一个新子目录。
此处,我们是把usbtmc目录放在了drivers/char目录下面
2.修改char目录下的Kconfig和Makefile
(1)修改Kconfig
sudogedit Kconfig
添加下面一句后
source"drivers/char/usbtmc/Kconfig"
它表示将usbtmc目录下的Kconfig挂载到char目录下的Kconfig里面(为了使本层的Kconfig文件能起作用,我们需要修改父目录的Kconfig文件,加入source语句)
1>对驱动程序而言,Kconfig通常和源代码处于同一目录。
2>如果你建立了一个新字目录,而且也希望Kconfig文件存在于该目录中的话,那么就必须在一个已存在的Kconfig文件中将它引入,需要用上面的
语句将其挂接在drivers/char目录中的Kconfig中。
(2)修改Makefile
添加一句话:
obj-$(CONFIG_USBTMC)+=usbtmc/
这行编译指令告诉模块构建系统在编译模块时需要进入usbtmc/子目录中。此时的驱动程序的编译取决于一个特殊配置CONFIG_USBTMC配置选项。
3.现在在我们自己些驱动程序文件夹中添加Kconfig和Makefile
(1)修改Kconfig
新建一个Kconfig添加下面的话
menu "USBTMC"
comment"USBTMC Driver"
config USBTMC
tristate "USBTMC"
defaultn
help
Ifyou say Y here,support for the usbtmc with computer interface will becompiled into he kernel and accessible via device node. You can also say M here and the driver will be built as a module named usbtmc.ko.
Ifunsure,say N.
endmenu
endmenu
正确配置好后,我们在源码下执行sudomake menuconfig后,在出现的LinuxKernel Configuration图形界面中选择DeviceDrivers下的characterdevcie中,将会看到新加的USBTCM菜单,
(2)修改Makefile
新建一个Makefile,添加下面的话
obj-$(CONFIG_USBTMC)+=usbtmc.o
此时,构建系统运行就将会进入usbtmc/目录下,并且将usbtmc.c编译为usbtmc.ko模块
注:
如果驱动程序源文件可能不只有一个,可以把Makefile做如下修改:
obj-$(CONFIG_USBTMC)+=usbtmc.o
usbtmc-objs:=usbtmc-main.o usbtmc-usb1.o
此时,usbtmc-main.c和usbtmc-usb1.c就一起被编译和连接到了usbtmc.ko某块中。
4.现在已经Ok了,现在我们可以进入linux内核目录下通过menuconfig可以找到我们的USBTMC选项(在Device_Drivers下的characterdevices里可以找到USBTMC)对其进行选定。然后退出,编译内核,就搞定了。
5.删除:
删除也很简单,首先在drivers/char目录下删掉自己的驱动文件夹。其次再删除Makefile和Kconfig之前添加的东西,就搞定了
三.详解:
Makefile,Kconfig和配置工具组成了Linux2.6内核的配置系统。
其中Makefile定义了Linux内核的编译规则,它是大型项目开发的产物。Linux环境下的大型项目开发中,系统被分为很多模块,而这些模块一般会经历几次修改,而在修改后的编译过程中,由于某些文件中存在依赖关系,人工编译效率低(有些文件不需要重新编译)且易出错,Makefile文件便应运而生。Makefile文件定义了模块间的依赖关系,指定文件的编译顺序,以及编译所使用的命令。它和make命令使得项目的源程序文件可以自动编译,提高了软件开发效率。到此,再谈一下make,它是用来维护程序模块关系和生成可执行程序的工具,它可以根据程序模块的修改情况重新编译链接生成中间代码或最终的可执行程序,省去那些重复的不必要的编译工作,提高编译效率。
Kconfig给用户提供配置选择的功能。通常配置内核会有四种方法,makeconfig(字符界面配置),makemenuconfig(菜单界面配置),makexconfig(依赖QT),makegconfig(依赖GTK+)。makeconfig比较适合专业人员,像初学者比较适合makemenuconfig,让我们重点关注一下它。当我们运行makemenuconfig时,配置工具会首先分析与体系结构相对应的/arch/xxx/Kconfig文件(xxx为传入的arch参数),它里面包含了除一些与体系结构相关的配置项和配置菜单外,还通过source语句引入了一系列Kconfig,配置工具依据这些Kconfig包含的菜单和项目就可以描绘出一个分层结构。
例如当我们运行makezImagine、makebzImagine等生成映像的命令时,会先检索顶层的Makefie(在arch/xxx/目录下的Makefile为顶层Makefile补充体系结构相关的信息),顶层Makefile的两个主要任务是:产生内核映像文件和内核模块。接着顶层Makefile会去递归地进入内核的各个子目录,然后分别调用子目录中的Makefile(这些Makefile记录编译目标),而进入哪些子目录取决于内核的配置。
当使用makemenuconfig,makeconfig命令时,生成的.config会在源码目录下记录哪些部分被编译入内核,哪些部分被编译为内核模块。简而言之,它是保存内核配置结果的文件。当我们装上Linux系统时,第一次查看源码下的所有文件,会发现没有.config文件,那是因为从来没配置过内核。当你运行makemenuconfig保存并退出时,再次查看就有这个文件了。
配置工具,包括配置命令解释器(对配置脚本中使用的命令进行解释)和配置用户界面(提供字符界面和图形界面),配置工具都是用脚本语言编写的。
1.在进入menuconfig配置界面时,会发现每个配置项目为布尔型(要么编译入内核,要么不编译,选项为“Y”或“N”),菜单上为配置选项的名字例如:“XXXDriver”,help后面的内容为帮助信息。
1>除了布尔型的配置项目外,还存在一种三态型(tristate)配置选项,它意味着要么编译入内核,要么编译为内核模块,要么不编译,选项为“Y”,“M”或“N”。
eg: obj-$(CONFIG_USBTMC) +=usbtmc.o
上面的脚本含义是:如果USBTMC选项被选择为“Y”或“M”,即obj-$(CONFIG_USBTMC)就等同于obj-y或obj-m时,则编译usbtmc.c,选Y的情况直接会将生成的目标代码直接连接到内核,为“M”的情况则会生成模块usbtmc.ko,如果USBTMC配置选项被选择为“N”,即obj-$(CONFIG_USBTMC)等同于obj-n时,则不编译usbtmc.c
2.Makefile
对内核源代码各级子目录中的kbuildMakefile进行介绍,
(1)目标定义
目标定义用来定义哪些内容要作为模块编译,哪些要编译并连接进内核
(a)obj-y:=foo.o
表示要由foo.c或者foo.s文件编译得到foo.o并连接进内核,而obj-m则表示该文件要作为模块编译。处了y,m以外的obj-x形式的目标都不会被编译。
(b)我们最常用的的做法是根据.config文件的CONFIG_变量来决定文件的编译方式:
eg:
obj-$(CONFIG_ISDN)+=isdn.o
(c)多个文件模块的定义
如果一个模块由多个文件组成,这时候应采用模块名加-objs后缀或者-y后缀的形式来定义模块的组成文件。
如:
obj-$(CONFIG_EXT2_FS)+=ext2.o
ext2-y:=balloc.o bitmap.o
模块的名字是ext2,由balloc.o和bitmap.o两个文件最终连接生成ext2.o直至ext2.ko文件。
3.Kconfig
内核配置脚本语法:
(1)大多数的内核配置选项都对应一个Kconfig中的一个菜单入口。
menu "USBTMC"
comment "USBTMC Driver"
config USBTMC
tristate "USBTMC"
default n
endmenu
(a)“config”关键字定义新的配置选项,之后的几行定义了该配置选项的属性。配置选项的属性包括类型,数据,输入提示,依赖关系(及反向依赖关系),帮助信息和默认值等。
(b)每个配置选项都必须指定类型,其他类型都基于这两种基本类型。类型定义后可以紧跟输入提示,下面两个脚本是等价的
脚本1:
bool“Networking support”
脚本2:
bool
promt“Networking support”
输入提示的一般格式如下提示:
prompt <prompt> [if <expr>]
其中可选的if用来表示该提示的依赖关系。
默认值的格式如下所示:
default<expr> [if <expr>]
一个配置选项可以存在任意多个默认值,这种情况下,只有第一个被定义的值是可用的。如果用户不设置对应的选项,配置选项的值就是默认值。
(c)依赖关系的格式如下所示:
dependson (或者 requires)<expr>
如果定义了多个依赖关系,它们之间用”&&”间隔。依赖关系也可以应用到该菜单中所有的其他选项中。
(4)反向依赖关系的格式如下所示:
select<symbol> [if <expr>]
A.depends能限定一个symbol的上限,即如果A依赖于B,则在B被配置为“Y”的情况下,A可以为“Y”,“M”和”N”;在B被配置为“M”的情况下,A可以被配置为“M”或“N”;B在被配置为“N”的情况下,A只能为”N”。
B.select能限定一个symbol的下限,若A反向依赖于B,则A的配置值会高于或等于B(正好与depends相反)。如果symbol反向依赖于多个对象,则它的下限是这些对象的对大值。
(5)帮助信息的格式如下:
help(或---help---)
开始
。。。
结束
帮组信息完全靠文本缩进识别结束。“---help---”和”help”的初衷在于将文件中的配置逻辑与给开发人员的提示分开。
3.菜单结构
菜单入口在菜单数结构中的位置可由两种方法决定。
(1)第一中方式如下所下:
menu“Network device support”
dependson NET
config NETDEVICES
endmenu
所有处于”menu”和”endmenu”之间的菜单入口都会成为“Networkdevice support”的子菜单。而且,所有子菜单选项都会继承父菜单的依赖关系,比如:“Networkdevice support”对“NET”的依赖被加到了配置选项NETDEVICES的依赖列表中。
(2)另一种方式是通过分析依赖关系生成菜单结构。如果菜单选项在一定程度上依赖于前面的选项,它就能成为该选项的子菜单。如果父选项为“N”,则子选项不可见;如果父选项为“Y”或“M”,则子选项可见。
Eg:
config MODULES
bool “Enable loadable module support”
config MODVERSIONS
bool “Set version information on all module symbole”
dependson MODULES
comment “module support disabled”
depends on !MODULES
MODVERSIONS直接依赖MODULES,如果MODULES不为“N”,该选项才可见。
(3)除此之外,Kconfig中还可能使用“choices…...endchoice”,”comment”,”if....endif”这样的语法结构。
其中
choice
<choiceoptions>
<choiceblock>
enchoice
它定义一个选择群,其接受的选项(choiceoptions)可以是前面描述的任何属性。在一个硬件有多个驱动的情况下使用,使用选择可以实现最终只有一个驱动被编译进内核或模块。选择群还可以接受的另一个选项是“optional”,
这样菜单入口就被设置为“N”,没有被选中。