驱动程序是硬件与操作系统之间的桥梁
驱动编写分为4个部分:
1头文件
2驱动模块的入口和出口
3声明信息
4.功能实现
b站链接: link
第一步包含头文件
#include <linux/init.h> 包含宏定义的头文件
#include <linux/module.h> 包含初始化加载模块的头文件
第二步驱动模块的入口和出口
module_init();
module_exit();
第三步声明模块拥有开源许可证
MODULE_LICENSE(“GPL”);
第四步功能实现
static int hello_init(void)
{
printk(“hello world \n”);
return 0;
}
static void hello_exit(void)
{
printk(“bye bye \n”);
}
内核模块加载的时候打印hello world ,内核模块卸载的时候打印bye bye
注意:打印的时候不能用printf()函数,用printk()函数,内核里面没有printf()函数
利用printk打印信息的时候得有\r\n,不然不会立即显示,只有下次需要打印的时候才把上次的数据给显示出来
helloworld 代码
//第一步,包含头文件
#include <linux/init.h> //包含宏定义的头文件
#include <linux/module.h> //包含初始化加载模块的头文件
static int hello_init(void)
{
printk("hello world \n");
return 0;
}
static void hello_exit(void)
{
printk("bye bye \n");
}
//第二步,驱动模块的入口和出口
module_init(hello_init);
module_exit(hello_exit);
//第三步,声明模块拥有开源许可证
MODULE_LICENSE("GPL");
//第四步,功能的实现
驱动编译
第一种方法:把驱动编译成模块,然后使用命令把驱动加载到内核里面
第二种方法:直接把驱动编译到内核
第一种方法
自行前往B站观看链接: link
在编译驱动的时候,按照该老师的方法报错,我采用的指令是
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu-
# aarch-linux-gnu-是我给交叉编译器重命的名
#arm64是指64位
#arm32是32位
加载驱动模块指令
insmod helloworld.ko
查看驱动是否加载上指令
lsmod
卸载驱动模块指令
rmmod helloworld
在加载过程中报错原因insmod、rmmod指令在sbin目录下,并不在bin目录下,可以将insmod与rmmod拷贝到bin目录,若没权限许可,加sudo 。
在执行该驱动的时候,未看见打印的信息,可以利用指令dmesg查看,清除内核log指令为dmesg -c。
第二种方法(把驱动编译进内核)
B站链接: link
第一步,在~/内核源码位置/drivers/char/目录下创建文件hello
cd ~/build_new/linux/drivers/char #我的内核源码是存放在~/build_new/linux下的
mkdir hello
第二步,在hello文件夹创建helloworld.c
//第一步,包含头文件
2 #include <linux/init.h> //包含宏定义的头文件
3 #include <linux/module.h> //包含初始化加载模块的头文件
4
5 static int hello_init(void)
6 {
7 printk("hello world \n");
8 return 0;
9 }
10
11 static void hello_exit(void)
12 {
13 printk("bye bye \n");
14 }
15 //第二步,驱动模块的入口和出口
16 module_init(hello_init);
17 module_exit(hello_exit);
18
19
20 //第三步,声明模块拥有开源许可证
21 MODULE_LICENSE("GPL");
第三步,在hello文件夹创建Makefile文件,并编写内容,如下
touch Makefile
vim Makefile
obj-$(CONFIG_HELLO)+=helloworld.o
第四步,在hello文件夹创建Kconfig文件,并编写如下内容
touch Kconfig
vim Kconfig
config HELLO
tristate "hello world"
help
hello hello
第五步,返回hello文件的上一级即char文件夹,修改Makefile文件内容
在第一行添加如下内容
obj-y += hello/
第六步,修改char文件夹的Kconfig文件
在 menu "Character devices"下添加
source "drivers/char/hello/Kconfig"
第七步,返回到内核源码文件目录,修改menuconfig,
cd ~/build_new/linux
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- menuconfig
#aarch64-linux-gnu-为我的交叉编译器名字
空格进行选择,*代表编译进内核,M代表编译为模块
修改后保存退出。
第八步,通过.config检查是否添加成功(此步可以忽略)
#在内核源码文件夹输入
vi .config
#输入/HELLO
可以看到如图所示的界面
第九步,编译内核
make -j5 ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu-
第十步,编译完内核后,会在~/build_new/linux/arch/arm64/boot下生成镜像
第十一步,把sd卡挂载到虚拟机
#先创建2个文件用于挂载sd卡
mkdi ~/data1
mkdir ~/data2
sudo mount /dev/sdb1 ~/data1
sudo mount /dev/sdb2 ~/data2
# 查看内核启动镜像名字
cd ~/data1
vim config.txt
# 可以看到kernel = kernel8
#将data1的kernel8.img重命名为kernel8_old.img
sudo mv kernel8.img kernel8_old.img
#然后将第十步编译的镜像拷贝到data1文件夹,并重命名为kernel8.img
sudo cp ~/build_new/linux/arch/arm64/boot/kernel8.img ~/data1/
# 然后退出挂载
sudo umount ~/data1
sudo umount ~/data1
最后将sd卡插入树莓派。
mkdir ~/a.txt
dmesg >a.txt
grep "hello" a.txt
可以看到驱动成功加载