Linux设备驱动之Kobject、Kset

LDD3中说,Kobject的作用为:

    1、sysfs 表述:在 sysfs 中出现的每个对象都对应一个 kobject, 它和内核交互来创建它的可见表述。

    2、热插拔事件处理 :kobject 子系统将产生的热插拔事件通知用户空间。
    3、数据结构关联:整体来看, 设备模型是一个极端复杂的数据结构,通过其间的大量链接而构成一个多层次的体系结构。kobject 实现了该结构并将其聚合在一起。 

    此篇文章,只分析第一条,kobject 与 kset sysfs 之间的关系。剩下的两条将在后续的两篇文章中分析

    

首先,什么是 kobject ,它也不过是内核里的一个结构体而已
    struct kobject {
        const char        *name;
        struct list_head    entry;
        struct kobject        *parent;
        struct kset        *kset;
        struct kobj_type    *ktype;
        ......// 省略一些暂时不想看到的东西
    };
那么,这个结构体有何特殊之处呢?
        每一个 kobject 对应 文件系统 /sys 里的一个 目录,目录的名字就是结构体中的 name
   
什么又是 kset ,kset 也是个结构体而已
    struct kset {
        struct list_head list;   
        struct kobject kobj;   
        struct kset_uevent_ops *uevent_ops;
        spinlock_t list_lock;
    };
    我们前面说了,每一个 kobj 对应 文件系统 /sys 里的一个 目录,那么每一个 kset 都包含了一个 kobj,那样的话,kset也对应于 /sys 里的一个 目录
    简单来说,kset 与 kobj 都是目录,既然是目录,那么在就是一个树状结构,每一个目录都将有一个 父节点,

        在kset中使用kset.kobj->parent 指定
        在kboject中使用  kobj->parent 指定
    显然,整个树状目录结构,都是通过kobj来构建的,只不过有些kobj嵌在Kset里,分析目录结构时把kset当成一个普通的kobj会好理解很多。

那么kset 有何特殊之处呢?
    我们可以看到 kset 结构中有一个链表,它目录下的 一些相同类型的kobj会在创建时链入链表,也就是说Kset是一些kobj的集合。    
    干说还是比较抽象的,那么我们就来看看 /sys 目录底下的这些东西,哪些是kset 哪些是kobj 结构又是怎样的。
    看过代码的应该知道,想要在/sys 目录下创建 目录,那就要 构造 kset 或者 kobj 设置并注册。
    对于kobject:
        kobject_create_and_add
        kobject_init_and_add
    对于kset:
        kset_create_and_add
    我在这3个函数中增加了prink打印语句,打印内核创建的每一个 kobj 或者 kset 的名字,以及父节点的名字,甚至它指向的kset的kobj的名字。
   
    原本我以为,较高层次的目录会是kset,因为它是个集合嘛,然而并不全是。
        the kset name is devices,no parent
            the kset name is system,parent's name is devices
            the kobject name is virtual,parent's name is devices   

        the kset name is bus,no parent
        the kset name is class,no parent
        the kset name is module,no parent
        the kobject name is fs,no parent
        the kobject name is dev,no parent
            the kobject name is block,parent's name is dev
            the kobject name is char,parent's name is dev    
   
        the kobject name is firmware,no parent
        the kobject name is kernel,no parent
            the kset name is slab,parent's name is kernel

        the kobject name is block,no parent
    写着no parent的,在/sys/目录下可以找到它们,对于devices、bus、class、module它们是kset
                                                                                          对于fs、dev、firmware、kernel、block 它们是 kobj
而且,我们还可以发现
    1、    kset 底下可以放 kset (但是无法链入链表,分析代码时会知道)
        the kset name is devices,no parent
                the kset name is system,parent's name is devices
    2、    kset 底下可以放 kobj (可以链入链表,也可以不链入)
        the kset name is devices,no parent
            the kobject name is virtual,parent's name is devices
    3、 kobject 底下可以放 kset (显然没链表的概念了)
        the kobject name is kernel,no parent
            the kset name is slab,parent's name is kernel
    4、 kobj 底下放 kobj (同样没有链表的概念)
        the kobject name is dev,no parent
            the kobject name is block,parent's name is dev

     如下图:黄色代表Kset 蓝色代表Kobject
       

sys

    那么,至此我们对kset kobj它们之间的联系就应该有一个比较浅显的认识了。

------------------------------------------------------------------------------------------------------------------------------------------------------

下面来分析代码,进一步摸索,先把图贴上来,虚线表示可能的其它一些连接情况。


---------------------------------------------------------------------------------------------------------------------------------------------------------------

    struct kobject *kobject_create_and_add(const char *name, struct kobject *parent)

        {
                struct kobject *kobj;
                kobj = kobject_create();
                retval = kobject_add(kobj, parent, "%s", name);
                return kobj;
        }

 

    kobject_create_and_add
        kobject_create        // kobj = kzalloc(sizeof(*kobj), GFP_KERNEL);
            kobject_init              // kobj->ktype = ktype;
            kobject_init_internal    // kref_init(&kobj->kref);
        kobject_add
            kobject_add_varg    // retval = kobject_set_name_vargs(kobj, fmt, vargs); // kobj->parent = parent;
            kobject_add_internal
            if (kobj->kset) {    // kobj->kset == NULL 不执行
                if (!parent)
                    parent = kobject_get(&kobj->kset->kobj);
                    kobj_kset_join(kobj);
                    kobj->parent = parent;
            }
            create_dir
                

    kobject_create_and_add 函数从 构建一个kobject到 在sysfs中创建路径一气呵成,其中没有关于kset的设置,仅仅是设置了parent ktype

    如果 kobject_create_and_add 传入的 parent 参数 是一个普通的kobject ,那么就与应于图中的③与⑤的关系

    如果 kobject_create_and_add 传入的 parent 参数 是一个kset->kobject,那么就与应于图中的③与④的关系

---------------------------------------------------------------------------------------------------------------------------------------------------------------

    priv->kobj.kset = bus->p->drivers_kset;  // 设置它所属的Kset
            error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL, "%s", drv->name);

 

    int kobject_init_and_add(struct kobject *kobj, struct kobj_type *ktype,
             struct kobject *parent, const char *fmt, ...)
    {
        kobject_init(kobj, ktype);
        retval = kobject_add_varg(kobj, parent, fmt, args);
    }
    kobject_init_and_add   
        kobject_init    // kobj->ktype = ktype;
             kobject_init_internal    // kref_init(&kobj->kref);
        kobject_add_varg    // retval = kobject_set_name_vargs(kobj, fmt, vargs); // kobj->parent = parent;
             kobject_add_internal
                 if (kobj->kset) {    // 将kobject 添加到它所指向的kset->list中
                     if (!parent)
                         parent = kobject_get(&kobj->kset->kobj);
                         kobj_kset_join(kobj);
                          kobj->parent = parent;  // 如果没有parent 将它所属的kset->kobj作为它的parent
                    }
              create_dir

    与kobject_create_and_add 相比 就是少了构建kobkject,然而这样给了我们设置kset的机会,同时往往不会设置parent

对应于图中的①与④的关系

---------------------------------------------------------------------------------------------------------------------------------------------------------------

    struct kset *kset_create_and_add(const char *name,
                 struct kset_uevent_ops *uevent_ops,
                 struct kobject *parent_kobj)
     

        kset = kset_create(name, uevent_ops, parent_kobj);

        error = kset_register(kset);
      }

    kset_create_and_add
        kset_create
            kset = kzalloc(sizeof(*kset), GFP_KERNEL);
            retval = kobject_set_name(&kset->kobj, name);
            kset->uevent_ops = uevent_ops;       
            kset->kobj.parent = parent_kobj;
            kset->kobj.ktype = &kset_ktype;
            kset->kobj.kset = NULL;
        kset_register
            kset_init(k);
                err = kobject_add_internal(&k->kobj);
                    parent = kobject_get(kobj->parent);
                    if (kobj->kset) {    // kobj->kset==NULL 不执行
                       ....
                   }
                    error = create_dir(kobj);
        kset_create_and_add 无法将 创建kset->kobj.kset 指向任何kset
        但是kset->kobj.parent 还是能和kobj.parent指向 普通的kobj 或者包含在kset里的kobj

    如果 kset_create_and_add 传入的 parent 参数 是一个普通的kobject ,那么就与应于图中的④与⑤的关系

    如果 kset_create_and_add 传入的 parent 参数 是一个kset->kobject,那么就与应于图中的②与④的关系

-------------------------------------------------------------------------------------------------------------------------------------------------------------

还有一种情况就是,创建一个 kset 并设置kset.kobject.kset

然后调用 kset_register

        kset_register
            kset_init(k);
                err = kobject_add_internal(&k->kobj);
                    parent = kobject_get(kobj->parent);
                   if (kobj->kset) {    // 将kobject 添加到它所指向的kset->list中
                     if (!parent)
                         parent = kobject_get(&kobj->kset->kobj);
                         kobj_kset_join(kobj);
                          kobj->parent = parent;  // 如果没有parent 将它所属的kset->kobj作为它的parent
                    }
                    error = create_dir(kobj);

    对应于图中④与⑥的关系。

-------------------------------------------------------------------------------------------------------------------------------------------------------------

    上面代码的细节,比如如何在/sys/创建路径请参考:http://blog.csdn.net/lizuobin2/article/details/51511336

到此,我们应该对 kobject kset sysfs 之间的目录关系比较清楚了,但是我们至少还应该看看ktype,至于Kset中的热插拔在第二条中分析好了。

    struct kobject {
        const char        *name;
        struct list_head    entry;
        struct kobject        *parent;
        struct kset        *kset;
        struct kobj_type    *ktype;
        struct kref        kref;

    ……
    };

    struct kobj_type {
        void (*release)(struct kobject *kobj);
        struct sysfs_ops *sysfs_ops;
        struct attribute **default_attrs;  //struct attribute *default_attrs[]
    };

    ktype 由一个release函数、一个sysfs_ops、一个指针数组(二维指针)组成

    1、release 函数

        每一个Kobject 都必须有一个release方法,有意思的是,release 函数并没有包括在kobject自身内,而是包含在它的结构体成员Ktype内。而且kobject在调用release之前应该保持稳定(不明白抄自LDD3)。

    2、struct attribute **default_attrs

        struct attribute {
            const char        *name;
            struct module        *owner;
            mode_t            mode;
        };

        default_attrs 指向的地方 是个指针数组,这些指针的类型为attribute ,那么这些attribute 就是该kobject的属性了,name 是属性的名字,在kobject目录下 表现为 文件 ,owner 指向模块的指针(如果有的话),那么该模块负责实现这些属性。mode 是保护位,通常是S_IRUGO,可写的则用S_IWUSR 仅为root提供写权限。default_attrs最后一个元素必须为0,要不然它找不着北~

    3、sysfs_opes  实现属性的方法

        struct sysfs{

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

            ssize_t *store(struct kobject *kobject, struct attribute *attr,char *buf, size_t size);

        }

    在内核里,一类设备往往使用相同的show , store函数。

附上一个例子:linux2.6.32.2 编译通过

[cpp] view plaincopy
print?
  1. </pre><p><pre name="code" class="cpp">#include <linux/device.h>     
  2. #include <linux/module.h>     
  3. #include <linux/kernel.h>     
  4. #include <linux/init.h>     
  5. #include <linux/string.h>     
  6. #include <linux/sysfs.h>     
  7. #include <linux/stat.h>     
  8.       
  9. MODULE_AUTHOR("David Xie");     
  10. MODULE_LICENSE("Dual BSD/GPL");    
  11.     
  12. ---------------------------------------default_attrs------------------------------------------------    
  13. /*对应于kobject的目录下的一个文件,Name成员就是文件名*/      
  14. struct attribute test_attr = {     
  15.     .name = "kobj_config",     
  16.     .mode = S_IRWXUGO,     
  17. };  
  18.     
  19. static struct attribute *def_attrs[] = {     
  20.     &test_attr,     
  21.     NULL,     
  22. };     
  23. ---------------------------------------sysfs_ops----------------------------------------------------          
  24. /*当读文件时执行的操作*/     
  25. ssize_t kobj_test_show(struct kobject *kobject, struct attribute *attr,char *buf)    
  26. {     
  27.     printk("have show.\n");     
  28.     printk("attrname:%s.\n", attr->name);     
  29.     sprintf(buf,"%s\n",attr->name);     
  30.     return strlen(attr->name)+2;     
  31. }    
  32.     
  33. /*当写文件时执行的操作*/      
  34. ssize_t kobj_test_store(struct kobject *kobject,struct attribute *attr,const char *buf, size_t count)    
  35. {     
  36.     printk("havestore\n");     
  37.     printk("write: %s\n",buf);     
  38.     return count;     
  39. }         
  40. //kobject对象的操作     
  41. struct sysfs_ops obj_test_sysops =     
  42. {     
  43.     .show = kobj_test_show,     
  44.     .store = kobj_test_store,     
  45. };   
  46. ---------------------------------------release-------------------------------------------------------    
  47. /*release方法释放该kobject对象*/      
  48. void obj_test_release(struct kobject *kobject)     
  49. {     
  50.     printk("eric_test: release .\n");     
  51. }   
  52. ---------------------------------------kobj_type-----------------------------------------------------        
  53.  /*定义kobject对象的一些属性及对应的操作*/     
  54. struct kobj_type ktype =      
  55. {     
  56.     .release = obj_test_release,     
  57.     .sysfs_ops=&obj_test_sysops,     
  58.     .default_attrs=def_attrs,     
  59. };    
  60.         
  61. struct kobject kobj;//声明kobject对象    
  62.      
  63. static int kobj_test_init(void)     
  64. {     
  65.     printk("kboject test init.\n");     
  66.     kobject_init_and_add(&kobj,&ktype,NULL,"kobject_test");//初始化kobject对象kobj,并将其注册到linux系统    
  67.     //kobject_init(&kobj);    
  68.     //kobj.ktype = &ktype;    
  69.     //kobj.parent = NULL;    
  70.     //kobject_set_name(&kobj, "kobject_test");    
  71.     //err = kobject_add(&kobj);    
  72.     return 0;     
  73. }     
  74.       
  75. static void kobj_test_exit(void)     
  76. {     
  77.     printk("kobject test exit.\n");     
  78.     kobject_del(&kobj);     
  79. }     
  80.       
  81. module_init(kobj_test_init);    
  82. module_exit(kobj_test_exit);   
</pre><p><pre name="code" class="cpp">#include <linux/device.h>   
#include <linux/module.h>   
#include <linux/kernel.h>   
#include <linux/init.h>   
#include <linux/string.h>   
#include <linux/sysfs.h>   
#include <linux/stat.h>   MODULE_AUTHOR("David Xie");   
MODULE_LICENSE("Dual BSD/GPL");  ---------------------------------------default_attrs------------------------------------------------  
/*对应于kobject的目录下的一个文件,Name成员就是文件名*/    
struct attribute test_attr = {   .name = "kobj_config",   .mode = S_IRWXUGO,   
};static struct attribute *def_attrs[] = {   &test_attr,   NULL,   
};   
---------------------------------------sysfs_ops----------------------------------------------------        
/*当读文件时执行的操作*/   
ssize_t kobj_test_show(struct kobject *kobject, struct attribute *attr,char *buf)  
{   printk("have show.\n");   printk("attrname:%s.\n", attr->name);   sprintf(buf,"%s\n",attr->name);   return strlen(attr->name)+2;   
}  /*当写文件时执行的操作*/    
ssize_t kobj_test_store(struct kobject *kobject,struct attribute *attr,const char *buf, size_t count)  
{   printk("havestore\n");   printk("write: %s\n",buf);   return count;   
}   	
//kobject对象的操作   
struct sysfs_ops obj_test_sysops =   
{   .show = kobj_test_show,   .store = kobj_test_store,   
}; 
---------------------------------------release-------------------------------------------------------  
/*release方法释放该kobject对象*/    
void obj_test_release(struct kobject *kobject)   
{   printk("eric_test: release .\n");   
} 
---------------------------------------kobj_type----------------------------------------------------- 	   /*定义kobject对象的一些属性及对应的操作*/   
struct kobj_type ktype =    
{   .release = obj_test_release,   .sysfs_ops=&obj_test_sysops,   .default_attrs=def_attrs,   
};  struct kobject kobj;//声明kobject对象  static int kobj_test_init(void)   
{   printk("kboject test init.\n");   kobject_init_and_add(&kobj,&ktype,NULL,"kobject_test");//初始化kobject对象kobj,并将其注册到linux系统  //kobject_init(&kobj);  //kobj.ktype = &ktype;  //kobj.parent = NULL;  //kobject_set_name(&kobj, "kobject_test");  //err = kobject_add(&kobj);  return 0;   
}   static void kobj_test_exit(void)   
{   printk("kobject test exit.\n");   kobject_del(&kobj);   
}   module_init(kobj_test_init);  
module_exit(kobj_test_exit); 



核心结论:

    1、sys 目录下的层次结构依赖于 kobject.parent ,未指定parent时,默认使用 kobject.kset.kobject 作为 parent,如果都没有,就出现在 /sys 目录下。

    2、该 kobject 目录下的属性文件依赖于 kobject.ktype


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/403864.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

图片不显示问题 图片url监测改变问题

问题&#xff1a;点击按钮换一换的时候&#xff0c;后台返回的三张小图片的地址还是原来的地址&#xff0c;但是三张小图确实是变了&#xff1b;这时候如果一开始头图是图3&#xff0c;点击换一换后&#xff0c;三张小图变了&#xff0c;此时还是想选择图3为头图&#xff1b;却…

限定虚拟机可用的CPU利用率

Windows Server 2012姗姗来迟&#xff0c;最新的Hyper-V 3给我们带来更多的惊喜&#xff0c;后续三篇博文和大家共同学习虚拟机CPU竞争机制。 第一部分&#xff1a;分配给虚拟机的CPU资源 第二部分&#xff1a;限定虚拟机可用的CPU利用率 第三部分&#xff1a;争夺CPU资源优先级…

Windows 7 文件夹共享

今天搞了下windows 7下的文件共享&#xff0c;总是搞不定&#xff0c;虽然以前也偶尔有成功过&#xff0c;但未作记录&#xff0c;现在要搞一时搞不定&#xff0c;所以决定好好记录一下。 win7的文件夹共享搞得实在是太麻烦了(对于一般用户而言)&#xff0c;为了权限控制&#…

1.the linux device model--kobject kset学习笔记

http://blog.chinaunix.net/uid-22547469-id-4590385.html?utm_sourcejiancool Linux设备模型就是一栋规模宏大的建筑&#xff0c;为了构建它&#xff0c;需要基本的建筑材料钢筋&#xff1a;kobject、若干钢筋组成的钢架结构&#xff1a;kset&#xff0c;还需要一种机制sysfs…

微信公众号开发笔记1-获取Access Token

获取你的Access Token a&#xff09;可以采用网址的形式&#xff1a; 用appid和appsecert获得access token&#xff0c;接口为https://api.weixin.qq.com/cgi-bin/token?grant_typeclient_credential&appid你的APPID&secret你的APPSECRET 替换中间的你的APPID和APPSEC…

ant更改主题色报错Inline JavaScript is not enabled. Is it set in your options? vue ant主题色更改 vue-cli3

问题&#xff1a;使用vue-cli3更改ant的主题色时候报错&#xff1a;Inline JavaScript is not enabled. Is it set in your options? 原因&#xff1a;我的问题是less-loader依赖包的版本为5.0.0&#xff0c;而官方要求必须是6.0.0&#xff1b; ERROR Failed to compile …

ant中table表格的多选框如何清空

项目需求&#xff1a;表格前加一列多选框&#xff0c;可以做多选和提交&#xff0c;还可以在提交后、重置或者翻页后对多选框清空 使用的组件是ant中下的可操作选择的table&#xff1b;这样我们就知道复选框选中的那些数据id&#xff0c;其实就是selectedRowKeys数组里的id&am…

SCCM 2012系列1 服务器准备上

各位您好&#xff0c;今天我将开始给大家分享微软最新的SCCM 2012系列文章&#xff0c;让大家逐步了解在企业内如何搭建SCCM 2012的同时&#xff0c;了解各个功能模块&#xff0c;对应自己的企业环境来看&#xff0c;那些功能是您现在所需要的。当然还可以看看SCCM 2012比之前…

近期H5项目开发小结

前言&#xff1a;2016差不多又过了半啦&#xff0c;最近参与了公司好几个h5项目&#xff08;严格来说&#xff0c;也只能算是推广页面活动&#xff09;。主要是新品牌的推广需要&#xff0c;当然也有给公司以前老客户做的案例。今天主要总结下为新品牌开发的2个h5推广&#xff…

依赖包报错Invalid options object. Less Loader has been initialized using an options object that does not

1.问题&#xff1a;yarn安装依赖包&#xff0c;启动项目报错 error in ./node_modules/ant-design-vue/dist/antd.less Module build failed: ValidationError: Invalid options object. Less Loader has been initialized using an options object that does not match the A…

Asp.net页面和Html页面之间的关系

Asp.net页面显然要转化为普通的html页面才能在浏览器中显示&#xff0c;但是对于两者的关系&#xff0c;或者说从服务器在接受请求处理请求这段时间内对asp.net页面的操作一直不是很明白&#xff0c;下边的一段话可以让人豁然开朗&#xff0c;虽然并未谈论技术&#xff0c;但简…

vue-cli2定制ant-design-vue主题

本篇是vue-cli2定制主题&#xff0c;vue-cli3通过vue.config.js定制主题点击此处 1.引入less和less-loader&#xff08;如果报错&#xff0c;请将less-loader版本更改到5.0.0&#xff09; npm install less less-loader --save2.在 vue cli 2 中定制主题&#xff0c;修改build…

YUV视频格式分析

Andrew Huang <bluedrum163.com> 转载请注明作者及联络方式在摄像头之类编程经常是会碰到YUV格式,而非大家比较熟悉的RGB格式. 我们可以把YUV看成是一个RGB的变种来理解.YUV的原理是把亮度与色度分离&#xff0c;研究证明,人眼对亮度的敏感超过色度。利用这个原理&#x…

自定义ant中table表格的展开图标 修改ant-vue-design中嵌套表格table的expandIcon自定义图标

效果&#xff1a; 1. <a-table:expandIcon"expandIcon":loading"loading":columns"columns":data-source"data"class"components-table-demo-nested"change"onChangeTable":scroll"{x:1300,y:y}":p…

Foundationd和Application Kit的类层次

Foundationd类 Application Kit类 转载于:https://www.cnblogs.com/ikodota/archive/2012/08/01/2618590.html

dup和dup2的使用方法

/*本文通过标准输出的重定向和恢复的过程来解释dup和dup2的使用方法*/#include <stdio.h> #include <unistd.h>#include <fcntl.h>//STDIN_FILENO标准输入描述符&#xff08;0&#xff09;//STDOUT_FILENO标准输出描述符&#xff08;1&#xff09; //STDERR_…

python多线程编程(2): 线程的创建、启动、挂起和退出

From: http://www.cnblogs.com/holbrook/archive/2012/03/02/2376940.html 如上一节&#xff0c;python的threading.Thread类有一个run方法&#xff0c;用于定义线程的功能函数&#xff0c;可以在自己的线程类中覆盖该方法。而创建自己的线程实例后&#xff0c;通过Thread类的…

记录ie下报XMLHttpRequest: 网络错误 0x80070005, 拒绝访问。

问题&#xff1a; 同样的调用接口&#xff0c;在谷歌是没有问题的&#xff0c;但是在ie下报错XMLHttpRequest: 网络错误 0x80070005, 拒绝访问。 1.分析&#xff1a; 对比了一下&#xff0c;相同的是接口传递参数错误导致报错&#xff0c;传递的参数自动带上了 " "…

MVC3.0+DWZ探索

将themes 文件移到 js文件 index.html 转载于:https://www.cnblogs.com/acyy/archive/2012/08/03/2621594.html