blob: e054a7b387a6fad22ea609a4c6343a662400adbe [file] [log] [blame]
Daniel Lezcano7c15fad2016-02-18 15:57:43 +00001/*
2 * Power debug tool (powerdebug)
Amit Arora39f29542010-09-14 12:03:22 +05303 *
Daniel Lezcano7c15fad2016-02-18 15:57:43 +00004 * Copyright (C) 2016, Linaro Limited.
Amit Arora39f29542010-09-14 12:03:22 +05305 *
Daniel Lezcano7c15fad2016-02-18 15:57:43 +00006 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
Amit Arora39f29542010-09-14 12:03:22 +053010 *
Daniel Lezcano7c15fad2016-02-18 15:57:43 +000011 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 *
20 */
Amit Arora39f29542010-09-14 12:03:22 +053021
Daniel Lezcano2e9df762011-06-15 15:45:12 +020022#define _GNU_SOURCE
23#include <stdio.h>
24#undef _GNU_SOURCE
25#include <sys/types.h>
26#include <stdbool.h>
27#include <dirent.h>
28#include <string.h>
29#include <stdlib.h>
Sanjay Singh Rawat03fdbc02014-05-27 16:52:27 +053030#include <unistd.h>
Daniel Lezcano2e9df762011-06-15 15:45:12 +020031
Amit Arorae9e16b02010-08-03 10:15:20 +053032#include "powerdebug.h"
Daniel Lezcanob301b082011-06-15 15:45:12 +020033#include "display.h"
Daniel Lezcano3d0aef42011-06-15 15:45:12 +020034#include "tree.h"
35#include "utils.h"
Amit Arorae9e16b02010-08-03 10:15:20 +053036
Daniel Lezcano3d0aef42011-06-15 15:45:12 +020037#define SYSFS_SENSOR "/sys/class/hwmon"
Daniel Lezcanod3ffa812011-03-26 22:06:22 +010038
Daniel Lezcano3d0aef42011-06-15 15:45:12 +020039static struct tree *sensor_tree;
40
41struct temp_info {
42 char name[NAME_MAX];
43 int temp;
44};
45
46struct fan_info {
47 char name[NAME_MAX];
48 int rpms;
49};
50
51struct sensor_info {
52 char name[NAME_MAX];
53 struct temp_info *temperatures;
54 struct fan_info *fans;
55 short nrtemps;
56 short nrfans;
57};
58
59static int sensor_dump_cb(struct tree *tree, void *data)
Amit Arorae9e16b02010-08-03 10:15:20 +053060{
Daniel Lezcano3d0aef42011-06-15 15:45:12 +020061 int i;
62 struct sensor_info *sensor = tree->private;
Amit Arorae9e16b02010-08-03 10:15:20 +053063
Daniel Lezcano3d0aef42011-06-15 15:45:12 +020064 if (!strlen(sensor->name))
65 return 0;
Amit Arorae9e16b02010-08-03 10:15:20 +053066
Daniel Lezcano3d0aef42011-06-15 15:45:12 +020067 printf("%s\n", sensor->name);
Amit Arorae9e16b02010-08-03 10:15:20 +053068
Daniel Lezcano3d0aef42011-06-15 15:45:12 +020069 for (i = 0; i < sensor->nrtemps; i++)
Daniel Lezcanoe262b592011-10-20 13:49:27 +020070 printf(" %s %.1f °C/V\n", sensor->temperatures[i].name,
Daniel Lezcano3d0aef42011-06-15 15:45:12 +020071 (float)sensor->temperatures[i].temp / 1000);
Amit Arorae9e16b02010-08-03 10:15:20 +053072
Daniel Lezcano3d0aef42011-06-15 15:45:12 +020073 for (i = 0; i < sensor->nrfans; i++)
74 printf(" %s %d rpm\n", sensor->fans[i].name,
75 sensor->fans[i].rpms);
Amit Arora422c52f2010-12-02 16:22:29 +053076
Amit Arora17552782010-12-02 12:23:14 +053077 return 0;
78}
Daniel Lezcano3d0aef42011-06-15 15:45:12 +020079
Daniel Lezcano3d0aef42011-06-15 15:45:12 +020080static struct sensor_info *sensor_alloc(void)
81{
82 struct sensor_info *sensor;
83
84 sensor = malloc(sizeof(*sensor));
85 if (sensor)
86 memset(sensor, 0, sizeof(*sensor));
87
88 return sensor;
89}
90
91static int read_sensor_cb(struct tree *tree, void *data)
92{
93 DIR *dir;
94 int value;
95 struct dirent dirent, *direntp;
96 struct sensor_info *sensor = tree->private;
97
98 int nrtemps = 0;
99 int nrfans = 0;
100
101 dir = opendir(tree->path);
102 if (!dir)
103 return -1;
104
105 file_read_value(tree->path, "name", "%s", sensor->name);
106
107 while (!readdir_r(dir, &dirent, &direntp)) {
108
109 if (!direntp)
110 break;
111
112 if (direntp->d_type != DT_REG)
113 continue;
114
115 if (!strncmp(direntp->d_name, "temp", 4)) {
116
117 if (file_read_value(tree->path, direntp->d_name, "%d",
118 &value))
119 continue;
120
121 sensor->temperatures =
122 realloc(sensor->temperatures,
123 sizeof(struct temp_info) * (nrtemps + 1));
124 if (!sensor->temperatures)
125 continue;
126
127 strcpy(sensor->temperatures[nrtemps].name,
128 direntp->d_name);
129 sensor->temperatures[nrtemps].temp = value;
130
131 nrtemps++;
132 }
133
134 if (!strncmp(direntp->d_name, "fan", 3)) {
135
136 if (file_read_value(tree->path, direntp->d_name, "%d",
137 &value))
138 continue;
139
140 sensor->fans =
141 realloc(sensor->fans,
142 sizeof(struct temp_info) * (nrfans + 1));
143 if (!sensor->fans)
144 continue;
145
146 strcpy(sensor->fans[nrfans].name,
147 direntp->d_name);
148 sensor->fans[nrfans].rpms = value;
149
150 nrfans++;
151 }
152 }
153
154 sensor->nrtemps = nrtemps;
155 sensor->nrfans = nrfans;
156
157 closedir(dir);
158
159 return 0;
160}
161
Shaojie Sunc1462e72013-08-20 20:35:15 +0800162static int read_sensor_info(struct tree *tree)
163{
164 return tree_for_each(tree, read_sensor_cb, NULL);
165}
166
Daniel Lezcano3d0aef42011-06-15 15:45:12 +0200167static int fill_sensor_cb(struct tree *t, void *data)
168{
169 struct sensor_info *sensor;
170
171 sensor = sensor_alloc();
172 if (!sensor)
173 return -1;
174
175 t->private = sensor;
176
177 if (!t->parent)
178 return 0;
179
180 return read_sensor_cb(t, data);
181}
182
183static int fill_sensor_tree(void)
184{
185 return tree_for_each(sensor_tree, fill_sensor_cb, NULL);
186}
187
188static int sensor_filter_cb(const char *name)
189{
190 /* let's ignore some directories in order to avoid to be
191 * pulled inside the sysfs circular symlinks mess/hell
192 * (choose the word which fit better)
193 */
194 if (!strcmp(name, "subsystem"))
195 return 1;
196
197 if (!strcmp(name, "driver"))
198 return 1;
199
200 if (!strcmp(name, "hwmon"))
201 return 1;
202
203 if (!strcmp(name, "power"))
204 return 1;
205
206 return 0;
207}
208
Daniel Lezcano2e9df762011-06-15 15:45:12 +0200209static int sensor_display_cb(struct tree *t, void *data)
210{
211 struct sensor_info *sensor = t->private;
212 int *line = data;
213 char buf[1024];
214 int i;
215
216 if (!strlen(sensor->name))
217 return 0;
218
219 sprintf(buf, "%s", sensor->name);
220 display_print_line(SENSOR, *line, buf, 1, t);
221
222 (*line)++;
223
224 for (i = 0; i < sensor->nrtemps; i++) {
Daniel Lezcanoe262b592011-10-20 13:49:27 +0200225 sprintf(buf, " %-35s%.1f", sensor->temperatures[i].name,
Daniel Lezcano2e9df762011-06-15 15:45:12 +0200226 (float)sensor->temperatures[i].temp / 1000);
227 display_print_line(SENSOR, *line, buf, 0, t);
228 (*line)++;
229 }
230
231 for (i = 0; i < sensor->nrfans; i++) {
232 sprintf(buf, " %-35s%d rpm", sensor->fans[i].name,
233 sensor->fans[i].rpms);
234 display_print_line(SENSOR, *line, buf, 0, t);
235 (*line)++;
236 }
237
238 return 0;
239}
240
Daniel Lezcanofa453332011-06-21 00:57:08 +0200241static int sensor_print_header(void)
242{
243 char *buf;
244 int ret;
245
246 if (asprintf(&buf, "%-36s%s", "Name", "Value") < 0)
247 return -1;
248
Daniel Lezcano372ffba2011-06-21 00:57:08 +0200249 ret = display_column_name(buf);
Daniel Lezcanofa453332011-06-21 00:57:08 +0200250
251 free(buf);
252
253 return ret;
254}
255
Shaojie Sunc1462e72013-08-20 20:35:15 +0800256static int sensor_print_info(struct tree *tree)
Daniel Lezcano2e9df762011-06-15 15:45:12 +0200257{
258 int ret, line = 0;
259
260 display_reset_cursor(SENSOR);
261
Daniel Lezcanofa453332011-06-21 00:57:08 +0200262 sensor_print_header();
Daniel Lezcano2e9df762011-06-15 15:45:12 +0200263
Shaojie Sunc1462e72013-08-20 20:35:15 +0800264 ret = tree_for_each(tree, sensor_display_cb, &line);
Daniel Lezcano2e9df762011-06-15 15:45:12 +0200265
266 display_refresh_pad(SENSOR);
267
268 return ret;
269}
270
Daniel Lezcanod42d7ad2016-02-22 15:02:57 +0100271static int sensor_load_info(void)
272{
273 if (sensor_tree)
274 return 0;
275
276 sensor_tree = tree_load(SYSFS_SENSOR, sensor_filter_cb, false);
277 if (!sensor_tree)
278 return -1;
279
280 if (fill_sensor_tree())
281 return -1;
282
283 return 0;
284}
285
Thara Gopinathd78818c2017-07-14 13:15:45 -0400286int sensor_dump(void)
287{
288 if (sensor_load_info())
289 return -1;
290
291 printf("\nSensor Information:\n");
292 printf("*******************\n\n");
293
294 return tree_for_each(sensor_tree, sensor_dump_cb, NULL);
295}
296
Shaojie Sunc1462e72013-08-20 20:35:15 +0800297static int sensor_display(bool refresh)
298{
Daniel Lezcanod42d7ad2016-02-22 15:02:57 +0100299 if (sensor_load_info()) {
300 display_print_error(SENSOR, 0, "Failed to read sensor info");
301 return 0;
302 }
303
304 if (refresh && read_sensor_info(sensor_tree))
Shaojie Sunc1462e72013-08-20 20:35:15 +0800305 return -1;
306
307 return sensor_print_info(sensor_tree);
308}
309
Daniel Lezcanob301b082011-06-15 15:45:12 +0200310static struct display_ops sensor_ops = {
311 .display = sensor_display,
312};
313
Daniel Lezcanob4eec7e2016-02-18 16:44:55 +0000314int sensor_init(struct powerdebug_options *options)
Daniel Lezcano3d0aef42011-06-15 15:45:12 +0200315{
Daniel Lezcanob4eec7e2016-02-18 16:44:55 +0000316 if (!(options->flags & SENSOR_OPTION))
317 return 0;
318
Daniel Lezcano1eedd482016-02-22 11:05:51 +0000319 return display_register(SENSOR, &sensor_ops);
Daniel Lezcano3d0aef42011-06-15 15:45:12 +0200320}