blob: 3b37bc6f01716659df7dbe8839a29e361cbf340e [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;
Sanjay Singh Rawat96f6e052014-05-26 11:35:02 +053040static bool sensor_error = false;
Daniel Lezcano3d0aef42011-06-15 15:45:12 +020041
42struct temp_info {
43 char name[NAME_MAX];
44 int temp;
45};
46
47struct fan_info {
48 char name[NAME_MAX];
49 int rpms;
50};
51
52struct sensor_info {
53 char name[NAME_MAX];
54 struct temp_info *temperatures;
55 struct fan_info *fans;
56 short nrtemps;
57 short nrfans;
58};
59
60static int sensor_dump_cb(struct tree *tree, void *data)
Amit Arorae9e16b02010-08-03 10:15:20 +053061{
Daniel Lezcano3d0aef42011-06-15 15:45:12 +020062 int i;
63 struct sensor_info *sensor = tree->private;
Amit Arorae9e16b02010-08-03 10:15:20 +053064
Daniel Lezcano3d0aef42011-06-15 15:45:12 +020065 if (!strlen(sensor->name))
66 return 0;
Amit Arorae9e16b02010-08-03 10:15:20 +053067
Daniel Lezcano3d0aef42011-06-15 15:45:12 +020068 printf("%s\n", sensor->name);
Amit Arorae9e16b02010-08-03 10:15:20 +053069
Daniel Lezcano3d0aef42011-06-15 15:45:12 +020070 for (i = 0; i < sensor->nrtemps; i++)
Daniel Lezcanoe262b592011-10-20 13:49:27 +020071 printf(" %s %.1f °C/V\n", sensor->temperatures[i].name,
Daniel Lezcano3d0aef42011-06-15 15:45:12 +020072 (float)sensor->temperatures[i].temp / 1000);
Amit Arorae9e16b02010-08-03 10:15:20 +053073
Daniel Lezcano3d0aef42011-06-15 15:45:12 +020074 for (i = 0; i < sensor->nrfans; i++)
75 printf(" %s %d rpm\n", sensor->fans[i].name,
76 sensor->fans[i].rpms);
Amit Arora422c52f2010-12-02 16:22:29 +053077
Amit Arora17552782010-12-02 12:23:14 +053078 return 0;
79}
Daniel Lezcano3d0aef42011-06-15 15:45:12 +020080
81int sensor_dump(void)
82{
83 printf("\nSensor Information:\n");
84 printf("*******************\n\n");
85
86 return tree_for_each(sensor_tree, sensor_dump_cb, NULL);
87}
88
89static struct sensor_info *sensor_alloc(void)
90{
91 struct sensor_info *sensor;
92
93 sensor = malloc(sizeof(*sensor));
94 if (sensor)
95 memset(sensor, 0, sizeof(*sensor));
96
97 return sensor;
98}
99
100static int read_sensor_cb(struct tree *tree, void *data)
101{
102 DIR *dir;
103 int value;
104 struct dirent dirent, *direntp;
105 struct sensor_info *sensor = tree->private;
106
107 int nrtemps = 0;
108 int nrfans = 0;
109
110 dir = opendir(tree->path);
111 if (!dir)
112 return -1;
113
114 file_read_value(tree->path, "name", "%s", sensor->name);
115
116 while (!readdir_r(dir, &dirent, &direntp)) {
117
118 if (!direntp)
119 break;
120
121 if (direntp->d_type != DT_REG)
122 continue;
123
124 if (!strncmp(direntp->d_name, "temp", 4)) {
125
126 if (file_read_value(tree->path, direntp->d_name, "%d",
127 &value))
128 continue;
129
130 sensor->temperatures =
131 realloc(sensor->temperatures,
132 sizeof(struct temp_info) * (nrtemps + 1));
133 if (!sensor->temperatures)
134 continue;
135
136 strcpy(sensor->temperatures[nrtemps].name,
137 direntp->d_name);
138 sensor->temperatures[nrtemps].temp = value;
139
140 nrtemps++;
141 }
142
143 if (!strncmp(direntp->d_name, "fan", 3)) {
144
145 if (file_read_value(tree->path, direntp->d_name, "%d",
146 &value))
147 continue;
148
149 sensor->fans =
150 realloc(sensor->fans,
151 sizeof(struct temp_info) * (nrfans + 1));
152 if (!sensor->fans)
153 continue;
154
155 strcpy(sensor->fans[nrfans].name,
156 direntp->d_name);
157 sensor->fans[nrfans].rpms = value;
158
159 nrfans++;
160 }
161 }
162
163 sensor->nrtemps = nrtemps;
164 sensor->nrfans = nrfans;
165
166 closedir(dir);
167
168 return 0;
169}
170
Shaojie Sunc1462e72013-08-20 20:35:15 +0800171static int read_sensor_info(struct tree *tree)
172{
173 return tree_for_each(tree, read_sensor_cb, NULL);
174}
175
Daniel Lezcano3d0aef42011-06-15 15:45:12 +0200176static int fill_sensor_cb(struct tree *t, void *data)
177{
178 struct sensor_info *sensor;
179
180 sensor = sensor_alloc();
181 if (!sensor)
182 return -1;
183
184 t->private = sensor;
185
186 if (!t->parent)
187 return 0;
188
189 return read_sensor_cb(t, data);
190}
191
192static int fill_sensor_tree(void)
193{
194 return tree_for_each(sensor_tree, fill_sensor_cb, NULL);
195}
196
197static int sensor_filter_cb(const char *name)
198{
199 /* let's ignore some directories in order to avoid to be
200 * pulled inside the sysfs circular symlinks mess/hell
201 * (choose the word which fit better)
202 */
203 if (!strcmp(name, "subsystem"))
204 return 1;
205
206 if (!strcmp(name, "driver"))
207 return 1;
208
209 if (!strcmp(name, "hwmon"))
210 return 1;
211
212 if (!strcmp(name, "power"))
213 return 1;
214
215 return 0;
216}
217
Daniel Lezcano2e9df762011-06-15 15:45:12 +0200218static int sensor_display_cb(struct tree *t, void *data)
219{
220 struct sensor_info *sensor = t->private;
221 int *line = data;
222 char buf[1024];
223 int i;
224
225 if (!strlen(sensor->name))
226 return 0;
227
228 sprintf(buf, "%s", sensor->name);
229 display_print_line(SENSOR, *line, buf, 1, t);
230
231 (*line)++;
232
233 for (i = 0; i < sensor->nrtemps; i++) {
Daniel Lezcanoe262b592011-10-20 13:49:27 +0200234 sprintf(buf, " %-35s%.1f", sensor->temperatures[i].name,
Daniel Lezcano2e9df762011-06-15 15:45:12 +0200235 (float)sensor->temperatures[i].temp / 1000);
236 display_print_line(SENSOR, *line, buf, 0, t);
237 (*line)++;
238 }
239
240 for (i = 0; i < sensor->nrfans; i++) {
241 sprintf(buf, " %-35s%d rpm", sensor->fans[i].name,
242 sensor->fans[i].rpms);
243 display_print_line(SENSOR, *line, buf, 0, t);
244 (*line)++;
245 }
246
247 return 0;
248}
249
Daniel Lezcanofa453332011-06-21 00:57:08 +0200250static int sensor_print_header(void)
251{
252 char *buf;
253 int ret;
254
255 if (asprintf(&buf, "%-36s%s", "Name", "Value") < 0)
256 return -1;
257
Daniel Lezcano372ffba2011-06-21 00:57:08 +0200258 ret = display_column_name(buf);
Daniel Lezcanofa453332011-06-21 00:57:08 +0200259
260 free(buf);
261
262 return ret;
263}
264
Shaojie Sunc1462e72013-08-20 20:35:15 +0800265static int sensor_print_info(struct tree *tree)
Daniel Lezcano2e9df762011-06-15 15:45:12 +0200266{
267 int ret, line = 0;
268
269 display_reset_cursor(SENSOR);
270
Daniel Lezcanofa453332011-06-21 00:57:08 +0200271 sensor_print_header();
Daniel Lezcano2e9df762011-06-15 15:45:12 +0200272
Shaojie Sunc1462e72013-08-20 20:35:15 +0800273 ret = tree_for_each(tree, sensor_display_cb, &line);
Daniel Lezcano2e9df762011-06-15 15:45:12 +0200274
275 display_refresh_pad(SENSOR);
276
277 return ret;
278}
279
Shaojie Sunc1462e72013-08-20 20:35:15 +0800280static int sensor_display(bool refresh)
281{
Sanjay Singh Rawat96f6e052014-05-26 11:35:02 +0530282 if (sensor_error) {
283 display_message(SENSOR,
284 "error: path " SYSFS_SENSOR " not found");
285 return -2;
286 }
287
Shaojie Sunc1462e72013-08-20 20:35:15 +0800288 if (refresh && read_sensor_info(sensor_tree))
289 return -1;
290
291 return sensor_print_info(sensor_tree);
292}
293
Daniel Lezcanob301b082011-06-15 15:45:12 +0200294static struct display_ops sensor_ops = {
295 .display = sensor_display,
296};
297
Daniel Lezcanob4eec7e2016-02-18 16:44:55 +0000298int sensor_init(struct powerdebug_options *options)
Daniel Lezcano3d0aef42011-06-15 15:45:12 +0200299{
Sanjay Singh Rawat96f6e052014-05-26 11:35:02 +0530300 int ret = 0;
301
Daniel Lezcanob4eec7e2016-02-18 16:44:55 +0000302 if (!(options->flags & SENSOR_OPTION))
303 return 0;
304
Sanjay Singh Rawat96f6e052014-05-26 11:35:02 +0530305 ret = display_register(SENSOR, &sensor_ops);
Sanjay Singh Rawat03fdbc02014-05-27 16:52:27 +0530306 if (ret)
Sanjay Singh Rawat96f6e052014-05-26 11:35:02 +0530307 printf("error: sensor display register failed");
308
309 if (access(SYSFS_SENSOR, F_OK))
310 sensor_error = true; /* set the flag */
311
Daniel Lezcano25fc4a32011-08-25 15:46:13 +0200312 sensor_tree = tree_load(SYSFS_SENSOR, sensor_filter_cb, false);
Daniel Lezcano3d0aef42011-06-15 15:45:12 +0200313 if (!sensor_tree)
314 return -1;
315
Daniel Lezcanocaafece2011-06-27 22:59:17 +0200316 if (fill_sensor_tree())
317 return -1;
318
Sanjay Singh Rawat96f6e052014-05-26 11:35:02 +0530319 return ret;
Daniel Lezcano3d0aef42011-06-15 15:45:12 +0200320}