blob: fd8100ecc48c35b7fffdf8671ff61e41ae4acf36 [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
80int sensor_dump(void)
81{
82 printf("\nSensor Information:\n");
83 printf("*******************\n\n");
84
85 return tree_for_each(sensor_tree, sensor_dump_cb, NULL);
86}
87
88static struct sensor_info *sensor_alloc(void)
89{
90 struct sensor_info *sensor;
91
92 sensor = malloc(sizeof(*sensor));
93 if (sensor)
94 memset(sensor, 0, sizeof(*sensor));
95
96 return sensor;
97}
98
99static int read_sensor_cb(struct tree *tree, void *data)
100{
101 DIR *dir;
102 int value;
103 struct dirent dirent, *direntp;
104 struct sensor_info *sensor = tree->private;
105
106 int nrtemps = 0;
107 int nrfans = 0;
108
109 dir = opendir(tree->path);
110 if (!dir)
111 return -1;
112
113 file_read_value(tree->path, "name", "%s", sensor->name);
114
115 while (!readdir_r(dir, &dirent, &direntp)) {
116
117 if (!direntp)
118 break;
119
120 if (direntp->d_type != DT_REG)
121 continue;
122
123 if (!strncmp(direntp->d_name, "temp", 4)) {
124
125 if (file_read_value(tree->path, direntp->d_name, "%d",
126 &value))
127 continue;
128
129 sensor->temperatures =
130 realloc(sensor->temperatures,
131 sizeof(struct temp_info) * (nrtemps + 1));
132 if (!sensor->temperatures)
133 continue;
134
135 strcpy(sensor->temperatures[nrtemps].name,
136 direntp->d_name);
137 sensor->temperatures[nrtemps].temp = value;
138
139 nrtemps++;
140 }
141
142 if (!strncmp(direntp->d_name, "fan", 3)) {
143
144 if (file_read_value(tree->path, direntp->d_name, "%d",
145 &value))
146 continue;
147
148 sensor->fans =
149 realloc(sensor->fans,
150 sizeof(struct temp_info) * (nrfans + 1));
151 if (!sensor->fans)
152 continue;
153
154 strcpy(sensor->fans[nrfans].name,
155 direntp->d_name);
156 sensor->fans[nrfans].rpms = value;
157
158 nrfans++;
159 }
160 }
161
162 sensor->nrtemps = nrtemps;
163 sensor->nrfans = nrfans;
164
165 closedir(dir);
166
167 return 0;
168}
169
Shaojie Sunc1462e72013-08-20 20:35:15 +0800170static int read_sensor_info(struct tree *tree)
171{
172 return tree_for_each(tree, read_sensor_cb, NULL);
173}
174
Daniel Lezcano3d0aef42011-06-15 15:45:12 +0200175static int fill_sensor_cb(struct tree *t, void *data)
176{
177 struct sensor_info *sensor;
178
179 sensor = sensor_alloc();
180 if (!sensor)
181 return -1;
182
183 t->private = sensor;
184
185 if (!t->parent)
186 return 0;
187
188 return read_sensor_cb(t, data);
189}
190
191static int fill_sensor_tree(void)
192{
193 return tree_for_each(sensor_tree, fill_sensor_cb, NULL);
194}
195
196static int sensor_filter_cb(const char *name)
197{
198 /* let's ignore some directories in order to avoid to be
199 * pulled inside the sysfs circular symlinks mess/hell
200 * (choose the word which fit better)
201 */
202 if (!strcmp(name, "subsystem"))
203 return 1;
204
205 if (!strcmp(name, "driver"))
206 return 1;
207
208 if (!strcmp(name, "hwmon"))
209 return 1;
210
211 if (!strcmp(name, "power"))
212 return 1;
213
214 return 0;
215}
216
Daniel Lezcano2e9df762011-06-15 15:45:12 +0200217static int sensor_display_cb(struct tree *t, void *data)
218{
219 struct sensor_info *sensor = t->private;
220 int *line = data;
221 char buf[1024];
222 int i;
223
224 if (!strlen(sensor->name))
225 return 0;
226
227 sprintf(buf, "%s", sensor->name);
228 display_print_line(SENSOR, *line, buf, 1, t);
229
230 (*line)++;
231
232 for (i = 0; i < sensor->nrtemps; i++) {
Daniel Lezcanoe262b592011-10-20 13:49:27 +0200233 sprintf(buf, " %-35s%.1f", sensor->temperatures[i].name,
Daniel Lezcano2e9df762011-06-15 15:45:12 +0200234 (float)sensor->temperatures[i].temp / 1000);
235 display_print_line(SENSOR, *line, buf, 0, t);
236 (*line)++;
237 }
238
239 for (i = 0; i < sensor->nrfans; i++) {
240 sprintf(buf, " %-35s%d rpm", sensor->fans[i].name,
241 sensor->fans[i].rpms);
242 display_print_line(SENSOR, *line, buf, 0, t);
243 (*line)++;
244 }
245
246 return 0;
247}
248
Daniel Lezcanofa453332011-06-21 00:57:08 +0200249static int sensor_print_header(void)
250{
251 char *buf;
252 int ret;
253
254 if (asprintf(&buf, "%-36s%s", "Name", "Value") < 0)
255 return -1;
256
Daniel Lezcano372ffba2011-06-21 00:57:08 +0200257 ret = display_column_name(buf);
Daniel Lezcanofa453332011-06-21 00:57:08 +0200258
259 free(buf);
260
261 return ret;
262}
263
Shaojie Sunc1462e72013-08-20 20:35:15 +0800264static int sensor_print_info(struct tree *tree)
Daniel Lezcano2e9df762011-06-15 15:45:12 +0200265{
266 int ret, line = 0;
267
268 display_reset_cursor(SENSOR);
269
Daniel Lezcanofa453332011-06-21 00:57:08 +0200270 sensor_print_header();
Daniel Lezcano2e9df762011-06-15 15:45:12 +0200271
Shaojie Sunc1462e72013-08-20 20:35:15 +0800272 ret = tree_for_each(tree, sensor_display_cb, &line);
Daniel Lezcano2e9df762011-06-15 15:45:12 +0200273
274 display_refresh_pad(SENSOR);
275
276 return ret;
277}
278
Shaojie Sunc1462e72013-08-20 20:35:15 +0800279static int sensor_display(bool refresh)
280{
281 if (refresh && read_sensor_info(sensor_tree))
282 return -1;
283
284 return sensor_print_info(sensor_tree);
285}
286
Daniel Lezcanob301b082011-06-15 15:45:12 +0200287static struct display_ops sensor_ops = {
288 .display = sensor_display,
289};
290
Daniel Lezcanob4eec7e2016-02-18 16:44:55 +0000291int sensor_init(struct powerdebug_options *options)
Daniel Lezcano3d0aef42011-06-15 15:45:12 +0200292{
Daniel Lezcanob4eec7e2016-02-18 16:44:55 +0000293 if (!(options->flags & SENSOR_OPTION))
294 return 0;
295
Daniel Lezcano25fc4a32011-08-25 15:46:13 +0200296 sensor_tree = tree_load(SYSFS_SENSOR, sensor_filter_cb, false);
Daniel Lezcano3d0aef42011-06-15 15:45:12 +0200297 if (!sensor_tree)
298 return -1;
299
Daniel Lezcanocaafece2011-06-27 22:59:17 +0200300 if (fill_sensor_tree())
301 return -1;
302
Daniel Lezcano1eedd482016-02-22 11:05:51 +0000303 return display_register(SENSOR, &sensor_ops);
Daniel Lezcano3d0aef42011-06-15 15:45:12 +0200304}