Merge branch develop-3.10
[firefly-linux-kernel-4.4.55.git] / tools / gator / daemon / HwmonDriver.cpp
1 /**
2  * Copyright (C) ARM Limited 2013-2014. All rights reserved.
3  *
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.
7  */
8
9 #include "HwmonDriver.h"
10
11 #include "libsensors/sensors.h"
12
13 #include "Logging.h"
14
15 // feature->type to input map
16 static sensors_subfeature_type getInput(const sensors_feature_type type) {
17         switch (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;
25         default:
26                 logg->logError(__FILE__, __LINE__, "Unsupported hwmon feature %i", type);
27                 handleException();
28         }
29 };
30
31 class HwmonCounter : public DriverCounter {
32 public:
33         HwmonCounter(DriverCounter *next, char *const name, const sensors_chip_name *chip, const sensors_feature *feature);
34         ~HwmonCounter();
35
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; }
43
44         int64_t read();
45
46 private:
47         void init(const sensors_chip_name *chip, const sensors_feature *feature);
48
49         const sensors_chip_name *chip;
50         const sensors_feature *feature;
51         char *label;
52         const char *title;
53         const char *display;
54         const char *counter_class;
55         const char *unit;
56         double previous_value;
57         int modifier;
58         int monotonic: 1,
59                 duplicate : 1;
60
61         // Intentionally unimplemented
62         HwmonCounter(const HwmonCounter &);
63         HwmonCounter &operator=(const HwmonCounter &);
64 };
65
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);
68
69         switch (feature->type) {
70         case SENSORS_FEATURE_IN:
71                 title = "Voltage";
72                 display = "maximum";
73                 counter_class = "absolute";
74                 unit = "V";
75                 modifier = 1000;
76                 monotonic = false;
77                 break;
78         case SENSORS_FEATURE_FAN:
79                 title = "Fan";
80                 display = "average";
81                 counter_class = "absolute";
82                 unit = "RPM";
83                 modifier = 1;
84                 monotonic = false;
85                 break;
86         case SENSORS_FEATURE_TEMP:
87                 title = "Temperature";
88                 display = "maximum";
89                 counter_class = "absolute";
90                 unit = "°C";
91                 modifier = 1000;
92                 monotonic = false;
93                 break;
94         case SENSORS_FEATURE_POWER:
95                 title = "Power";
96                 display = "maximum";
97                 counter_class = "absolute";
98                 unit = "W";
99                 modifier = 1000000;
100                 monotonic = false;
101                 break;
102         case SENSORS_FEATURE_ENERGY:
103                 title = "Energy";
104                 display = "accumulate";
105                 counter_class = "delta";
106                 unit = "J";
107                 modifier = 1000000;
108                 monotonic = true;
109                 break;
110         case SENSORS_FEATURE_CURR:
111                 title = "Current";
112                 display = "maximum";
113                 counter_class = "absolute";
114                 unit = "A";
115                 modifier = 1000;
116                 monotonic = false;
117                 break;
118         case SENSORS_FEATURE_HUMIDITY:
119                 title = "Humidity";
120                 display = "average";
121                 counter_class = "absolute";
122                 unit = "%";
123                 modifier = 1000;
124                 monotonic = false;
125                 break;
126         default:
127                 logg->logError(__FILE__, __LINE__, "Unsupported hwmon feature %i", feature->type);
128                 handleException();
129         }
130
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) {
133                         duplicate = true;
134                         counter->duplicate = true;
135                         break;
136                 }
137         }
138 }
139
140 HwmonCounter::~HwmonCounter() {
141         free((void *)label);
142 }
143
144 int64_t HwmonCounter::read() {
145         double value;
146         double result;
147         const sensors_subfeature *subfeature;
148
149         // Keep in sync with the read check in HwmonDriver::readEvents
150         subfeature = sensors_get_subfeature(chip, feature, getInput(feature->type));
151         if (!subfeature) {
152                 logg->logError(__FILE__, __LINE__, "No input value for hwmon sensor %s", label);
153                 handleException();
154         }
155
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);
158                 handleException();
159         }
160
161         result = (monotonic ? value - previous_value : value);
162         previous_value = value;
163
164         return result;
165 }
166
167 HwmonDriver::HwmonDriver() {
168 }
169
170 HwmonDriver::~HwmonDriver() {
171         sensors_cleanup();
172 }
173
174 void HwmonDriver::readEvents(mxml_node_t *const) {
175         int err = sensors_init(NULL);
176         if (err) {
177                 logg->logMessage("Failed to initialize libsensors! (%d)", err);
178                 return;
179         }
180         sensors_sysfs_no_scaling = 1;
181
182         int chip_nr = 0;
183         const sensors_chip_name *chip;
184         while ((chip = sensors_get_detected_chips(NULL, &chip_nr))) {
185                 int feature_nr = 0;
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?
190                         double value;
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)) {
193                                 continue;
194                         }
195
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);
203                         delete [] chip_name;
204
205                         setCounters(new HwmonCounter(getCounters(), name, chip, feature));
206                 }
207         }
208 }
209
210 void HwmonDriver::writeEvents(mxml_node_t *root) const {
211         root = mxmlNewElement(root, "category");
212         mxmlElementSetAttr(root, "name", "hwmon");
213
214         char buf[1024];
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());
221                 } else {
222                         mxmlElementSetAttr(node, "name", counter->getLabel());
223                 }
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());
229                 }
230                 if (strcmp(counter->getDisplay(), "average") == 0 || strcmp(counter->getDisplay(), "maximum") == 0) {
231                         mxmlElementSetAttr(node, "average_selection", "yes");
232                 }
233                 snprintf(buf, sizeof(buf), "libsensors %s sensor %s (%s)", counter->getTitle(), counter->getLabel(), counter->getName());
234                 mxmlElementSetAttr(node, "description", buf);
235         }
236 }
237
238 void HwmonDriver::start() {
239         for (DriverCounter *counter = getCounters(); counter != NULL; counter = counter->getNext()) {
240                 if (!counter->isEnabled()) {
241                         continue;
242                 }
243                 counter->read();
244         }
245 }