DEVICE_ATTR的使用

DEVICE_ATTR的使用

使用DEVICE_ATTR,可以在sys fs中添加“文件”,通过修改该文件内容,可以实现在运行过程中动态控制device的目的。类似的还有DRIVER_ATTR,BUS_ATTR,CLASS_ATTR。这几个东东的区别就是,DEVICE_ATTR对应的文件在/sys/devices/目录中对应的device下面。而其他几个分别在driver,bus,class中对应的目录下。这次主要介绍DEVICE_ATTR,其他几个类似。
在documentation/driver-model/Device.txt中有对DEVICE_ATTR的详细介绍,这儿主要说明使用方法。

先看看DEVICE_ATTR的原型:
DEVICE_ATTR(_name, _mode, _show, _store)
_name:名称,也就是将在sys fs中生成的文件名称。
_mode:上述文件的访问权限,与普通文件相同,UGO的格式。
_show:显示函数,cat该文件时,此函数被调用。
_store:写函数,echo内容到该文件时,此函数被调用。

看看我们怎么填充这些要素:
名称可以随便起一个,便于记忆,并能体现其功能即可。模式可以为只读0444,只写0222,或者读写都行的0666。当然也可以对User\Group\Other进行区别。
显示和写入函数就需要实现了。

显示函数的一般实现:
static ssize_t xxx_show(struct device *dev, struct device_attribute *attr, char *buf)
{
 return scnprintf(buf, PAGE_SIZE, "%d\n", dma_dump_flag);
}
实现相对简单,调用了个很阳春的scnprintf,把数据放到buf中,就算大功告成了。至于buf中的内容怎么显示出来,这个先略过。

写入函数的一般实现:
static ssize_t xxx_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
 unsigned long num;
 if (strict_strtoul(buf, 0, &num))
  return -EINVAL;
 if (num < 0)
  return -EINVAL;
 mutex_lock(&xxx_lock);
 dma_dump_flag = num;
 mutex_unlock(&xxx_lock);
 return count;
}

注意:return count,一般count大小就是一个PAGE_SIZE。 如果这个函数 return 0,这个store函数将被无限循环调用导致系统crash,why?

函数名中的后缀_show和_store当然不是必须的,只是便于标识。


DEVICE_ATTR的定义例子:
static DEVICE_ATTR(xxx, 0666, xxx_show, xxx_store);  该代码可以防止文件的任何位置,只要别引起编译错误!

是不是这样就搞定了?当然没有,还需要调用函数device_create_file来传教sys fs中的文件。
调用方法:
device_create_file(&pdev->dev, &dev_attr_xxx);文件不是创建在某个device目录下么,pdev->dev就是该device。dev_attr_xxx就是在xxx前加上dev_attr_,好像是废话,不过现实就是这样。开始还找了半天,dev_attr_xxx在哪儿定义? 看看 #define DEVICE_ATTR(_name, _mode, _show, _store)这个宏定义就明白了。

device_create_file的调用例子:
  ret = device_create_file(&pdev->dev, &dev_attr_xxx);
  if (ret != 0) {
   dev_err(&pdev->dev,
    "Failed to create xxx sysfs files: %d\n", ret);
   return ret;
  }

这个代码最好放在device的probe函数中
原因么,在documentation/driver-model/Device.txt中有说明。

下面看看DEVICE_ATTR的定义:
#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_attribute定义:
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的功能就是定义一个device_attribute结构体对象。
device_create_file利用该对象在device下创建文件。

/**
 * device_create_file - create sysfs attribute file for device.
 * @dev: device.
 * @attr: device attribute descriptor.
 */
int device_create_file(struct device *dev,
         const struct device_attribute *attr)
{
 int error = 0;
 if (dev)
  error = sysfs_create_file(&dev->kobj, &attr->attr);
 return error;
}

------------------------------------------------分割线-----------------------------------------------------------

------------------------------------------------分割线-----------------------------------------------------------

简单分析:
1 本样例主要测试kobject结构,kobject对应sysfs文件系统中的一个目录,该目录对应一个具体的事物。
2 首先通过example_kobj = kobject_create_and_add("kobject_example", kernel_kobj);将该结构加入   到/sys/kernel目录下[kernel_kobj为kernel子系统的kobject结构],形成层次结构,并且在父目录下建立该子目录[kobject->sd指向该kobject所在的目录节点]。
3 通过retval = sysfs_create_group(example_kobj, &attr_group)将事物的3个特色属性与其对应的kobject绑定起来,将该文件操作接口和sysfs系统结合起来。使得可以通过kobj_attribute中的show何store进行实际的内核读写操作,该函数实际上在父目录下新建3个文件,结构用sysfs_dirent表示。且sysfs_dirent->s_attr.attr=相应属性结构,据此可获得读写该文件的方法。
4 每个struct attribute结构对应kobject目录下一个文件,文件的读写方法由kobj_attribute中的show和store指定,kobj_attribute是kobject属性导出的接口
 struct attribute{
           const char *name;
           struct module* owner;
           mode_t mode;
}
 struct kobj_attribute{
          struct attribute attr;
          ssize_t (*show)(struct kobject* kobj,struct kobj_attribute* attr,char* buf);
          ssize_t (*store)(struct kobject* kobj,struct kobj_attribute* attr,const char* buf,size_t count);
}
5当使用结束时,调用kobject_put(example_kobj)删除该kobject结构,及其对应的目录和文件。
扩展:实际上对于不同子系统有不同的属性和属性操作函数
比如:在genhd.h文件中,磁盘属性操作结构为,disk_attribute是磁盘属性导出的接口



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值