sysfs属性节点可以实现用户空间与硬件交互,如设置管教电平,设置寄存器值等,控制驱动的具体功能。下面是如何在驱动中创建设备属性节点:
一、device_create_file
device_create_file用于在sys下创建设备的属性节点
int device_create_file(struct device *dev, const struct device_attribute *attr)
注意:第一个参数为device型,不是cdev,这个参数一般使用device_create()的返回值
device_attribute : 使用DEVICE_ATTR(_name, _mode, _show, _store)初始化,注意name的形式
现在就是要创建这个函数需要的两个参数。
1. 初始化属性结构体device_attribute
1).相关结构体
struct attribute {
const char *name; // 属性文件的名字
struct module *owner; // 属性文件的所有者
mode_t mode;
#ifdef CONFIG_DEBUG_LOCK_ALLOC
struct lock_class_key *key;
struct lock_class_key skey;
#endif
};
struct device_attribute {
struct attribute attr; // 内置的attribute 结构体
ssize_t (*show)(struct device *dev, struct device_attribute *attr, //属性文件的show方法(也就是读)
char *buf);
ssize_t (*store)(struct device *dev, struct device_attribute *attr, //属性文件的store方法(也就是写)
const char *buf, size_t count);
};
2). 初始化device_attribute结构体
- 使用DEVICE_ATTR初始化device_attribute
DEVICE_ATTR(_name, _mode, _show, _store)
_name:名称,也就是将在sysfs中生成的文件名称。
_mode:上述文件的访问权限,与普通文件相同,UGO的格式。只读0444,只写0222,或者读写都行的0666。
_show:显示函数,cat该文件时,此函数被调用。
_store:写函数,echo内容到该文件时,此函数被调用
宏定义:
#define DEVICE_ATTR(_name, _mode, _show, _store) \
struct device_attribute dev_attr_##_name = __ATTR(_name, _mode, _show, _store)
#define __ATTR(_name,_mode,_show,_store) { \
.attr = {.name = __stringify(_name), .mode = _mode }, \
.show = _show,
.store = _store,}
可以发现DEVICE_ATTR就是初始化了结构体device_attribute,下面是实例:
static DEVICE_ATTR(demo, (S_IRUGO | S_IWUSR | S_IWGRP),demo_show,demo_store);
static DEVICE_ATTR(demo, 0444,demo_show,NULL);
**注意:**mode可以直接定义成只读0444,只写0222,或者读写都行的0666。。
_show和_store函数当没有的时候用NULL赋值,对函数的名称和内容没有具体要求,甚至可以和别的属性相同。
- 直接赋值device_attribute结构体
直接赋值device_attribute结构体代码示例:
static struct device_attribute dev_attr_demo = {
.attr = {
.name = "demo",
.mode = (S_IRUGO | S_IWUSR)
},
.show = demo_show,
.store = demo_store,
};
2. 构建 struct device *dev 参数
1). 没有总线的字符设备驱动
struct class *class_create(struct module *owner, const char *name)
参数:
owner : 一般为 THIS_MODULE
name : 创建的class类名
对应是在/sys/class/下创建类目录
struct class_device *device_create(struct class *cls,
struct class_device *parent,
dev_t devt,
void *drvdata,
const char *fmt, ...)
struct class: class_create()返回值,必须在本函数调用之前先被创建
parent:父节点指针
devt:设备号,如果devt不为0,创建设备文件
drvdata:被添加到该设备回调的数据
fmt:设备名称
对应是在/dev/下创建设备节点
例子:device_create(demo_class, NULL, MKDEV(tmp_major, 0), NULL, "demo");
注意:在删除模块的时候要使用以下两个函数删除创建的文件
device_destroy(struct class *cls, dev_t devt);
class_destroy(struct class *cls);
注意两个函数的调用顺序
2). platform总线驱动
直接在probe函数中调用device_create_file创建属性节点。
代码示例:
static DEVICE_ATTR(led, S_IWUSR | S_IRUGO, NULL, led_action_store);
static int __devinit demo_probe(struct platform_device *pdev)
{
int ret = 0;
/* led gpio init. */
..................
ret = device_create_file(&pdev->dev, &dev_attr_demo);
if (ret)
return ret;
return 0;
}
3.代码示例(没有总线的字符设备驱动)
.......................
static ssize_t demo_show(struct device *dev, struct device_attribute *attr, char *buf)
{
sprintf(buf,"read,demo temp is %d\n",temp); /*将“read,demo temp is %d”写入buf中,%d是temp的值*/
return 0;
}
static ssize_t demo_store(struct device *dev, struct device_attribute *attr,const char *buf, size_t size)
{
sscanf(buf, "%d", &temp); /*将buf中的值以%d的形式赋值给temp*/
printk(KERN_NOTICE "write,demo temp is %d/n",temp);
return size;
}
/*这里show和store的函数名没有格式要求,可以为NULL,但是函数的参数必须符合格式要求*/
static DEVICE_ATTR(demo, (S_IRUGO | S_IWUSR),demo_show,demo_store);
.................
int demo_init(void)
{
.................
demo_class = class_create(THIS_MODULE, "demo");
devdemo = device_create(demo_class, NULL, MKDEV(demo_major, 0), NULL, "cdevdemo");
device_create_file(demo,&dev_attr_demo);
.....................
}
二、sysfs_create_group
sysfs_create_group可以用于一次创建多个属性节点
1. 初始化device_attribute,这里创建多个节点
static DEVICE_ATTR(demo1, (S_IRUGO | S_IWUSR | S_IWGRP),demo_show,demo_store);
2. 定义属性结构体数组
static struct attribute *demo_attrs[] = {
&dev_attr_demo1.attr,
&dev_attr_demo2.attr,
&dev_attr_demo3.attr,
NULL, //这里必须要以NULL结尾
}; //末尾有分号
3. 定义attribute属性结构体数组到属性组中
static const struct attribute_group demo_attr_grp = {
.attrs = demo_attrs,
}
4. 创建sysfs接口
sysfs_create_group(&pdev->dev.kobj,&dev_attr_led);
5. 代码示例:
static DEVICE_ATTR(demo1, (S_IRUGO | S_IWUSR | S_IWGRP),demo_show,demo_store);
static DEVICE_ATTR(demo2, (S_IRUGO | S_IWUSR | S_IWGRP),demo_show,demo_store);
static DEVICE_ATTR(demo3, (S_IRUGO | S_IWUSR | S_IWGRP),demo_show,demo_store);
static struct attribute *demo_attrs[] = {
&dev_attr_demo1.attr,
&dev_attr_demo2.attr,
&dev_attr_demo3.attr,
NULL, //这里必须要以NULL结尾
}; //末尾有分号
static const struct attribute_group demo_attr_grp = {
.attrs = demo_attrs,
}
static int __devinit demo_probe(struct platform_device *pdev)
{
int ret = 0;
/* led gpio init. */
..................
ret = sysfs_create_group(&pdev->dev.kobj,&demo_attr_grp);
if (ret)
return ret;
return 0;
}
6. 删除接口:
sysfs_remove_groupsysfs_create_group(&pdev->dev.kobj,&demo_attr_grp);