// SPDX-License-Identifier: GPL-2.0 /* * Sample kset and ktype implementation * * Copyright (C) 2004-2007 Greg Kroah-Hartman <[email protected]> * Copyright (C) 2007 Novell Inc. */ #include <linux/kobject.h> #include <linux/string.h> #include <linux/sysfs.h> #include <linux/slab.h> #include <linux/module.h> #include <linux/init.h> /* * This module shows how to create a kset in sysfs called * /sys/kernel/kset-example * Then tree kobjects are created and assigned to this kset, "foo", "baz", * and "bar". In those kobjects, attributes of the same name are also * created and if an integer is written to these files, it can be later * read out of it. */ /* * This is our "object" that we will create a few of and register them with * sysfs. */ struct foo_obj { … }; #define to_foo_obj(x) … /* a custom attribute that works just for a struct foo_obj. */ struct foo_attribute { … }; #define to_foo_attr(x) … /* * The default show function that must be passed to sysfs. This will be * called by sysfs for whenever a show function is called by the user on a * sysfs file associated with the kobjects we have registered. We need to * transpose back from a "default" kobject to our custom struct foo_obj and * then call the show function for that specific object. */ static ssize_t foo_attr_show(struct kobject *kobj, struct attribute *attr, char *buf) { … } /* * Just like the default show function above, but this one is for when the * sysfs "store" is requested (when a value is written to a file.) */ static ssize_t foo_attr_store(struct kobject *kobj, struct attribute *attr, const char *buf, size_t len) { … } /* Our custom sysfs_ops that we will associate with our ktype later on */ static const struct sysfs_ops foo_sysfs_ops = …; /* * The release function for our object. This is REQUIRED by the kernel to * have. We free the memory held in our object here. * * NEVER try to get away with just a "blank" release function to try to be * smarter than the kernel. Turns out, no one ever is... */ static void foo_release(struct kobject *kobj) { … } /* * The "foo" file where the .foo variable is read from and written to. */ static ssize_t foo_show(struct foo_obj *foo_obj, struct foo_attribute *attr, char *buf) { … } static ssize_t foo_store(struct foo_obj *foo_obj, struct foo_attribute *attr, const char *buf, size_t count) { … } /* Sysfs attributes cannot be world-writable. */ static struct foo_attribute foo_attribute = …; /* * More complex function where we determine which variable is being accessed by * looking at the attribute for the "baz" and "bar" files. */ static ssize_t b_show(struct foo_obj *foo_obj, struct foo_attribute *attr, char *buf) { … } static ssize_t b_store(struct foo_obj *foo_obj, struct foo_attribute *attr, const char *buf, size_t count) { … } static struct foo_attribute baz_attribute = …; static struct foo_attribute bar_attribute = …; /* * Create a group of attributes so that we can create and destroy them all * at once. */ static struct attribute *foo_default_attrs[] = …; ATTRIBUTE_GROUPS(…); /* * Our own ktype for our kobjects. Here we specify our sysfs ops, the * release function, and the set of default attributes we want created * whenever a kobject of this type is registered with the kernel. */ static const struct kobj_type foo_ktype = …; 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) { … } static void destroy_foo_obj(struct foo_obj *foo) { … } static int __init example_init(void) { … } static void __exit example_exit(void) { … } module_init(…) …; module_exit(example_exit); MODULE_DESCRIPTION(…) …; MODULE_LICENSE(…) …; MODULE_AUTHOR(…) …;