| |
| |
| |
| |
| |
| |
| |
| #include <linux/kobject.h> |
| #include <linux/string.h> |
| #include <linux/sysfs.h> |
| #include <linux/slab.h> |
| #include <linux/module.h> |
| #include <linux/init.h> |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| struct foo_obj { |
| <------>struct kobject kobj; |
| <------>int foo; |
| <------>int baz; |
| <------>int bar; |
| }; |
| #define to_foo_obj(x) container_of(x, struct foo_obj, kobj) |
| |
| |
| struct foo_attribute { |
| <------>struct attribute attr; |
| <------>ssize_t (*show)(struct foo_obj *foo, struct foo_attribute *attr, char *buf); |
| <------>ssize_t (*store)(struct foo_obj *foo, struct foo_attribute *attr, const char *buf, size_t count); |
| }; |
| #define to_foo_attr(x) container_of(x, struct foo_attribute, attr) |
| |
| |
| |
| |
| |
| |
| |
| |
| static ssize_t foo_attr_show(struct kobject *kobj, |
| <------><------><------> struct attribute *attr, |
| <------><------><------> char *buf) |
| { |
| <------>struct foo_attribute *attribute; |
| <------>struct foo_obj *foo; |
| |
| <------>attribute = to_foo_attr(attr); |
| <------>foo = to_foo_obj(kobj); |
| |
| <------>if (!attribute->show) |
| <------><------>return -EIO; |
| |
| <------>return attribute->show(foo, attribute, buf); |
| } |
| |
| |
| |
| |
| |
| static ssize_t foo_attr_store(struct kobject *kobj, |
| <------><------><------> struct attribute *attr, |
| <------><------><------> const char *buf, size_t len) |
| { |
| <------>struct foo_attribute *attribute; |
| <------>struct foo_obj *foo; |
| |
| <------>attribute = to_foo_attr(attr); |
| <------>foo = to_foo_obj(kobj); |
| |
| <------>if (!attribute->store) |
| <------><------>return -EIO; |
| |
| <------>return attribute->store(foo, attribute, buf, len); |
| } |
| |
| |
| static const struct sysfs_ops foo_sysfs_ops = { |
| <------>.show = foo_attr_show, |
| <------>.store = foo_attr_store, |
| }; |
| |
| |
| |
| |
| |
| |
| |
| |
| static void foo_release(struct kobject *kobj) |
| { |
| <------>struct foo_obj *foo; |
| |
| <------>foo = to_foo_obj(kobj); |
| <------>kfree(foo); |
| } |
| |
| |
| |
| |
| static ssize_t foo_show(struct foo_obj *foo_obj, struct foo_attribute *attr, |
| <------><------><------>char *buf) |
| { |
| <------>return sprintf(buf, "%d\n", foo_obj->foo); |
| } |
| |
| static ssize_t foo_store(struct foo_obj *foo_obj, struct foo_attribute *attr, |
| <------><------><------> const char *buf, size_t count) |
| { |
| <------>int ret; |
| |
| <------>ret = kstrtoint(buf, 10, &foo_obj->foo); |
| <------>if (ret < 0) |
| <------><------>return ret; |
| |
| <------>return count; |
| } |
| |
| |
| static struct foo_attribute foo_attribute = |
| <------>__ATTR(foo, 0664, foo_show, foo_store); |
| |
| |
| |
| |
| |
| static ssize_t b_show(struct foo_obj *foo_obj, struct foo_attribute *attr, |
| <------><------> char *buf) |
| { |
| <------>int var; |
| |
| <------>if (strcmp(attr->attr.name, "baz") == 0) |
| <------><------>var = foo_obj->baz; |
| <------>else |
| <------><------>var = foo_obj->bar; |
| <------>return sprintf(buf, "%d\n", var); |
| } |
| |
| static ssize_t b_store(struct foo_obj *foo_obj, struct foo_attribute *attr, |
| <------><------> const char *buf, size_t count) |
| { |
| <------>int var, ret; |
| |
| <------>ret = kstrtoint(buf, 10, &var); |
| <------>if (ret < 0) |
| <------><------>return ret; |
| |
| <------>if (strcmp(attr->attr.name, "baz") == 0) |
| <------><------>foo_obj->baz = var; |
| <------>else |
| <------><------>foo_obj->bar = var; |
| <------>return count; |
| } |
| |
| static struct foo_attribute baz_attribute = |
| <------>__ATTR(baz, 0664, b_show, b_store); |
| static struct foo_attribute bar_attribute = |
| <------>__ATTR(bar, 0664, b_show, b_store); |
| |
| |
| |
| |
| |
| static struct attribute *foo_default_attrs[] = { |
| <------>&foo_attribute.attr, |
| <------>&baz_attribute.attr, |
| <------>&bar_attribute.attr, |
| <------>NULL, |
| }; |
| ATTRIBUTE_GROUPS(foo_default); |
| |
| |
| |
| |
| |
| |
| static struct kobj_type foo_ktype = { |
| <------>.sysfs_ops = &foo_sysfs_ops, |
| <------>.release = foo_release, |
| <------>.default_groups = foo_default_groups, |
| }; |
| |
| static struct kset *example_kset; |
| static struct foo_obj *foo_obj; |
| static struct foo_obj *bar_obj; |
| static struct foo_obj *baz_obj; |
| |
| static struct foo_obj *create_foo_obj(const char *name) |
| { |
| <------>struct foo_obj *foo; |
| <------>int retval; |
| |
| <------> |
| <------>foo = kzalloc(sizeof(*foo), GFP_KERNEL); |
| <------>if (!foo) |
| <------><------>return NULL; |
| |
| <------> |
| <------> * As we have a kset for this kobject, we need to set it before calling |
| <------> * the kobject core. |
| <------> */ |
| <------>foo->kobj.kset = example_kset; |
| |
| <------> |
| <------> * Initialize and add the kobject to the kernel. All the default files |
| <------> * will be created here. As we have already specified a kset for this |
| <------> * kobject, we don't have to set a parent for the kobject, the kobject |
| <------> * will be placed beneath that kset automatically. |
| <------> */ |
| <------>retval = kobject_init_and_add(&foo->kobj, &foo_ktype, NULL, "%s", name); |
| <------>if (retval) { |
| <------><------>kobject_put(&foo->kobj); |
| <------><------>return NULL; |
| <------>} |
| |
| <------> |
| <------> * We are always responsible for sending the uevent that the kobject |
| <------> * was added to the system. |
| <------> */ |
| <------>kobject_uevent(&foo->kobj, KOBJ_ADD); |
| |
| <------>return foo; |
| } |
| |
| static void destroy_foo_obj(struct foo_obj *foo) |
| { |
| <------>kobject_put(&foo->kobj); |
| } |
| |
| static int __init example_init(void) |
| { |
| <------> |
| <------> * Create a kset with the name of "kset_example", |
| <------> * located under /sys/kernel/ |
| <------> */ |
| <------>example_kset = kset_create_and_add("kset_example", NULL, kernel_kobj); |
| <------>if (!example_kset) |
| <------><------>return -ENOMEM; |
| |
| <------> |
| <------> * Create three objects and register them with our kset |
| <------> */ |
| <------>foo_obj = create_foo_obj("foo"); |
| <------>if (!foo_obj) |
| <------><------>goto foo_error; |
| |
| <------>bar_obj = create_foo_obj("bar"); |
| <------>if (!bar_obj) |
| <------><------>goto bar_error; |
| |
| <------>baz_obj = create_foo_obj("baz"); |
| <------>if (!baz_obj) |
| <------><------>goto baz_error; |
| |
| <------>return 0; |
| |
| baz_error: |
| <------>destroy_foo_obj(bar_obj); |
| bar_error: |
| <------>destroy_foo_obj(foo_obj); |
| foo_error: |
| <------>kset_unregister(example_kset); |
| <------>return -EINVAL; |
| } |
| |
| static void __exit example_exit(void) |
| { |
| <------>destroy_foo_obj(baz_obj); |
| <------>destroy_foo_obj(bar_obj); |
| <------>destroy_foo_obj(foo_obj); |
| <------>kset_unregister(example_kset); |
| } |
| |
| module_init(example_init); |
| module_exit(example_exit); |
| MODULE_LICENSE("GPL v2"); |
| MODULE_AUTHOR("Greg Kroah-Hartman <greg@kroah.com>"); |
| |