本文已参与「新人创作礼」活动,一起开启掘金创作之路。
杂项设备驱动代码模板
/*********这几个是必备的头文件**********/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
int misc_open(struct inode* inode, struct file *file)
{
printk("[misc]open misc\n"); // 打开设备信号
return 0;
}
int misc_release(struct inode *inode, struct file *file)
{
printk("[misc]release misc\n"); // 释放设备
return 0;
}
// 应用层读取驱动层信号
ssize_t misc_read(struct inode *inode, char __user *ubuf, size_t size, loff_t *loff_t)
{
char kbuf[128] = "kernel to user str";
if(copy_to_user(ubuf, kbuf, sizeof(kbuf)) == 0)
{
printk("return data error");
}
return 0;
}
// 应用成写入驱动层信号
ssize_t misc_write(struct inode *inode, char __user *ubuf, size_t size, loff_t *loff_t)
{
char kbuf[128];
if(copy_from_user(kbuf,ubuf,size) == 0)
{
printk("[user to kernel]%s\r\n",kbuf);
}
return 0;
}
// 文件操作结构体
struct file_operations misc_fops = {
.owner = THIS_MODULE,
.open = misc_open,
.release = misc_release,
.read = misc_read,
.write = misc_write,
};
struct miscdevice misc_dev = {
.minor = MISC_DYNAMIC_MINOR,// 次设备号为杂项设备
.name = "misc_mod", // 设备节点名字
.fops = &misc_fops // 绑定文件操作结构体指针
};
static int __init misc_init(void)
{
int ret;
ret = misc_register(&misc_dev);
if(ret < 0)
{
printk("misc_dev register error\r\n");
return -1;
}
return 0;
}
static void __exit misc_exit(void)
{
misc_deregister(&misc_dev);
}
module_init(misc_init); // 加载初始化信号绑定
module_exit(misc_exit); // 卸载信号绑定
MODULE_AUTHOR("stylle"); // 作者
MODULE_DESCRIPTION("misc driver"); // 驱动介绍可以不写
MODULE_LICENSE("GPL");// 开源协议
杂项设备的驱动是驱动开发中最简单最方便的,核心就是处理write信号和read信号做出对应的反应。
驱动编译成模块
如果需要将驱动编译成模块前提是有编译好的kernel,并且开发板是烧录的该版本的kernel,编译成模块我们只需要新建一个Makefile文件:
ARCH = arm # 32位:arm 64位:arm64
# 交叉编译器前缀 例如我这里交叉编译gcc就是arm-linux-gcc这里就填写 arm-linux-
CROSS_COMPILE = aarch64-linux-gnu-
KDIR := /home/qlqcetc/nuc977bsp/02.linux_kernel # 编译完成的内核路径
TARGET = misc # 目标文件名:misc.ko
EXEC = $(TARGET)
obj-m :=$(TARGET).o
PWD :=$(shell pwd)
all:
$(MAKE) -C $(KDIR) M=$(PWD) modules
clean:
rm -rf *.o *~core.depend.*.cmd *.ko *.mod.c .tmp_versions $(TARGET)
然后我们只需要make就会生成.ko文件,然后将ko文件拷贝到开发板中,加载驱动使用insmod、卸载内核使用rmmod。
insmod misc.ko
ls /dev # 打印驱动列表查看我们的misc_mod是否加载进去
rmmod misc
ls /dev # 卸载成功后应该会消失
驱动编译进内核
如果要将驱动编译到内核中去则需要新建两个文件一个Makefile一个Kconfig Makefile
obj-$(CONFIG_MISC) += misc.o #这里的misc.o文件名是需要对应自己的.c文件生成的.o文件名
Kconfig
config MISC
tristate "auto reg" # 显示在图形化配置菜单中的名字
depends on HELLO # 依赖HELLO 模块才能选择
help
auto reg help # 图形化配置的help提示信息
相关的Kconfig配置还有以下几条:
-
config MISC配置选项的名称
-
tristate 表示的驱动的状态,三种状态是把驱动编译成模块,把驱动编译到内核,不编译。与之对应的还 有 bool 分别是编译到内核,不编译
-
A depends on B 表示只有在选择 B 的时候才可以选择 A 比如我想直接去掉 LED 相关的驱动,我们直接改.config 文件可以吗?可以,但是不推荐。如果有依赖的话, 直接修改.config 是不成功的。
-
select 反向依赖,该选项被选中时,后面的定义也会被选中。
然后我们还需要修改上一层目录的Makefile和上一层的Kconfig也就是Kernel下的driver目录下的Makefile和Kconfig文件
Makefile的更改就是加上驱动所在的路径
obj-y表示编译到内核中
obj-m表示编译成模块
obj-$表示可以在图形化配置中进行选择
Kconfig的更改就是加上驱动所在的路径下的Kconfig文件
然后进入kernel根目录下使用make menuconfig命令就可以进入设备驱动配置,这里还需要有一个点需要主义就是这个menu这里menu对应的参数就是我们驱动列表的参数
因为我们这里的Kconfig中source填写在最后所以这里的选项也应该是在最后,然后我们使用空格就可以选择驱动编译的情况:
*表示编译进内核
M表示编译成模块