1d9d16e16SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
244bfe16eSGreg Kroah-Hartman /*
344bfe16eSGreg Kroah-Hartman * Sample kset and ktype implementation
444bfe16eSGreg Kroah-Hartman *
544bfe16eSGreg Kroah-Hartman * Copyright (C) 2004-2007 Greg Kroah-Hartman <greg@kroah.com>
644bfe16eSGreg Kroah-Hartman * Copyright (C) 2007 Novell Inc.
744bfe16eSGreg Kroah-Hartman */
844bfe16eSGreg Kroah-Hartman #include <linux/kobject.h>
944bfe16eSGreg Kroah-Hartman #include <linux/string.h>
1044bfe16eSGreg Kroah-Hartman #include <linux/sysfs.h>
115a0e3ad6STejun Heo #include <linux/slab.h>
1244bfe16eSGreg Kroah-Hartman #include <linux/module.h>
1344bfe16eSGreg Kroah-Hartman #include <linux/init.h>
1444bfe16eSGreg Kroah-Hartman
1544bfe16eSGreg Kroah-Hartman /*
1644bfe16eSGreg Kroah-Hartman * This module shows how to create a kset in sysfs called
1744bfe16eSGreg Kroah-Hartman * /sys/kernel/kset-example
1844bfe16eSGreg Kroah-Hartman * Then tree kobjects are created and assigned to this kset, "foo", "baz",
1944bfe16eSGreg Kroah-Hartman * and "bar". In those kobjects, attributes of the same name are also
2044bfe16eSGreg Kroah-Hartman * created and if an integer is written to these files, it can be later
2144bfe16eSGreg Kroah-Hartman * read out of it.
2244bfe16eSGreg Kroah-Hartman */
2344bfe16eSGreg Kroah-Hartman
2444bfe16eSGreg Kroah-Hartman
2544bfe16eSGreg Kroah-Hartman /*
2644bfe16eSGreg Kroah-Hartman * This is our "object" that we will create a few of and register them with
2744bfe16eSGreg Kroah-Hartman * sysfs.
2844bfe16eSGreg Kroah-Hartman */
2944bfe16eSGreg Kroah-Hartman struct foo_obj {
3044bfe16eSGreg Kroah-Hartman struct kobject kobj;
3144bfe16eSGreg Kroah-Hartman int foo;
3244bfe16eSGreg Kroah-Hartman int baz;
3344bfe16eSGreg Kroah-Hartman int bar;
3444bfe16eSGreg Kroah-Hartman };
3544bfe16eSGreg Kroah-Hartman #define to_foo_obj(x) container_of(x, struct foo_obj, kobj)
3644bfe16eSGreg Kroah-Hartman
3744bfe16eSGreg Kroah-Hartman /* a custom attribute that works just for a struct foo_obj. */
3844bfe16eSGreg Kroah-Hartman struct foo_attribute {
3944bfe16eSGreg Kroah-Hartman struct attribute attr;
4044bfe16eSGreg Kroah-Hartman ssize_t (*show)(struct foo_obj *foo, struct foo_attribute *attr, char *buf);
4144bfe16eSGreg Kroah-Hartman ssize_t (*store)(struct foo_obj *foo, struct foo_attribute *attr, const char *buf, size_t count);
4244bfe16eSGreg Kroah-Hartman };
4344bfe16eSGreg Kroah-Hartman #define to_foo_attr(x) container_of(x, struct foo_attribute, attr)
4444bfe16eSGreg Kroah-Hartman
4544bfe16eSGreg Kroah-Hartman /*
4644bfe16eSGreg Kroah-Hartman * The default show function that must be passed to sysfs. This will be
4744bfe16eSGreg Kroah-Hartman * called by sysfs for whenever a show function is called by the user on a
4844bfe16eSGreg Kroah-Hartman * sysfs file associated with the kobjects we have registered. We need to
4944bfe16eSGreg Kroah-Hartman * transpose back from a "default" kobject to our custom struct foo_obj and
5044bfe16eSGreg Kroah-Hartman * then call the show function for that specific object.
5144bfe16eSGreg Kroah-Hartman */
foo_attr_show(struct kobject * kobj,struct attribute * attr,char * buf)5244bfe16eSGreg Kroah-Hartman static ssize_t foo_attr_show(struct kobject *kobj,
5344bfe16eSGreg Kroah-Hartman struct attribute *attr,
5444bfe16eSGreg Kroah-Hartman char *buf)
5544bfe16eSGreg Kroah-Hartman {
5644bfe16eSGreg Kroah-Hartman struct foo_attribute *attribute;
5744bfe16eSGreg Kroah-Hartman struct foo_obj *foo;
5844bfe16eSGreg Kroah-Hartman
5944bfe16eSGreg Kroah-Hartman attribute = to_foo_attr(attr);
6044bfe16eSGreg Kroah-Hartman foo = to_foo_obj(kobj);
6144bfe16eSGreg Kroah-Hartman
6244bfe16eSGreg Kroah-Hartman if (!attribute->show)
6344bfe16eSGreg Kroah-Hartman return -EIO;
6444bfe16eSGreg Kroah-Hartman
6544bfe16eSGreg Kroah-Hartman return attribute->show(foo, attribute, buf);
6644bfe16eSGreg Kroah-Hartman }
6744bfe16eSGreg Kroah-Hartman
6844bfe16eSGreg Kroah-Hartman /*
6944bfe16eSGreg Kroah-Hartman * Just like the default show function above, but this one is for when the
7044bfe16eSGreg Kroah-Hartman * sysfs "store" is requested (when a value is written to a file.)
7144bfe16eSGreg Kroah-Hartman */
foo_attr_store(struct kobject * kobj,struct attribute * attr,const char * buf,size_t len)7244bfe16eSGreg Kroah-Hartman static ssize_t foo_attr_store(struct kobject *kobj,
7344bfe16eSGreg Kroah-Hartman struct attribute *attr,
7444bfe16eSGreg Kroah-Hartman const char *buf, size_t len)
7544bfe16eSGreg Kroah-Hartman {
7644bfe16eSGreg Kroah-Hartman struct foo_attribute *attribute;
7744bfe16eSGreg Kroah-Hartman struct foo_obj *foo;
7844bfe16eSGreg Kroah-Hartman
7944bfe16eSGreg Kroah-Hartman attribute = to_foo_attr(attr);
8044bfe16eSGreg Kroah-Hartman foo = to_foo_obj(kobj);
8144bfe16eSGreg Kroah-Hartman
8244bfe16eSGreg Kroah-Hartman if (!attribute->store)
8344bfe16eSGreg Kroah-Hartman return -EIO;
8444bfe16eSGreg Kroah-Hartman
8544bfe16eSGreg Kroah-Hartman return attribute->store(foo, attribute, buf, len);
8644bfe16eSGreg Kroah-Hartman }
8744bfe16eSGreg Kroah-Hartman
8844bfe16eSGreg Kroah-Hartman /* Our custom sysfs_ops that we will associate with our ktype later on */
8952cf25d0SEmese Revfy static const struct sysfs_ops foo_sysfs_ops = {
9044bfe16eSGreg Kroah-Hartman .show = foo_attr_show,
9144bfe16eSGreg Kroah-Hartman .store = foo_attr_store,
9244bfe16eSGreg Kroah-Hartman };
9344bfe16eSGreg Kroah-Hartman
9444bfe16eSGreg Kroah-Hartman /*
9544bfe16eSGreg Kroah-Hartman * The release function for our object. This is REQUIRED by the kernel to
9644bfe16eSGreg Kroah-Hartman * have. We free the memory held in our object here.
9744bfe16eSGreg Kroah-Hartman *
9844bfe16eSGreg Kroah-Hartman * NEVER try to get away with just a "blank" release function to try to be
9944bfe16eSGreg Kroah-Hartman * smarter than the kernel. Turns out, no one ever is...
10044bfe16eSGreg Kroah-Hartman */
foo_release(struct kobject * kobj)10144bfe16eSGreg Kroah-Hartman static void foo_release(struct kobject *kobj)
10244bfe16eSGreg Kroah-Hartman {
10344bfe16eSGreg Kroah-Hartman struct foo_obj *foo;
10444bfe16eSGreg Kroah-Hartman
10544bfe16eSGreg Kroah-Hartman foo = to_foo_obj(kobj);
10644bfe16eSGreg Kroah-Hartman kfree(foo);
10744bfe16eSGreg Kroah-Hartman }
10844bfe16eSGreg Kroah-Hartman
10944bfe16eSGreg Kroah-Hartman /*
11044bfe16eSGreg Kroah-Hartman * The "foo" file where the .foo variable is read from and written to.
11144bfe16eSGreg Kroah-Hartman */
foo_show(struct foo_obj * foo_obj,struct foo_attribute * attr,char * buf)11244bfe16eSGreg Kroah-Hartman static ssize_t foo_show(struct foo_obj *foo_obj, struct foo_attribute *attr,
11344bfe16eSGreg Kroah-Hartman char *buf)
11444bfe16eSGreg Kroah-Hartman {
1155a242d85SNguyen Dinh Phi return sysfs_emit(buf, "%d\n", foo_obj->foo);
11644bfe16eSGreg Kroah-Hartman }
11744bfe16eSGreg Kroah-Hartman
foo_store(struct foo_obj * foo_obj,struct foo_attribute * attr,const char * buf,size_t count)11844bfe16eSGreg Kroah-Hartman static ssize_t foo_store(struct foo_obj *foo_obj, struct foo_attribute *attr,
11944bfe16eSGreg Kroah-Hartman const char *buf, size_t count)
12044bfe16eSGreg Kroah-Hartman {
1215fd637e7SRastislav Barlik int ret;
1225fd637e7SRastislav Barlik
1235fd637e7SRastislav Barlik ret = kstrtoint(buf, 10, &foo_obj->foo);
1245fd637e7SRastislav Barlik if (ret < 0)
1255fd637e7SRastislav Barlik return ret;
1265fd637e7SRastislav Barlik
12744bfe16eSGreg Kroah-Hartman return count;
12844bfe16eSGreg Kroah-Hartman }
12944bfe16eSGreg Kroah-Hartman
130de510989SRusty Russell /* Sysfs attributes cannot be world-writable. */
13144bfe16eSGreg Kroah-Hartman static struct foo_attribute foo_attribute =
132de510989SRusty Russell __ATTR(foo, 0664, foo_show, foo_store);
13344bfe16eSGreg Kroah-Hartman
13444bfe16eSGreg Kroah-Hartman /*
13520ef9f46SRadu Voicilas * More complex function where we determine which variable is being accessed by
13644bfe16eSGreg Kroah-Hartman * looking at the attribute for the "baz" and "bar" files.
13744bfe16eSGreg Kroah-Hartman */
b_show(struct foo_obj * foo_obj,struct foo_attribute * attr,char * buf)13844bfe16eSGreg Kroah-Hartman static ssize_t b_show(struct foo_obj *foo_obj, struct foo_attribute *attr,
13944bfe16eSGreg Kroah-Hartman char *buf)
14044bfe16eSGreg Kroah-Hartman {
14144bfe16eSGreg Kroah-Hartman int var;
14244bfe16eSGreg Kroah-Hartman
14344bfe16eSGreg Kroah-Hartman if (strcmp(attr->attr.name, "baz") == 0)
14444bfe16eSGreg Kroah-Hartman var = foo_obj->baz;
14544bfe16eSGreg Kroah-Hartman else
14644bfe16eSGreg Kroah-Hartman var = foo_obj->bar;
1475a242d85SNguyen Dinh Phi return sysfs_emit(buf, "%d\n", var);
14844bfe16eSGreg Kroah-Hartman }
14944bfe16eSGreg Kroah-Hartman
b_store(struct foo_obj * foo_obj,struct foo_attribute * attr,const char * buf,size_t count)15044bfe16eSGreg Kroah-Hartman static ssize_t b_store(struct foo_obj *foo_obj, struct foo_attribute *attr,
15144bfe16eSGreg Kroah-Hartman const char *buf, size_t count)
15244bfe16eSGreg Kroah-Hartman {
1535fd637e7SRastislav Barlik int var, ret;
15444bfe16eSGreg Kroah-Hartman
1555fd637e7SRastislav Barlik ret = kstrtoint(buf, 10, &var);
1565fd637e7SRastislav Barlik if (ret < 0)
1575fd637e7SRastislav Barlik return ret;
1585fd637e7SRastislav Barlik
15944bfe16eSGreg Kroah-Hartman if (strcmp(attr->attr.name, "baz") == 0)
16044bfe16eSGreg Kroah-Hartman foo_obj->baz = var;
16144bfe16eSGreg Kroah-Hartman else
16244bfe16eSGreg Kroah-Hartman foo_obj->bar = var;
16344bfe16eSGreg Kroah-Hartman return count;
16444bfe16eSGreg Kroah-Hartman }
16544bfe16eSGreg Kroah-Hartman
16644bfe16eSGreg Kroah-Hartman static struct foo_attribute baz_attribute =
167de510989SRusty Russell __ATTR(baz, 0664, b_show, b_store);
16844bfe16eSGreg Kroah-Hartman static struct foo_attribute bar_attribute =
169de510989SRusty Russell __ATTR(bar, 0664, b_show, b_store);
17044bfe16eSGreg Kroah-Hartman
17144bfe16eSGreg Kroah-Hartman /*
17220ef9f46SRadu Voicilas * Create a group of attributes so that we can create and destroy them all
17344bfe16eSGreg Kroah-Hartman * at once.
17444bfe16eSGreg Kroah-Hartman */
17544bfe16eSGreg Kroah-Hartman static struct attribute *foo_default_attrs[] = {
17644bfe16eSGreg Kroah-Hartman &foo_attribute.attr,
17744bfe16eSGreg Kroah-Hartman &baz_attribute.attr,
17844bfe16eSGreg Kroah-Hartman &bar_attribute.attr,
17944bfe16eSGreg Kroah-Hartman NULL, /* need to NULL terminate the list of attributes */
18044bfe16eSGreg Kroah-Hartman };
181c484a678SKimberly Brown ATTRIBUTE_GROUPS(foo_default);
18244bfe16eSGreg Kroah-Hartman
18344bfe16eSGreg Kroah-Hartman /*
18444bfe16eSGreg Kroah-Hartman * Our own ktype for our kobjects. Here we specify our sysfs ops, the
18544bfe16eSGreg Kroah-Hartman * release function, and the set of default attributes we want created
18644bfe16eSGreg Kroah-Hartman * whenever a kobject of this type is registered with the kernel.
18744bfe16eSGreg Kroah-Hartman */
188862f6a84SThomas Weißschuh static const struct kobj_type foo_ktype = {
18944bfe16eSGreg Kroah-Hartman .sysfs_ops = &foo_sysfs_ops,
19044bfe16eSGreg Kroah-Hartman .release = foo_release,
191c484a678SKimberly Brown .default_groups = foo_default_groups,
19244bfe16eSGreg Kroah-Hartman };
19344bfe16eSGreg Kroah-Hartman
19444bfe16eSGreg Kroah-Hartman static struct kset *example_kset;
19544bfe16eSGreg Kroah-Hartman static struct foo_obj *foo_obj;
19644bfe16eSGreg Kroah-Hartman static struct foo_obj *bar_obj;
19744bfe16eSGreg Kroah-Hartman static struct foo_obj *baz_obj;
19844bfe16eSGreg Kroah-Hartman
create_foo_obj(const char * name)19944bfe16eSGreg Kroah-Hartman static struct foo_obj *create_foo_obj(const char *name)
20044bfe16eSGreg Kroah-Hartman {
20144bfe16eSGreg Kroah-Hartman struct foo_obj *foo;
20244bfe16eSGreg Kroah-Hartman int retval;
20344bfe16eSGreg Kroah-Hartman
20444bfe16eSGreg Kroah-Hartman /* allocate the memory for the whole object */
20544bfe16eSGreg Kroah-Hartman foo = kzalloc(sizeof(*foo), GFP_KERNEL);
20644bfe16eSGreg Kroah-Hartman if (!foo)
20744bfe16eSGreg Kroah-Hartman return NULL;
20844bfe16eSGreg Kroah-Hartman
20944bfe16eSGreg Kroah-Hartman /*
21044bfe16eSGreg Kroah-Hartman * As we have a kset for this kobject, we need to set it before calling
21144bfe16eSGreg Kroah-Hartman * the kobject core.
21244bfe16eSGreg Kroah-Hartman */
21344bfe16eSGreg Kroah-Hartman foo->kobj.kset = example_kset;
21444bfe16eSGreg Kroah-Hartman
21544bfe16eSGreg Kroah-Hartman /*
21644bfe16eSGreg Kroah-Hartman * Initialize and add the kobject to the kernel. All the default files
21744bfe16eSGreg Kroah-Hartman * will be created here. As we have already specified a kset for this
21844bfe16eSGreg Kroah-Hartman * kobject, we don't have to set a parent for the kobject, the kobject
21944bfe16eSGreg Kroah-Hartman * will be placed beneath that kset automatically.
22044bfe16eSGreg Kroah-Hartman */
22144bfe16eSGreg Kroah-Hartman retval = kobject_init_and_add(&foo->kobj, &foo_ktype, NULL, "%s", name);
22244bfe16eSGreg Kroah-Hartman if (retval) {
223185000fcSLi Zefan kobject_put(&foo->kobj);
22444bfe16eSGreg Kroah-Hartman return NULL;
22544bfe16eSGreg Kroah-Hartman }
22644bfe16eSGreg Kroah-Hartman
22744bfe16eSGreg Kroah-Hartman /*
22844bfe16eSGreg Kroah-Hartman * We are always responsible for sending the uevent that the kobject
22944bfe16eSGreg Kroah-Hartman * was added to the system.
23044bfe16eSGreg Kroah-Hartman */
23144bfe16eSGreg Kroah-Hartman kobject_uevent(&foo->kobj, KOBJ_ADD);
23244bfe16eSGreg Kroah-Hartman
23344bfe16eSGreg Kroah-Hartman return foo;
23444bfe16eSGreg Kroah-Hartman }
23544bfe16eSGreg Kroah-Hartman
destroy_foo_obj(struct foo_obj * foo)23644bfe16eSGreg Kroah-Hartman static void destroy_foo_obj(struct foo_obj *foo)
23744bfe16eSGreg Kroah-Hartman {
23844bfe16eSGreg Kroah-Hartman kobject_put(&foo->kobj);
23944bfe16eSGreg Kroah-Hartman }
24044bfe16eSGreg Kroah-Hartman
example_init(void)2417ec7fb39SQinghuang Feng static int __init example_init(void)
24244bfe16eSGreg Kroah-Hartman {
24344bfe16eSGreg Kroah-Hartman /*
24444bfe16eSGreg Kroah-Hartman * Create a kset with the name of "kset_example",
24544bfe16eSGreg Kroah-Hartman * located under /sys/kernel/
24644bfe16eSGreg Kroah-Hartman */
24744bfe16eSGreg Kroah-Hartman example_kset = kset_create_and_add("kset_example", NULL, kernel_kobj);
24844bfe16eSGreg Kroah-Hartman if (!example_kset)
24944bfe16eSGreg Kroah-Hartman return -ENOMEM;
25044bfe16eSGreg Kroah-Hartman
25144bfe16eSGreg Kroah-Hartman /*
25244bfe16eSGreg Kroah-Hartman * Create three objects and register them with our kset
25344bfe16eSGreg Kroah-Hartman */
25444bfe16eSGreg Kroah-Hartman foo_obj = create_foo_obj("foo");
25544bfe16eSGreg Kroah-Hartman if (!foo_obj)
25644bfe16eSGreg Kroah-Hartman goto foo_error;
25744bfe16eSGreg Kroah-Hartman
25844bfe16eSGreg Kroah-Hartman bar_obj = create_foo_obj("bar");
25944bfe16eSGreg Kroah-Hartman if (!bar_obj)
26044bfe16eSGreg Kroah-Hartman goto bar_error;
26144bfe16eSGreg Kroah-Hartman
26244bfe16eSGreg Kroah-Hartman baz_obj = create_foo_obj("baz");
26344bfe16eSGreg Kroah-Hartman if (!baz_obj)
26444bfe16eSGreg Kroah-Hartman goto baz_error;
26544bfe16eSGreg Kroah-Hartman
26644bfe16eSGreg Kroah-Hartman return 0;
26744bfe16eSGreg Kroah-Hartman
26844bfe16eSGreg Kroah-Hartman baz_error:
26944bfe16eSGreg Kroah-Hartman destroy_foo_obj(bar_obj);
27044bfe16eSGreg Kroah-Hartman bar_error:
27144bfe16eSGreg Kroah-Hartman destroy_foo_obj(foo_obj);
27244bfe16eSGreg Kroah-Hartman foo_error:
273e756bc56SBjorn Helgaas kset_unregister(example_kset);
27444bfe16eSGreg Kroah-Hartman return -EINVAL;
27544bfe16eSGreg Kroah-Hartman }
27644bfe16eSGreg Kroah-Hartman
example_exit(void)2777ec7fb39SQinghuang Feng static void __exit example_exit(void)
27844bfe16eSGreg Kroah-Hartman {
27944bfe16eSGreg Kroah-Hartman destroy_foo_obj(baz_obj);
28044bfe16eSGreg Kroah-Hartman destroy_foo_obj(bar_obj);
28144bfe16eSGreg Kroah-Hartman destroy_foo_obj(foo_obj);
28244bfe16eSGreg Kroah-Hartman kset_unregister(example_kset);
28344bfe16eSGreg Kroah-Hartman }
28444bfe16eSGreg Kroah-Hartman
28544bfe16eSGreg Kroah-Hartman module_init(example_init);
28644bfe16eSGreg Kroah-Hartman module_exit(example_exit);
287*161364bdSJeff Johnson MODULE_DESCRIPTION("Sample kset and ktype implementation");
28807afb6acSGreg Kroah-Hartman MODULE_LICENSE("GPL v2");
28944bfe16eSGreg Kroah-Hartman MODULE_AUTHOR("Greg Kroah-Hartman <greg@kroah.com>");
290