说道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表示的是写方法。

当然_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);创建接口

通过以上简单的三个步骤,就可以在adb shell 终端查看到接口了。当我们将数据 echo 到接口中时,在上层实际上完成了一次 write 操作,对应到 kernel ,调用了驱动中的 “store”。同理,当我们cat 一个 接口时则会调用 “show” 。到这里,只是简单的建立了 android 层到 kernel 的桥梁,真正实现对硬件操作的,还是在 "show" 和 "store" 中完成的。

其实呢?!用个proc文件系统的就知道,这个就和proc中的write和read一样的,以我的理解:proc有点老了,以后肯定会大量使用attribute,proc好比是Windows XP,attribute就像是Windows Seven




###############################################################

为了更好地了解kobject的层次关系,有必要了解一下这种层次关系的表现机制:sysfs。本文简单地学习了一下sysfs,大部分内容来自内核文档sysfs.txt。好了,开始我们的学习之旅,呵呵。

何为sysfs

sysfs是一种基于ram的文件系统,它提供了一种用于向用户空间展现内核空间里的对象、属性和链接。sysfs与kobject层次紧密相连,它将kobject层次关系表现出来,使得用户空间可以看见这些层次关系。

在控制台输入命令“mount -t sysfs sysfs /sys”,就可以在/sys目录下看到这些层次关系了。

目录的创建

对于每个注册到系统的kobject,在sysfs中都有一个目录来展现它,这个目录(AA)会作为某个目录(A)的子目录而被创建,我们知道目录AA代表kobject,那么目录A则代表kobject->parent,显示这种目录层次关系可以很好地向用户展现kobject层次结构。在sysfs中位于顶层的那些目录,分别代表着不同的子系统,每个新加入的kobject都应该归属于某一个子系统。

sysfs会把目录所代表的kobject存储在目录的dentry结构的d_fsdata字段,这样当文件打开和关闭的时候,sysfs可以直接对kobject做引用计数。

属性

在sysfs中,kobject的属性表现为一个普通的文件。sysfs将文件的I/O操作重定向到那些为该属性定义的方法,提供了一种读写属性的机制。

属性应该表现为ASCII文本文件,并且最好每个文件只包含一个值。当然,每个文件仅包含一个值可能会有害于效率,所以如果一个文件包含某种类型的数据的数组也是被接受的。不建议在一个文件中包含不同数据类型的数据和多行数据。

属性的定义如下:

struct attribute {

        char                    * name;

        struct module  *owner;

        mode_t                  mode;

    };

int sysfs_create_file(struct kobject * kobj, const struct attribute * attr);

在kobj所在目录下创建一个属性文件,文件名为attr->name

    void sysfs_remove_file(struct kobject * kobj, const struct attribute * attr);

将属性文件attr->name从kobj所在目录下移除

为了使对属性的读写变得有意义,一般将attribute结构嵌入到其他数据结构中。子系统通常都会定义自己的属性结构,并且提供添加和删除属性文件的包裹函数。

例如,设备驱动模型为device子系统定义了相应的属性结构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);

    };

int device_create_file(struct device *, struct device_attribute *);

在/sys/devices/xxx/目录下创建device属性文件

    void device_remove_file(struct device *, struct device_attribute *);

移除/sys/devices/xxx/目录下的device属性文件

系统提供了一个宏方便定义device属性:

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

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

其中,__ATTR定义如下:

#define __ATTR(_name,_mode,_show,_store) { /

     .attr = {.name = __stringify(_name), .mode = _mode }, /

     .show = _show,     /

     .store = _store,     /

    }

例如,定义一个device属性,名为foo,读写该文件的方法分别为show_foo和store_foo:

static DEVICE_ATTR(foo, S_IWUSR | S_IRUGO, show_foo, store_foo);

将宏展开为:

static struct device_attribute dev_attr_foo = {

            .attr = {

                          .name = "foo",

                          .mode = S_IWUSR | S_IRUGO,

},

            .show = show_foo,

            .store = store_foo,

    };

子系统特定的回调函数

当子系统定义一个新的属性类型时,必须实现一组sysfs操作,从而将文件的读写调用(read/write调用)重定向到属性拥有者的show和store方法。

struct sysfs_ops {

        ssize_t (*show)(struct kobject *, struct attribute *, char *);

        ssize_t (*store)(struct kobject *, struct attribute *, const char *);

    };

当读写一个文件时,sysfs将为此类型调用合适的方法,这些方法会将kobject结构和attribute结构转换为合适的指针类型,然后调用与之关联的相关的方法。注意,子系统必须已经为此类型定义好了kobj_type作为此类型的描述符,因为sysfs_ops指针存储在kobj_type中。

举个例子:

#define to_dev_attr(_attr) container_of(_attr, struct device_attribute, attr)

    #define to_dev(d) container_of(d, struct device, kobj)

static ssize_t dev_attr_show(struct kobject * kobj, struct attribute * attr, char * buf)

    {

        struct device_attribute * dev_attr = to_dev_attr(attr);

        struct device * dev = to_dev(kobj);

        ssize_t ret = 0;

if (dev_attr->show)

                ret = dev_attr->show(dev, buf);

        return ret;

    }

属性的读写

为了读写属性,当定义属性时,必须指定show和/或者store方法:

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);

sysfs allocates a buffer of size (PAGE_SIZE) and passes it to the

method. Sysfs will call the method exactly once for each read or

write. This forces the following behavior on the method

implementations:

- On read(2), the show() method should fill the entire buffer. 

  Recall that an attribute should only be exporting one value, or an

  array of similar values, so this shouldn't be that expensive.

This allows userspace to do partial reads and forward seeks

  arbitrarily over the entire file at will. If userspace seeks back to

  zero or does a pread(2) with an offset of '0' the show() method will

  be called again, rearmed, to fill the buffer.

- On write(2), sysfs expects the entire buffer to be passed during the

  first write. Sysfs then passes the entire buffer to the store()

  method. 

  

    当写一个sysfs文件时,用户空间的进程应该先读取整个文件,然后修改希望改变的值,最后将整个缓冲区回写到文件中。

Attribute method implementations should operate on an identical buffer when reading and writing values.

其他注意事项:

- Writing causes the show() method to be rearmed regardless of current file position.(???)

- 缓冲区的大小应总是为PAGE_SIZE个字节。在i386上,PAGE_SIZE=4096

- show方法应该返回放入缓冲区的字节数,即snprintf的返回值

- show方法应该总是使用snprintf

- store方法应该返回实际使用的字节数,可以使用strlen来得到

- show和/或者store方法可能会出错,所以当失败时,记得返回错误值

- The object passed to the methods will be pinned in memory via sysfs

  referencing counting its embedded object. However, the physical 

  entity (e.g. device) the object represents may not be present. Be 

  sure to have a way to check this, if necessary. (???)

    下面的代码展示了device属性的一个简单的实现:

static ssize_t show_name(struct device *dev, struct device_attribute *attr, char *buf)

    {

         return snprintf(buf, PAGE_SIZE, "%s/n", dev->name);

    }

static ssize_t store_name(struct device * dev, const char * buf)

    {

         sscanf(buf, "%20s", dev->name);

         return strnlen(buf, PAGE_SIZE);

    }

static DEVICE_ATTR(name, S_IRUGO, show_name, store_name);

注意,实际应用时,并不允许从用户空间设置设备的名字,这里仅举个例子。

sysfs顶层目录结构

sysfs目录结构展现了内核数据结构之间的关系,顶层目录结构如下:

block/

bus/

class/

dev/

devices/

firmware/

net/

fs/

下面捡几个重要的目录进行说明:

devices目录展现了系统中的设备树,它直接对应于内核中的设备树,即device的层次结构 ;

bus目录下包含了若干目录,每个目录表示系统中的一个总线,且每个目录下又包含两个子目录:devices、drivers。其中devices子目录下包含系统中发现的device的符号链接,这些符号链接分别指向/sys/devices/xxx目录下对应的目录;drivers子目录下包含特定总线上的那些用于驱动每个设备的驱动程序的目录(可见,一个驱动程序只会出现在某一个特定的总线上);

当前接口

目前sysfs中存在以下接口:

- devices (include/linux/device.h)

    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);

    };

属性的声明:

DEVICE_ATTR(_name, _mode, _show, _store);

属性的创建和移除:

int device_create_file(struct device *device, struct device_attribute * attr);

    void device_remove_file(struct device * dev, struct device_attribute * attr);

- bus drivers (include/linux/device.h)

    bus属性:

struct bus_attribute {

        struct attribute        attr;

        ssize_t (*show)(struct bus_type *, char * buf);

        ssize_t (*store)(struct bus_type *, const char * buf);

    };

属性的声明:

BUS_ATTR(_name, _mode, _show, _store)

属性的创建和移除:

int bus_create_file(struct bus_type *, struct bus_attribute *);

    void bus_remove_file(struct bus_type *, struct bus_attribute *);

- device drivers (include/linux/device.h)

    driver属性:

struct driver_attribute {

        struct attribute        attr;

        ssize_t (*show)(struct device_driver *, char * buf);

        ssize_t (*store)(struct device_driver *, const char * buf,

                         size_t count);

    };

属性的声明:

DRIVER_ATTR(_name, _mode, _show, _store)

属性的创建和移除:

int driver_create_file(struct device_driver *, struct driver_attribute *);

    void driver_remove_file(struct device_driver *, struct driver_attribute *);

DEVICE_ATTR的更多相关文章

  1. DEVICE_ATTR的使用

    DEVICE_ATTR的使用 使用DEVICE_ATTR,可以在sys fs中添加“文件”,通过修改该文件内容,可以实现在运行过程中动态控制device的目的. 类似的还有DRIVER_ATTR,BU ...

  2. static DEVICE_ATTR(val, S_IRUGO | S_IWUSR, hello_val_show, hello_val_store); 的作用

    在 老罗的android例程里面有 static DEVICE_ATTR(val, S_IRUGO | S_IWUSR, hello_val_show, hello_val_store); /*读取设 ...

  3. DEVICE_ATTR实例分析

    在内核中, sysfs 属性一般是由 __ATTR 系列的宏来声明的,如对设备的使用 DEVICE_ATTR ,对总线使用 BUS_ATTR ,对驱动使用 DRIVER_ATTR ,对类别(class ...

  4. Linux内核宏DEVICE_ATTR使用

    1.前言 在Linux驱动程序编写中,使用DEVICE_ATTR宏,可以定义一个struct device_attribute设备属性,并使用sysfs的API函数,便可以在设备目录下创建出属性文件, ...

  5. DEVICE_ATTR设置设备属性

    DEVICE_ATTR设置设备属性 为了在sysfs下生成可控节点,方便上层调用. sysfs是一个基于RAM的文件系统,它和Kobject一起,可以将Kernel的数据结构导出到用户空间,以文件目录 ...

  6. Linux设备管理(四)_从sysfs回到ktype

    sysfs是一个基于ramfs的文件系统,在2.6内核开始引入,用来导出内核对象(kernel object)的数据.属性到用户空间.与同样用于查看内核数据的proc不同,sysfs只关心具有层次结构 ...

  7. 基於tiny4412的Linux內核移植--- 中斷和GPIO學習(2)

    作者 彭東林 pengdonglin137@163.com 平臺 tiny4412 ADK Linux-4.4.4 u-boot使用的U-Boot 2010.12,是友善自帶的,爲支持設備樹和uIma ...

  8. linux设备模型

    device_driver和device必须依附总线.总线.驱动.设备最终会落实为sysfs中的一个目录.kobject对应sysfs的一个目录. attribute直接落实sysfs中的一个文件,如 ...

  9. sis9280触摸ic 基于rk3288 的安卓4.4的 多点触摸

    前言:sis提供的驱动ic.基于rk3288的安卓系统.亲眼看到人家完成一次移植.很激动的记下一些东西..虽然我看不懂.其实现在的工作也不需要看懂.叫人协助就好,只需要知道有这个东西. 1linux下 ...

随机推荐

  1. How To Handle MLOG$_AP_SUPPLIER_SITES_AL, MLOG$_AP_SUPPLIERS Growing So Much? Having Lots of Data

    How To Handle MLOG$_AP_SUPPLIER_SITES_AL, MLOG$_AP_SUPPLIERS Growing So Much? Having Lots of Data (文 ...

  2. Swift基础之UIPickerView和小animate的使用

    写一个简单的UIPickerView的使用Demo,比较简单,其中和一个小动画的结合使用 UIPickerView的使用基本上跟OC语言中的一样,就是写法的样式问题,想必开发过OC的应该不需要多讲了, ...

  3. ROS机器人程序设计(原书第2版)补充资料 (捌) 第八章 导航功能包集入门 navigation

    ROS机器人程序设计(原书第2版)补充资料 (捌) 第八章 导航功能包集入门 navigation 书中,大部分出现hydro的地方,直接替换为indigo或jade或kinetic,即可在对应版本中 ...

  4. JVM内存区域划分(JDK6/7/8中的变化)

    前言 Java程序的运行是通过Java虚拟机来实现的.通过类加载器将class字节码文件加载进JVM,然后根据预定的规则执行.Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同 ...

  5. 关于Android PullTorefreshScrollview回到顶部实例

    列表滑动下面显示按钮,点击按钮回到顶部的功能,一般scrollview会有滑动监听的事件,通过setOnScrollChangeListener()滑动监听滑动的距离来判断是否显示按钮就好了,但是Pu ...

  6. T-SQL动态查询(2)——关键字查询

    接上文:T-SQL动态查询(1)--简介 前言: 在开发功能的过程中,我们常常会遇到类似以下情景:应用程序有一个查询功能,允许用户在很多查询条件中选择所需条件.这个也是本系列的关注点. 但是有时候你也 ...

  7. 高斯函数 --> 高斯分布(正态分布)

    具有如下形式的函数就是高斯函数. 其中a,b,c都是实数常数,a大于0 .由于在博客中写数学公式比较麻烦,还是直接放照片吧. 字写的很难看,不过应该可以看清楚.:(

  8. 使用FMDB多线程访问数据库,及database is locked的问题

    每日更新关注:http://weibo.com/hanjunqiang  新浪微博 今天终于解决了多线程同时访问数据库时,报数据库锁定的问题,错误信息是: Unknown error finalizi ...

  9. Mybatis执行BaseExecutor(二)

    BaseExecutor是Executor的一个子类,是一个抽象类,其实现了接口Executor的部分方法,并提供了三个抽象方法doUpdate.doFlushStatements和doQuery在他 ...

  10. WIP完工入库及完工退回的几个重要问题

    1.必须向CST_COMP_SNAP_INTERFACE表中插入此工单所有工序的数据(也就是说同样的工单插入多条,只是工序号不一样) 标准文档: Note: If there are multiple ...