Linux设备模型之注册kobject和 kset

来源:互联网 发布:重庆sem优化 编辑:程序博客网 时间:2024/04/30 20:46
------------------------------------------------
#纯属个人理解,如有问题敬请谅解!
#kernel version: 2.6.26
#Author: andy wang
-------------------------------------------------
在建立linxu设备模型中kobject是一个重要的而且基础的数据结构,如果向内核注册一个kobject就相当于在sysfs文件系统下建立一个目录 .kobject又被嵌入到一个更大结构kset当中 ,在设备模型中 总线,设备,驱动就是典型的ket模型.
下面引用ULK3中的一张图来看看:

这个图很清晰的给我们展示了一个驱动注册到pci总线上后.sys下的目录结构. 从这里我们我们可以看出使用sysfs文件系统建立起来的设备模型是很有层次的.
pci和drivers都是一个ket组成,serial由kobj构成, 在serial这个目录下面有一个属性文件new-id .
 
注册kobject对象
我们这里就从创建并注册kobject对象开始吧,
636 struct kobject *kobject_create_and_add(const char *name, struct kobject *parent)
637 {
638         struct kobject *kobj;
639         int retval;
640
641         kobj = kobject_create();
642         if (!kobj)
643                 return NULL;
644
645         retval = kobject_add(kobj, parent, "%s", name);
646         if (retval) {
647                 printk(KERN_WARNING "%s: kobject_add error: %d/n",
648                        __func__, retval);
649                 kobject_put(kobj);
650                 kobj = NULL;
651         }
652         return kobj;
653 }
第641行, 在内存中分配一个kobject, 并调用kobject_init()初始化这个kobject. 第645行的函数就是要把这个kobject注册到内核中了.
看看kobject_add()实现流程:
kobject_add()->kobject_add_varg()->kobject_set_name_vargs()->kobject_add_internal()->create_dir()->sysfs_create_dir() ; 从这个流程可以看到注册一个kobject实际上就是在sysfs文件系统中创建一个目录.前面几个函数都是较简单的,这里主要看看kobject_add_internal()函数:
158 static int kobject_add_internal(struct kobject *kobj)
159 {
160         int error = 0;
161         struct kobject *parent;
162
163         if (!kobj)
164                 return -ENOENT;
165
166         if (!kobj->name || !kobj->name[0]) {
167                 pr_debug("kobject: (%p): attempted to be registered with empty "
168                          "name!/n", kobj);
169                 WARN_ON(1);
170                 return -EINVAL;
171         }
172
173         parent = kobject_get(kobj->parent);
174
175         /* join kset if set, use it as parent if we do not already have one */
176         if (kobj->kset) {
177                 if (!parent)
178                         parent = kobject_get(&kobj->kset->kobj);
179                 kobj_kset_join(kobj);
180                 kobj->parent = parent;
181         }
182
183         pr_debug("kobject: '%s' (%p): %s: parent: '%s', set: '%s'/n",
184                  kobject_name(kobj), kobj, __func__,
185                  parent ? kobject_name(parent) : "<NULL>",
186                  kobj->kset ? kobject_name(&kobj->kset->kobj) : "<NULL>");
187
188         error = create_dir(kobj);
189         if (error) {
190                 kobj_kset_leave(kobj);
191                 kobject_put(parent);
192                 kobj->parent = NULL;
193
194                 /* be noisy on error issues */
195                 if (error == -EEXIST)
196                         printk(KERN_ERR "%s failed for %s with "
197                                "-EEXIST, don't try to register things with "
198                                "the same name in the same directory./n",
199                                __func__, kobject_name(kobj));
200                 else
201                         printk(KERN_ERR "%s failed for %s (%d)/n",
202                                __func__, kobject_name(kobj), error);
203                 dump_stack();
204         } else
205                 kobj->state_in_sysfs = 1;
206
207         return error;
208 }
第166行代码是判断kobj的名字,我们的目录是要有名字的. 173行代码,增加kobj父亲的引用计数
第176-180行代码, 如果kobj设置了kset, 在kobj未指定父对象的情况下,把ket->kobj设为这个kobj的父亲,并将kobj对象添加到kset的kobj list中.
第188行代码create_dir()在以前已经分析过了,就是在sysfs下创建一个目录文件撒.
 
注册kset对象
在分析了kobj的注册以后再来分析ket的注册就比较简单了.
Kset创建并注册流程:
kset_create_and_add()-> kset_create()->kset_register()->kobject_add_internal()->kobject_uevent();
其实ket的注册流程和kobj的注册流程基本上都是一样的,ket的注册实际上就把它嵌套的kobj注册到内核中了,同样也会在sysfs相应位置建立一个目录.
但与注册kobj不同的是, 在注册一个kset时会调用函数kobject_uevent(&k->kobj, KOBJ_ADD) 通过netlink把KOBJ_ADD事件发送到用户层的udev ,在udev收到内核发的这个消息时就会执行相应的事件了.