From: "Eugeny S. Mints" <eugeny.mints@gmail.com>
To: pm list <linux-pm@lists.osdl.org>
Subject: [PATCH] PowerOP, PowerOP Core, 1/2
Date: Sat, 02 Sep 2006 19:15:24 +0400 [thread overview]
Message-ID: <44F9A00C.1050507@gmail.com> (raw)
[-- Attachment #1: Type: text/plain, Size: 288 bytes --]
The PowerOP Core provides completely arch independent interface
to create and control operating points which consist of arbitrary
subset of power parameters available on a certain platform.
Also, PowerOP Core provides optional SysFS interface to access
operating point from userspace.
[-- Attachment #2: powerop.core.patch --]
[-- Type: text/x-patch, Size: 25165 bytes --]
diff --git a/include/linux/powerop.h b/include/linux/powerop.h
new file mode 100644
index 0000000..704620d
--- /dev/null
+++ b/include/linux/powerop.h
@@ -0,0 +1,42 @@
+/*
+ * PowerOP core definitions
+ *
+ * Author: Eugeny S. Mints <eugeny.@nomadgs.com>
+ *
+ * 2006 (C) Nomad Global Solutions, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ *
+ * Based on ideas and code by Todd Poynor <tpoynor@mvista.com>
+ */
+#ifndef __POWEROP_H__
+#define __POWEROP_H__
+
+#define POWEROP_MAX_OPT_NAME_LENGTH 32
+
+#define POWEROP_REGISTER_EVENT 1
+#define POWEROP_UNREGISTER_EVENT 2
+
+/* Interface to an arch PM Core layer */
+struct powerop_driver {
+ char *name;
+ void *(*create_point) (const char *pwr_params, va_list args);
+ int (*set_point) (void *md_opt);
+ int (*get_point) (void *md_opt, const char *pwr_params, va_list args);
+};
+
+int powerop_driver_register(struct powerop_driver *p);
+void powerop_driver_unregister(struct powerop_driver *p);
+
+/* Main PowerOP Core interface */
+int powerop_register_point(const char *id, const char *pwr_params, ...);
+int powerop_unregister_point(const char *id);
+int powerop_set_point(const char *id);
+int powerop_get_point(const char *id, const char *pwr_params, ...);
+int powerop_get_registered_opt_names(char *opt_names_list[], int *length);
+void powerop_put_registered_opt_names(char *opt_names_list[]);
+int powerop_register_notifier(struct notifier_block *nb);
+int powerop_unregister_notifier(struct notifier_block *nb);
+
+#endif /* __POWEROP_H__ */
diff --git a/include/linux/powerop_sysfs.h b/include/linux/powerop_sysfs.h
new file mode 100644
index 0000000..40b5379
--- /dev/null
+++ b/include/linux/powerop_sysfs.h
@@ -0,0 +1,59 @@
+/*
+ * PowerOP SysFS UI
+ *
+ * Author: Todd Poynor <tpoynor@mvista.com>
+ * 2006-08 Update by Eugeny S. Mints <eugeny@nomadgs.com>
+ *
+ * 2005 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+
+#ifndef __POWEROP_SYSFS_H__
+#define __POWEROP_SYSFS_H__
+
+#ifdef CONFIG_POWEROP_SYSFS
+
+#include <linux/sysfs.h>
+#include <linux/kobject.h>
+
+struct powerop_pwr_param_attribute {
+ struct attribute attr;
+ ssize_t(*store) (void *md_opt, char *pname, const char *buf,
+ size_t count);
+};
+
+#define powerop_pwr_param_attr(_name) \
+static struct powerop_pwr_param_attribute _name##_attr = { \
+ .attr = { \
+ .name = __stringify(_name), \
+ .mode = 0644, \
+ .owner = THIS_MODULE, \
+ }, \
+ .store = _name##_store, \
+}
+
+#define to_powerop_pwr_param_attr(_attr) container_of(_attr,\
+ struct powerop_pwr_param_attribute, attr)
+
+int powerop_sysfs_register_pwr_params(struct attribute **param_attrs);
+void powerop_sysfs_unregister_pwr_params(struct attribute **param_attrs);
+#else
+
+#define powerop_param_attr(_name)
+#define to_powerop_pwr_param_attr(_attr)
+
+static inline int
+powerop_sysfs_register_pwr_params(struct attribute **param_attrs)
+{
+ return 0;
+}
+
+static inline void
+powerop_sysfs_unregister_pwr_params(struct attribute **param_attrs)
+{
+}
+#endif /* CONFIG_POWEROP_SYSFS */
+
+#endif /*__POWEROP_SYSFS_H__*/
diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig
index ae44a70..2bef726 100644
--- a/kernel/power/Kconfig
+++ b/kernel/power/Kconfig
@@ -104,3 +104,31 @@ config SUSPEND_SMP
bool
depends on HOTPLUG_CPU && X86 && PM
default y
+
+#
+# powerop
+#
+
+menu "PowerOP (Power Management)"
+
+config POWEROP
+ tristate "PowerOP Core"
+ help
+
+config POWEROP_SYSFS
+ bool "Enable PowerOP sysfs interface"
+ depends on PM && POWEROP && SYSFS
+ help
+
+config POWEROP_SYSFS_OP_CREATE
+ bool "Enable creation of operating point via sysfs interface"
+ depends on POWEROP_SYSFS
+ help
+
+config POWEROP_SYSFS_OP_DEBUG_IF
+ bool "Enable special hw operating point"
+ depends on POWEROP_SYSFS
+ help
+ "hw point(ro) is used to get snapshots of power parameter values"
+
+endmenu
diff --git a/kernel/power/Makefile b/kernel/power/Makefile
index 8d0af3d..1045163 100644
--- a/kernel/power/Makefile
+++ b/kernel/power/Makefile
@@ -10,3 +10,12 @@ obj-$(CONFIG_SOFTWARE_SUSPEND) += swsusp
obj-$(CONFIG_SUSPEND_SMP) += smp.o
obj-$(CONFIG_MAGIC_SYSRQ) += poweroff.o
+
+# PowerOP
+
+powerop-pm-objs := powerop.o
+ifeq ($(CONFIG_POWEROP_SYSFS),y)
+ powerop-pm-objs += powerop_sysfs.o
+endif
+
+obj-$(CONFIG_POWEROP) += powerop-pm.o
diff --git a/kernel/power/main.c b/kernel/power/main.c
index 6d295c7..b113f79 100644
--- a/kernel/power/main.c
+++ b/kernel/power/main.c
@@ -16,6 +16,7 @@ #include <linux/errno.h>
#include <linux/init.h>
#include <linux/pm.h>
#include <linux/console.h>
+#include <linux/module.h>
#include "power.h"
@@ -233,7 +234,7 @@ int pm_suspend(suspend_state_t state)
decl_subsys(power,NULL,NULL);
-
+EXPORT_SYMBOL_GPL(power_subsys);
/**
* state - control system power state.
diff --git a/kernel/power/powerop.c b/kernel/power/powerop.c
new file mode 100644
index 0000000..88faf4f
--- /dev/null
+++ b/kernel/power/powerop.c
@@ -0,0 +1,407 @@
+/*
+ * PowerOP Core routines
+ *
+ * Author: Eugeny S. Mints <eugeny@nomadgs.com>
+ * 2006 (C) Nomad Global Solutions, Inc.
+ *
+ * Original Author: Todd Poynor <tpoynor@mvista.com>
+ *
+ * 2005 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/notifier.h>
+#include <linux/powerop.h>
+
+#include "powerop_point.h"
+#include "powerop_sysfs_point.h"
+
+/*
+ * FIXME: temporary limit. next implementation will handle unlimited number
+ * of operating point
+ */
+#define POWEROP_MAX_OPT_NUMBER 20
+/* current number of registered operating points */
+static int registered_opt_number;
+
+/* array of registered opereting point names */
+static char *registered_names[POWEROP_MAX_OPT_NUMBER];
+
+/* notifications about an operating point registration/deregistration */
+static BLOCKING_NOTIFIER_HEAD(powerop_notifier_list);
+
+static struct powerop_driver *powerop_driver;
+
+/* list of named operating points maintained by PowerOP Core layer */
+static struct list_head named_opt_list;
+static DECLARE_MUTEX(named_opt_list_mutex);
+static int powerop_initialized;
+
+/* hw access serialization */
+static DECLARE_MUTEX(powerop_mutex);
+
+/* Auxiliary PowerOP Core internal routines */
+
+static void *create_point(const char *pwr_params, va_list args)
+{
+ void *res;
+
+ down(&powerop_mutex);
+ res = powerop_driver && powerop_driver->create_point ?
+ powerop_driver->create_point(pwr_params, args) : NULL;
+ up(&powerop_mutex);
+
+ return res;
+}
+
+static int set_point(void *md_opt)
+{
+ int rc;
+
+ down(&powerop_mutex);
+ rc = md_opt && powerop_driver && powerop_driver->set_point ?
+ powerop_driver->set_point(md_opt) : -EINVAL;
+ up(&powerop_mutex);
+
+ return rc;
+}
+
+/**
+ * get_point - get value of specified power paramenters
+ * @md_opt: pointer to operating point to be processed or NULL to get
+ * values of currently active operating point
+ * @pwr_params - name of requested power parameters
+ * @args - array of result placeholders
+ *
+ * Get value of specified power paramenters of operating
+ * point pointed by 'md_opt'. Returns 0 on success, error code otherwise
+ */
+static int get_point(void *md_opt, const char *pwr_params, va_list args)
+{
+ int rc;
+
+ down(&powerop_mutex);
+ rc = powerop_driver && powerop_driver->get_point ?
+ powerop_driver->get_point(md_opt, pwr_params, args) : -EINVAL;
+ up(&powerop_mutex);
+
+ return rc;
+}
+
+/* PowerOP Core public interface */
+
+int powerop_driver_register(struct powerop_driver *p)
+{
+ int error = -EBUSY;
+
+ if (!powerop_driver) {
+ printk(KERN_INFO "PowerOP registering driver %s.\n", p->name);
+ powerop_driver = p;
+ error = 0;
+ }
+
+ return error;
+}
+EXPORT_SYMBOL_GPL(powerop_driver_register);
+
+void powerop_driver_unregister(struct powerop_driver *p)
+{
+ if (powerop_driver == p) {
+ printk(KERN_INFO "PowerOP unregistering driver %s\n", p->name);
+ powerop_driver = NULL;
+ }
+}
+EXPORT_SYMBOL_GPL(powerop_driver_unregister);
+
+/**
+ * powerop_register_point - register an operating point
+ * @id: operating point name
+ * @pwr_params: set of (power parameter name, value) pairs
+ *
+ * Add new operating point with a given name to
+ * operating points list. A caller passes power parameters for new operating
+ * points as pairs of name/value and passes only those parameter names the
+ * caller is interested in. PowerOP Core calls powerop driver to initialize
+ * arch dependent part of new operating point and links new named operating
+ * point to the list maintained by PowerOP Core. Returns zero on success,
+ * -EEXIST or error code otherwise
+ */
+int powerop_register_point(const char *id, const char *pwr_params, ...)
+{
+ int err = 0;
+ struct powerop_point *opt, *tmpopt;
+ va_list args;
+
+ if ((!powerop_initialized) || (id == NULL) ||
+ (strlen(id) > POWEROP_MAX_OPT_NAME_LENGTH) ||
+ (registered_opt_number >= POWEROP_MAX_OPT_NUMBER))
+ return -EINVAL;
+
+ /* check whether operating point with specified name already exists */
+ down(&named_opt_list_mutex);
+ list_for_each_entry_safe(opt, tmpopt, &named_opt_list, node) {
+ if (strcmp(kobject_name(&opt->kobj), id) == 0) {
+ err = -EEXIST;
+ break;
+ }
+ }
+ up(&named_opt_list_mutex);
+
+ if (err == -EEXIST)
+ return err;
+
+ if ((opt = kzalloc(sizeof(struct powerop_point), GFP_KERNEL)) == NULL)
+ return -ENOMEM;
+
+ if ((registered_names[registered_opt_number] =
+ kzalloc(sizeof(char) * POWEROP_MAX_OPT_NAME_LENGTH,
+ GFP_KERNEL)) == NULL) {
+ err = -ENOMEM;
+ goto fail_name_nomem;
+ }
+
+ va_start(args, pwr_params);
+ opt->md_opt = create_point(pwr_params, args);
+ va_end(args);
+
+ if (opt->md_opt == NULL) {
+ err = -EINVAL;
+ goto fail_opt_create;
+ }
+
+ err = kobject_set_name(&opt->kobj, id);
+ if (err != 0)
+ goto fail_set_name;
+
+ down(&named_opt_list_mutex);
+ err = powerop_sysfs_register_point(opt);
+ if (err != 0) {
+ up(&named_opt_list_mutex);
+ goto fail_set_name;
+ }
+
+ list_add_tail(&opt->node, &named_opt_list);
+ strcpy(registered_names[registered_opt_number], id);
+ registered_opt_number++;
+ up(&named_opt_list_mutex);
+
+ blocking_notifier_call_chain(&powerop_notifier_list,
+ POWEROP_REGISTER_EVENT, id);
+ return 0;
+
+ fail_set_name:
+ kfree(opt->md_opt);
+
+ fail_opt_create:
+ kfree(registered_names[registered_opt_number]);
+
+ fail_name_nomem:
+ kfree(opt);
+ return err;
+}
+EXPORT_SYMBOL_GPL(powerop_register_point);
+
+/**
+ * powerop_unregister_point - unregister am operating point
+ * @id: name of operating point
+ *
+ * Search for operating point with specified name and remove it from
+ * operating points list. Returns zero on success, -EINVAL if no operating
+ * point with specified name is found
+ */
+int powerop_unregister_point(const char *id)
+{
+ struct powerop_point *opt, *tmpopt;
+ int i = 0, ret = -EINVAL;
+
+ if ((!powerop_initialized) || (id == NULL))
+ return ret;
+
+ down(&named_opt_list_mutex);
+
+ list_for_each_entry_safe(opt, tmpopt, &named_opt_list, node) {
+ if (strcmp(kobject_name(&opt->kobj), id) == 0) {
+ /* FIXME: can't remove a point if it's the active */
+ list_del(&opt->node);
+ powerop_sysfs_unregister_point(opt);
+ kfree(opt->md_opt);
+ kfree(opt);
+ ret = 0;
+ break;
+ }
+ }
+
+ for (i = 0; i < registered_opt_number; i++) {
+ if (strcmp(registered_names[registered_opt_number], id) == 0) {
+ kfree(registered_names[i]);
+ registered_names[i] =
+ registered_names[registered_opt_number];
+ break;
+ }
+ }
+ registered_opt_number++;
+ up(&named_opt_list_mutex);
+
+ blocking_notifier_call_chain(&powerop_notifier_list,
+ POWEROP_UNREGISTER_EVENT, id);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(powerop_unregister_point);
+
+/**
+ * powerop_set_point - set systems to the operating point
+ * @id: name of operating point
+ *
+ * Search for operating point with specified name and switch the system to the
+ * specified operating point. Returns zero on success, -EINVAL if no operating
+ * point with specified name is found or error code otherwise
+ */
+int powerop_set_point(const char *id)
+{
+ struct powerop_point *opt, *selected_opt = NULL;
+ int ret;
+
+ if ((!powerop_initialized) || (id == NULL))
+ return -EINVAL;
+
+ down(&named_opt_list_mutex);
+
+ list_for_each_entry(opt, &named_opt_list, node) {
+ if (strcmp(kobject_name(&opt->kobj), id) == 0) {
+ selected_opt = opt;
+ break;
+ }
+ }
+
+ ret = (selected_opt == NULL) ? -EINVAL : set_point(opt->md_opt);
+ if (ret == 0)
+ powerop_sysfs_set_activeop(id);
+
+ up(&named_opt_list_mutex);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(powerop_set_point);
+
+/**
+ * powerop_get_point - get operating point pwr parameter values
+ * @id: name of operating point or NULL to get values for current active
+ * operating point
+ * @pwr_params: set of (power parameter name, result placeholder) pairs
+ *
+ * Search for operating point with specified name
+ * and return value of power parameters corresponding to the operating point.
+ * NULL name is reserved to get power parameter values of current active
+ * operating point (from hardware). Returns zero on success, -EINVAL if no
+ * operating point with specified name is found
+ */
+int powerop_get_point(const char *id, const char *pwr_params, ...)
+{
+ int ret = -EINVAL;
+ struct powerop_point *opt;
+ va_list args;
+ void *md_opt = NULL;
+
+ if (!powerop_initialized)
+ return ret;
+
+ down(&named_opt_list_mutex);
+
+ /* FIXME: get rid of sema for NULL case */
+ if (id != NULL) {
+ list_for_each_entry(opt, &named_opt_list, node) {
+ if (strcmp(kobject_name(&opt->kobj), id) == 0) {
+ md_opt = opt->md_opt;
+ ret = 0;
+ break;
+ }
+ }
+ /*
+ * name is specified but corresponding operating point
+ * is not found
+ */
+ if (ret != 0)
+ goto out;
+ }
+
+ va_start(args, pwr_params);
+ ret = get_point(md_opt, pwr_params, args);
+ va_end(args);
+ out:
+ up(&named_opt_list_mutex);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(powerop_get_point);
+
+/**
+ * powerop_get_registered_opt_names - get registered operating point names list
+ * @opt_names_list: array of pointers to name strings
+ * @length: array size
+ *
+ */
+int powerop_get_registered_opt_names(char *opt_names_list[], int *num)
+{
+ down(&named_opt_list_mutex);
+ opt_names_list = registered_names;
+ *num = registered_opt_number;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(powerop_get_registered_opt_names);
+
+void powerop_put_registered_opt_names(char *opt_names_list[])
+{
+ up(&named_opt_list_mutex);
+}
+EXPORT_SYMBOL_GPL(powerop_put_registered_opt_names);
+
+int powerop_register_notifier(struct notifier_block *nb)
+{
+ return blocking_notifier_chain_register(&powerop_notifier_list, nb);
+}
+EXPORT_SYMBOL(powerop_register_notifier);
+
+int powerop_unregister_notifier(struct notifier_block *nb)
+{
+ return blocking_notifier_chain_unregister(&powerop_notifier_list, nb);
+}
+EXPORT_SYMBOL(powerop_unregister_notifier);
+
+static int __init powerop_init(void)
+{
+ int rc = 0;
+
+ INIT_LIST_HEAD(&named_opt_list);
+ rc = powerop_sysfs_init();
+ if (rc == 0)
+ powerop_initialized = 1;
+
+ return rc;
+}
+
+static void __exit powerop_exit(void)
+{
+ struct powerop_point *opt, *tmp_opt;
+
+ down(&named_opt_list_mutex);
+
+ list_for_each_entry_safe(opt, tmp_opt, &named_opt_list, node) {
+ list_del(&opt->node);
+ powerop_sysfs_unregister_point(opt);
+ kfree(opt->md_opt);
+ kfree(opt);
+ }
+
+ up(&named_opt_list_mutex);
+ powerop_sysfs_exit();
+}
+
+module_init(powerop_init);
+module_exit(powerop_exit);
+
+MODULE_DESCRIPTION("PowerOP Core");
+MODULE_LICENSE("GPL");
diff --git a/kernel/power/powerop_point.h b/kernel/power/powerop_point.h
new file mode 100644
index 0000000..64b5591
--- /dev/null
+++ b/kernel/power/powerop_point.h
@@ -0,0 +1,36 @@
+/*
+ * PowerOP core non-public header
+ *
+ * Author: Eugeny S. Mints <eugeny.@nomadgs.com>
+ *
+ * 2006 (C) Nomad Global Solutions, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ *
+ * Based on ideas and code by Todd Poynor <tpoynor@mvista.com>
+ */
+#ifndef __POWEROP_INT_H__
+#define __POWEROP_INT_H__
+
+#define POWEROP_MAX_OPT_NAME_LENGTH 32
+
+/**
+ * struct powerop_point - PowerOP Core representation of operating point
+ * @kobj: hook to reference an operating point in some arch independent way
+ * (for ex. sysfs)
+ * @md_opt: pointer to opaque arch dependent set of power parameters
+ *
+ */
+struct powerop_point {
+ struct kobject kobj;
+ void *md_opt;
+ struct list_head node;
+#ifdef CONFIG_POWEROP_SYSFS
+ struct completion released;
+#endif
+};
+
+#define to_namedop(_kobj) container_of(_kobj, struct powerop_point, kobj)
+
+#endif /* __POWEROP_INT_H__ */
diff --git a/kernel/power/powerop_sysfs.c b/kernel/power/powerop_sysfs.c
new file mode 100644
index 0000000..94906c9
--- /dev/null
+++ b/kernel/power/powerop_sysfs.c
@@ -0,0 +1,254 @@
+/*
+ * PowerOP sysfs UI
+ *
+ * Author: Todd Poynor <tpoynor@mvista.com>
+ *
+ * Integration with updated PowerOP interface by
+ * Eugeny S. Mints <eugeny@nomadgs.com>
+ *
+ * 2005 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kobject.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/powerop.h>
+#include <linux/powerop_sysfs.h>
+
+#include "powerop_sysfs_point.h"
+
+#define POWEROP_SYSFS_HW_OPT "hw"
+
+extern struct subsystem power_subsys;
+
+static DECLARE_MUTEX(activeop_mutex);
+static char activeop[POWEROP_MAX_OPT_NAME_LENGTH];
+
+#define powerop_attr(_name) \
+static struct subsys_attribute _name##_attr = { \
+ .attr = { \
+ .name = __stringify(_name), \
+ .mode = 0644, \
+ .owner = THIS_MODULE, \
+ }, \
+ .show = _name##_show, \
+ .store = _name##_store, \
+}
+
+static struct attribute_group param_attr_group;
+
+static void powerop_sysfs_point_release(struct kobject *kobj)
+{
+ struct powerop_point *op = to_namedop(kobj);
+
+ complete(&op->released);
+ return;
+}
+
+static ssize_t
+powerop_sysfs_pwr_param_attr_show(struct kobject *kobj, struct attribute *attr,
+ char *buf)
+{
+ struct powerop_point *opt = to_namedop(kobj);
+ ssize_t ret = 0;
+ int pval = 0;
+
+#ifdef CONFIG_POWEROP_SYSFS_OP_DEBUG_IF
+ if (strcmp(kobject_name(&opt->kobj), POWEROP_SYSFS_HW_OPT) == 0)
+ ret = powerop_get_point(NULL, attr->name, &pval);
+ else
+#endif /* CONFIG_POWEROP_SYSFS_OP_DEBUG_IF */
+ ret = powerop_get_point(kobject_name(&opt->kobj), attr->name,
+ &pval);
+
+ return ret ? 0 : sprintf(buf, "%d\n", pval);
+}
+
+static ssize_t
+powerop_sysfs_pwr_param_attr_store(struct kobject *kobj,
+ struct attribute *attr, const char *buf,
+ size_t count)
+{
+#ifdef CONFIG_POWEROP_SYSFS_OP_CREATE
+ struct powerop_pwr_param_attribute *param_attr =
+ to_powerop_pwr_param_attr(attr);
+ struct powerop_point *opt = to_namedop(kobj);
+ ssize_t ret = 0;
+
+#ifdef CONFIG_POWEROP_SYSFS_OP_DEBUG_IF
+ if (strcmp(kobject_name(&opt->kobj), POWEROP_SYSFS_HW_OPT) == 0)
+ return -EINVAL;
+#endif /* CONFIG_POWEROP_SYSFS_OP_DEBUG_IF */
+ if (param_attr->store)
+ ret = param_attr->store(opt->md_opt, attr->name, buf, count);
+
+ return ret;
+#else
+ return -ENOTSUPP;
+#endif /* CONFIG_POWEROP_SYSFS_OP_CREATE */
+}
+
+static struct sysfs_ops powerop_sysfs_ops = {
+ .show = powerop_sysfs_pwr_param_attr_show,
+ .store = powerop_sysfs_pwr_param_attr_store,
+};
+
+static struct kobj_type ktype_powerop_point = {
+ .release = powerop_sysfs_point_release,
+ .sysfs_ops = &powerop_sysfs_ops,
+};
+
+#ifdef CONFIG_POWEROP_SYSFS_OP_CREATE
+static ssize_t new_show(struct subsystem *subsys, char *buf)
+{
+ return 0;
+}
+
+static ssize_t new_store(struct subsystem *subsys, const char *buf, size_t n)
+{
+ int rc = 0;
+
+ return ((rc = powerop_register_point(buf, " ")) == 0) ? n : rc;
+}
+
+powerop_attr(new);
+#endif /* CONFIG_POWEROP_SYSFS_OP_CREATE */
+
+static ssize_t active_show(struct subsystem *subsys, char *buf)
+{
+ int ret = 0;
+
+ down(&activeop_mutex);
+ ret = sprintf(buf, "%s\n", activeop);
+ up(&activeop_mutex);
+
+ return ret;
+}
+
+static ssize_t active_store(struct subsystem *subsys, const char *buf,
+ size_t n)
+{
+ int error;
+
+ return (error = powerop_set_point(buf)) == 0 ? n : error;
+}
+
+powerop_attr(active);
+
+static struct attribute *g[] = {
+#ifdef CONFIG_POWEROP_SYSFS_OP_CREATE
+ &new_attr.attr,
+#endif /* CONFIG_POWEROP_SYSFS_OP_CREATE */
+ &active_attr.attr,
+ NULL,
+};
+
+static struct attribute_group attr_group = {
+ .attrs = g,
+};
+
+static int create_point_attrs(struct kobject *kobj)
+{
+ int error = 0;
+
+ if (param_attr_group.attrs)
+ if ((error = sysfs_create_group(kobj, ¶m_attr_group)))
+ printk(KERN_ERR
+ "sysfs_create_group for op %s failed.\n",
+ kobject_name(kobj));
+ return error;
+}
+
+static void remove_point_attrs(struct kobject *kobj)
+{
+ if (param_attr_group.attrs)
+ sysfs_remove_group(kobj, ¶m_attr_group);
+}
+
+int powerop_sysfs_register_point(struct powerop_point *op)
+{
+ int error;
+
+ op->kobj.ktype = &ktype_powerop_point;
+ op->kobj.kset = &power_subsys.kset;
+ init_completion(&op->released);
+
+ if ((error = kobject_register(&op->kobj))) {
+ printk(KERN_ERR "PowerOP kobject_register for op %s failed.\n",
+ kobject_name(&op->kobj));
+ return error;
+ }
+
+ /* FIXME: check rc */
+ create_point_attrs(&op->kobj);
+ return 0;
+}
+
+void powerop_sysfs_unregister_point(struct powerop_point *op)
+{
+ remove_point_attrs(&op->kobj);
+ kobject_unregister(&op->kobj);
+ wait_for_completion(&op->released);
+}
+
+void powerop_sysfs_set_activeop(const char *id)
+{
+ down(&activeop_mutex);
+ strcpy(activeop, id);
+ up(&activeop_mutex);
+}
+
+int powerop_sysfs_register_pwr_params(struct attribute **param_attrs)
+{
+ if (param_attr_group.attrs)
+ return -EBUSY;
+
+ param_attr_group.attrs = param_attrs;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(powerop_sysfs_register_pwr_params);
+
+void powerop_sysfs_unregister_pwr_params(struct attribute **param_attrs)
+{
+ if (param_attr_group.attrs != param_attrs)
+ return;
+
+ param_attr_group.attrs = NULL;
+}
+EXPORT_SYMBOL_GPL(powerop_sysfs_unregister_pwr_params);
+
+int powerop_sysfs_init(void)
+{
+ int error;
+
+ if (param_attr_group.attrs == NULL) {
+ printk(KERN_ERR "PowerOP SysFS: register pwr params first!\n");
+ return -EINVAL;
+ }
+
+ if ((error =
+ sysfs_create_group(&power_subsys.kset.kobj, &attr_group))) {
+ printk(KERN_ERR "PowerOP subsys sysfs_create_group failed.\n");
+ return error;
+ }
+#ifdef CONFIG_POWEROP_SYSFS_OP_DEBUG_IF
+ if (powerop_register_point(POWEROP_SYSFS_HW_OPT, " "))
+ printk(KERN_ERR "PowerOP subsys HW point creation failed\n");
+#endif
+ powerop_sysfs_set_activeop("Unknown");
+ return 0;
+}
+
+void powerop_sysfs_exit(void)
+{
+ powerop_sysfs_unregister_pwr_params(param_attr_group.attrs);
+ sysfs_remove_group(&power_subsys.kset.kobj, &attr_group);
+}
diff --git a/kernel/power/powerop_sysfs_point.h b/kernel/power/powerop_sysfs_point.h
new file mode 100644
index 0000000..9c0baa9
--- /dev/null
+++ b/kernel/power/powerop_sysfs_point.h
@@ -0,0 +1,42 @@
+/*
+ * PowerOP SysFS non-public header
+ *
+ * Author: Eugeny S. Mints <eugeny.@nomadgs.com>
+ *
+ * 2006 (C) Nomad Global Solutions, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+#ifndef __POWEROP_SYSFS_INT_H__
+#define __POWEROP_SYSFS_INT_H__
+#include "powerop_point.h"
+
+#ifdef CONFIG_POWEROP_SYSFS
+int powerop_sysfs_register_point(struct powerop_point *opt);
+void powerop_sysfs_unregister_point(struct powerop_point *op);
+void powerop_sysfs_set_activeop(const char *id);
+int powerop_sysfs_init(void);
+void powerop_sysfs_exit(void);
+#else
+static inline int powerop_sysfs_register_point(struct powerop_point *opt)
+{
+ return 0;
+}
+static inline int powerop_sysfs_unregister_point(struct powerop_point *opt)
+{
+ return 0;
+}
+static inline void powerop_sysfs_set_activeop(const char *id)
+{
+}
+static inline int powerop_sysfs_init(void)
+{
+ return 0;
+}
+static inline void powerop_sysfs_exit(void)
+{
+}
+#endif /* CONFIG_POWEROP_SYSFS */
+
+#endif /* __POWEROP_SYSFS_INT_H__ */
[-- Attachment #3: Type: text/plain, Size: 0 bytes --]
next reply other threads:[~2006-09-02 15:15 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2006-09-02 15:15 Eugeny S. Mints [this message]
-- strict thread matches above, loose matches on Subject: below --
2006-09-14 14:37 [PATCH] PowerOP, PowerOP Core, 1/2 Eugeny S. Mints
2006-09-18 10:44 ` [linux-pm] " Pavel Machek
2006-09-18 11:32 ` Eugeny S. Mints
2006-09-18 19:58 ` Eugeny S. Mints
2006-09-18 20:07 ` Vitaly Wool
2006-09-18 13:23 ` Greg KH
2006-09-18 13:23 ` Greg KH
2006-09-19 21:37 Scott E. Preece
2006-09-22 20:34 Scott E. Preece
2006-09-23 11:18 ` [linux-pm] " Pavel Machek
2006-09-24 21:33 ` Matthew Locke
2006-09-24 21:45 ` Pavel Machek
2006-09-24 23:13 ` David Brownell
2006-09-29 21:44 Eugeny S. Mints
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=44F9A00C.1050507@gmail.com \
--to=eugeny.mints@gmail.com \
--cc=linux-pm@lists.osdl.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.