[lm-sensors] [PATCH 1/2] hwmon: add new hwmon-core interface
Lucas Stach
dev at lynxeye.de
Thu Dec 8 22:10:00 CET 2011
This adds a new hwmon-core interface to centralize sysfs handling
and enable cooperation with other in-kernel drivers.
v3:
- checkpatch clean
v4:
- more flexible interface to allow different capabilities for
every sensor and holes in sensor numbering
- corrected a few oversights
- split out vid and vrm handling as separate feature
- support 2d attributes for trip point and treshold handling
Signed-off-by: Lucas Stach <dev at lynxeye.de>
---
drivers/hwmon/Makefile | 1 +
drivers/hwmon/hwmon-core.c | 511 ++++++++++++++++++++++++++++++++++++++++++++
include/linux/hwmon-core.h | 229 ++++++++++++++++++++
3 files changed, 741 insertions(+), 0 deletions(-)
create mode 100644 drivers/hwmon/hwmon-core.c
create mode 100644 include/linux/hwmon-core.h
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 8251ce8..c7bb343 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -3,6 +3,7 @@
#
obj-$(CONFIG_HWMON) += hwmon.o
+obj-$(CONFIG_HWMON) += hwmon-core.o
obj-$(CONFIG_HWMON_VID) += hwmon-vid.o
# APCI drivers
diff --git a/drivers/hwmon/hwmon-core.c b/drivers/hwmon/hwmon-core.c
new file mode 100644
index 0000000..3d044ad
--- /dev/null
+++ b/drivers/hwmon/hwmon-core.c
@@ -0,0 +1,511 @@
+/*
+ * hwmon-core.c
+ * Copyright (C) 2011 Lucas Stach <dev at lynxeye.de>
+ *
+ * hwmon-core interface implementation
+ *
+ * Provides functions to create/destroy a sysfs interface out of a
+ * hwmon_device_instance definition. The hwmon_device_instance interface could
+ * also be used to communicate with other drivers within the kernel.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/hwmon-core.h>
+#include <linux/hwmon-sysfs.h>
+
+/* building blocks */
+#define HWMON_NAME_SIZE 32
+
+struct hwmon_device_attribute {
+ struct sensor_device_attribute_2 sensor_dev;
+ struct device *hw_device;
+ enum hwmon_feature feature;
+ u32 subfeature;
+ char name[HWMON_NAME_SIZE];
+ struct list_head node;
+};
+
+enum entry_type {
+ value,
+ text
+};
+
+enum entry_count {
+ single,
+ multi,
+ trip,
+ thre
+};
+
+struct caps_info {
+ char *format;
+ mode_t mode;
+ u32 subfeature;
+ enum entry_type type;
+ enum entry_count count;
+};
+
+/* caps_info structs are used to define how the sysfs interface looks like*/
+static struct caps_info generic_caps_info[] = {
+ [generic_name] = {"name", S_IRUGO,
+ generic_name, text, single},
+ [generic_update_interval] = {"update_interval", S_IRUGO|S_IWUGO,
+ generic_update_interval,
+ value, single}
+};
+
+static struct caps_info in_caps_info[] = {
+ [in_input] = {"in%u_input", S_IRUGO,
+ in_input, value, multi},
+ [in_min] = {"in%u_min", S_IRUGO|S_IWUGO,
+ in_min, value, multi},
+ [in_max] = {"in%u_max", S_IRUGO|S_IWUGO,
+ in_max, value, multi},
+ [in_lcrit] = {"in%u_lcrit", S_IRUGO|S_IWUGO,
+ in_lcrit, value, multi},
+ [in_crit] = {"in%u_crit", S_IRUGO|S_IWUGO,
+ in_crit, value, multi},
+ [in_average] = {"in%u_average", S_IRUGO,
+ in_average, value, multi},
+ [in_lowest] = {"in%u_lowest", S_IRUGO,
+ in_lowest, value, multi},
+ [in_highest] = {"in%u_highest", S_IRUGO,
+ in_highest, value, multi},
+ [in_reset_history] = {"in%u_reset_history", S_IWUGO,
+ in_reset_history, value, multi},
+ [in_reset_history_glob] = {"in_reset_history", S_IWUGO,
+ in_reset_history_glob,
+ value, single},
+ [in_label] = {"in%u_label", S_IRUGO,
+ in_label, text, multi},
+ [in_alarm] = {"in%u_alarm", S_IRUGO,
+ in_alarm, value, multi},
+ [in_min_alarm] = {"in%u_min_alarm", S_IRUGO,
+ in_min_alarm, value, multi},
+ [in_max_alarm] = {"in%u_max_alarm", S_IRUGO,
+ in_max_alarm, value, multi},
+ [in_lcrit_alarm] = {"in%u_lcrit_alarm", S_IRUGO,
+ in_lcrit_alarm, value, multi},
+ [in_crit_alarm] = {"in%u_crit_alarm", S_IRUGO,
+ in_crit_alarm, value, multi},
+ [in_beep] = {"in%u_beep", S_IRUGO|S_IWUGO,
+ in_beep, value, multi}
+};
+
+static struct caps_info cpu_caps_info[] = {
+ [in_vid] = {"cpu%u_vid", S_IRUGO,
+ in_vid, value, multi},
+ [in_vrm] = {"vrm", S_IRUGO|S_IWUGO,
+ in_vrm, value, single},
+};
+
+static struct caps_info fan_caps_info[] = {
+ [fan_input] = {"fan%u_input", S_IRUGO,
+ fan_input, value, multi},
+ [fan_min] = {"fan%u_min", S_IRUGO|S_IWUGO,
+ fan_min, value, multi},
+ [fan_max] = {"fan%u_max", S_IRUGO|S_IWUGO,
+ fan_max, value, multi},
+ [fan_div] = {"fan%u_div", S_IRUGO|S_IWUGO,
+ fan_div, value, multi},
+ [fan_pulses] = {"fan%u_pulses", S_IRUGO|S_IWUGO,
+ fan_pulses, value, multi},
+ [fan_target] = {"fan%u_target", S_IRUGO|S_IWUGO,
+ fan_target, value, multi},
+ [fan_label] = {"fan%u_label", S_IRUGO,
+ fan_label, text, multi},
+ [fan_alarm] = {"fan%u_alarm", S_IRUGO,
+ fan_alarm, value, multi},
+ [fan_beep] = {"fan%u_beep", S_IRUGO|S_IWUGO,
+ fan_beep, value, multi},
+ [fan_fault] = {"fan%u_fault", S_IRUGO,
+ fan_fault, value, multi}
+};
+
+static struct caps_info pwm_caps_info[] = {
+ [pwm_input] = {"pwm%u", S_IRUGO|S_IWUGO,
+ pwm_input, value, multi},
+ [pwm_enable] = {"pwm%u_enable", S_IRUGO|S_IWUGO,
+ pwm_enable, value, multi},
+ [pwm_mode] = {"pwm%u_mode", S_IRUGO|S_IWUGO,
+ pwm_mode, value, multi},
+ [pwm_freq] = {"pwm%u_freq", S_IRUGO|S_IWUGO,
+ pwm_freq, value, multi},
+ [pwm_auto_channels_temp] = {"pwm%u_auto_channels_temp",
+ S_IRUGO|S_IWUGO, pwm_freq,
+ value, multi},
+ [pwm_auto_point_pwm] = {"pwm%u_auto_point%u_pwm", S_IRUGO|S_IWUGO,
+ pwm_auto_point_pwm, value, trip},
+ [pwm_auto_point_temp] = {"pwm%u_auto_point%u_temp", S_IRUGO|S_IWUGO,
+ pwm_auto_point_temp, value, trip},
+ [pwm_auto_point_temp_hyst] = {"pwm%u_auto_point%u_temp",
+ S_IRUGO|S_IWUGO, pwm_auto_point_temp,
+ value, trip},
+};
+
+static struct caps_info temp_caps_info[] = {
+ [temp_type] = {"temp%u_type,", S_IRUGO|S_IWUGO,
+ temp_type, value, multi},
+ [temp_input] = {"temp%u_input", S_IRUGO,
+ temp_input, value, multi},
+ [temp_min] = {"temp%u_min", S_IRUGO|S_IWUGO,
+ temp_min, value, multi},
+ [temp_max] = {"temp%u_max", S_IRUGO|S_IWUGO,
+ temp_max, value, multi},
+ [temp_max_hyst] = {"temp%u_max_hyst", S_IRUGO|S_IWUGO,
+ temp_max_hyst, value, multi},
+ [temp_lcrit] = {"temp%u_lcrit", S_IRUGO|S_IWUGO,
+ temp_lcrit, value, multi},
+ [temp_crit] = {"temp%u_crit", S_IRUGO|S_IWUGO,
+ temp_crit, value, multi},
+ [temp_crit_hyst] = {"temp%u_crit_hyst", S_IRUGO|S_IWUGO,
+ temp_crit_hyst, value, multi},
+ [temp_emergency] = {"temp%u_emergency", S_IRUGO|S_IWUGO,
+ temp_emergency, value, multi},
+ [temp_emergency_hyst] = {"temp%u_emergency_hyst", S_IRUGO|S_IWUGO,
+ temp_emergency_hyst, value, multi},
+ [temp_offset] = {"temp%u_offset", S_IRUGO|S_IWUGO,
+ temp_offset, value, multi},
+ [temp_label] = {"temp%u_label", S_IRUGO,
+ temp_label, text, multi},
+ [temp_lowest] = {"temp%u_lowest", S_IRUGO,
+ temp_lowest, value, multi},
+ [temp_highest] = {"temp%u_highest", S_IRUGO,
+ temp_highest, value, multi},
+ [temp_reset_history] = {"temp%u_reset_history", S_IWUGO,
+ temp_reset_history, value, multi},
+ [temp_reset_history_glob] = {"temp_reset_history", S_IWUGO,
+ temp_reset_history_glob,
+ value, single},
+ [temp_alarm] = {"temp%u_alarm", S_IRUGO,
+ temp_alarm, value, multi},
+ [temp_min_alarm] = {"temp%u_min_alarm", S_IRUGO,
+ temp_min_alarm, value, multi},
+ [temp_max_alarm] = {"temp%u_max_alarm", S_IRUGO,
+ temp_max_alarm, value, multi},
+ [temp_lcrit_alarm] = {"temp%u_lcrit_alarm", S_IRUGO,
+ temp_lcrit_alarm, value, multi},
+ [temp_crit_alarm] = {"temp%u_crit_alarm", S_IRUGO,
+ temp_crit_alarm, value, multi},
+ [temp_emergency_alarm] = {"temp%u_emergency_alarm", S_IRUGO,
+ temp_emergency_alarm,
+ value, multi},
+ [temp_beep] = {"temp%u_beep", S_IRUGO|S_IWUGO,
+ temp_beep, value, multi},
+ [temp_fault] = {"temp%u_fault", S_IRUGO,
+ temp_fault, value, multi},
+ [temp_threshold] = {"temp%u_threshold%u", S_IRUGO|S_IWUGO,
+ temp_threshold, value, thre},
+ [temp_threshold_triggered] = {"temp%u_threshold%u_triggered",
+ S_IRUGO, temp_threshold_triggered,
+ value, thre},
+ [temp_auto_point_pwm] = {"temp%u_auto_point%u_pwm", S_IRUGO|S_IWUGO,
+ temp_auto_point_pwm, value, trip},
+ [temp_auto_point_temp] = {"temp%u_auto_point%u_temp",
+ S_IRUGO|S_IWUGO,
+ temp_auto_point_temp, value, trip},
+ [temp_auto_point_temp_hyst] = {"temp%u_auto_point%u_temp_hyst",
+ S_IRUGO|S_IWUGO,
+ temp_auto_point_temp_hyst, value, trip}
+};
+
+static struct caps_info curr_caps_info[] = {
+ [curr_input] = {"curr%u_input", S_IRUGO,
+ curr_input, value, multi},
+ [curr_min] = {"curr%u_min", S_IRUGO|S_IWUGO,
+ curr_min, value, multi},
+ [curr_max] = {"curr%u_max", S_IRUGO|S_IWUGO,
+ curr_max, value, multi},
+ [curr_lcrit] = {"curr%u_lcrit", S_IRUGO|S_IWUGO,
+ curr_lcrit, value, multi},
+ [curr_crit] = {"curr%u_crit", S_IRUGO|S_IWUGO,
+ curr_crit, value, multi},
+ [curr_average] = {"curr%u_average", S_IRUGO,
+ curr_average, value, multi},
+ [curr_lowest] = {"curr%u_lowest", S_IRUGO,
+ curr_lowest, value, multi},
+ [curr_highest] = {"curr%u_highest", S_IRUGO,
+ curr_highest, value, multi},
+ [curr_reset_history] = {"curr%u_reset_history", S_IWUGO,
+ curr_reset_history, value, multi},
+ [curr_reset_history_glob] = {"curr_reset_history", S_IWUGO,
+ curr_reset_history_glob,
+ value, single},
+ [curr_alarm] = {"curr%u_alarm", S_IRUGO,
+ curr_alarm, value, multi},
+ [curr_min_alarm] = {"curr%u_min_alarm", S_IRUGO,
+ curr_min_alarm, value, multi},
+ [curr_max_alarm] = {"curr%u_max_alarm", S_IRUGO,
+ curr_max_alarm, value, multi},
+ [curr_lcrit_alarm] = {"curr%u_lcrit_alarm", S_IRUGO,
+ curr_lcrit_alarm, value, multi},
+ [curr_crit_alarm] = {"curr%u_crit_alarm", S_IRUGO,
+ curr_crit_alarm, value, multi},
+ [curr_beep] = {"curr%u_beep", S_IRUGO|S_IWUGO,
+ curr_beep, value, multi}
+};
+
+static struct caps_info power_caps_info[] = {
+ [power_input] = {"power%u_input", S_IRUGO,
+ power_input, value, multi},
+ [power_input_lowest] = {"power%u_input_lowest", S_IRUGO,
+ power_input_lowest, value, multi},
+ [power_input_highest] = {"power%u_input_highest", S_IRUGO,
+ power_input_highest, value, multi},
+ [power_reset_history] = {"power%u_reset_history", S_IWUGO,
+ power_reset_history, value, multi},
+ [power_reset_history_glob] = {"power_reset_history", S_IWUGO,
+ power_reset_history_glob,
+ value, multi},
+ [power_accuracy] = {"power%u_accuracy", S_IRUGO,
+ power_accuracy, value, multi},
+ [power_average] = {"power%u_average", S_IRUGO,
+ power_average, value, multi},
+ [power_average_interval] = {"power%u_average_interval", S_IRUGO|S_IWUGO,
+ power_average_interval,
+ value, multi},
+ [power_average_interval_min] = {"power%u_average_interval_min", S_IRUGO,
+ power_average_min,
+ value, multi},
+ [power_average_interval_max] = {"power%u_average_interval_max", S_IRUGO,
+ power_average_max,
+ value, multi},
+ [power_average_min] = {"power%u_average_min", S_IRUGO|S_IWUGO,
+ power_average_min, value, multi},
+ [power_average_max] = {"power%u_average_max", S_IRUGO|S_IWUGO,
+ power_average_max, value, multi},
+ [power_average_lowest] = {"power%u_average_lowest", S_IRUGO,
+ power_average_lowest,
+ value, multi},
+ [power_average_highest] = {"power%u_average_highest", S_IRUGO,
+ power_average_highest,
+ value, multi},
+ [power_cap] = {"power%u_cap", S_IRUGO|S_IWUGO,
+ power_cap, value, multi},
+ [power_cap_hyst] = {"power%u_cap_hyst", S_IRUGO|S_IWUGO,
+ power_cap_hyst, value, multi},
+ [power_cap_min] = {"power%u_cap_min", S_IRUGO,
+ power_cap_min, value, multi},
+ [power_cap_max] = {"power%u_cap_max", S_IRUGO,
+ power_cap_max, value, multi},
+ [power_max] = {"power%u_max", S_IRUGO|S_IWUGO,
+ power_max, value, multi},
+ [power_crit] = {"power%u_crit", S_IRUGO|S_IWUGO,
+ power_crit, value, multi},
+ [power_alarm] = {"power%u_alarm", S_IRUGO,
+ power_alarm, value, multi},
+ [power_cap_alarm] = {"power%u_cap_alarm", S_IRUGO,
+ power_cap_alarm, value, multi},
+ [power_max_alarm] = {"power%u_max_alarm", S_IRUGO,
+ power_max_alarm, value, multi},
+ [power_crit_alarm] = {"power%u_crit_alarm", S_IRUGO,
+ power_crit_alarm, value, multi}
+};
+
+static struct caps_info energy_caps_info[] = {
+ [energy_input] = {"energy%u_input", S_IRUGO,
+ energy_input, value, multi}
+};
+
+static struct caps_info humidity_caps_info[] = {
+ [humidity_input] = {"humidity%u_input", S_IRUGO,
+ humidity_input, value, multi}
+};
+
+static struct caps_info intrusion_caps_info[] = {
+ [intrusion_alarm] = {"intrusion%u_alarm", S_IRUGO|S_IWUGO,
+ intrusion_alarm, value, multi},
+ [intrusion_beep] = {"intrusion%u_beep", S_IRUGO|S_IWUGO,
+ intrusion_beep, value, multi}
+};
+
+static struct caps_info *caps_lookup[] = {
+ generic_caps_info,
+ in_caps_info,
+ cpu_caps_info,
+ fan_caps_info,
+ pwm_caps_info,
+ temp_caps_info,
+ curr_caps_info,
+ power_caps_info,
+ energy_caps_info,
+ humidity_caps_info,
+ intrusion_caps_info
+};
+
+/* basic building block functions */
+
+#define to_hwmon_device_attr(_sensor_attr) \
+ container_of(_sensor_attr, struct hwmon_device_attribute, sensor_dev)
+
+static ssize_t get_text(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+ struct hwmon_device_attribute *hw_attr = to_hwmon_device_attr(attr);
+ struct hwmon_device_instance *hw_dev =
+ dev_get_drvdata(hw_attr->hw_device);
+ return hw_dev->get_text_attr(hw_attr->hw_device, hw_attr->feature,
+ hw_attr->subfeature, attr->index, buf);
+}
+
+static ssize_t get_num(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+ struct hwmon_device_attribute *hw_attr = to_hwmon_device_attr(attr);
+ struct hwmon_device_instance *hw_dev =
+ dev_get_drvdata(hw_attr->hw_device);
+ int value, ret;
+ ret = hw_dev->get_numeric_attr(hw_attr->hw_device, hw_attr->feature,
+ hw_attr->subfeature, attr->index, attr->nr, &value);
+ if (ret)
+ return ret;
+ ret = snprintf(buf, PAGE_SIZE, "%d\n", value);
+ return ret;
+}
+
+static ssize_t set_num(struct device *dev, struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+ struct hwmon_device_attribute *hw_attr = to_hwmon_device_attr(attr);
+ struct hwmon_device_instance *hw_dev =
+ dev_get_drvdata(hw_attr->hw_device);
+ int ret;
+ long value;
+ if (kstrtol(buf, 10, &value))
+ return -EINVAL;
+ ret = hw_dev->set_numeric_attr(hw_attr->hw_device, hw_attr->feature,
+ hw_attr->subfeature, attr->index, attr->nr, value);
+ if (ret)
+ return ret;
+ return count;
+}
+
+/* functions to build/destroy sysfs */
+static int new_sysfs_entry(const char *name, mode_t mode,
+ enum hwmon_feature feature, u32 subfeature,
+ enum entry_type type, u8 index, u8 nr, struct list_head *list,
+ struct device *dev)
+{
+ struct hwmon_device_attribute *hw_dev_attr;
+ int ret = 0;
+
+ hw_dev_attr = kzalloc(sizeof(struct hwmon_device_attribute),
+ GFP_KERNEL);
+ if (!hw_dev_attr)
+ return -ENOMEM;
+
+ strlcpy(hw_dev_attr->name, name, HWMON_NAME_SIZE);
+
+ hw_dev_attr->sensor_dev.dev_attr.attr.mode = mode;
+ if (mode && S_IRUGO) {
+ if (type == value)
+ hw_dev_attr->sensor_dev.dev_attr.show = &get_num;
+ else
+ hw_dev_attr->sensor_dev.dev_attr.show = &get_text;
+ }
+ if (mode && S_IWUGO)
+ hw_dev_attr->sensor_dev.dev_attr.store = &set_num;
+
+ hw_dev_attr->sensor_dev.dev_attr.attr.name = hw_dev_attr->name;
+ hw_dev_attr->sensor_dev.index = index;
+ hw_dev_attr->sensor_dev.nr = nr;
+ hw_dev_attr->hw_device = dev;
+ hw_dev_attr->feature = feature;
+ hw_dev_attr->subfeature = subfeature;
+ sysfs_attr_init(&hw_dev_attr->sensor_dev.dev_attr.attr);
+
+ ret = device_create_file(dev->parent,
+ &hw_dev_attr->sensor_dev.dev_attr);
+ if (ret) {
+ kfree(hw_dev_attr);
+ return ret;
+ }
+
+ list_add(&hw_dev_attr->node, list);
+
+ return 0;
+}
+
+int hwmon_create_sysfs(struct device *dev)
+{
+ struct hwmon_device_instance *hw_dev = dev_get_drvdata(dev);
+ struct hwmon_device_caps *caps = &hw_dev->caps;
+ char attr_name[HWMON_NAME_SIZE];
+ int i, j, k, count;
+ unsigned long bit;
+
+ INIT_LIST_HEAD(&hw_dev->sysfs_node);
+
+ for (i = 0; i < hwmon_feature_size; i++) {
+ if (!caps->num_channels[i])
+ continue;
+
+ for (j = 1; j <= caps->num_channels[i]; j++) {
+ if (!caps->subfeature_caps[i][j-1])
+ continue;
+
+ for_each_set_bit(bit,
+ (long *)&caps->subfeature_caps[i][j-1], 32) {
+ struct caps_info info = caps_lookup[i][bit];
+ if ((info.count == single) && (j > 1))
+ continue;
+
+ if (info.count == trip)
+ count = caps->num_trippoints[i][j-1];
+ else if (info.count == thre)
+ count = caps->num_thresholds[i][j-1];
+ else
+ count = 1;
+
+ for (k = 1; k <= count; k++) {
+ snprintf(attr_name, HWMON_NAME_SIZE,
+ info.format, j, k);
+
+ if (new_sysfs_entry(attr_name,
+ info.mode, i,
+ info.subfeature,
+ info.type, j, k,
+ &hw_dev->sysfs_node,
+ dev))
+ goto fail;
+ }
+ }
+ }
+ }
+
+ return 0;
+
+fail:
+ hwmon_destroy_sysfs(dev);
+ return -EAGAIN;
+}
+EXPORT_SYMBOL_GPL(hwmon_create_sysfs);
+
+void hwmon_destroy_sysfs(struct device *dev)
+{
+ struct hwmon_device_instance *hw_dev = dev_get_drvdata(dev);
+ struct hwmon_device_attribute *hw_dev_attr, *tmp;
+
+ list_for_each_entry_safe(hw_dev_attr, tmp, &hw_dev->sysfs_node, node) {
+ device_remove_file(dev->parent,
+ &hw_dev_attr->sensor_dev.dev_attr);
+ list_del(&hw_dev_attr->node);
+ kfree(hw_dev_attr);
+ }
+}
+EXPORT_SYMBOL_GPL(hwmon_destroy_sysfs);
+
+MODULE_AUTHOR("Lucas Stach <dev at lynxeye.de>");
+MODULE_DESCRIPTION("Hardware monitoring core API");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/hwmon-core.h b/include/linux/hwmon-core.h
new file mode 100644
index 0000000..c065d67
--- /dev/null
+++ b/include/linux/hwmon-core.h
@@ -0,0 +1,229 @@
+/**
+ * hwmon-core.h
+ * Copyright (C) 2011 Lucas Stach <dev at lynxeye.de>
+ *
+ * hwmon-core interface definitions
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef HWMON_CORE_H_
+#define HWMON_CORE_H_
+
+int hwmon_create_sysfs(struct device *dev);
+
+void hwmon_destroy_sysfs(struct device *dev);
+
+/*
+ * enum hwmon_feature: used as a lookup into the channel and subfeature array
+ */
+enum hwmon_feature {
+ hwmon_feature_generic,
+ hwmon_feature_in,
+ hwmon_feature_cpu,
+ hwmon_feature_fan,
+ hwmon_feature_pwm,
+ hwmon_feature_temp,
+ hwmon_feature_curr,
+ hwmon_feature_power,
+ hwmon_feature_energy,
+ hwmon_feature_humidity,
+ hwmon_feature_intrusion,
+
+ hwmon_feature_size /* dummy entry */
+};
+
+/*
+ * enums to describe the position of the subfeature caps in their
+ * respective bitfields and for use in the query api
+ */
+enum generic_attr {
+ generic_name,
+ generic_update_interval
+};
+
+enum in_attr {
+ in_input,
+ in_min,
+ in_max,
+ in_lcrit,
+ in_crit,
+ in_average,
+ in_lowest,
+ in_highest,
+ in_reset_history,
+ in_reset_history_glob,
+ in_label,
+ in_alarm,
+ in_min_alarm,
+ in_max_alarm,
+ in_lcrit_alarm,
+ in_crit_alarm,
+ in_vid,
+ in_vrm,
+ in_beep
+};
+
+enum cpu_attr {
+ cpu_vid,
+ cpu_vrm
+};
+
+enum fan_attr {
+ fan_input,
+ fan_min,
+ fan_max,
+ fan_div,
+ fan_pulses,
+ fan_target,
+ fan_label,
+ fan_alarm,
+ fan_beep,
+ fan_fault
+};
+
+enum pwm_attr {
+ pwm_input,
+ pwm_enable,
+ pwm_mode,
+ pwm_freq,
+ pwm_auto_channels_temp,
+ pwm_auto_point_pwm,
+ pwm_auto_point_temp,
+ pwm_auto_point_temp_hyst
+};
+
+enum temp_attr {
+ temp_type,
+ temp_input,
+ temp_min,
+ temp_max,
+ temp_max_hyst,
+ temp_lcrit,
+ temp_crit,
+ temp_crit_hyst,
+ temp_emergency,
+ temp_emergency_hyst,
+ temp_offset,
+ temp_label,
+ temp_lowest,
+ temp_highest,
+ temp_reset_history,
+ temp_reset_history_glob,
+ temp_alarm,
+ temp_min_alarm,
+ temp_max_alarm,
+ temp_lcrit_alarm,
+ temp_crit_alarm,
+ temp_emergency_alarm,
+ temp_beep,
+ temp_fault,
+ temp_auto_point_pwm,
+ temp_auto_point_temp,
+ temp_auto_point_temp_hyst,
+ temp_threshold,
+ temp_threshold_triggered
+};
+
+enum curr_attr {
+ curr_input,
+ curr_min,
+ curr_max,
+ curr_lcrit,
+ curr_crit,
+ curr_average,
+ curr_lowest,
+ curr_highest,
+ curr_reset_history,
+ curr_reset_history_glob,
+ curr_alarm,
+ curr_min_alarm,
+ curr_max_alarm,
+ curr_lcrit_alarm,
+ curr_crit_alarm,
+ curr_beep
+};
+
+enum power_attr {
+ power_input,
+ power_input_lowest,
+ power_input_highest,
+ power_reset_history,
+ power_reset_history_glob,
+ power_accuracy,
+ power_average,
+ power_average_interval,
+ power_average_interval_min,
+ power_average_interval_max,
+ power_average_min,
+ power_average_max,
+ power_average_lowest,
+ power_average_highest,
+ power_cap,
+ power_cap_hyst,
+ power_cap_min,
+ power_cap_max,
+ power_max,
+ power_crit,
+ power_alarm,
+ power_cap_alarm,
+ power_max_alarm,
+ power_crit_alarm
+};
+
+enum energy_attr {
+ energy_input
+};
+
+enum humidity_attr {
+ humidity_input
+};
+
+enum intrusion_attr {
+ intrusion_alarm,
+ intrusion_beep
+};
+
+/* the core interface */
+struct hwmon_device_caps {
+ /*
+ * number of channels
+ * (feature to index mapping through enum hwmon_feature)
+ * a channel count of 0 denotes an unsupported feature
+ */
+ u8 num_channels[hwmon_feature_size];
+
+ /*
+ * attach your num_channels[feature] sized arrays of bitfields here
+ * to indicate subfeature capabilities, a zero bitfield denotes an
+ * unsupported sensor
+ */
+ u32 *subfeature_caps[hwmon_feature_size];
+ u8 *num_trippoints[hwmon_feature_size];
+ /* XXX: we have only temp thresholds at this point, so we are wasting a
+ * few pointers here, but better be future safe
+ */
+ u8 *num_thresholds[hwmon_feature_size];
+};
+
+struct hwmon_device_instance {
+ struct hwmon_device_caps caps;
+ int (*get_numeric_attr) (struct device *hw_device,
+ enum hwmon_feature feature, u32 subfeature, u8 index,
+ u8 nr, int *value);
+ int (*set_numeric_attr) (struct device *hw_device,
+ enum hwmon_feature feature, u32 subfeature, u8 index,
+ u8 nr, int value);
+ int (*get_text_attr) (struct device *hw_device,
+ enum hwmon_feature feature, u32 subfeature, u8 index,
+ char *buf);
+ struct list_head sysfs_node;
+ void *inst_data;
+};
+
+/* helper function to assist filling the subfeature bitfields */
+#define HWMON_CAP(_cap_enum) (u32)BIT(_cap_enum)
+
+#endif /* HWMON_CORE_H_ */
--
1.7.7.3
More information about the lm-sensors
mailing list