史上最详细Linux 虚拟文件系统sysfs之属性文件attribute 整理(二)

对于一位专业的工程师而言:自己所属的工作不能存在丝毫马虎

本文主要分析和探讨1. sysfs之属性文件attribute file是如何注册?直白些(不装B),我们怎么去使用attribute 来操作硬件设备,从而实现我们的功能。

这里需要sysfs 虚拟文件系统相关的背景知识,最好去了解sysfs 的机制与理论知识,本文尽量不牵扯太多。

一、什么是属性?什么是Kobject?

      在众多操作系统当中,例如windows 操作系统随处可见的文件,然而把所有的软件都放置在文件目录当中,文件系统基本都是树形结构,而作为操作系统的始祖UNIX,到Linux 也是一切皆文件,好处就是使用者与底层设备隔离,用户不需要去对硬件设备做过多了解也可以随意使用,在sysfs下每个目录 由Kobject表示,每一个文件由attribute 表示;直白些,看到的文件对应程序当中的attribute 结构体,看到的目录对应于程序当中的 Kobject结构体。

说道sysfs接口,就不得不提到函数宏 DEVICE_ATTR,原型是

#define DEVICE_ATTR(_name, _mode, _show, _store) \

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

函数宏DEVICE_ATTR内封装的是__ATTR(_name,_mode,_show,_stroe)方法

_show:表示的是读方法,

_stroe表示的是写方法。

 

/* 自定义device属性结构 */ 
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);
}

当然_ATTR不是独生子女,他还有一系列的姊妹__ATTR_RO宏只有读方法,__ATTR_NULL等等

如对设备的使用        DEVICE_ATTR   

对驱动使用               DRIVER_ATTR

对总线使用               BUS_ATTR 

对类别 (class) 使用  CLASS_ATTR

这四个高级的宏来自于<include/linux/device.h> 

DEVICE_ATTR  宏声明有四个参数,分别是名称、权限位、读函数、写函数。其中读函数和写函数是读写功能函数的函数名。

如果你完成了DEVICE_ATTR函数宏的填充,下面就需要创建接口了

例如:

    static DEVICE_ATTR(polling, S_IRUGO | S_IWUSR, show_polling, set_polling);
    static struct attribute *dev_attrs[] = {
            &dev_attr_polling.attr,
            NULL,
    };

当你想要实现的接口名字是polling的时候,需要实现结构体struct attribute *dev_attrs[]

其中成员变量的名字必须是&dev_attr_polling.attr

然后再封装

    static struct attribute_group dev_attr_grp = {
            .attrs = dev_attrs,
    };

在利用sysfs_create_group(&pdev->dev.kobj, &dev_attr_grp);创建接口

二、实例演练

光看上面一叠ctrl+c 之后ctrl+v出来的理论终极功夫不到家的,纸上得来终觉浅。

同样以led灯的驱动为例:

步骤一、实现函数宏DEVICE_ATTR的填充

static DEVICE_ATTR(blink, 0664, NULL, aw2013_store_blink);
static DEVICE_ATTR(led_time, 0664, aw2013_led_time_show, aw2013_led_time_store);
static DEVICE_ATTR(led_status, 0664, aw2013_led_status_show, NULL);

static ssize_t aw2013_store_blink(struct device *dev,
			     struct device_attribute *attr,
			     const char *buf, size_t len)
{
	unsigned long blinking;
	struct led_classdev *led_cdev = dev_get_drvdata(dev);
	struct aw2013_led *led =
			container_of(led_cdev, struct aw2013_led, cdev);
	ssize_t ret = -EINVAL;

	ret = kstrtoul(buf, 10, &blinking);
	if (ret)
		return ret;
	mutex_lock(&led->pdata->led->lock);
	aw2013_led_blink_set(led, blinking);
	mutex_unlock(&led->pdata->led->lock);

	return len;
}
步骤二、创建接口并封装

static struct attribute *aw2013_led_attributes[] = {
	&dev_attr_blink.attr,
	&dev_attr_led_time.attr,
	&dev_attr_led_status.attr,
	NULL,
};

static struct attribute_group aw2013_led_attr_group = {
	.attrs = aw2013_led_attributes
};
最后利用sysfs_create_group()创建属性文件组

rc = sysfs_create_group(&led->cdev.dev->kobj,&aw2013_led_attr_group);

这样我们就可以使用adb 去sys/class/leds/name下面去使用上面注册的三个属性文件:blink,led_time,led_status


以后~~分析的比较粗浅、后续会深入。

推荐一篇不错的:sysfs文件系统一

点击打开链接







猜你喜欢

转载自blog.csdn.net/clam_zxf/article/details/74012357
今日推荐