MTK开发之—强大的DEVICE_ATTR宏

本文详细介绍了Linux驱动程序中用于创建sysfs文件的DEVICE_ATTR宏,包括其定义、参数含义及如何使用。通过示例展示了如何定义show和store函数,以及如何在驱动中创建和操作设备属性文件,从而实现用户空间与内核空间的交互。此外,还解释了权限验证宏VERIFY_OCTAL_PERMISSIONS的作用。
摘要由CSDN通过智能技术生成

1.简介

使用DEVICE_ATTR宏,可以实现驱动程序中在sys目录自动创建文件,我们只需要实现show和store函数即可.

使用该宏创建出来的文件,在应用层就能通过cat和echo命令来对文件进行读写驱动设备,实现交互.

这个宏真真是极好的,为我们大大地提供了便利,并且非常简单方便好用

2.DEVICE_ATTR宏定义

DEVICE_ATTR定义位于kernel/include/linux/device.h中,定义如下所示:

#define DEVICE_ATTR(_name, _mode, _show, _store) \
    struct device_attribute dev_attr_##_name = __ATTR(_name, _mode, _show, _store)

其中又使用了device_attribute结构体与__ATTR宏

device_attribute结构体也定义在kernel/include/linux/device.h中,__ATTR定义在kernel/include/linux/sysfs.h中。

定义如下所示:

#define __ATTR(_name, _mode, _show, _store) {	\
	.attr = {.name = __stringify(_name),		\
	.mode = VERIFY_OCTAL_PERMISSIONS(_mode) },	\
	.show	= _show,						\
	.store	= _store,						\
}

/* interface for exporting device attributes */
struct device_attribute {
	struct attribute	attr;
	ssize_t (*show)(struct device *dev, struct device_attribute *attr,
			char *buf);
	ssize_t (*store)(struct device *dev, struct device_attribute *attr,
			 const char *buf, size_t count);
};

DEVICE_ATTR中的四个参数含义为:

	_name:在sysfs中生产的文件名称
	_mode: 该文件具有的权限,与普通文件相同,UGO(usr/group/others)格式
	_show: 当cat命令作用于该文件时调用该函数
	_store: 当echo数据到该文件时调用该函数

__ATTR宏中VERIFY_OCTAL_PERMISSIONS的作用是对权限进行限制检查,该宏也定义在kernel/include/linux/sysfs.h中

/* Permissions on a sysfs file: you didn't miss the 0 prefix did you? */
#define VERIFY_OCTAL_PERMISSIONS(perms)					\
	(BUILD_BUG_ON_ZERO((perms) < 0) +				\
	 BUILD_BUG_ON_ZERO((perms) > 0777) +				\
	 /* User perms >= group perms >= other perms */			\
	 BUILD_BUG_ON_ZERO(((perms) >> 6) < (((perms) >> 3) & 7)) +	\
	 BUILD_BUG_ON_ZERO((((perms) >> 3) & 7) < ((perms) & 7)) +	\
	 /* Other writable?  Generally considered a bad idea. */	\
	 BUILD_BUG_ON_ZERO((perms) & 2) +				\
	 (perms))

这里从注释上也看的比较清晰权限的要求:
1.User perms >= group perms >= other perms
2. Other writable? Generally considered a bad idea.

关于改宏的定义就介绍到这里

3.展开DEVICE_ATTR宏定义

//读函数,也就是cat命令时将会调用该函数
static ssize_t reg_show(struct device *dev, struct device_attribute *attr, char *buf)
{
    return buf;
}
//写函数,也就是echo命令时,将会调用该函数.
static ssize_t reg_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t len)   
{
    return len;
}
//定义一个名字为reg的设备属性文件
static DEVICE_ATTR(reg, S_IWUSR|S_IRUSR, reg_show, reg_store);

将其展开,实际就是定义了一个为device_attribute类型的结构体,还将其成员变量进行了初始化,如下:

struct device_attribute dev_attr_reg ={  
    .attr = {.name = "reg", 
    .mode = S_IWUSR|S_IRUSR },     
    .show = reg_show,                 
    .store = reg_store,             
}

4.使用示例

#include <board.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
#include <linux/delay.h>
#include <linux/regulator/consumer.h>
#include <sound/soc.h>
#include <sound/jack.h>

static  char dataBuf[100] = "123";

//读函数,也就是cat命令时将会调用该函数
static ssize_t reg_show(struct device *dev, struct device_attribute *attr, char *buf)
{
    return sprintf(buf, "%s\n", dataBuf);
}

//写函数,也就是echo命令时,将会调用该函数.
static ssize_t reg_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t len)
{
    sprintf(dataBuf, "%s", buf);
    return len;
}

//定义一个名字为reg的设备属性文件
static DEVICE_ATTR(reg, S_IWUSR|S_IRUSR, reg_show, reg_store); 
                
struct file_operations my_test_ops = {
    .owner  = THIS_MODULE,
};

static int major;
static struct class *cls;
static int my_test_init(void)
{
	struct device *mydev;   

	major = register_chrdev(0,"my_test", &my_test_ops);

	cls = class_create(THIS_MODULE, "my_test_class");

	mydev = device_create(cls, 0, MKDEV(major,0), NULL, "dev_attr_test");  
    
	//在dev_attr_test设备目录下创建一个reg属性文件
    if(sysfs_create_file(&(mydev->kobj), &dev_attr_reg.attr)){    
        return -1;
	}
    return 0;
}

static void my_test_exit(void)
{
	device_destroy(cls, MKDEV(major,0));
	class_destroy(cls);
	unregister_chrdev(major, "my_test");
}

module_init(my_test_init);
module_exit(my_test_exit);
MODULE_LICENSE("GPL");
//因为本人的是个比较大的驱动文件,为了展示方便,以上代码参考了这篇文章:[感谢作者](https://www.cnblogs.com/lifexy/p/9799778.html)

实际的驱动片段是这样的:


static DEVICE_ATTR(reg, S_IWUSR | S_IRUGO, aw21024_reg_show, aw21024_reg_store);
static DEVICE_ATTR(hwen, S_IWUSR | S_IRUGO, aw21024_hwen_show, aw21024_hwen_store);
static DEVICE_ATTR(rgbcolor, S_IWUSR | S_IRUGO, NULL, aw21024_rgbcolor_store);
static DEVICE_ATTR(effect, S_IWUSR | S_IRUGO, aw21024_effect_show, aw21024_effect_store);

static struct attribute *aw21024_attributes[] = {
	&dev_attr_reg.attr,
	&dev_attr_hwen.attr,
	&dev_attr_rgbcolor.attr,
	&dev_attr_effect.attr,
	NULL
};

static struct attribute_group aw21024_attribute_group = {
	.attrs = aw21024_attributes
};

ret = sysfs_create_group(&aw21024->cdev.dev->kobj, &aw21024_attribute_group);

于是我们在设备节点下就能看到相关的文件,比如reg、effect、hwen等,这些都是我们通过DEVICE_ATTR宏实现的,
然后通过cat与echo命令就可以对该文件进行读写,而读写时实际调用的就是后面的show与rstore函数
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

东皇※太一

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值