《【北京迅为】itop-3568开发板驱动开发指南.pdf》 学习笔记
Kconfig 语法
Linux 内核里的 Kconfig 文件用来生成图形化配置界面(make menuconfig),内核的每一层目录里都有一个 Kconfig 文件,父目录的 Kconfig 会读取其子目录的 Kconfig,从而将所有目录的配置集合起来。
下面是 Kconfig 的一些基础语法:
- Mainmenu
Mainmenu 是主菜单,输入 make menuconfig 后进入的第一个菜单就是 Mainmenu,
- comment
comment 用于定义提示信息,
- source
source 用于读取另一个 Kconfig 文件,
- menu 和 endmenu
menu 后接菜单名,endmenu 与 menu 成对使用,
- config
config 用来定义配置选项,如下图所示,定义了一个选项 MODULE_COMPRESS_GZIP,该选项被定为 bool 型,其他类型还包括 tristate(三态,y/n/m),string,hex(十六进制)和 int,
- if 和 endif
if/endif 用来进行条件判断,
- depends on 和 select
depends on 用来指定依赖关系,只有依赖项配置被打开,才能使能当前配置项;select 用来表示反向依赖,当前配置项被打开时,其 select 的配置项也会自动打开,
- choice 和 endchoice
choice 和 endchoice 中间的配置项供用户多选一,
- menuconfig
menuconfig 是 menu 和 config 的结合体,它既是菜单,又是一个配置项,但 menuconfig 不像 menu 一样有 endmenu 这样的结尾标志,所以仅靠 menuconfig 是无法做到嵌套使用的,还需要 if/endif 的配合。
.config 配置文件
通过 make menuconfig 修改完内核配置后,内核根目录会生成一个 .config 文件(由 kernel/scripts/kconfig 命令生成),编译内核时,顶层 Makefile 会读取 .config 文件的内容,根据该文件里的配置来编译内核。
defconfig 配置文件
defconfig 位于 kernel/arch/$(ARCH)/configs 目录,是 Linux 系统默认的配置文件,比如,itop-3568 SDK 编译内核时,会自动调用 kernel/arch/arm64/configs/ 目录下的 rockchip_linux_defconfig 文件。
由于每次通过图形界面修改完内核配置后都会更新 kernel/.config,但 rockchip_linux_defconfig 没有得到更新,所以每次改完 .config 后需要使用 make savedefconfig
生成 defconfig,然后替换掉旧的 rockchip_linux_defconfig 文件。反过来,如果 .config 文件出了问题,想恢复成 rockchip_linux_defconfig 里的配置,则需要使用 make rockchip_linux_defconfig
来自动生成新的 .config。(使用命令“make ARCH=arch XXX_defconfig”命令会根据 arch/$(arch)/configs 目录下的 XXX_defconfig 自动生成.config)
上面的原文档的描述,本人实测结果:原 SDK 的 kernel/arch/arm64/configs/rockchip_linux_defconfig 就是 kernel/.config,如果我使用 make savedefconfig 生成的 defconfig 去替换 rockchip_linux_defconfig,会出现内核编译报错,暂时不知道是什么原因,所以我现在直接用 make menuconfig 生成的 .config 替换 rockchip_linux_defconfig。
另外,原 rockchip_linux_defconfig 文件记得备份😶
Kconfig 实验
接下来我们来做个简单的实验,通过 Kconfig 将一个驱动添加到内核。
我所用到的驱动文件是上一篇文章的 hellowolrd.c,
#include <linux/module.h>
#include <linux/kernel.h>
static int __init helloworld_init(void) //驱动入口函数
{
printk("helloworld init.\n");
return 0;
}
static void __exit helloworld_exit(void) //驱动出口函数
{
printk("helloworld exit\n");
}
module_init(helloworld_init); //注册入口函数
module_exit(helloworld_exit); //注册出口函数
MODULE_LICENSE("GPL v2"); //同意GPL协议
MODULE_AUTHOR("xiaohui"); //作者信息
该驱动并不属于任何类,所以我把它放到杂项驱动的目录下,进入 kernel/drivers/misc,创建一个空文件夹,将驱动源码复制到该文件夹,
新建或者从附近文件夹拷贝 Kconfig 和 Makefile 文件,
Kconfig 内容如下,配置选项位于 HELLOWORLD 目录下,该配置项目的数据类型为 tristate 三态型,默认不打开配置,
Makefile 文件内容如下,通过配置项目 CONFIG_HELLOWORLD 来决定如何编译 helloworld.c(Makefile 里的 CONFIG_XXX
必须与 KCONFIG 里的 config XXX
对应,区分大小写)
同时,在实验驱动文件上一层目录的 Kconfig 文件里添加一行,表示 hello 目录下的配置信息被上一层引用,
上层目录的 Makefile 文件也要更新,将 hello 文件夹作为编译目标加到 Makefile 文件中,
添加 Kconfig 和 Makefile 后,在内核根目录输入 make ARCH=arm64 menuconfig
,进入图形化配置工具,然后打开 helloworld 驱动(Device–>Misc devices–>HELLOWORLD),
驱动配置修改完成后,就可以开始编译内核了,下面几步是原文档提到的(但我没有编译成功)
报错如下:
后来通过下面的方法成功完成编译,(上次编译报错后,必须先用以前正确的配置文件替换 arch/arm64/configs/rockchip_linux_defconfig 和 .config)
此时默认配置文件中,helloworld 已经被选择编入内核,
另外,如果 helloworld 编译失败(编入内核失败),就不会出现下图的 .o
文件,
将编译后的内核镜像烧录到开发板上,开发板启动是出现了 helloword 被加载的提示信息,说明驱动移植成功。