1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
|
/*
* kobject.c - library routines for handling generic kernel objects
*/
#define DEBUG 0
#include <linux/kobject.h>
#include <linux/string.h>
#include <linux/module.h>
#include <linux/stat.h>
/**
* kobject_populate_dir - populate directory with attributes.
* @kobj: object we're working on.
*
* Most subsystems have a set of default attributes that
* are associated with an object that registers with them.
* This is a helper called during object registration that
* loops through the default attributes of the subsystem
* and creates attributes files for them in sysfs.
*
*/
static int kobject_populate_dir(struct kobject * kobj)
{
struct subsystem * s = kobj->subsys;
struct attribute * attr;
int error = 0;
int i;
if (s && s->default_attrs) {
for (i = 0; (attr = s->default_attrs[i]); i++) {
if ((error = sysfs_create_file(kobj,attr)))
break;
}
}
return error;
}
/**
* kobject_init - initialize object.
* @kobj: object in question.
*/
void kobject_init(struct kobject * kobj)
{
atomic_set(&kobj->refcount,1);
INIT_LIST_HEAD(&kobj->entry);
}
/**
* kobject_register - register an object.
* @kobj: object in question.
*
* For now, fill in the replicated fields in the object's
* directory entry, and create a dir in sysfs.
* This stuff should go away in the future, as we move
* more implicit things to sysfs.
*/
int kobject_register(struct kobject * kobj)
{
int error = 0;
struct subsystem * s = subsys_get(kobj->subsys);
struct kobject * parent = kobject_get(kobj->parent);
pr_debug("kobject %s: registering\n",kobj->name);
if (parent)
pr_debug(" parent is %s\n",parent->name);
if (s) {
down_write(&s->rwsem);
if (parent)
list_add_tail(&kobj->entry,&parent->entry);
else {
list_add_tail(&kobj->entry,&s->list);
kobj->parent = &s->kobj;
}
up_write(&s->rwsem);
}
if (strlen(kobj->name)) {
error = sysfs_create_dir(kobj);
if (!error) {
error = kobject_populate_dir(kobj);
if (error)
sysfs_remove_dir(kobj);
}
}
return error;
}
/**
* kobject_unregister - unlink an object.
* @kobj: object going away.
*
* The device has been told to be removed, but may
* not necessarily be disappearing from the kernel.
* So, we remove the directory and decrement the refcount
* that we set with kobject_register().
*
* Eventually (maybe now), the refcount will hit 0, and
* put_device() will clean the device up.
*/
void kobject_unregister(struct kobject * kobj)
{
pr_debug("kobject %s: unregistering\n",kobj->name);
sysfs_remove_dir(kobj);
if (kobj->subsys) {
down_write(&kobj->subsys->rwsem);
list_del_init(&kobj->entry);
up_write(&kobj->subsys->rwsem);
}
kobject_put(kobj);
}
/**
* kobject_get - increment refcount for object.
* @kobj: object.
*/
struct kobject * kobject_get(struct kobject * kobj)
{
struct kobject * ret = kobj;
if (kobj && atomic_read(&kobj->refcount) > 0)
atomic_inc(&kobj->refcount);
else
ret = NULL;
return ret;
}
/**
* kobject_put - decrement refcount for object.
* @kobj: object.
*
* Decrement the refcount, and check if 0. If it is, then
* we're gonna need to clean it up, and decrement the refcount
* of its parent.
*
* @kobj->parent could point to its subsystem, which we also
* want to decrement the reference count for. We always dec
* the refcount for the parent, but only do so for the subsystem
* if it points to a different place than the parent.
*/
void kobject_put(struct kobject * kobj)
{
struct kobject * parent = kobj->parent;
struct subsystem * s = kobj->subsys;
if (!atomic_dec_and_test(&kobj->refcount))
return;
pr_debug("kobject %s: cleaning up\n",kobj->name);
if (s) {
if (s->release)
s->release(kobj);
if (&s->kobj != parent)
subsys_put(s);
}
if (parent)
kobject_put(parent);
}
void subsystem_init(struct subsystem * s)
{
kobject_init(&s->kobj);
init_rwsem(&s->rwsem);
INIT_LIST_HEAD(&s->list);
}
/**
* subsystem_register - register a subsystem.
* @s: the subsystem we're registering.
*/
int subsystem_register(struct subsystem * s)
{
subsystem_init(s);
if (s->parent)
s->kobj.parent = &s->parent->kobj;
pr_debug("subsystem %s: registering\n",s->kobj.name);
if (s->parent)
pr_debug(" parent is %s\n",s->parent->kobj.name);
return kobject_register(&s->kobj);
}
void subsystem_unregister(struct subsystem * s)
{
pr_debug("subsystem %s: unregistering\n",s->kobj.name);
kobject_unregister(&s->kobj);
}
EXPORT_SYMBOL(kobject_init);
EXPORT_SYMBOL(kobject_register);
EXPORT_SYMBOL(kobject_unregister);
EXPORT_SYMBOL(kobject_get);
EXPORT_SYMBOL(kobject_put);
EXPORT_SYMBOL(subsystem_init);
EXPORT_SYMBOL(subsystem_register);
EXPORT_SYMBOL(subsystem_unregister);
|