Commit 44bfe16e1083d66f97a5289e359c52ee2c8b19a7
1 parent
40efcb05f2
Exists in
master
and in
20 other branches
kobject: add sample code for how to use ksets/ktypes/kobjects
This is a more complex example showing how to create a kset and a ktype and some default attributes for a group of kobjects. Cc: Kay Sievers <kay.sievers@vrfy.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Showing 2 changed files with 279 additions and 1 deletions Side-by-side Diff
samples/kobject/Makefile
samples/kobject/kset-example.c
1 | +/* | |
2 | + * Sample kset and ktype implementation | |
3 | + * | |
4 | + * Copyright (C) 2004-2007 Greg Kroah-Hartman <greg@kroah.com> | |
5 | + * Copyright (C) 2007 Novell Inc. | |
6 | + * | |
7 | + * Released under the GPL version 2 only. | |
8 | + * | |
9 | + */ | |
10 | +#include <linux/kobject.h> | |
11 | +#include <linux/string.h> | |
12 | +#include <linux/sysfs.h> | |
13 | +#include <linux/module.h> | |
14 | +#include <linux/init.h> | |
15 | + | |
16 | +/* | |
17 | + * This module shows how to create a kset in sysfs called | |
18 | + * /sys/kernel/kset-example | |
19 | + * Then tree kobjects are created and assigned to this kset, "foo", "baz", | |
20 | + * and "bar". In those kobjects, attributes of the same name are also | |
21 | + * created and if an integer is written to these files, it can be later | |
22 | + * read out of it. | |
23 | + */ | |
24 | + | |
25 | + | |
26 | +/* | |
27 | + * This is our "object" that we will create a few of and register them with | |
28 | + * sysfs. | |
29 | + */ | |
30 | +struct foo_obj { | |
31 | + struct kobject kobj; | |
32 | + int foo; | |
33 | + int baz; | |
34 | + int bar; | |
35 | +}; | |
36 | +#define to_foo_obj(x) container_of(x, struct foo_obj, kobj) | |
37 | + | |
38 | +/* a custom attribute that works just for a struct foo_obj. */ | |
39 | +struct foo_attribute { | |
40 | + struct attribute attr; | |
41 | + ssize_t (*show)(struct foo_obj *foo, struct foo_attribute *attr, char *buf); | |
42 | + ssize_t (*store)(struct foo_obj *foo, struct foo_attribute *attr, const char *buf, size_t count); | |
43 | +}; | |
44 | +#define to_foo_attr(x) container_of(x, struct foo_attribute, attr) | |
45 | + | |
46 | +/* | |
47 | + * The default show function that must be passed to sysfs. This will be | |
48 | + * called by sysfs for whenever a show function is called by the user on a | |
49 | + * sysfs file associated with the kobjects we have registered. We need to | |
50 | + * transpose back from a "default" kobject to our custom struct foo_obj and | |
51 | + * then call the show function for that specific object. | |
52 | + */ | |
53 | +static ssize_t foo_attr_show(struct kobject *kobj, | |
54 | + struct attribute *attr, | |
55 | + char *buf) | |
56 | +{ | |
57 | + struct foo_attribute *attribute; | |
58 | + struct foo_obj *foo; | |
59 | + | |
60 | + attribute = to_foo_attr(attr); | |
61 | + foo = to_foo_obj(kobj); | |
62 | + | |
63 | + if (!attribute->show) | |
64 | + return -EIO; | |
65 | + | |
66 | + return attribute->show(foo, attribute, buf); | |
67 | +} | |
68 | + | |
69 | +/* | |
70 | + * Just like the default show function above, but this one is for when the | |
71 | + * sysfs "store" is requested (when a value is written to a file.) | |
72 | + */ | |
73 | +static ssize_t foo_attr_store(struct kobject *kobj, | |
74 | + struct attribute *attr, | |
75 | + const char *buf, size_t len) | |
76 | +{ | |
77 | + struct foo_attribute *attribute; | |
78 | + struct foo_obj *foo; | |
79 | + | |
80 | + attribute = to_foo_attr(attr); | |
81 | + foo = to_foo_obj(kobj); | |
82 | + | |
83 | + if (!attribute->store) | |
84 | + return -EIO; | |
85 | + | |
86 | + return attribute->store(foo, attribute, buf, len); | |
87 | +} | |
88 | + | |
89 | +/* Our custom sysfs_ops that we will associate with our ktype later on */ | |
90 | +static struct sysfs_ops foo_sysfs_ops = { | |
91 | + .show = foo_attr_show, | |
92 | + .store = foo_attr_store, | |
93 | +}; | |
94 | + | |
95 | +/* | |
96 | + * The release function for our object. This is REQUIRED by the kernel to | |
97 | + * have. We free the memory held in our object here. | |
98 | + * | |
99 | + * NEVER try to get away with just a "blank" release function to try to be | |
100 | + * smarter than the kernel. Turns out, no one ever is... | |
101 | + */ | |
102 | +static void foo_release(struct kobject *kobj) | |
103 | +{ | |
104 | + struct foo_obj *foo; | |
105 | + | |
106 | + foo = to_foo_obj(kobj); | |
107 | + kfree(foo); | |
108 | +} | |
109 | + | |
110 | +/* | |
111 | + * The "foo" file where the .foo variable is read from and written to. | |
112 | + */ | |
113 | +static ssize_t foo_show(struct foo_obj *foo_obj, struct foo_attribute *attr, | |
114 | + char *buf) | |
115 | +{ | |
116 | + return sprintf(buf, "%d\n", foo_obj->foo); | |
117 | +} | |
118 | + | |
119 | +static ssize_t foo_store(struct foo_obj *foo_obj, struct foo_attribute *attr, | |
120 | + const char *buf, size_t count) | |
121 | +{ | |
122 | + sscanf(buf, "%du", &foo_obj->foo); | |
123 | + return count; | |
124 | +} | |
125 | + | |
126 | +static struct foo_attribute foo_attribute = | |
127 | + __ATTR(foo, 0666, foo_show, foo_store); | |
128 | + | |
129 | +/* | |
130 | + * More complex function where we determine which varible is being accessed by | |
131 | + * looking at the attribute for the "baz" and "bar" files. | |
132 | + */ | |
133 | +static ssize_t b_show(struct foo_obj *foo_obj, struct foo_attribute *attr, | |
134 | + char *buf) | |
135 | +{ | |
136 | + int var; | |
137 | + | |
138 | + if (strcmp(attr->attr.name, "baz") == 0) | |
139 | + var = foo_obj->baz; | |
140 | + else | |
141 | + var = foo_obj->bar; | |
142 | + return sprintf(buf, "%d\n", var); | |
143 | +} | |
144 | + | |
145 | +static ssize_t b_store(struct foo_obj *foo_obj, struct foo_attribute *attr, | |
146 | + const char *buf, size_t count) | |
147 | +{ | |
148 | + int var; | |
149 | + | |
150 | + sscanf(buf, "%du", &var); | |
151 | + if (strcmp(attr->attr.name, "baz") == 0) | |
152 | + foo_obj->baz = var; | |
153 | + else | |
154 | + foo_obj->bar = var; | |
155 | + return count; | |
156 | +} | |
157 | + | |
158 | +static struct foo_attribute baz_attribute = | |
159 | + __ATTR(baz, 0666, b_show, b_store); | |
160 | +static struct foo_attribute bar_attribute = | |
161 | + __ATTR(bar, 0666, b_show, b_store); | |
162 | + | |
163 | +/* | |
164 | + * Create a group of attributes so that we can create and destory them all | |
165 | + * at once. | |
166 | + */ | |
167 | +static struct attribute *foo_default_attrs[] = { | |
168 | + &foo_attribute.attr, | |
169 | + &baz_attribute.attr, | |
170 | + &bar_attribute.attr, | |
171 | + NULL, /* need to NULL terminate the list of attributes */ | |
172 | +}; | |
173 | + | |
174 | +/* | |
175 | + * Our own ktype for our kobjects. Here we specify our sysfs ops, the | |
176 | + * release function, and the set of default attributes we want created | |
177 | + * whenever a kobject of this type is registered with the kernel. | |
178 | + */ | |
179 | +static struct kobj_type foo_ktype = { | |
180 | + .sysfs_ops = &foo_sysfs_ops, | |
181 | + .release = foo_release, | |
182 | + .default_attrs = foo_default_attrs, | |
183 | +}; | |
184 | + | |
185 | +static struct kset *example_kset; | |
186 | +static struct foo_obj *foo_obj; | |
187 | +static struct foo_obj *bar_obj; | |
188 | +static struct foo_obj *baz_obj; | |
189 | + | |
190 | +static struct foo_obj *create_foo_obj(const char *name) | |
191 | +{ | |
192 | + struct foo_obj *foo; | |
193 | + int retval; | |
194 | + | |
195 | + /* allocate the memory for the whole object */ | |
196 | + foo = kzalloc(sizeof(*foo), GFP_KERNEL); | |
197 | + if (!foo) | |
198 | + return NULL; | |
199 | + | |
200 | + /* | |
201 | + * As we have a kset for this kobject, we need to set it before calling | |
202 | + * the kobject core. | |
203 | + */ | |
204 | + foo->kobj.kset = example_kset; | |
205 | + | |
206 | + /* | |
207 | + * Initialize and add the kobject to the kernel. All the default files | |
208 | + * will be created here. As we have already specified a kset for this | |
209 | + * kobject, we don't have to set a parent for the kobject, the kobject | |
210 | + * will be placed beneath that kset automatically. | |
211 | + */ | |
212 | + retval = kobject_init_and_add(&foo->kobj, &foo_ktype, NULL, "%s", name); | |
213 | + if (retval) { | |
214 | + kfree(foo); | |
215 | + return NULL; | |
216 | + } | |
217 | + | |
218 | + /* | |
219 | + * We are always responsible for sending the uevent that the kobject | |
220 | + * was added to the system. | |
221 | + */ | |
222 | + kobject_uevent(&foo->kobj, KOBJ_ADD); | |
223 | + | |
224 | + return foo; | |
225 | +} | |
226 | + | |
227 | +static void destroy_foo_obj(struct foo_obj *foo) | |
228 | +{ | |
229 | + kobject_put(&foo->kobj); | |
230 | +} | |
231 | + | |
232 | +static int example_init(void) | |
233 | +{ | |
234 | + /* | |
235 | + * Create a kset with the name of "kset_example", | |
236 | + * located under /sys/kernel/ | |
237 | + */ | |
238 | + example_kset = kset_create_and_add("kset_example", NULL, kernel_kobj); | |
239 | + if (!example_kset) | |
240 | + return -ENOMEM; | |
241 | + | |
242 | + /* | |
243 | + * Create three objects and register them with our kset | |
244 | + */ | |
245 | + foo_obj = create_foo_obj("foo"); | |
246 | + if (!foo_obj) | |
247 | + goto foo_error; | |
248 | + | |
249 | + bar_obj = create_foo_obj("bar"); | |
250 | + if (!bar_obj) | |
251 | + goto bar_error; | |
252 | + | |
253 | + baz_obj = create_foo_obj("baz"); | |
254 | + if (!baz_obj) | |
255 | + goto baz_error; | |
256 | + | |
257 | + return 0; | |
258 | + | |
259 | +baz_error: | |
260 | + destroy_foo_obj(bar_obj); | |
261 | +bar_error: | |
262 | + destroy_foo_obj(foo_obj); | |
263 | +foo_error: | |
264 | + return -EINVAL; | |
265 | +} | |
266 | + | |
267 | +static void example_exit(void) | |
268 | +{ | |
269 | + destroy_foo_obj(baz_obj); | |
270 | + destroy_foo_obj(bar_obj); | |
271 | + destroy_foo_obj(foo_obj); | |
272 | + kset_unregister(example_kset); | |
273 | +} | |
274 | + | |
275 | +module_init(example_init); | |
276 | +module_exit(example_exit); | |
277 | +MODULE_LICENSE("GPL"); | |
278 | +MODULE_AUTHOR("Greg Kroah-Hartman <greg@kroah.com>"); |