瑞芯微RK3568芯片是一款定位中高端的通用型SOC,采用22nm制程工艺,搭载一颗四核Cortex-A55处理器和Mali G52 2EE 图形处理器。RK3568 支持4K 解码和 1080P 编码,支持SATA/PCIE/USB3.0 外围接口。RK3568内置独立NPU,可用于轻量级人工智能应用。RK3568 支持安卓 11 和 linux 系统,主要面向物联网网关、NVR 存储、工控平板、工业检测、工控盒、卡拉 OK、云终端、车载中控等行业。
【公众号】迅为电子
【粉丝群】824412014(加群获取驱动文档+例程)
【视频观看】嵌入式学习之Linux驱动(第二篇 字符设备基础_全新升级)_基于RK3568
【购买链接】迅为RK3568开发板瑞芯微Linux安卓鸿蒙ARM核心板人工智能AI主板
第13章 杂项设备驱动实验
经过前面章节的学习,我们已经对字符设备驱动框架有了一定的理解,而本章要讲解的杂项设备属于特殊的一种字符型设备,是对字符设备的一种封装,为最简单的字符设备。为什么从字符设备中单独提取出了杂项设备呢?杂项设备又要如何进行使用呢?带着疑问,让我们进行杂项设备的学习吧!
13.1 杂项设备驱动简介
在Linux中,把无法归类的五花八门的设备定义成杂项设备。相较于字符设备,杂项设备有以下两个优点:
(1)节省主设备号:杂项设备的主设备号固定为10,而字符设备不管是动态分配还是静态分配设备号,都会消耗一个主设备号,进而造成了主设备号浪费。当系统中注册了多个misc设备驱动时,只需使用子设备号进行区分即可。
(2)使用简单:当使用普通的字符设备驱动时,如果开发人员需要导出操作接口给用户空间,就需要注册对应的字符驱动,并创建字符设备class从而自动在/dev下生成设备节点,而misc驱动只需要将基本信息通过结构体传递给相应处理函数即可。
在驱动中使用miscdevice结构体描述misc设备,该结构体定义在“内核源码/include/linux/miscdevice.h”文件中(在下面的实验代码中需要加入该头文件的引用),具体内容如下所示:
struct miscdevice {
int minor; /* 子设备号 需要用户填写*/
const char *name;/* 设备名 需要用户填写*/
const struct file_operations *fops;/* 设备操作集 需要用户填写*/
struct list_head list;
struct device *parent;
struct device *this_device;
const struct attribute_group **groups;
const char *nodename;
umode_t mode;
};
定义一个misc 设备,一般只需要填充minor、name、fops 这三个成员变量。
minor指次设备号,可以从“内核源码/include/linux/miscdevice.h”文件中预定义的次设备号挑选,也可以自行定义子设备号(没有被其他设备使用即可),通常情况下将该参数设置为MISC_DYNAMIC_MINOR,表示自动分配子设备号。
name表示misc设备的名字。misc设备驱动注册成功之后,会在dev目录下生成名为name的设备节点。
fops 指向了file_operations的结构体,表示字符设备的操作集合。
13.2 杂项设备的注册和卸载
不同于字符设备的注册和卸载的繁琐,杂项设备的注册可以直接使用函数misc_register函数来完成,杂项设备的卸载可以直接使用misc_deregister函数来完成。上述两个函数均定义在“内核源码/include/linux/miscdevice.h”文件当中。
杂项设备的注册:
函数原型:
int misc_register(struct miscdevice *misc)
函数作用:
基于misc_class构造一个设备,将miscdevice结构挂载到misc_list列表上,并初始化与linux设备模型相关的结构。进而起到杂项设备注册的作用。
参数含义:
misc: 杂项设备的结构体指针
函数返回值:申请成功返回0,申请失败返回负数
杂项设备的卸载:
函数原型:
int misc_deregister(struct miscdevice *misc)
函数作用:
从mist_list中删除miscdevice,进而起到杂项设备卸载的作用。
参数含义:
misc: 杂项设备的结构体指针
**函数返回值:**卸载成功返回0,申请失败返回负数
至此,注册和卸载杂项设备的API函数就讲解完成了,会在接下来的驱动章节中对上述函数进行具体使用。
13.3 杂项设备驱动框架
MISC驱动一般使用以下结构:
static struct file_operations xxx_fops{
.owner = THIS_MODULE,
.read = xxx_read,
......
};
struct miscdevice xxx_dev{
.minor = MISC_DYNAMIC_MINOR,
.name = "xxx",
.fops = &xxx_fops
};
static int __init xxx_init(void) //驱动入口函数
{
int ret;
printk(KERN_EMERG "xxx_init\r\n");
ret = misc_register(&xxx_dev);//注册杂项设备
if(ret<0)
{
printk( "misc_register failed\r\n");
}
printk( "misc_register ok\r\n");
return 0;
}
static void __exit xxx_exit(void) //驱动出口函数
{
printk(KERN_EMERG "xxx_exit\r\n");
misc_deregister(&xxx_dev); //卸载杂项设备
}
module_init(xxx_init); //注册入口函数
module_exit(xxx_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("topeet");
13.4 实验程序的编写
本实验对应的网盘路径为:iTOP-RK3568开发板【底板V1.7版本】\03_【iTOP-RK3568开发板】指南教程\02_Linux驱动配套资料\04_Linux驱动例程\08。
本小节将编写最简单的misc驱动,在驱动入口函数中通过misc_register(…)函数注册杂项设备驱动,在驱动出口函数中通过misc_deregister(…)函数注销杂项设备驱动。编写完成的miscdevice.c代码如下所示:
#include <linux/init.h> //初始化头文件
#include <linux/module.h> //最基本的文件,支持动态添加和卸载模块。
#include <linux/miscdevice.h> //注册杂项设备头文件
#include <linux/fs.h> //注册设备节点的文件结构体
struct file_operations misc_fops = { //文件操作集
.owner = THIS_MODULE 将owner字段指向本模块,可以避免在模块的操作正在被使用时卸载该模
};
struct miscdevice misc_dev = { //杂项设备结构体
.minor = MISC_DYNAMIC_MINOR, //动态申请的次设备号
.name = "test", //杂项设备名字是hello_misc
.fops = &misc_fops, //文件操作集
};
static int __init misc_init(void)
{
int ret;
ret = misc_register(&misc_dev); //在初始化函数中注册杂项设备
if (ret < 0)
{
printk("misc registe is error \n"); //打印注册杂项设备失败
}
printk("misc registe is succeed \n");//打印注册杂项设备成功
return 0;
}
static void __exit misc_exit(void)
{
misc_deregister(&misc_dev); //在卸载函数中注销杂项设备
printk(" misc goodbye! \n");
}
module_init(misc_init);
module_exit(misc_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("topeet");
13.5 运行测试
13.5.1 编译驱动程序
在上一小节中的miscdevice.c代码同一目录下创建 Makefile 文件,Makefile 文件内容如下所示:
export ARCH=arm64#设置平台架构
export CROSS_COMPILE=aarch64-linux-gnu-#交叉编译器前缀
obj-m += miscdevice.o #此处要和你的驱动源文件同名
KDIR :=/home/topeet/Linux/linux_sdk/kernel #这里是你的内核目录
PWD ?= $(shell pwd)
all:
make -C $(KDIR) M=$(PWD) modules #make操作
clean:
make -C $(KDIR) M=$(PWD) clean #make clean操作
Makefile保存退出之后,来到存放miscdevice.c和Makefile文件目录下,如下图(图13-1)所示:
然后使用命令“make”进行驱动的编译,编译完成如下图(图 13-2)所示:
编译完生成 miscdevice.ko目标文件,如下图(图 13-3)所示:
至此我们的驱动模块就编译成功了,下面进行驱动的运行测试。
13.5.2 运行测试
将编译生成的驱动模块miscdevice.ko拷贝到开发板上,输入以下命令加载驱动模块。
insmod miscdevice.ko
可以看到驱动加载之后,打印“misc registe is succeed”,说明misc驱动注册成功。输入以下命令查看加载的驱动模块,驱动加载成功如下(图13-5)所示:
然后来到/sys/class/misc目录下,可以看到名为“test”的文件夹已经被创建了,在/sys/class/misc目录下有misc类的所有设备,每个注册的杂项设备对应一个文件夹目录,如下图(图13-6)所示:
驱动加载成功之后会生成/dev/test设备驱动文件,输入以下命令查看杂项设备的主次设备号。
ls /dev/test -al
结果如下图(图 13-8)所示:
从上图可以看出,/dev/test这个杂项设备的主设备号为10,次设备号为53,最后可以使用以下命令对驱动进行卸载,卸载完成如下图(图 13-9)所示:
rmmod miscdevice.ko