• Linux的kobject机制


    作者:Younger Liu

    本作品采用知识共享署名-非商业性使用-相同方式共享 3.0 未本地化版本许可协议进行许可。

    sysfs文件系统下的每个目录对应于一个kobjksetkobj的封装,内嵌了一个kobj,其代表kset自身,ktype代表属性操作集,但由于通用性,因此把ktype单独剥离出来,kobjksetktype成为了各个驱动模型最底层的关联元素,并由此形成了sys下的各种拓扑结构。

    1         kobjectkset,子系统层次结构

    内核通常用kobject 结构将各个对象连接起来组成一个分层的结构体系。

     

     一个 kset是嵌入到相同类型结构的 kobject的集合。

    structkobj_type 关注的是对象的类型,而structkset关心的是对象的集合,可认为ksetkobjects的顶层容器类。每个 kset在内部包含自己的 kobject,并可以用多种处理kobject的方法处理kset kset总是在 sysfs中出现;一旦设置了 kset并把它添加到系统中, 将在 sysfs 中创建一个目录;kobjects不必在 sysfs中表示,kset中的每一个 kobject成员都在sysfs中得到表述。

     

    2         如何实现sysfs接口

    kobject是在 sysfs虚拟文件系统后的机制。对每个在 sysfs中的目录,在内核中都会有一个 kobject与之对应。每个 kobject都输出一个或多个属性,它在 kobject sysfs 目录中以文件的形式出现,其中的内容由内核产生。 

    当创建kobject , 每个 kobject都被给定一系列默认属性。这些属性保存在kobj_type结构中:

    struct kobj_type {
     void (*release)(struct kobject *);
     struct sysfs_ops *sysfs_ops;/*提供实现以下属性的方法*/
     struct attribute **default_attrs; /*用于保存类型属性列表(指针的指针) */
    };
    
    struct attribute {
     char *name;/*属性的名字( 在 kobject 的 sysfs 目录中显示)*/
     struct module *owner;/*指向模块的指针(如果有), 此模块负责实现这个属性*/
     mode_t mode; /*属性的保护位,modes 的宏定义在 <linux/stat.h>:例如S_IRUGO 为只读属性等等*/
    }; /*default_attrs 列表中的最后一个元素必须用 0 填充*/ 

      

     sysfs 读写这些属性是由 kobj_type->sysfs_ops成员中的函数完成的:

     struct sysfs_ops { ssize_t (*show)(struct kobject *kobj, struct attribute*attr, char *buffer);

     

    当用户空间读取一个属性时,内核会使用指向 kobject的指针(kobj)和正确的属性结构(*attr)来调用show方法,该方法将给定属性值编码进缓冲(buffer)(注意不要越界( PAGE_SIZE字节)),并返回实际数据长度。sysfs的约定要求每个属性应当包含一个可读值;若返回大量信息,需将它分为多个属性.

    也可对所有 kobject 关联的属性使用同一个 show 方法,用传递到函数的 attr 指针来判断所请求的属性。有的 show方法包含对属性名字的检查。有的show方法会将属性结构嵌入另一个结构,这个结构包含需要返回属性值的信息,这时可用container_of获得上层结构的指针以返回属性值的信息。

    store方法将存在缓冲(buffer)的数据( size为数据的长度,不能超过 PAGE_SIZE )解码并保存新值到属性(*attr,返回实际解码的字节数。store方法只在拥有属性的写权限时才能被调用。此时注意:接收来自用户空间的数据一定要验证其合法性。如果到数据不匹配,返回一个负的错误值。

     

    3         案例

    /**********************************************
     * Author:lewiyon@hotmail.com
     * File name:kset_sample.c
     * Description: ksetexample
     * Date: 2011-12-10
     *********************************************/
     
    #include <linux/kobject.h>
    #include <linux/string.h>
    #include <linux/sysfs.h>
    #include <linux/slab.h>
    #include <linux/module.h>
    #include <linux/init.h>
     
    /*
     * 将要创建的文件foo对应的kobj.
     */
    struct foo_obj {
           struct kobject kobj;
           int foo;
           int baz;
           int bar;
    };
    /* 通过域成员返回结构体的指针 */
    #define to_foo_obj(x) container_of(x, struct foo_obj, kobj)
     
    /* 属性 */
    struct foo_attribute {
           struct attributeattr;
           ssize_t(*show)(struct foo_obj *foo, struct foo_attribute *attr, char *buf);
           ssize_t(*store)(struct foo_obj *foo, struct foo_attribute *attr, const char *buf,size_t count);
    };
    
    #define to_foo_attr(x) container_of(x, struct foo_attribute,attr)
    
    /*
     * 属性foo信息显示函数 (涉及文件目录foo/)
     */
    static ssize_t foo_attr_show(struct kobject *kobj,
                              struct attribute *attr,
                              char *buf)
    {
           struct foo_attribute*attribute;
           struct foo_obj *foo;
    
           attribute =to_foo_attr(attr);
           foo =to_foo_obj(kobj);
    
           if(!attribute->show)
                  return -EIO;
    
           returnattribute->show(foo, attribute, buf);
    }
    
    /*
     * 属性foo存储函数(涉及文件目录foo/) (when a value is writtento a file.)
     */
    static ssize_t foo_attr_store(struct kobject *kobj,
                               struct attribute *attr,
                               const char *buf, size_t len)
    {
           struct foo_attribute*attribute;
           struct foo_obj *foo;
    
           attribute =to_foo_attr(attr);
           foo =to_foo_obj(kobj);
    
           if(!attribute->store)
                  return -EIO;
    
           returnattribute->store(foo, attribute, buf, len);
    }
    
    /* 
     * foo的show/store列表
     */
    static const struct sysfs_ops foo_sysfs_ops = {
           .show =foo_attr_show,
           .store =foo_attr_store,
    };
    
    /*
     * The release functionfor our object.  This is REQUIRED by thekernel to
     * have.  We free the memory held in our object here.
     */
    static void foo_release(struct kobject *kobj)
    {
           struct foo_obj *foo;
     
           foo =to_foo_obj(kobj);
           kfree(foo);
    }
    
    /*
     * 当需要从foo文件中读取信息时,调用此函数
     */
    static ssize_t foo_show(struct foo_obj *foo_obj, structfoo_attribute *attr,
                         char*buf)
    {
           return sprintf(buf,"%d
    ", foo_obj->foo);
    }
    
    /*
     * 当往foo文件写入信息时,调用此函数
     */
    static ssize_t foo_store(struct foo_obj *foo_obj, structfoo_attribute *attr,
                          const char *buf, size_t count)
    {
           sscanf(buf,"%du", &foo_obj->foo);
           return count;
    }
    
    static struct foo_attribute foo_attribute =
           __ATTR(foo, 0666,foo_show, foo_store);
    
    /*
     * foo_ktype的属性列表
     */
    static struct attribute *foo_default_attrs[] = {
           &foo_attribute.attr,
           NULL,     /* need to NULL terminate the list ofattributes */
    };
     
    /*
     * 定义kobj_type结构体
     * 指定sysfs_ops,release函数, 属性列表foo_default_attrs
     */
    static struct kobj_type foo_ktype = {
           .sysfs_ops =&foo_sysfs_ops,
           .release =foo_release,
           .default_attrs =foo_default_attrs,
    };
    
    static struct kset *example_kset;
    static struct foo_obj *foo_obj;
    
    static struct foo_obj *create_foo_obj(const char *name)
    {
           struct foo_obj *foo;
           int retval;
    
           /* allocate thememory for the whole object */
           foo =kzalloc(sizeof(*foo), GFP_KERNEL);
           if (!foo)
                  return NULL;
    
           foo->kobj.kset =example_kset;
    
        /*
         * 初始化kobject数据结结构foo->lobj,
         * 即在foo->kobj的层次组织kset中创建个名为name的文件foo/foo
         * 成功返回0
         */
           retval =kobject_init_and_add(&foo->kobj, &foo_ktype, NULL, "%s",name);
           if (retval) {
            /* 减小kobj的引用计数 */
                  kobject_put(&foo->kobj);
                  return NULL;
           }
           /*
            * 发送 KOBJ_ADD / KOBJ_REMOVE 等事件
            * We are always responsible for sending theuevent that the kobject
            * was added to the system.
            */
           kobject_uevent(&foo->kobj,KOBJ_ADD);
    
           return foo;
    }
    
    static void destroy_foo_obj(struct foo_obj *foo)
    {
        /* 减小kobj的引用计数 */
           kobject_put(&foo->kobj);
    }
    
    static int __init example_init(void)
    {
        /* 
         * 动态地在kernel_kobj所对应的目录/sys/kernel/下创建一个目录kset_example
         * 并返回kset_example对应的kset
         */
           example_kset = kset_create_and_add("kset_example",NULL, kernel_kobj);
           if (!example_kset)
                  return-ENOMEM;
     
           foo_obj =create_foo_obj("foo");
           if (!foo_obj)
                  gotofoo_error;
    
          return 0;
    
    foo_error:
           return -EINVAL;
    }
    
    static void __exit example_exit(void)
    {
           destroy_foo_obj(foo_obj);
           kset_unregister(example_kset);
    }
    
    module_init(example_init);
    module_exit(example_exit);
    MODULE_LICENSE("GPL");
    MODULE_AUTHOR("lewiyon <lewiyon@hotmail.com>"); 

     

    4         参考资料:

    sysfs文件系统详解:http://blog.chinaunix.net/u1/55599/showart_1089096.html

    sysfs.h源码详析:http://blog.chinaunix.net/u1/55599/showart_1091002.html

     

    作者:Younger Liu

    本作品采用知识共享署名-非商业性使用-相同方式共享 3.0 未本地化版本许可协议进行许可。

    
  • 相关阅读:
    day15
    day13
    day12
    使用modelsim直接仿真IP(FIFO)
    整理:FPGA选型
    Quartus 中调用modelsim的流程及*.vt或*.vht自动生成
    quartus ip核破解
    LDO ,开关电源DC-DC的优缺点
    硬件工程师面试经历2015---笔试篇
    出色的硬件工程师必备的几项“硬”实力
  • 原文地址:https://www.cnblogs.com/youngerchina/p/5624550.html
Copyright © 2020-2023  润新知