创建sysfs节点之device_create_file、sysfs_create_group

来源:互联网 发布:vb延时函数 编辑:程序博客网 时间:2024/05/23 17:56

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);
阅读全文
0 0
原创粉丝点击