2 * Copyright (C) ARM Limited 2013-2014. All rights reserved.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
9 #include "HwmonDriver.h"
11 #include "libsensors/sensors.h"
15 // feature->type to input map
16 static sensors_subfeature_type getInput(const sensors_feature_type type) {
18 case SENSORS_FEATURE_IN: return SENSORS_SUBFEATURE_IN_INPUT;
19 case SENSORS_FEATURE_FAN: return SENSORS_SUBFEATURE_FAN_INPUT;
20 case SENSORS_FEATURE_TEMP: return SENSORS_SUBFEATURE_TEMP_INPUT;
21 case SENSORS_FEATURE_POWER: return SENSORS_SUBFEATURE_POWER_INPUT;
22 case SENSORS_FEATURE_ENERGY: return SENSORS_SUBFEATURE_ENERGY_INPUT;
23 case SENSORS_FEATURE_CURR: return SENSORS_SUBFEATURE_CURR_INPUT;
24 case SENSORS_FEATURE_HUMIDITY: return SENSORS_SUBFEATURE_HUMIDITY_INPUT;
26 logg->logError(__FILE__, __LINE__, "Unsupported hwmon feature %i", type);
31 class HwmonCounter : public DriverCounter {
33 HwmonCounter(DriverCounter *next, char *const name, const sensors_chip_name *chip, const sensors_feature *feature);
36 const char *getLabel() const { return label; }
37 const char *getTitle() const { return title; }
38 bool isDuplicate() const { return duplicate; }
39 const char *getDisplay() const { return display; }
40 const char *getCounterClass() const { return counter_class; }
41 const char *getUnit() const { return unit; }
42 int getModifier() const { return modifier; }
47 void init(const sensors_chip_name *chip, const sensors_feature *feature);
49 const sensors_chip_name *chip;
50 const sensors_feature *feature;
54 const char *counter_class;
56 double previous_value;
61 // Intentionally unimplemented
62 HwmonCounter(const HwmonCounter &);
63 HwmonCounter &operator=(const HwmonCounter &);
66 HwmonCounter::HwmonCounter(DriverCounter *next, char *const name, const sensors_chip_name *chip, const sensors_feature *feature) : DriverCounter(next, name), chip(chip), feature(feature), duplicate(false) {
67 label = sensors_get_label(chip, feature);
69 switch (feature->type) {
70 case SENSORS_FEATURE_IN:
73 counter_class = "absolute";
78 case SENSORS_FEATURE_FAN:
81 counter_class = "absolute";
86 case SENSORS_FEATURE_TEMP:
87 title = "Temperature";
89 counter_class = "absolute";
94 case SENSORS_FEATURE_POWER:
97 counter_class = "absolute";
102 case SENSORS_FEATURE_ENERGY:
104 display = "accumulate";
105 counter_class = "delta";
110 case SENSORS_FEATURE_CURR:
113 counter_class = "absolute";
118 case SENSORS_FEATURE_HUMIDITY:
121 counter_class = "absolute";
127 logg->logError(__FILE__, __LINE__, "Unsupported hwmon feature %i", feature->type);
131 for (HwmonCounter * counter = static_cast<HwmonCounter *>(next); counter != NULL; counter = static_cast<HwmonCounter *>(counter->getNext())) {
132 if (strcmp(label, counter->getLabel()) == 0 && strcmp(title, counter->getTitle()) == 0) {
134 counter->duplicate = true;
140 HwmonCounter::~HwmonCounter() {
144 int64_t HwmonCounter::read() {
147 const sensors_subfeature *subfeature;
149 // Keep in sync with the read check in HwmonDriver::readEvents
150 subfeature = sensors_get_subfeature(chip, feature, getInput(feature->type));
152 logg->logError(__FILE__, __LINE__, "No input value for hwmon sensor %s", label);
156 if (sensors_get_value(chip, subfeature->number, &value) != 0) {
157 logg->logError(__FILE__, __LINE__, "Can't get input value for hwmon sensor %s", label);
161 result = (monotonic ? value - previous_value : value);
162 previous_value = value;
167 HwmonDriver::HwmonDriver() {
170 HwmonDriver::~HwmonDriver() {
174 void HwmonDriver::readEvents(mxml_node_t *const) {
175 int err = sensors_init(NULL);
177 logg->logMessage("Failed to initialize libsensors! (%d)", err);
180 sensors_sysfs_no_scaling = 1;
183 const sensors_chip_name *chip;
184 while ((chip = sensors_get_detected_chips(NULL, &chip_nr))) {
186 const sensors_feature *feature;
187 while ((feature = sensors_get_features(chip, &feature_nr))) {
188 // Keep in sync with HwmonCounter::read
189 // Can this counter be read?
191 const sensors_subfeature *const subfeature = sensors_get_subfeature(chip, feature, getInput(feature->type));
192 if ((subfeature == NULL) || (sensors_get_value(chip, subfeature->number, &value) != 0)) {
196 // Get the name of the counter
197 int len = sensors_snprintf_chip_name(NULL, 0, chip) + 1;
198 char *chip_name = new char[len];
199 sensors_snprintf_chip_name(chip_name, len, chip);
200 len = snprintf(NULL, 0, "hwmon_%s_%d_%d", chip_name, chip_nr, feature->number) + 1;
201 char *const name = new char[len];
202 snprintf(name, len, "hwmon_%s_%d_%d", chip_name, chip_nr, feature->number);
205 setCounters(new HwmonCounter(getCounters(), name, chip, feature));
210 void HwmonDriver::writeEvents(mxml_node_t *root) const {
211 root = mxmlNewElement(root, "category");
212 mxmlElementSetAttr(root, "name", "hwmon");
215 for (HwmonCounter *counter = static_cast<HwmonCounter *>(getCounters()); counter != NULL; counter = static_cast<HwmonCounter *>(counter->getNext())) {
216 mxml_node_t *node = mxmlNewElement(root, "event");
217 mxmlElementSetAttr(node, "counter", counter->getName());
218 mxmlElementSetAttr(node, "title", counter->getTitle());
219 if (counter->isDuplicate()) {
220 mxmlElementSetAttrf(node, "name", "%s (0x%x)", counter->getLabel(), counter->getKey());
222 mxmlElementSetAttr(node, "name", counter->getLabel());
224 mxmlElementSetAttr(node, "display", counter->getDisplay());
225 mxmlElementSetAttr(node, "class", counter->getCounterClass());
226 mxmlElementSetAttr(node, "units", counter->getUnit());
227 if (counter->getModifier() != 1) {
228 mxmlElementSetAttrf(node, "modifier", "%d", counter->getModifier());
230 if (strcmp(counter->getDisplay(), "average") == 0 || strcmp(counter->getDisplay(), "maximum") == 0) {
231 mxmlElementSetAttr(node, "average_selection", "yes");
233 snprintf(buf, sizeof(buf), "libsensors %s sensor %s (%s)", counter->getTitle(), counter->getLabel(), counter->getName());
234 mxmlElementSetAttr(node, "description", buf);
238 void HwmonDriver::start() {
239 for (DriverCounter *counter = getCounters(); counter != NULL; counter = counter->getNext()) {
240 if (!counter->isEnabled()) {