关于linux设备模型kobject,kset,ktype
--------------------------------------------------------
本文系本站原创,欢迎转载!
转载请注明出处:http://www.cnblogs.com/gdt-a20
--------------------------------------------------------
一、sysfs文件系统下的每个目录对应于一个kobj,kset是kobj的封装,内嵌了一个kobj,其代表kset自身,ktype代表属性操作集,但由于通用性,因此把ktype单独剥离出来,kobj,kset,ktype成为了各个驱动模型最底层的关联元素,并由此形成了sys下的各种拓扑结构。
二、关于kobject
首先看一下kobject的原型
1 struct kobject {
2 const char *name; //名字
3 struct list_head entry; //连接到kset建立层次结构
4 struct kobject *parent; //指向父节点,面向对象的层次架构
5 struct kset *kset;
6 struct kobj_type *ktype; //属性文件
7 struct sysfs_dirent *sd;
8 struct kref kref; //引用计数
9 unsigned int state_initialized:1; //初始化状态...
10 unsigned int state_in_sysfs:1;
11 unsigned int state_add_uevent_sent:1;
12 unsigned int state_remove_uevent_sent:1;
13 unsigned int uevent_suppress:1;
14 };
分析一下kobject的初始化过程
初始化函数为
1 ---int kobject_init_and_add(struct kobject *kobj, struct kobj_type *ktype, //参数为kobject和属性结构体
2 struct kobject *parent, const char *fmt, ...)
3 {
4 va_list args;
5 int retval;
6 kobject_init(kobj, ktype);
7 va_start(args, fmt);
8 retval = kobject_add_varg(kobj, parent, fmt, args);
9 va_end(args);
10 return retval;
11 }
12 ---void kobject_init(struct kobject *kobj, struct kobj_type *ktype)
13 {
14 char *err_str;
15 if (!kobj) { //kobj为NULL错误退出
16 err_str = "invalid kobject pointer!";
17 goto error;
18 }
19 if (!ktype) { //ktype为NULL错误退出
20 err_str = "must have a ktype to be initialized properly!/n";
21 goto error;
22 }
23 if (kobj->state_initialized) { //如果初始化状态为1报错
24 /* do not error out as sometimes we can recover */
25 printk(KERN_ERR "kobject (%p): tried to init an initialized "
26 "object, something is seriously wrong./n", kobj);
27 dump_stack();
28 }
29 kobject_init_internal(kobj); //初始化kobj
30 kobj->ktype = ktype; //关联obj和ktype
31 return;
32 error:
33 printk(KERN_ERR "kobject (%p): %s/n", kobj, err_str);
34 dump_stack();
35 }
36 -------static void kobject_init_internal(struct kobject *kobj)
37 {
38 if (!kobj)
39 return;
40 kref_init(&kobj->kref); //计数变成1
41 INIT_LIST_HEAD(&kobj->entry); //都指向自己,prev和next
42 kobj->state_in_sysfs = 0;
43 kobj->state_add_uevent_sent = 0;
44 kobj->state_remove_uevent_sent = 0;
45 kobj->state_initialized = 1;
46 }
47 -------static int kobject_add_varg(struct kobject *kobj, struct kobject *parent,
48 const char *fmt, va_list vargs)
49 {
50 int retval;
51 retval = kobject_set_name_vargs(kobj, fmt, vargs); //设置名字,名字中不能有“/”
52 if (retval) {
53 printk(KERN_ERR "kobject: can not set name properly!/n");
54 return retval;
55 }
56 kobj->parent = parent; //设置parent,其父节点
57 return kobject_add_internal(kobj);
58 }
59 ----static int kobject_add_internal(struct kobject *kobj)
60 {
61 int error = 0;
62 struct kobject *parent;
63 if (!kobj)
64 return -ENOENT;
65 if (!kobj->name || !kobj->name[0]) { //名字不能为空
66 WARN(1, "kobject: (%p): attempted to be registered with empty "
67 "name!/n", kobj);
68 return -EINVAL;
69 }
70 parent = kobject_get(kobj->parent); //如果parent为真,则增加kobj->kref计数,也就是父节点的引用计数
71 /* join kset if set, use it as parent if we do not already have one */
72 if (kobj->kset) {
73 if (!parent)
74 parent = kobject_get(&kobj->kset->kobj); //如果kobj-parent父节点为NULL那么就用kobj->kset->kobj
75 // 作其父节点,并增加其引用计数
76 kobj_kset_join(kobj); //把kobj的entry成员添加到kobj->kset>list的尾部,现在的层次就是
77 kobj->parent = parent; //kobj->kset->list指向kobj->parent
78 } // ->parent 指向kset->kobj
79 pr_debug("kobject: '%s' (%p): %s: parent: '%s', set: '%s'/n",
80 kobject_name(kobj), kobj, __func__,
81 parent ? kobject_name(parent) : "<NULL>",
82 kobj->kset ? kobject_name(&kobj->kset->kobj) : "<NULL>");
83 error = create_dir(kobj); //利用kobj创建目录和属性文件,其中会判断,如果parent为NULL那么就在sysfs_root下创建
84 if (error) {
85 kobj_kset_leave(kobj);
86 kobject_put(parent);
87 kobj->parent = NULL;
88 /* be noisy on error issues */
89 if (error == -EEXIST)
90 printk(KERN_ERR "%s failed for %s with "
91 "-EEXIST, don't try to register things with "
92 "the same name in the same directory./n",
93 __func__, kobject_name(kobj));
94 else
95 printk(KERN_ERR "%s failed for %s (%d)/n",
96 __func__, kobject_name(kobj), error);
97 dump_stack();
98 } else
99 kobj->state_in_sysfs = 1;
100 return error;
101 }
102 ---static int create_dir(struct kobject *kobj)
103 {
104 int error = 0;
105 if (kobject_name(kobj)) {
106 error = sysfs_create_dir(kobj); //创建目录
107 if (!error) {
108 error = populate_dir(kobj); //创建属性文件
109 if (error)
110 sysfs_remove_dir(kobj);
111 }
112 }
113 return error;
114 }
三、关于 kset
首先看一下kset的原型
1 struct kset {
2 struct list_head list; //连接着他下面的kobj成员,与kobj-entry关联
3 spinlock_t list_lock;
4 struct kobject kobj; //代表kset自己
5 const struct kset_uevent_ops *uevent_ops;
6 };
再来看一下kset的初始化操作,kset表现为更高级一点的kobj,其初始化操作仍然是围绕其内部的kobj展开的。
1 struct kset *kset_create_and_add(const char *name,
2 const struct kset_uevent_ops *uevent_ops,
3 struct kobject *parent_kobj)
4 {
5 struct kset *kset;
6 int error;
7 kset = kset_create(name, uevent_ops, parent_kobj); //创建kset,关联操作函数和其父节点
8 if (!kset)
9 return NULL;
10 error = kset_register(kset);
11 if (error) {
12 kfree(kset);
13 return NULL;
14 }
15 return kset;
16 }
17 ---static struct kset *kset_create(const char *name,
18 const struct kset_uevent_ops *uevent_ops,
19 struct kobject *parent_kobj)
20 {
21 struct kset *kset;
22 int retval;
23 kset = kzalloc(sizeof(*kset), GFP_KERNEL); //申请结构体内存
24 if (!kset)
25 return NULL;
26 retval = kobject_set_name(&kset->kobj, name); //设置名字
27 if (retval) {
28 kfree(kset);
29 return NULL;
30 }
31 kset->uevent_ops = uevent_ops; //关联操作函数
32 kset->kobj.parent = parent_kobj; //关联父节点
33 /*
34 * The kobject of this kset will have a type of kset_ktype and belong to
35 * no kset itself. That way we can properly free it when it is
36 * finished being used.
37 */
38 kset->kobj.ktype = &kset_ktype; //关联属性文件
39 kset->kobj.kset = NULL;
40 return kset;
41 }
42 ----int kset_register(struct kset *k)
43 {
44 int err;
45 if (!k)
46 return -EINVAL;
47 kset_init(k);
48 err = kobject_add_internal(&k->kobj); //调用kobj操作函数
49 if (err)
50 return err;
51 kobject_uevent(&k->kobj, KOBJ_ADD);
52 return 0;
53 }
54 ----void kset_init(struct kset *k)
55 {
56 kobject_init_internal(&k->kobj); //调用kobj操作函数
57 INIT_LIST_HEAD(&k->list);
58 spin_lock_init(&k->list_lock);
59 }
四、上面给出了kobj,kset的初始化过程,以及相互产生关联的关键点,下面给出整体的一个流程图: