blob: b8c04526a451d58dc5c1209edfcf175b80b79f9a [file] [log] [blame]
Amit Arora39f29542010-09-14 12:03:22 +05301/*******************************************************************************
Amit Kucheriac0e17fc2011-01-17 09:35:52 +02002 * Copyright (C) 2010, Linaro Limited.
Amit Arora39f29542010-09-14 12:03:22 +05303 *
4 * This file is part of PowerDebug.
5 *
6 * All rights reserved. This program and the accompanying materials
7 * are made available under the terms of the Eclipse Public License v1.0
8 * which accompanies this distribution, and is available at
9 * http://www.eclipse.org/legal/epl-v10.html
10 *
11 * Contributors:
12 * Amit Arora <amit.arora@linaro.org> (IBM Corporation)
13 * - initial API and implementation
14 *******************************************************************************/
15
Daniel Lezcano2e9df762011-06-15 15:45:12 +020016#define _GNU_SOURCE
17#include <stdio.h>
18#undef _GNU_SOURCE
19#include <sys/types.h>
20#include <stdbool.h>
21#include <dirent.h>
22#include <string.h>
23#include <stdlib.h>
Sanjay Singh Rawat03fdbc02014-05-27 16:52:27 +053024#include <unistd.h>
Daniel Lezcano2e9df762011-06-15 15:45:12 +020025
Amit Arorae9e16b02010-08-03 10:15:20 +053026#include "powerdebug.h"
Daniel Lezcanob301b082011-06-15 15:45:12 +020027#include "display.h"
Amit Arorae9e16b02010-08-03 10:15:20 +053028#include "sensor.h"
Daniel Lezcano3d0aef42011-06-15 15:45:12 +020029#include "tree.h"
30#include "utils.h"
Amit Arorae9e16b02010-08-03 10:15:20 +053031
Daniel Lezcano3d0aef42011-06-15 15:45:12 +020032#define SYSFS_SENSOR "/sys/class/hwmon"
Daniel Lezcanod3ffa812011-03-26 22:06:22 +010033
Daniel Lezcano3d0aef42011-06-15 15:45:12 +020034static struct tree *sensor_tree;
Sanjay Singh Rawat96f6e052014-05-26 11:35:02 +053035static bool sensor_error = false;
Daniel Lezcano3d0aef42011-06-15 15:45:12 +020036
37struct temp_info {
38 char name[NAME_MAX];
39 int temp;
40};
41
42struct fan_info {
43 char name[NAME_MAX];
44 int rpms;
45};
46
47struct sensor_info {
48 char name[NAME_MAX];
49 struct temp_info *temperatures;
50 struct fan_info *fans;
51 short nrtemps;
52 short nrfans;
53};
54
55static int sensor_dump_cb(struct tree *tree, void *data)
Amit Arorae9e16b02010-08-03 10:15:20 +053056{
Daniel Lezcano3d0aef42011-06-15 15:45:12 +020057 int i;
58 struct sensor_info *sensor = tree->private;
Amit Arorae9e16b02010-08-03 10:15:20 +053059
Daniel Lezcano3d0aef42011-06-15 15:45:12 +020060 if (!strlen(sensor->name))
61 return 0;
Amit Arorae9e16b02010-08-03 10:15:20 +053062
Daniel Lezcano3d0aef42011-06-15 15:45:12 +020063 printf("%s\n", sensor->name);
Amit Arorae9e16b02010-08-03 10:15:20 +053064
Daniel Lezcano3d0aef42011-06-15 15:45:12 +020065 for (i = 0; i < sensor->nrtemps; i++)
Daniel Lezcanoe262b592011-10-20 13:49:27 +020066 printf(" %s %.1f °C/V\n", sensor->temperatures[i].name,
Daniel Lezcano3d0aef42011-06-15 15:45:12 +020067 (float)sensor->temperatures[i].temp / 1000);
Amit Arorae9e16b02010-08-03 10:15:20 +053068
Daniel Lezcano3d0aef42011-06-15 15:45:12 +020069 for (i = 0; i < sensor->nrfans; i++)
70 printf(" %s %d rpm\n", sensor->fans[i].name,
71 sensor->fans[i].rpms);
Amit Arora422c52f2010-12-02 16:22:29 +053072
Amit Arora17552782010-12-02 12:23:14 +053073 return 0;
74}
Daniel Lezcano3d0aef42011-06-15 15:45:12 +020075
76int sensor_dump(void)
77{
78 printf("\nSensor Information:\n");
79 printf("*******************\n\n");
80
81 return tree_for_each(sensor_tree, sensor_dump_cb, NULL);
82}
83
84static struct sensor_info *sensor_alloc(void)
85{
86 struct sensor_info *sensor;
87
88 sensor = malloc(sizeof(*sensor));
89 if (sensor)
90 memset(sensor, 0, sizeof(*sensor));
91
92 return sensor;
93}
94
95static int read_sensor_cb(struct tree *tree, void *data)
96{
97 DIR *dir;
98 int value;
99 struct dirent dirent, *direntp;
100 struct sensor_info *sensor = tree->private;
101
102 int nrtemps = 0;
103 int nrfans = 0;
104
105 dir = opendir(tree->path);
106 if (!dir)
107 return -1;
108
109 file_read_value(tree->path, "name", "%s", sensor->name);
110
111 while (!readdir_r(dir, &dirent, &direntp)) {
112
113 if (!direntp)
114 break;
115
116 if (direntp->d_type != DT_REG)
117 continue;
118
119 if (!strncmp(direntp->d_name, "temp", 4)) {
120
121 if (file_read_value(tree->path, direntp->d_name, "%d",
122 &value))
123 continue;
124
125 sensor->temperatures =
126 realloc(sensor->temperatures,
127 sizeof(struct temp_info) * (nrtemps + 1));
128 if (!sensor->temperatures)
129 continue;
130
131 strcpy(sensor->temperatures[nrtemps].name,
132 direntp->d_name);
133 sensor->temperatures[nrtemps].temp = value;
134
135 nrtemps++;
136 }
137
138 if (!strncmp(direntp->d_name, "fan", 3)) {
139
140 if (file_read_value(tree->path, direntp->d_name, "%d",
141 &value))
142 continue;
143
144 sensor->fans =
145 realloc(sensor->fans,
146 sizeof(struct temp_info) * (nrfans + 1));
147 if (!sensor->fans)
148 continue;
149
150 strcpy(sensor->fans[nrfans].name,
151 direntp->d_name);
152 sensor->fans[nrfans].rpms = value;
153
154 nrfans++;
155 }
156 }
157
158 sensor->nrtemps = nrtemps;
159 sensor->nrfans = nrfans;
160
161 closedir(dir);
162
163 return 0;
164}
165
Shaojie Sunc1462e72013-08-20 20:35:15 +0800166static int read_sensor_info(struct tree *tree)
167{
168 return tree_for_each(tree, read_sensor_cb, NULL);
169}
170
Daniel Lezcano3d0aef42011-06-15 15:45:12 +0200171static int fill_sensor_cb(struct tree *t, void *data)
172{
173 struct sensor_info *sensor;
174
175 sensor = sensor_alloc();
176 if (!sensor)
177 return -1;
178
179 t->private = sensor;
180
181 if (!t->parent)
182 return 0;
183
184 return read_sensor_cb(t, data);
185}
186
187static int fill_sensor_tree(void)
188{
189 return tree_for_each(sensor_tree, fill_sensor_cb, NULL);
190}
191
192static int sensor_filter_cb(const char *name)
193{
194 /* let's ignore some directories in order to avoid to be
195 * pulled inside the sysfs circular symlinks mess/hell
196 * (choose the word which fit better)
197 */
198 if (!strcmp(name, "subsystem"))
199 return 1;
200
201 if (!strcmp(name, "driver"))
202 return 1;
203
204 if (!strcmp(name, "hwmon"))
205 return 1;
206
207 if (!strcmp(name, "power"))
208 return 1;
209
210 return 0;
211}
212
Daniel Lezcano2e9df762011-06-15 15:45:12 +0200213static int sensor_display_cb(struct tree *t, void *data)
214{
215 struct sensor_info *sensor = t->private;
216 int *line = data;
217 char buf[1024];
218 int i;
219
220 if (!strlen(sensor->name))
221 return 0;
222
223 sprintf(buf, "%s", sensor->name);
224 display_print_line(SENSOR, *line, buf, 1, t);
225
226 (*line)++;
227
228 for (i = 0; i < sensor->nrtemps; i++) {
Daniel Lezcanoe262b592011-10-20 13:49:27 +0200229 sprintf(buf, " %-35s%.1f", sensor->temperatures[i].name,
Daniel Lezcano2e9df762011-06-15 15:45:12 +0200230 (float)sensor->temperatures[i].temp / 1000);
231 display_print_line(SENSOR, *line, buf, 0, t);
232 (*line)++;
233 }
234
235 for (i = 0; i < sensor->nrfans; i++) {
236 sprintf(buf, " %-35s%d rpm", sensor->fans[i].name,
237 sensor->fans[i].rpms);
238 display_print_line(SENSOR, *line, buf, 0, t);
239 (*line)++;
240 }
241
242 return 0;
243}
244
Daniel Lezcanofa453332011-06-21 00:57:08 +0200245static int sensor_print_header(void)
246{
247 char *buf;
248 int ret;
249
250 if (asprintf(&buf, "%-36s%s", "Name", "Value") < 0)
251 return -1;
252
Daniel Lezcano372ffba2011-06-21 00:57:08 +0200253 ret = display_column_name(buf);
Daniel Lezcanofa453332011-06-21 00:57:08 +0200254
255 free(buf);
256
257 return ret;
258}
259
Shaojie Sunc1462e72013-08-20 20:35:15 +0800260static int sensor_print_info(struct tree *tree)
Daniel Lezcano2e9df762011-06-15 15:45:12 +0200261{
262 int ret, line = 0;
263
264 display_reset_cursor(SENSOR);
265
Daniel Lezcanofa453332011-06-21 00:57:08 +0200266 sensor_print_header();
Daniel Lezcano2e9df762011-06-15 15:45:12 +0200267
Shaojie Sunc1462e72013-08-20 20:35:15 +0800268 ret = tree_for_each(tree, sensor_display_cb, &line);
Daniel Lezcano2e9df762011-06-15 15:45:12 +0200269
270 display_refresh_pad(SENSOR);
271
272 return ret;
273}
274
Shaojie Sunc1462e72013-08-20 20:35:15 +0800275static int sensor_display(bool refresh)
276{
Sanjay Singh Rawat96f6e052014-05-26 11:35:02 +0530277 if (sensor_error) {
278 display_message(SENSOR,
279 "error: path " SYSFS_SENSOR " not found");
280 return -2;
281 }
282
Shaojie Sunc1462e72013-08-20 20:35:15 +0800283 if (refresh && read_sensor_info(sensor_tree))
284 return -1;
285
286 return sensor_print_info(sensor_tree);
287}
288
Daniel Lezcanob301b082011-06-15 15:45:12 +0200289static struct display_ops sensor_ops = {
290 .display = sensor_display,
291};
292
Daniel Lezcano3d0aef42011-06-15 15:45:12 +0200293int sensor_init(void)
294{
Sanjay Singh Rawat96f6e052014-05-26 11:35:02 +0530295 int ret = 0;
296
297 ret = display_register(SENSOR, &sensor_ops);
Sanjay Singh Rawat03fdbc02014-05-27 16:52:27 +0530298 if (ret)
Sanjay Singh Rawat96f6e052014-05-26 11:35:02 +0530299 printf("error: sensor display register failed");
300
301 if (access(SYSFS_SENSOR, F_OK))
302 sensor_error = true; /* set the flag */
303
Daniel Lezcano25fc4a32011-08-25 15:46:13 +0200304 sensor_tree = tree_load(SYSFS_SENSOR, sensor_filter_cb, false);
Daniel Lezcano3d0aef42011-06-15 15:45:12 +0200305 if (!sensor_tree)
306 return -1;
307
Daniel Lezcanocaafece2011-06-27 22:59:17 +0200308 if (fill_sensor_tree())
309 return -1;
310
Sanjay Singh Rawat96f6e052014-05-26 11:35:02 +0530311 return ret;
Daniel Lezcano3d0aef42011-06-15 15:45:12 +0200312}