在深入学习之前,先了解驱动最基本的架构以及驱动模块的加载,后续的内容便是在当前基础上添砖加瓦。驱动运行有两种方式:
- 将驱动编译进 Linux 内核,内核启动时自动运行驱动程序
- 将驱动编译成模块(.ko 文件),内核启动以后,使用 insmod 或 modprobe 加载驱动模块
这里我们采用第二种方式,方便调试,只需加载驱动,无需编译内核,等确定没问题以后再根据需要编译到内核。
一、最基本的驱动架构
驱动模块在被加载时,可能需要一些初始化操作,这就要用到 linux内核提供的宏:
- module_init:注册 ko模块被加载到内核,系统会调用的函数
- module_exit:注册 ko模块从内核卸载,系统会调用的函数
#include <linux/module.h> // MODULE_LICENSE、MODULE_AUTHOR
#include <linux/init.h> // module_init、module_exit
// 模块被加载时调用
static int __init chrdevbase_init(void)
{
printk("chrdevbase init!\n");
return 0;
}
// 模块被卸载时调用
static void __exit chrdevbase_exit(void)
{
printk("chrdevbase exit!\n");
}
module_init(chrdevbase_init); //注册模块加载函数 chrdevbase_init
module_exit(chrdevbase_exit); //注册模块卸载函数 chrdevbase_exit
注意:内核中使用 printk 来输出控制台信息
二、编译驱动模块
这就需要 Makefile 来实现了,模板如下,关于模板的解析,请参考: Linux驱动Makefile脚本解析
ARCH := arm
CROSS_COMPILE := arm-linux-gnueabihf-
CC := $(CROSS_COMPILE)gcc
KERNEL_DIR := /home/gzx/tool/imx6ull-alientek-emmc/IMX6ULL/kernel/4.1.15/linux-imx-4.1.15-source-compiled
CURRENR_DIR := $(shell pwd)
MODULE_NAME := chrdevbase
obj-m := $(MODULE_NAME).o
build: kernel_modules
kernel_modules:
$(MAKE) -C $(KERNEL_DIR) M=$(CURRENR_DIR) modules
# $(CC) -o $(MODULE_NAME)App main.c
.PHONY:clean
clean:
$(MAKE) -C $(KERNEL_DIR) M=$(CURRENR_DIR) clean
输入make开始编译,编译成功后会在当前目录下生成 .ko 文件,这就是模块文件。
三、加载驱动模块
1、创建目录 /lib/modules/4.1.15
内核默认去 /lib/modules/xxx 下找模块文件,其中 xxx 是内核版本,可以使用uname -r 命令查看。如果目录不存在,需手动创建
2、加载模块
加载模块有两种方法:insmod 和 modprobe 命令
- insmod 命令:只会加载指定路径下的某个模块,不会解决依赖
- modprobe:会帮忙解决依赖,也就是如果加载 a 模块需要 b 模块,那么会先加载 b 模块,再加载 a 模块
insmod 命令
命令格式:insmod xxx.ko
root@ATK-IMX6U:/lib/modules/4.1.15# insmod chrdevbase.ko
chrdevbase init!
modprobe 命令
使用modprobe命令之前需要先使用 depmod 命令,depmod 命令会扫描一下 /lib/modules/4.1.15 目录下有哪些模块,并将结果写入到 modules.dep 文件中。
执行 depmod 以后会生成如下文件。如果出现了 could not open /lib/modules/xxx/modules.order,请参考本文结尾部分的解决方案。
接下来就是使用 modprobe 命令将模块加载到内核,加载模块不需要加上后缀!命令格式为:modprobe 模块名
root@ATK-IMX6U:/lib/modules/4.1.15# modprobe chrdevbase
chrdevbase init!
3、查看系统中存在的模块
直接输入 lsmod 命令便可查看当前系统中已经加载到内核的模块
4、卸载已存在的模块
使用 rmmod 命令卸载已经存在的模块,命令格式: rmmod 模块名
root@ATK-IMX6U:/lib/modules/4.1.15# rmmod chrdevbase
chrdevbase exit!
四、解决 could not open /lib/modules/4.1.15/modules.order
根据提示,我们知道是因为modules.order 和 modules.builtin文件缺失。
正点原子的内核源码编译成功后,会在顶层目录下生成 modules.order 和 modules.builtin,我们只需把这两个文件拷贝到开发板的 /lib/modules/xxxx 目录下
参考文章:
Linux驱动编译报错ERROR: Kernel configuration is invalid怎么办_毛炳浩的博客-CSDN博客
imx6ull驱动开发经验_rmmod: error: ../libkmod/libkmod.c:514 lookup_buil_fhqlongteng的博客-CSDN博客