162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Sample kobject implementation
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2004-2007 Greg Kroah-Hartman <greg@kroah.com>
662306a36Sopenharmony_ci * Copyright (C) 2007 Novell Inc.
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci#include <linux/kobject.h>
962306a36Sopenharmony_ci#include <linux/string.h>
1062306a36Sopenharmony_ci#include <linux/sysfs.h>
1162306a36Sopenharmony_ci#include <linux/module.h>
1262306a36Sopenharmony_ci#include <linux/init.h>
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci/*
1562306a36Sopenharmony_ci * This module shows how to create a simple subdirectory in sysfs called
1662306a36Sopenharmony_ci * /sys/kernel/kobject-example  In that directory, 3 files are created:
1762306a36Sopenharmony_ci * "foo", "baz", and "bar".  If an integer is written to these files, it can be
1862306a36Sopenharmony_ci * later read out of it.
1962306a36Sopenharmony_ci */
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_cistatic int foo;
2262306a36Sopenharmony_cistatic int baz;
2362306a36Sopenharmony_cistatic int bar;
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci/*
2662306a36Sopenharmony_ci * The "foo" file where a static variable is read from and written to.
2762306a36Sopenharmony_ci */
2862306a36Sopenharmony_cistatic ssize_t foo_show(struct kobject *kobj, struct kobj_attribute *attr,
2962306a36Sopenharmony_ci			char *buf)
3062306a36Sopenharmony_ci{
3162306a36Sopenharmony_ci	return sysfs_emit(buf, "%d\n", foo);
3262306a36Sopenharmony_ci}
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_cistatic ssize_t foo_store(struct kobject *kobj, struct kobj_attribute *attr,
3562306a36Sopenharmony_ci			 const char *buf, size_t count)
3662306a36Sopenharmony_ci{
3762306a36Sopenharmony_ci	int ret;
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci	ret = kstrtoint(buf, 10, &foo);
4062306a36Sopenharmony_ci	if (ret < 0)
4162306a36Sopenharmony_ci		return ret;
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci	return count;
4462306a36Sopenharmony_ci}
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci/* Sysfs attributes cannot be world-writable. */
4762306a36Sopenharmony_cistatic struct kobj_attribute foo_attribute =
4862306a36Sopenharmony_ci	__ATTR(foo, 0664, foo_show, foo_store);
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci/*
5162306a36Sopenharmony_ci * More complex function where we determine which variable is being accessed by
5262306a36Sopenharmony_ci * looking at the attribute for the "baz" and "bar" files.
5362306a36Sopenharmony_ci */
5462306a36Sopenharmony_cistatic ssize_t b_show(struct kobject *kobj, struct kobj_attribute *attr,
5562306a36Sopenharmony_ci		      char *buf)
5662306a36Sopenharmony_ci{
5762306a36Sopenharmony_ci	int var;
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	if (strcmp(attr->attr.name, "baz") == 0)
6062306a36Sopenharmony_ci		var = baz;
6162306a36Sopenharmony_ci	else
6262306a36Sopenharmony_ci		var = bar;
6362306a36Sopenharmony_ci	return sysfs_emit(buf, "%d\n", var);
6462306a36Sopenharmony_ci}
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_cistatic ssize_t b_store(struct kobject *kobj, struct kobj_attribute *attr,
6762306a36Sopenharmony_ci		       const char *buf, size_t count)
6862306a36Sopenharmony_ci{
6962306a36Sopenharmony_ci	int var, ret;
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	ret = kstrtoint(buf, 10, &var);
7262306a36Sopenharmony_ci	if (ret < 0)
7362306a36Sopenharmony_ci		return ret;
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	if (strcmp(attr->attr.name, "baz") == 0)
7662306a36Sopenharmony_ci		baz = var;
7762306a36Sopenharmony_ci	else
7862306a36Sopenharmony_ci		bar = var;
7962306a36Sopenharmony_ci	return count;
8062306a36Sopenharmony_ci}
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_cistatic struct kobj_attribute baz_attribute =
8362306a36Sopenharmony_ci	__ATTR(baz, 0664, b_show, b_store);
8462306a36Sopenharmony_cistatic struct kobj_attribute bar_attribute =
8562306a36Sopenharmony_ci	__ATTR(bar, 0664, b_show, b_store);
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci/*
8962306a36Sopenharmony_ci * Create a group of attributes so that we can create and destroy them all
9062306a36Sopenharmony_ci * at once.
9162306a36Sopenharmony_ci */
9262306a36Sopenharmony_cistatic struct attribute *attrs[] = {
9362306a36Sopenharmony_ci	&foo_attribute.attr,
9462306a36Sopenharmony_ci	&baz_attribute.attr,
9562306a36Sopenharmony_ci	&bar_attribute.attr,
9662306a36Sopenharmony_ci	NULL,	/* need to NULL terminate the list of attributes */
9762306a36Sopenharmony_ci};
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci/*
10062306a36Sopenharmony_ci * An unnamed attribute group will put all of the attributes directly in
10162306a36Sopenharmony_ci * the kobject directory.  If we specify a name, a subdirectory will be
10262306a36Sopenharmony_ci * created for the attributes with the directory being the name of the
10362306a36Sopenharmony_ci * attribute group.
10462306a36Sopenharmony_ci */
10562306a36Sopenharmony_cistatic struct attribute_group attr_group = {
10662306a36Sopenharmony_ci	.attrs = attrs,
10762306a36Sopenharmony_ci};
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_cistatic struct kobject *example_kobj;
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_cistatic int __init example_init(void)
11262306a36Sopenharmony_ci{
11362306a36Sopenharmony_ci	int retval;
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci	/*
11662306a36Sopenharmony_ci	 * Create a simple kobject with the name of "kobject_example",
11762306a36Sopenharmony_ci	 * located under /sys/kernel/
11862306a36Sopenharmony_ci	 *
11962306a36Sopenharmony_ci	 * As this is a simple directory, no uevent will be sent to
12062306a36Sopenharmony_ci	 * userspace.  That is why this function should not be used for
12162306a36Sopenharmony_ci	 * any type of dynamic kobjects, where the name and number are
12262306a36Sopenharmony_ci	 * not known ahead of time.
12362306a36Sopenharmony_ci	 */
12462306a36Sopenharmony_ci	example_kobj = kobject_create_and_add("kobject_example", kernel_kobj);
12562306a36Sopenharmony_ci	if (!example_kobj)
12662306a36Sopenharmony_ci		return -ENOMEM;
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	/* Create the files associated with this kobject */
12962306a36Sopenharmony_ci	retval = sysfs_create_group(example_kobj, &attr_group);
13062306a36Sopenharmony_ci	if (retval)
13162306a36Sopenharmony_ci		kobject_put(example_kobj);
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	return retval;
13462306a36Sopenharmony_ci}
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_cistatic void __exit example_exit(void)
13762306a36Sopenharmony_ci{
13862306a36Sopenharmony_ci	kobject_put(example_kobj);
13962306a36Sopenharmony_ci}
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_cimodule_init(example_init);
14262306a36Sopenharmony_cimodule_exit(example_exit);
14362306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
14462306a36Sopenharmony_ciMODULE_AUTHOR("Greg Kroah-Hartman <greg@kroah.com>");
145