瑞芯微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主板
第96章 优化属性文件读写函数实验
在上个章节中,我们创建具有属性的自定义 kobject,并且能够读取和写入值。那么读写属性文件有什么作用呢?我们可以通过属性文件实现用户空间和内核空间信息交换的功能。通过属性文件实现用户空间和内核空间信息交换,用户可以根据自己的需求自定义属性和操作,增强了系统的灵活性和可定制性。本章节我们在上个章节实验的基础上优化属性文件读写函数实验。让我们开始吧!
96.1实验程序的编写
96.1.1 驱动程序编写
本实验对应的网盘路径为:iTOP-RK3568开发板【底板V1.7版本】\03_【iTOP-RK3568开发板】指南教程\02_Linux驱动配套资料\04_Linux驱动例程\71_attr02\module。
我们编写驱动代码,在驱动代码中,创建了一个自定义的 kobject,并在 sysfs 中创建了两个属性文件,并实现了读取和写入这些属性的功能。属性对象 value1 和 value2 被定义为 kobj_attribute 结构体,并使用 __ATTR 宏进行初始化。编写完成的attr.c代码如下所示:
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/configfs.h>
#include <linux/kernel.h>
#include <linux/kobject.h>
#include <linux/sysfs.h>
// 自定义的kobject结构体,包含一个kobject对象和两个整型值
struct mykobj
{
struct kobject kobj;
int value1;
int value2;
};
// 定义了mykobj结构体指针变量mykobject01
struct mykobj *mykobject01;
// 自定义的show函数,用于读取属性值
ssize_t show_myvalue1(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
{
ssize_t count;
count = sprintf(buf, "show_myvalue1\n");
return count;
};
// 自定义的store函数,用于写入属性值
ssize_t store_myvalue1(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count)
{
printk("buf is %s\n", buf);
return count;
};
// 自定义的show函数,用于读取属性值
ssize_t show_myvalue2(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
{
ssize_t count;
count = sprintf(buf, "show_myvalue2\n");
return count;
};
// 自定义的store函数,用于写入属性值
ssize_t store_myvalue2(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count)
{
printk("buf is %s\n", buf);
return count;
};
// 定义attribute对象value1和value2
struct kobj_attribute value1 = __ATTR(value1, 0664, show_myvalue1, store_myvalue1);
struct kobj_attribute value2 = __ATTR(value2, 0664, show_myvalue2, store_myvalue2);
// 自定义的kobject释放函数
static void dynamic_kobj_release(struct kobject *kobj)
{
struct mykobj *mykobject01 = container_of(kobj, struct mykobj, kobj);
printk("kobject: (%p): %s\n", kobj, __func__);
kfree(mykobject01);
}
// 将attribute对象放入数组中
struct attribute *myattr[] = {
&value1.attr,
&value2.attr,
NULL,
};
// 自定义的show函数,用于读取属性值
ssize_t myshow(struct kobject *kobj, struct attribute *attr, char *buf)
{
ssize_t count;
struct kobj_attribute *kobj_attr = container_of(attr, struct kobj_attribute, attr);
count = kobj_attr->show(kobj, kobj_attr, buf);
return count;
}
// 自定义的store函数,用于写入属性值
ssize_t mystore(struct kobject *kobj, struct attribute *attr, const char *buf, size_t size)
{
struct kobj_attribute *kobj_attr = container_of(attr, struct kobj_attribute, attr);
return kobj_attr->store(kobj, kobj_attr, buf, size);
}
// 自定义的sysfs_ops结构体,包含show和store函数指针
struct sysfs_ops myops = {
.show = myshow,
.store = mystore,
};
// 自定义的kobj_type结构体,包含释放函数、默认属性和sysfs_ops
static struct kobj_type mytype = {
.release = dynamic_kobj_release,
.default_attrs = myattr,
.sysfs_ops = &myops,
};
// 模块的初始化函数
static int mykobj_init(void)
{
int ret;
// 分配并初始化mykobject01
mykobject01 = kzalloc(sizeof(struct mykobj), GFP_KERNEL);
mykobject01->value1 = 1;
mykobject01->value2 = 1;
// 初始化并添加mykobject01到内核中,名为"mykobject01"
ret = kobject_init_and_add(&mykobject01->kobj, &mytype, NULL, "%s", "mykobject01");
return 0;
}
// 模块的退出函数
static void mykobj_exit(void)
{
// 释放mykobject01
kobject_put(&mykobject01->kobj);
}
module_init(mykobj_init); // 指定模块的初始化函数
module_exit(mykobj_exit); // 指定模块的退出/
MODULE_LICENSE("GPL"); // 模块使用的许可证
MODULE_AUTHOR("topeet"); // 模块的作者
96.2 运行测试
96.2.1 编译驱动程序
在上一小节中的attr.c代码同一目录下创建 Makefile 文件,Makefile 文件内容如下所示:
export ARCH=arm64#设置平台架构
export CROSS_COMPILE=aarch64-linux-gnu-#交叉编译器前缀
obj-m += attr.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的内容注释已在上图添加,保存退出之后,来到存放attr.c和Makefile文件目录下,如下图(图96-1)所示:
图 96-1
然后使用命令“make”进行驱动的编译,编译完成如下图(图96-2)所示:
图 96-2
编译完生成attr.ko目标文件,如下图(图96-3)所示:
图 96-3
至此驱动模块就编译成功了,接下来进行测试。
96.2.2 运行测试
开发板启动之后,使用以下命令进行驱动模块的加载,如下图(图96-4)所示:
insmod attr.ko
图96-4
驱动加载之后,我们进入/sys/目录下,可以看到创建生成的myobject01,如下图所示
图96-5
我们进到myobject01目录下,可以看到创建的属性文件value1和value2。
图96-6
我们可以使用echo和cat命令对属性值进行写入和读取,如下图所示:
图96-7
最后可以使用以下命令进行驱动的卸载,如下图(图96-8)所示:
rmmod attr
图 96-8
至此,优化属性文件读写实验就完成了。