添加驱动模块到内核的两种方法
1. 放在内核源代码树中
步骤总结:
- 新建文件夹
- 编写Makefile、编写Kconfig
- 修改上层Kconfig
- 执行make menuconfig
- 执行make zImage 或 make modules
1.1 源码放入文件夹
例如:添加一个按键字符设备模块
-
在内核目录下的 drivers/char 目录下新建文件夹 mykey
-
在 drivers/char/ 下的 Makefile 中添加一行
obj-m += mykey/ 这行指令告诉模块构建系统,在编译模块时需要进入 mykey/ 子目录中有可能的选择是,驱动程序的编译取决于一个特殊的配置选项,例如 CONFIG_MYKEY ,则指令要替换成 obj-$(CONFIG_MYKEY) += mykey/
-
最后,在 drivers/char/mykey/ 目录下添加一个 Makefile,其中需要有下面这行指令
obj-m += mykey.o 表示进入 mykey/ 子目录后,要将 mykey.c 编译成 mykey.o,但最终会生成 mykey.ko 文件如果加了编译选项,则指令如下 obj-$(CONFIG_MYKEY) += mykey.o
-
另外,如果后续你的按键程序需要使用到其他的源文件,可以将 mykey/ 目录下的 Makefile 做如下修改
obj-$(CONFIG_MYKEY) += mykey.o mykey-objs := mykey_main.o other.o 表示 mykey_main.c 和 other.c 会一起被编译和链接进 mykey.ko 文件
1.2 源码放入设备总目录下
如果只有一两个源文件,则可以选择不新建文件夹,直接将 mykey.c 放入到 drivers/char/ 目录下,在 drivers/char/ 目录下的 Makefile 中添加如下指令即可
obj-m += mykey.o如果配置了编译选项,则指令为
obj-$(CONFIG_MYKEY) += mykey.o如果有多个源文件,则指令为
obj-$(CONFIG_MYKEY) += mykey.o
mykey-objs := mykey_main.o other.o
即将原本 drivers/char/mykey/Makefile 的内容全部写到 drivers/char/Makefile 中。
1.3 管理配置选项
-
在 drivers/char/mykey/ 目录下新建一个 Kconfig 文件(如果没有独立目录,则直接在 drivers/char/Kconfig 中添加)
-
添加如下内容(实例)
config MYKEYtristate "This is config of mykey"default nhelp If you chose Y, support this key function, this key will be compiledinto the kernel.you can also chose M, then this driver will be built as a module named mykey.ko.
-
第一行定义了该选项所代表的配置目标(注意 CONFIG_ 前缀不必写上)
-
第二行声明选项类型为 “tristate” ,它有三个选项N Y M,Y表示可以编译进内核,M表示作为模块编译,N表示不操作。
-
第三行是默认的选项类型
-
help 表示为该选项提供帮助文档
-
除了上述选项外,还有其他选项,比如 depends 指令,规定了该选项的依赖选项,表示必须将依赖选项设置,才可以选择本选项
depends on MENU_KEY
-
在 drivers/char/Kconfig 文件中添加
source “drivers/char/mykey/Kconfig”
执行 make menuconfig 后结果如下
如果 Kconfig 的内容改成这样(带菜单)
menu "Config my key"config MYKEY tristate "This is config of mykey" default n help If you chose Y, support this key function, this key will be compiledinto the kernel. you can also chose M, then this driver will be built as a module named mykey.ko.endmenu
make menuconfig 找到 MYKEY(可以看到多出一个菜单来)
按 “h” 进入 help
make menuconfig 之前看一眼内核根目录下的 .config 文件, CONFIG_MYKEY 还未定义
我们使用 make menuconfig 将 CONFIG_MYKEY 选项选择为 M 后,看一下内核目录下的 .config 文件
别忘了在 drivers/char/mykey/Makefile 中添加内容
obj-$(CONFIG_MYKEY) += mykey.o
make modules 后观察 drivers/char/mykey/ 目录下的文件,多出了许多文件,其中包括 key.ko
如果要编译进内核中, CONFIG_MYKEY 选项选择为 Y ,然后执行 make zImage,会发现生成的zImage镜像大小增加了一些,但是不会在 drivers/char/mykey/ 下生成 key.ko ,不过会生成 key.o
PS:obj-y(对应 make zImage))是指将模块编译进内核(zImage)
obj-m(对应 make modules)是指编译模块生成 ko 文件
2. 放在内核代码外
如果我们希望编写的模块可以被动态的加载到内核中,即使用 insmod、modprobe 命令,则不能将模块代码直接放入内核源码树中了。
只需在自己编写的模块目录中新建一个 Makefile 文件,由于是在内核源码外围,所以我们需要告诉 make 工具如何找到内核源代码文件和基础的 Makefile 文件
为什么需要找到内核源码和基础 Makefile 文件?
答:因为驱动代码中使用到了内核提供的函数、头文件等等,编译成最终的 ko 文件也是要遵循内核的编译方法
Makefile 中一定要包含以下指令
make -C 内核所在路径 M=$PWD modulesobj-m += mykey.o
一般的 Makefile 的写法如下:
KERN_DIR = /home/内核路径all:make -C $(KERN_DIR) M=`pwd` modulesclean:make -C $(KERN_DIR) M=`pwd` modules cleanobj-m += mykey.o
执行make后,生成mykey.ko文件,使用动态加载命令插入进内核
insmod mykey.ko