当编译了模块后,如果希望模块随系统一起启动,那么需要将模块静态编译进内核。将模块静态编译入内核,需要完成一些必要的步骤。
一、向内核添加模块
向Linux内核添加驱动模块,需要完成4个工作。
1、编写驱动程序文件。
2、将驱动程序文件放到Linux内核源码包的相应目录中,如果没有合适的目录,可以自己建立一个目录存放驱动文件程序文件。
3、在目录的Kconfig文件中添加新驱动程序对应的项目编译选择。
4、在目录的Makefile文件中添加新驱动程序的编译语句。
二、Kconfig
今天学习了驱动程序模块的安装与卸载,在这个过程中发现,内核的目录中有许多的Kconfig、Makefile文件,但是不知道为什么需要这些文件,这些文件又是用来做什么的。下面我就一起来学习下这些文件的作用是什么。
首先我们来学习什么Makefile,什么是Kconfig ,什么是.config
Makefile:一个文本形式的文件,其中包含一些规则告诉make编译哪些文件以及怎样编译这些文件。
Kconfig:一个文本形式的文件,其中主要作用是在内核配置时候,作为配置选项。
.config:文件是在进行内核配置的时候,经过配置后生成的内核编译参考文件。
三、Kconfig的语法
1、主要语法总览
Kconfig配置文件描述了一系列的菜单入口。除了帮助信息之外,每一行都以一个关键字开始,这些关键字如下:
config
menuconfig
choice/endchoice
comment
menu/endmenu
if/endif
前5个关键字都定义了一个菜单选项,if/endif是一个条件选项。下面对常用的一些语法进行说明。
2、菜单入口(config)
大多数的选项都定义了一个配置选项,其它选项则有助于对它们进行组织。(原文:Most entries define a config option, all other entries help to organize them.)一个配置选项定义可以是下面的形式:
config MODVERSIONS
bool "Set version information on all module symbols"
depends MODULES
help
Usually, modules have to be recompiled whenever you switch to a new kernel. ...
每行都是以关键字开始,并可以接多个参数。"config" 为定义了一新的配置选项。下面的几行定义了该配置
选项的属性。属性可以是该配置选项的类型,输入提示(input prompt),依赖关系,帮助信息和默认值。配置选项可以用相同的名字定义多次,但每个定义只能有一个输入提示并且类型还不能冲突。
菜单选项可以有多个属性。并不要求这些属性可以用在任何地方。
类型定义:"bool"/"tristate"/"string"/"hex"/"int"
每个配置选项都必须指定类型。有两个基本类型:tristate 和 string,其他类型都是基于这两个基本类型。类型定义可以用输入提示,所以下面的两个例子是等价的:
bool "Networking support" 和
bool
prompt "Networking support"
- 输入提示: "prompt" <prompt> ["if" <expr>]
每个菜单选项最多只能有一个显示给用户的输入提示。可以用 "if" 来表示该提示的依赖关系,当然这是可选的。
- 默认值:"default" <expr> ["if" <expr>]
一个配置选项可以有任意多个默认值。如果有多个默认值,那么只有第一个被定义的值是可用的。默认值并不是只限于应用在定义他们的菜单选项。这就意味着默认值可以定义在任何地方或被更早的定义覆盖。
如果用户没有设置(通过上面的输入提示),配置选项的值就是默认值。如果可以显示输入提示的话,就会把默认值显示给用户,并可以让用户进行修改。 默认值的依赖关系可以用 "if" 添加。(可选项)
- 依赖关系:"depends on"/"requires" <expr>
为一菜单选项定义依赖关系。如果定义了多个依赖关系,它们之间用 '&&' 间隔。依赖关系也可以应用到该菜单中所有的其它选项(同样接受一if表达式),所以下面的两个例子是等价的:
bool "foo" if BAR default y if BAR 和
depends on BAR
bool "foo"
default y
- 反向依赖关系:"select" <symbol> ["if" <expr>] 尽管普通的依赖关系可以降低一选项的上限,反向依赖能将这一限制降的更低。当前菜单选项的值是symbol的最小值。如果symbol被选择了多次,上限就是其中的最大值。反向依赖只能用在 boolean 或 tristate 选项上。
- 数据范围:"range" <symbol> <symbol> ["if" <expr>]
为int和hex类型的选项设置可以接受输入值范围。用户只能输入大于等于第一个symbol,小于等于第二个symbol的值。
- 帮助信息: "help" or "---help---" 定义一帮助信息。帮助信息的结束就由缩进的水平决定的,这也就意味着信息是在第一个比帮助信息开始行的缩进小的行结束。
"---help---" 和 "help" 在实现的作用上没有区别,"---help---" 有助于将文件中的配置逻辑与 给开发人员的提示分开。
3、菜单结构(menu)
菜单在树中的位置可由两种方法决定。第一种可以是这样:
menu "Network device support"
depends NET
config NETDEVICES
...
endmenu
所有的在"menu" ... "endmenu" 之间都是"Network device support"的子菜单。所有的子菜单选项都继承了父菜单的依赖关系,比如,"NET"的依赖关系就被加到了配置选项NETDEVICES的依赖列表中。
还有就是通过分析依赖关系生成菜单的结构。如果菜单选项在一定程度上依赖于前面的选项,它就能成为该选项的子菜单。首先,前面的(父)选项必须是依赖列表中的一部分并且它们中必须有满足下面两个条件的选项: - 如果父选项为'n',子选项必须不可见。 - 如果父选项可见,子选项才能可见。
config MODULES
bool "Enable loadable module support"
config MODVERSIONS
bool "Set version information on all module symbols"
depends MODULES
comment "module support disabled"
depends !MODULES
MODVERSIONS 直接依赖 MODULES,这就意味着如果MODULES不为'n',该选项才可见。换句话说,当MODULES可见时,选项才可见(MODULES的(空)依赖关系也是选项依赖关系的一部分)。
4、菜单选择(choice)
选择菜单定义一组选项。此选项的类型只能是boolean或tristate型。该选项的语法如下:
"choice"
<choice options>
<choice block>
"endchoice"
在一个硬件有多个驱动的情况下可以使用choice菜单,使用choice菜单可以实现最终只有一个驱动被编译进入内核中。choice菜单可以接受的另一个选项是optional,这样选项就被设置为N,表示没有被选中。
5、注释菜单(comment)
注释菜单定义了配置过程中显示给用户的注释。此注释也可以输出到文件中,以备查看。注释的语法如下:
comment <prompt>
<comment options>
在注释中唯一可以定义的属性是依赖关系,其他的熟悉不可以定义。
四、应用实例:在内核中新增加add_sub模块
下面讲解一个综合实例,假设我们将要在内核中添加一个add_sub模块。考虑add_sub模块功能,决定将模块加到内核源码的drivers目录中。在drivers目录中增加一个add_sub_Kconfig子目录。add_sub模块的源码目录add_sub_Kconfig如下:
在内核中增加了子目录,需要为相应的目录创建Kconfig和Makefile文件,才能对模块进行配置和编译。同时子目录的父目录中的Kconfig和Makefile文件也需要修改,以子目录中的Kconfig和Makefile文件能够被引用。
在新增加的add_sub_Kconfig目录中应该包含如下的Kconfig文件:
为了使这个Kconfig文件能起到作用,需要修改/drivier/Kconfig文件,在文件的末尾增加以下内容:
脚本中的source表示引用新的Kconfig文件,参数Kconfig文件的相对路径名。同时为了使add_sub和test模块被编译,需要在add_sub_Kconfig目录中增加一个Makefile文件,该Makefile文件如下:
为了使整个add_sub_Kconfig目录能够引起编译器的注意,add_sub_Kconfig的父目录drivers中的Makefile文件也需要增加如下脚本。
增加了Kconfig和Makefile文件之后新的add_sub_Kconfig树形目录如下:
五、对add_sub模块进行配置
1、在内核源代码目录下执行 make menuconfig命令。
2、选择Device Drivers选项,再选择Select选项。
3、在进入的界面中选择ADD_SUB选项,该选项就是Kconfig文件中menu菜单定义的,再选择Select选项。