1.字符驱动介绍:
字符驱动:按照字节流镜像读写操作的设备,读写数据分先后顺序,例如:点灯、按键、IIC、SPI、等等都是字符设备,这些设备的驱动叫字符驱动设备
Linux应用层如何调用驱动:
字符设备驱动的编写,主要就是驱动对应的open、close、read函数的编写
驱动层的函数被封装在file_operations这个结构体成员变量中
file_operations通过接口抽象简化了系统调用与驱动的交互,而硬件初始化(如时钟配置)由底层框架或库函数自动处理,开发者只需关注核心逻辑(如GPIO引脚配置和数据传输)
2.字符驱动的加载与卸载:
实现的linux驱动程序可以直接编译到内核里,也就是zlmage,但每次完成要重新烧录内核,不方便所以采用模块挂载载卸载方式,只需要对ko文件做操作即可
module_init(); // 加载你写的函数
module_exit(); // 卸载
需要注意的是,在虚拟机编译程序的时候需要引用内核模块代码,也就是说虚拟机得有设备里一个版本的内核模块的代码,在写完程序后需要调用内核模块代码为依赖做编译,虚拟机的内核模块版本要和设备里的内核模块版本一致否则无法挂载和卸载,需要编译内核源码,得到ZImage和dtb设备树做为程序编译的依赖
3.代码:
c代码:
#include <linux/module.h>
static int __init chrdevbase_init(void)
{
return 0;
}
static void __exit chrdevbase_exit(void)
{
}
// 核心修正点:添加以下声明
MODULE_LICENSE("GPL"); // 必须声明许可证(例如GPL)
MODULE_AUTHOR("Narnat"); // 可选:作者信息
MODULE_DESCRIPTION("chrdevbase"); // 可选:模块描述
// 模块入口与出口
module_init(chrdevbase_init);
module_exit(chrdevbase_exit);
Makefile:
# 设置绝对路径(避免相对路径引发的错误)
KERNELDIR := /home/saisi/RK3568/SDK/linux/rk3568_linux_sdk/kernel
CURRENT_PATH := $(shell pwd)
# 必须明确指定架构和交叉编译器!!!
ARCH := arm64
# 关键修正点:使用ARM官方工具链的正确前缀和路径
TOOLCHAIN_PATH := /usr/local/arm-gnu-toolchain-12.3.rel1-x86_64-aarch64-none-linux-gnu/bin
CROSS_COMPILE := $(TOOLCHAIN_PATH)/aarch64-none-linux-gnu-
# 模块名称
obj-m := chrdevbase.o
build: kernel_modules
kernel_modules:
$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) modules
clean:
$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) ARCH=$(ARCH) clean
解释:
KERNELDIR := /home/saisi/RK3568/SDK/linux/rk3568_linux_sdk/kernel
CURRENT_PATH := $(shell pwd)
分别指定内核源码路径以及你要编译的模块路径
ARCH := arm64
TOOLCHAIN_PATH := /usr/local/arm-gnu-toolchain-12.3.rel1-x86_64-aarch64-none-linux-gnu/bin
CROSS_COMPILE := $(TOOLCHAIN_PATH)/aarch64-none-linux-gnu-
指定架构,指定交叉编译器路径,指定交叉编译工具名称因为要调用不同交叉工具所以不写完整
交叉编译的原因是虚拟机为x86系统,而设备为arm所以要想编译的程序能在arm上跑要做交叉编译
# 模块名称
obj-m := chrdevbase.o
将此模块编译成可加载内核模块
build: kernel_modules
kernel_modules:
$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) modules
切换内核源码目录构建系统,指定模块源码位置为当前目录,明确架构arm64,指定交叉编译工具前缀,需要具体的交叉编译工具会自己去寻找
clean:
$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) ARCH=$(ARCH) clean
清理编译生成的文件(如 .ko, .o, .mod.c 等),同样通过内核构建系统执行
4.加载与挂载
加载
insmod
不能解决模块依赖关系
modprobe
能解决模块依赖关系但要建立/lib/modules/文件通过uname -r查看内核版本,第一次使用要用depmod
卸载
rmmod