aboutsummaryrefslogtreecommitdiffstats
path: root/samples/kobject/kset-example.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2008-01-25 11:34:42 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2008-01-25 11:35:13 -0500
commitdf8dc74e8a383eaf2d9b44b80a71ec6f0e52b42e (patch)
treebc3799a43e8b94fa84b32e37b1c124d5e4868f50 /samples/kobject/kset-example.c
parent556a169dab38b5100df6f4a45b655dddd3db94c1 (diff)
parent4a3ad20ccd8f4d2a0535cf98fa83f7b561ba59a9 (diff)
Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-2.6
This can be broken down into these major areas: - Documentation updates (language translations and fixes, as well as kobject and kset documenatation updates.) - major kset/kobject/ktype rework and fixes. This cleans up the kset and kobject and ktype relationship and architecture, making sense of things now, and good documenation and samples are provided for others to use. Also the attributes for kobjects are much easier to handle now. This cleaned up a LOT of code all through the kernel, making kobjects easier to use if you want to. - struct bus_type has been reworked to now handle the lifetime rules properly, as the kobject is properly dynamic. - struct driver has also been reworked, and now the lifetime issues are resolved. - the block subsystem has been converted to use struct device now, and not "raw" kobjects. This patch has been in the -mm tree for over a year now, and finally all the issues are worked out with it. Older distros now properly work with new kernels, and no userspace updates are needed at all. - nozomi driver is added. This has also been in -mm for a long time, and many people have asked for it to go in. It is now in good enough shape to do so. - lots of class_device conversions to use struct device instead. The tree is almost all cleaned up now, only SCSI and IB is the remaining code to fix up... * git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-2.6: (196 commits) Driver core: coding style fixes Kobject: fix coding style issues in kobject c files Kobject: fix coding style issues in kobject.h Driver core: fix coding style issues in device.h spi: use class iteration api scsi: use class iteration api rtc: use class iteration api power supply : use class iteration api ieee1394: use class iteration api Driver Core: add class iteration api Driver core: Cleanup get_device_parent() in device_add() and device_move() UIO: constify function pointer tables Driver Core: constify the name passed to platform_device_register_simple driver core: fix build with SYSFS=n sysfs: make SYSFS_DEPRECATED depend on SYSFS Driver core: use LIST_HEAD instead of call to INIT_LIST_HEAD in __init kobject: add sample code for how to use ksets/ktypes/kobjects kobject: add sample code for how to use kobjects in a simple manner. kobject: update the kobject/kset documentation kobject: remove old, outdated documentation. ...
Diffstat (limited to 'samples/kobject/kset-example.c')
-rw-r--r--samples/kobject/kset-example.c278
1 files changed, 278 insertions, 0 deletions
diff --git a/samples/kobject/kset-example.c b/samples/kobject/kset-example.c
new file mode 100644
index 000000000000..b0a1b4fe6584
--- /dev/null
+++ b/samples/kobject/kset-example.c
@@ -0,0 +1,278 @@
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 */
30struct 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. */
39struct 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 */
53static 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 */
73static 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 */
90static 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 */
102static 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 */
113static 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
119static 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
126static 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 */
133static 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
145static 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
158static struct foo_attribute baz_attribute =
159 __ATTR(baz, 0666, b_show, b_store);
160static 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 */
167static 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 */
179static struct kobj_type foo_ktype = {
180 .sysfs_ops = &foo_sysfs_ops,
181 .release = foo_release,
182 .default_attrs = foo_default_attrs,
183};
184
185static struct kset *example_kset;
186static struct foo_obj *foo_obj;
187static struct foo_obj *bar_obj;
188static struct foo_obj *baz_obj;
189
190static 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
227static void destroy_foo_obj(struct foo_obj *foo)
228{
229 kobject_put(&foo->kobj);
230}
231
232static 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
259baz_error:
260 destroy_foo_obj(bar_obj);
261bar_error:
262 destroy_foo_obj(foo_obj);
263foo_error:
264 return -EINVAL;
265}
266
267static 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
275module_init(example_init);
276module_exit(example_exit);
277MODULE_LICENSE("GPL");
278MODULE_AUTHOR("Greg Kroah-Hartman <greg@kroah.com>");