本文乃fireaxe原创,使用GPL发布,可以自由拷贝,转载。但转载请保持文档的完整性,并注明原作者及原链接。内容可任意使用,但对因使用该内容引起的后果不做任何保证。
作者:fireaxe.hq@outlook.com
博客:fireaxe.blog.chinaunix.net
- kobject: 在 Linux 设备模型中最基本的对象,它的功能是提供引用计数和维持父子(parent)结构、平级(sibling)目录关系,上面的 device, device_driver 等各对象都是以 kobject 基础功能之上实现的;
- kset: 它用来对同类型对象提供一个包装集合,在内核数据结构上它也是由内嵌一个 kboject 实现,因而它同时也是一个 kobject (面向对象 OOP 概念中的继承关系) ,具有 kobject 的全部功能;
- 在 /sys 根目录之下的都是 kset,它们组织了 /sys 的顶层目录视图;
- 在部分 kset 下有二级或更深层次的 kset;
- 每个 kset 目录下再包含着一个或多个 kobject,这表示一个集合所包含的 kobject 结构体;
- 在 kobject 下有属性(attrs)文件和属性组(attr_group),属性组就是组织属性的一个目录,它们一起向用户层提供了表示和操作这个 kobject 的属性特征的接口;
- 在 kobject 下还有一些符号链接文件,指向其它的 kobject,这些符号链接文件用于组织上面所说的 device, driver, bus_type, class, module 之间的关系;
- 不同类型如设备类型的、设备驱动类型的 kobject 都有不同的属性,不同驱动程序支持的 sysfs 接口也有不同的属性文件;而相同类型的设备上有很多相同的属性文件;
点击(此处)折叠或打开
- cpufreq_global_kobject = kobject_create_and_add("cpufreq", &cpu_subsys.dev_root->kobj);
点击(此处)折叠或打开
-
kobject_init(&policy->kobj, &ktype_cpufreq);
-
-
-
kobject_add(&policy->kobj, cpufreq_global_kobject,
-
"policy%u",
- cpumask_first(policy->related_cpus));
点击(此处)折叠或打开
-
static const struct sysfs_ops sysfs_ops = {
-
-
-
.show = show,
-
.store = store,
-
};
-
-
static struct attribute *default_attrs[] = {
-
&cpuinfo_min_freq.attr,
-
&cpuinfo_max_freq.attr,
-
&cpuinfo_transition_latency.attr,
-
&scaling_min_freq.attr,
-
&scaling_max_freq.attr,
-
&affected_cpus.attr,
-
&related_cpus.attr,
-
&scaling_governor.attr,
-
&scaling_driver.attr,
-
&scaling_available_governors.attr,
-
&scaling_setspeed.attr,
-
NULL
-
};
-
-
static struct kobj_type ktype_cpufreq = {
-
.sysfs_ops = &sysfs_ops,
-
.default_attrs = default_attrs,
-
.release = cpufreq_sysfs_release,
- };
- release用于释放资源,一般应该不需要;
- sysfs_ops中实现了两个函数show()与store(),对属性文件读写时调用这两个函数;
- default_attrs中定义了要显示的属性,是一个struct attribute的指针数组。
点击(此处)折叠或打开
-
#define cpufreq_freq_attr_rw(_name) \
-
-
-
static struct freq_attr _name = \
-
__ATTR(_name, 0644, show_##_name, store_##_name)
-
- cpufreq_freq_attr_rw(scaling_setspeed);
点击(此处)折叠或打开
- static struct freq_attr scaling_setspeed = __ATTR(scaling_setspeed, 0644, show_scaling_setspeed, store_scaling_setspeed)
点击(此处)折叠或打开
-
static ssize_t show(struct kobject *kobj, struct attribute *attr, char *buf)
-
-
-
{
-
struct cpufreq_policy *policy = to_policy(kobj);
-
struct freq_attr *fattr = to_attr(attr);
-
ssize_t ret;
-
-
down_read(&policy->rwsem);
-
-
if (fattr->show)
-
ret = fattr->show(policy, buf);
-
else
-
ret = -EIO;
-
-
up_read(&policy->rwsem);
-
-
return ret;
-
}
-
-
static ssize_t store(struct kobject *kobj, struct attribute *attr,
-
const char *buf, size_t count)
-
{
-
struct cpufreq_policy *policy = to_policy(kobj);
-
struct freq_attr *fattr = to_attr(attr);
-
ssize_t ret = -EINVAL;
-
-
get_online_cpus();
-
-
if (!cpu_online(policy->cpu))
-
goto unlock;
-
-
down_write(&policy->rwsem);
-
-
if (fattr->store)
-
ret = fattr->store(policy, buf, count);
-
else
-
ret = -EIO;
-
-
up_write(&policy->rwsem);
-
unlock:
-
put_online_cpus();
-
-
return ret;
- }
点击(此处)折叠或打开
-
static int create_dir(struct kobject *kobj)
-
-
-
{
-
const struct kobj_ns_type_operations *ops;
-
int error;
-
-
error = sysfs_create_dir_ns(kobj, kobject_namespace(kobj));
-
if (error)
-
return error;
-
-
error = populate_dir(kobj);
-
if (error) {
-
sysfs_remove_dir(kobj);
-
return error;
-
}
-
.....
-
}
-
-
static int populate_dir(struct kobject *kobj)
-
{
-
......
-
if (t && t->default_attrs) {
-
for (i = 0; (attr = t->default_attrs[i]) != NULL; i++) {
-
error = sysfs_create_file(kobj, attr);
-
if (error)
-
break;
-
}
-
}
-
return error;
- }
点击(此处)折叠或打开
-
int __must_check sysfs_create_dir_ns(struct kobject *kobj, const void *ns);
-
-
-
int __must_check sysfs_rename_dir_ns(struct kobject *kobj, const char *new_name, const void *new_ns);
-
int __must_check sysfs_create_mount_point(struct kobject *parent_kobj, const char *name);
-
int __must_check sysfs_create_file_ns(struct kobject *kobj, const struct attribute *attr, const void *ns);
-
int __must_check sysfs_create_files(struct kobject *kobj, const struct attribute **attr);
-
int __must_check sysfs_chmod_file(struct kobject *kobj, const struct attribute *attr, umode_t mode);
-
int __must_check sysfs_create_bin_file(struct kobject *kobj, const struct bin_attribute *attr);
- int __must_check sysfs_create_link(struct kobject *kobj, struct kobject *target, const char *name);
点击(此处)折叠或打开
-
#ifndef TEST_SYSFS_H_H
-
-
-
#define TEST_SYSFS_H_H
-
-
#include <linux/module.h> /* for modules */
-
#include <linux/blkdev.h>
-
#include <linux/mount.h>
-
#include <linux/fsnotify.h>
-
#include <linux/fs.h> /* file_operations */
-
#include <linux/uaccess.h> /* copy_(to,from)_user */
-
#include <linux/init.h> /* module_init, module_exit */
-
#include <linux/slab.h> /* kmalloc, kfree */
-
#include <linux/device.h>
-
#include <linux/cdev.h>
-
#include <linux/io.h>
-
#include <linux/debugfs.h>
-
#include <linux/mm.h>
-
#include <asm/uaccess.h>
-
#include <linux/cpu.h>
-
-
struct wicca_sysfs
-
{
-
struct kobject kobj;
-
struct rw_semaphore rwsem;
-
u32 limit_min;
-
u32 limit_max;
-
u32 value;
-
};
-
-
struct test1_attr {
-
struct attribute attr;
-
ssize_t (*show)(struct wicca_sysfs*, char *);
-
ssize_t (*store)(struct wicca_sysfs*, const char *, size_t count);
-
};
-
-
#define wicca_attr_ro(_name) \
-
static struct test1_attr _name = \
-
__ATTR(_name, 0444, show_##_name, NULL)
-
-
#define wicca_attr_ro_perm(_name, _perm) \
-
static struct test1_attr _name = \
-
__ATTR(_name, _perm, show_##_name, NULL)
-
-
#define wicca_attr_rw(_name) \
-
static struct test1_attr _name = \
-
__ATTR(_name, 0644, show_##_name, store_##_name)
-
- #endif /* TEST_SYSFS_H_H */
点击(此处)折叠或打开
-
/** test_sysfs module
-
-
-
* this module shall be installed into kernel
-
*/
-
-
#include "test_sysfs.h"
-
-
static ssize_t store_scaling_limit_min(struct wicca_sysfs *wicca, const char *buf, size_t count)
-
{
-
int ret, temp;
-
printk("calling %s\n", __func__);
-
-
ret = sscanf(buf, "%u", &temp);
-
if (ret != 1)
-
{
-
return -EINVAL;
-
}
-
-
if ((temp < wicca->limit_max) && (temp <= 10))
-
{
-
wicca->limit_min = temp;
-
}
-
-
return count;
-
}
-
-
static ssize_t show_scaling_limit_min(struct wicca_sysfs *wicca, char *buf)
-
{
-
printk("calling %s\n", __func__);
-
-
return sprintf(buf, "%u\n", wicca->limit_min);
-
}
-
-
-
static ssize_t store_scaling_limit_max(struct wicca_sysfs *wicca, const char *buf, size_t count)
-
{
-
int ret, temp;
-
printk("calling %s\n", __func__);
-
-
ret = sscanf(buf, "%u", &temp);
-
if (ret != 1)
-
{
-
return -EINVAL;
-
}
-
-
if ((temp > wicca->limit_min) && (temp <= 20))
-
{
-
wicca->limit_max = temp;
-
}
-
-
return count;
-
}
-
-
static ssize_t show_scaling_limit_max(struct wicca_sysfs *wicca, char *buf)
-
{
-
printk("calling %s\n", __func__);
-
return sprintf(buf, "%u\n", wicca->limit_max);
-
}
-
-
static ssize_t store_scaling_set_value(struct wicca_sysfs *wicca, const char *buf, size_t count)
-
{
-
int ret, temp;
-
printk("calling %s\n", __func__);
-
-
ret = sscanf(buf, "%u", &temp);
-
if (ret != 1)
-
{
-
return -EINVAL;
-
}
-
-
if ((temp <= wicca->limit_max) && (temp >= wicca->limit_min))
-
{
-
wicca->value = temp;
-
}
-
-
-
return count;
-
}
-
-
static ssize_t show_scaling_set_value(struct wicca_sysfs *wicca, char *buf)
-
{
-
printk("calling %s\n", __func__);
-
return sprintf(buf, "%u\n", wicca->value);
-
}
-
-
static ssize_t show_scaling_get_sqrt(struct wicca_sysfs *wicca, char *buf)
-
{
-
printk("calling %s\n", __func__);
-
return sprintf(buf, "%lu\n", int_sqrt(wicca->value));
-
}
-
-
static ssize_t show_scaling_get_factorial(struct wicca_sysfs *wicca, char *buf)
-
{
-
u32 tmp;
-
u32 i;
-
printk("calling %s\n", __func__);
-
-
for (i=0, tmp=1; i<wicca->value; i++)
-
{
-
tmp *= (i+1);
-
}
-
return sprintf(buf, "%u\n", tmp);
-
}
-
-
wicca_attr_rw(scaling_limit_min);
-
wicca_attr_rw(scaling_limit_max);
-
wicca_attr_rw(scaling_set_value);
-
wicca_attr_ro(scaling_get_sqrt);
-
wicca_attr_ro(scaling_get_factorial);
-
-
static struct attribute *default_attrs[] = {
-
&scaling_limit_min.attr,
-
&scaling_limit_max.attr,
-
&scaling_set_value.attr,
-
&scaling_get_sqrt.attr,
-
NULL
-
};
-
-
#define to_test1(k) container_of(k, struct wicca_sysfs, kobj)
-
#define to_attr(a) container_of(a, struct test1_attr, attr)
-
-
static ssize_t show(struct kobject *kobj, struct attribute *attr, char *buf)
-
{
-
struct wicca_sysfs *test1 = to_test1(kobj);
-
struct test1_attr *fattr = to_attr(attr);
-
ssize_t ret;
-
-
down_read(&test1->rwsem);
-
ret = fattr->show(test1, buf);
-
up_read(&test1->rwsem);
-
-
return ret;
-
}
-
-
static ssize_t store(struct kobject *kobj, struct attribute *attr,
-
const char *buf, size_t count)
-
{
-
struct wicca_sysfs *test1 = to_test1(kobj);
-
struct test1_attr *fattr = to_attr(attr);
-
ssize_t ret = -EINVAL;
-
-
get_online_cpus();
-
-
down_write(&test1->rwsem);
-
ret = fattr->store(test1, buf, count);
-
up_write(&test1->rwsem);
-
-
put_online_cpus();
-
-
return ret;
-
}
-
-
static struct sysfs_ops sysfs_ops = {
-
.show = show,
-
.store = store,
-
};
-
-
static struct kobj_type ktype_test1 = {
-
.sysfs_ops = &sysfs_ops,
-
.default_attrs = default_attrs,
-
};
-
-
struct kobject *wicca_global_kobject;
-
EXPORT_SYMBOL(wicca_global_kobject);
-
-
static int __init sysfs_demon_init(void)
-
{
-
int ret;
-
struct wicca_sysfs *test1;
-
-
wicca_global_kobject = kobject_create_and_add("wicca", &cpu_subsys.dev_root->kobj);
-
BUG_ON(!wicca_global_kobject);
-
-
test1 = kzalloc(sizeof(*test1), GFP_KERNEL);
-
if (!test1)
-
{
-
return -1;
-
}
-
-
ret = kobject_init_and_add(&test1->kobj, &ktype_test1,
-
wicca_global_kobject, "test%d", 1);
-
if (ret)
-
{
-
return -1;
-
}
-
-
init_rwsem(&test1->rwsem);
-
test1->limit_min = 1;
-
test1->limit_max = 10;
-
test1->value = 3;
-
-
ret = sysfs_create_file(&test1->kobj, &scaling_get_factorial.attr);
-
if (ret)
-
{
-
return -1;
-
}
-
-
return ret;
-
}
-
-
static void __exit sysfs_demon_exit(void)
-
{
-
pr_debug("wicca sysfs exit");
-
}
-
-
module_init(sysfs_demon_init);
-
module_exit(sysfs_demon_exit);
-
-
MODULE_LICENSE("GPL");
- MODULE_AUTHOR("Marco Hao");
本文乃fireaxe原创,使用GPL发布,可以自由拷贝,转载。但转载请保持文档的完整性,并注明原作者及原链接。内容可任意使用,但对因使用该内容引起的后果不做任何保证。
作者:fireaxe.hq@outlook.com
博客:fireaxe.blog.chinaunix.net