gallium/hud: Remove superfluous debug
[mesa.git] / src / gallium / auxiliary / hud / hud_sensors_temp.c
1 /**************************************************************************
2 *
3 * Copyright (C) 2016 Steven Toth <stoth@kernellabs.com>
4 * Copyright (C) 2016 Zodiac Inflight Innovations
5 * All Rights Reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the
9 * "Software"), to deal in the Software without restriction, including
10 * without limitation the rights to use, copy, modify, merge, publish,
11 * distribute, sub license, and/or sell copies of the Software, and to
12 * permit persons to whom the Software is furnished to do so, subject to
13 * the following conditions:
14 *
15 * The above copyright notice and this permission notice (including the
16 * next paragraph) shall be included in all copies or substantial portions
17 * of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
22 * IN NO EVENT SHALL THE AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR
23 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 *
27 **************************************************************************/
28
29 #if HAVE_LIBSENSORS
30 /* Purpose: Extract lm-sensors data, expose temperature, power, voltage. */
31
32 #include "hud/hud_private.h"
33 #include "util/list.h"
34 #include "os/os_time.h"
35 #include "util/u_memory.h"
36 #include <stdio.h>
37 #include <unistd.h>
38 #include <dirent.h>
39 #include <stdlib.h>
40 #include <unistd.h>
41 #include <inttypes.h>
42 #include <sys/types.h>
43 #include <sys/stat.h>
44 #include <unistd.h>
45 #include <sensors/sensors.h>
46
47 /* TODO: We don't handle dynamic sensor discovery / arrival or removal.
48 * Static globals specific to this HUD category.
49 */
50 static int gsensors_temp_count = 0;
51 static struct list_head gsensors_temp_list;
52
53 struct sensors_temp_info
54 {
55 struct list_head list;
56
57 /* Combined chip and feature name, human readable. */
58 char name[64];
59
60 /* The type of measurement, critical or current. */
61 unsigned int mode;
62
63 uint64_t last_time;
64
65 char chipname[64];
66 char featurename[128];
67
68 sensors_chip_name *chip;
69 const sensors_feature *feature;
70 double current, min, max, critical;
71 };
72
73 static double
74 get_value(const sensors_chip_name *name, const sensors_subfeature *sub)
75 {
76 double val;
77 int err;
78
79 err = sensors_get_value(name, sub->number, &val);
80 if (err) {
81 fprintf(stderr, "ERROR: Can't get value of subfeature %s\n", sub->name);
82 val = 0;
83 }
84 return val;
85 }
86
87 static void
88 get_sensor_values(struct sensors_temp_info *sti)
89 {
90 const sensors_subfeature *sf;
91
92 switch(sti->mode) {
93 case SENSORS_VOLTAGE_CURRENT:
94 sf = sensors_get_subfeature(sti->chip, sti->feature,
95 SENSORS_SUBFEATURE_IN_INPUT);
96 if (sf)
97 sti->current = get_value(sti->chip, sf);
98 break;
99 case SENSORS_CURRENT_CURRENT:
100 sf = sensors_get_subfeature(sti->chip, sti->feature,
101 SENSORS_SUBFEATURE_CURR_INPUT);
102 if (sf) {
103 /* Sensors API returns in AMPs, even though driver is reporting mA,
104 * convert back to mA */
105 sti->current = get_value(sti->chip, sf) * 1000;
106 }
107 break;
108 case SENSORS_TEMP_CURRENT:
109 sf = sensors_get_subfeature(sti->chip, sti->feature,
110 SENSORS_SUBFEATURE_TEMP_INPUT);
111 if (sf)
112 sti->current = get_value(sti->chip, sf);
113 break;
114 case SENSORS_TEMP_CRITICAL:
115 sf = sensors_get_subfeature(sti->chip, sti->feature,
116 SENSORS_SUBFEATURE_TEMP_CRIT);
117 if (sf)
118 sti->critical = get_value(sti->chip, sf);
119 break;
120 case SENSORS_POWER_CURRENT:
121 sf = sensors_get_subfeature(sti->chip, sti->feature,
122 SENSORS_SUBFEATURE_POWER_INPUT);
123 if (sf) {
124 /* Sensors API returns in WATTs, even though driver is reporting mW,
125 * convert back to mW */
126 sti->current = get_value(sti->chip, sf) * 1000;
127 }
128 break;
129 }
130
131 sf = sensors_get_subfeature(sti->chip, sti->feature,
132 SENSORS_SUBFEATURE_TEMP_MIN);
133 if (sf)
134 sti->min = get_value(sti->chip, sf);
135
136 sf = sensors_get_subfeature(sti->chip, sti->feature,
137 SENSORS_SUBFEATURE_TEMP_MAX);
138 if (sf)
139 sti->max = get_value(sti->chip, sf);
140 }
141
142 static struct sensors_temp_info *
143 find_sti_by_name(const char *n, unsigned int mode)
144 {
145 list_for_each_entry(struct sensors_temp_info, sti, &gsensors_temp_list, list) {
146 if (sti->mode != mode)
147 continue;
148 if (strcasecmp(sti->name, n) == 0)
149 return sti;
150 }
151 return 0;
152 }
153
154 static void
155 query_sti_load(struct hud_graph *gr)
156 {
157 struct sensors_temp_info *sti = gr->query_data;
158 uint64_t now = os_time_get();
159
160 if (sti->last_time) {
161 if (sti->last_time + gr->pane->period <= now) {
162 get_sensor_values(sti);
163
164 switch (sti->mode) {
165 case SENSORS_TEMP_CURRENT:
166 hud_graph_add_value(gr, (uint64_t) sti->current);
167 break;
168 case SENSORS_TEMP_CRITICAL:
169 hud_graph_add_value(gr, (uint64_t) sti->critical);
170 break;
171 case SENSORS_VOLTAGE_CURRENT:
172 hud_graph_add_value(gr, (uint64_t)(sti->current * 1000));
173 break;
174 case SENSORS_CURRENT_CURRENT:
175 hud_graph_add_value(gr, (uint64_t) sti->current);
176 break;
177 case SENSORS_POWER_CURRENT:
178 hud_graph_add_value(gr, (uint64_t) sti->current);
179 break;
180 }
181
182 sti->last_time = now;
183 }
184 }
185 else {
186 /* initialize */
187 get_sensor_values(sti);
188 sti->last_time = now;
189 }
190 }
191
192 static void
193 free_query_data(void *p)
194 {
195 struct sensors_temp_info *sti = (struct sensors_temp_info *) p;
196 list_del(&sti->list);
197 if (sti->chip)
198 sensors_free_chip_name(sti->chip);
199 FREE(sti);
200 sensors_cleanup();
201 }
202
203 /**
204 * Create and initialize a new object for a specific sensor interface dev.
205 * \param pane parent context.
206 * \param dev_name device name, EG. 'coretemp-isa-0000.Core 1'
207 * \param mode query type (NIC_DIRECTION_RX/WR/RSSI) statistics.
208 */
209 void
210 hud_sensors_temp_graph_install(struct hud_pane *pane, const char *dev_name,
211 unsigned int mode)
212 {
213 struct hud_graph *gr;
214 struct sensors_temp_info *sti;
215
216 int num_devs = hud_get_num_sensors(0);
217 if (num_devs <= 0)
218 return;
219
220 sti = find_sti_by_name(dev_name, mode);
221 if (!sti)
222 return;
223
224 gr = CALLOC_STRUCT(hud_graph);
225 if (!gr)
226 return;
227
228 snprintf(gr->name, sizeof(gr->name), "%.6s..%s (%s)",
229 sti->chipname,
230 sti->featurename,
231 sti->mode == SENSORS_VOLTAGE_CURRENT ? "Volts" :
232 sti->mode == SENSORS_CURRENT_CURRENT ? "Amps" :
233 sti->mode == SENSORS_TEMP_CURRENT ? "Curr" :
234 sti->mode == SENSORS_POWER_CURRENT ? "Pow" :
235 sti->mode == SENSORS_TEMP_CRITICAL ? "Crit" : "Unkn");
236
237 gr->query_data = sti;
238 gr->query_new_value = query_sti_load;
239
240 /* Don't use free() as our callback as that messes up Gallium's
241 * memory debugger. Use simple free_query_data() wrapper.
242 */
243 gr->free_query_data = free_query_data;
244
245 hud_pane_add_graph(pane, gr);
246 switch (sti->mode) {
247 case SENSORS_TEMP_CURRENT:
248 case SENSORS_TEMP_CRITICAL:
249 hud_pane_set_max_value(pane, 120);
250 break;
251 case SENSORS_VOLTAGE_CURRENT:
252 hud_pane_set_max_value(pane, 12);
253 break;
254 case SENSORS_CURRENT_CURRENT:
255 hud_pane_set_max_value(pane, 5000);
256 break;
257 case SENSORS_POWER_CURRENT:
258 hud_pane_set_max_value(pane, 5000 /* mW */);
259 break;
260 }
261 }
262
263 static void
264 create_object(const char *chipname, const char *featurename,
265 const sensors_chip_name *chip, const sensors_feature *feature,
266 int mode)
267 {
268 struct sensors_temp_info *sti = CALLOC_STRUCT(sensors_temp_info);
269
270 sti->mode = mode;
271 sti->chip = (sensors_chip_name *) chip;
272 sti->feature = feature;
273 strcpy(sti->chipname, chipname);
274 strcpy(sti->featurename, featurename);
275 snprintf(sti->name, sizeof(sti->name), "%s.%s", sti->chipname,
276 sti->featurename);
277
278 list_addtail(&sti->list, &gsensors_temp_list);
279 gsensors_temp_count++;
280 }
281
282 static void
283 build_sensor_list(void)
284 {
285 const sensors_chip_name *chip;
286 const sensors_chip_name *match = 0;
287 const sensors_feature *feature;
288 int chip_nr = 0;
289
290 char name[256];
291 while ((chip = sensors_get_detected_chips(match, &chip_nr))) {
292 sensors_snprintf_chip_name(name, sizeof(name), chip);
293
294 /* Get all features and filter accordingly. */
295 int fnr = 0;
296 while ((feature = sensors_get_features(chip, &fnr))) {
297 char *featurename = sensors_get_label(chip, feature);
298 if (!featurename)
299 continue;
300
301 /* Create a 'current' and 'critical' object pair.
302 * Ignore sensor if its not temperature based.
303 */
304 switch(feature->type) {
305 case SENSORS_FEATURE_TEMP:
306 create_object(name, featurename, chip, feature,
307 SENSORS_TEMP_CURRENT);
308 create_object(name, featurename, chip, feature,
309 SENSORS_TEMP_CRITICAL);
310 break;
311 case SENSORS_FEATURE_IN:
312 create_object(name, featurename, chip, feature,
313 SENSORS_VOLTAGE_CURRENT);
314 break;
315 case SENSORS_FEATURE_CURR:
316 create_object(name, featurename, chip, feature,
317 SENSORS_CURRENT_CURRENT);
318 break;
319 case SENSORS_FEATURE_POWER:
320 create_object(name, featurename, chip, feature,
321 SENSORS_POWER_CURRENT);
322 break;
323 default:
324 break;
325 }
326 free(featurename);
327 }
328 }
329 }
330
331 /**
332 * Initialize internal object arrays and display lmsensors HUD help.
333 * \param displayhelp true if the list of detected devices should be
334 displayed on the console.
335 * \return number of detected lmsensor devices.
336 */
337 int
338 hud_get_num_sensors(bool displayhelp)
339 {
340 /* Return the number of sensors detected. */
341 if (gsensors_temp_count)
342 return gsensors_temp_count;
343
344 int ret = sensors_init(NULL);
345 if (ret)
346 return 0;
347
348 list_inithead(&gsensors_temp_list);
349
350 /* Scan /sys/block, for every object type we support, create and
351 * persist an object to represent its different statistics.
352 */
353 build_sensor_list();
354
355 if (displayhelp) {
356 list_for_each_entry(struct sensors_temp_info, sti, &gsensors_temp_list, list) {
357 char line[64];
358 switch (sti->mode) {
359 case SENSORS_TEMP_CURRENT:
360 snprintf(line, sizeof(line), " sensors_temp_cu-%s", sti->name);
361 break;
362 case SENSORS_TEMP_CRITICAL:
363 snprintf(line, sizeof(line), " sensors_temp_cr-%s", sti->name);
364 break;
365 case SENSORS_VOLTAGE_CURRENT:
366 snprintf(line, sizeof(line), " sensors_volt_cu-%s", sti->name);
367 break;
368 case SENSORS_CURRENT_CURRENT:
369 snprintf(line, sizeof(line), " sensors_curr_cu-%s", sti->name);
370 break;
371 case SENSORS_POWER_CURRENT:
372 snprintf(line, sizeof(line), " sensors_pow_cu-%s", sti->name);
373 break;
374 }
375
376 puts(line);
377 }
378 }
379
380 return gsensors_temp_count;
381 }
382
383 #endif /* HAVE_LIBSENSORS */