blob: bf672771a90e2a546b5d5f9690ca9ed577b5f48a [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>
24
Amit Arorae9e16b02010-08-03 10:15:20 +053025#include "powerdebug.h"
Daniel Lezcanob301b082011-06-15 15:45:12 +020026#include "display.h"
Amit Arorae9e16b02010-08-03 10:15:20 +053027#include "sensor.h"
Daniel Lezcano3d0aef42011-06-15 15:45:12 +020028#include "tree.h"
29#include "utils.h"
Amit Arorae9e16b02010-08-03 10:15:20 +053030
Daniel Lezcano3d0aef42011-06-15 15:45:12 +020031#define SYSFS_SENSOR "/sys/class/hwmon"
Daniel Lezcanod3ffa812011-03-26 22:06:22 +010032
Daniel Lezcano3d0aef42011-06-15 15:45:12 +020033static struct tree *sensor_tree;
Sanjay Singh Rawat96f6e052014-05-26 11:35:02 +053034static bool sensor_error = false;
Daniel Lezcano3d0aef42011-06-15 15:45:12 +020035
36struct temp_info {
37 char name[NAME_MAX];
38 int temp;
39};
40
41struct fan_info {
42 char name[NAME_MAX];
43 int rpms;
44};
45
46struct sensor_info {
47 char name[NAME_MAX];
48 struct temp_info *temperatures;
49 struct fan_info *fans;
50 short nrtemps;
51 short nrfans;
52};
53
54static int sensor_dump_cb(struct tree *tree, void *data)
Amit Arorae9e16b02010-08-03 10:15:20 +053055{
Daniel Lezcano3d0aef42011-06-15 15:45:12 +020056 int i;
57 struct sensor_info *sensor = tree->private;
Amit Arorae9e16b02010-08-03 10:15:20 +053058
Daniel Lezcano3d0aef42011-06-15 15:45:12 +020059 if (!strlen(sensor->name))
60 return 0;
Amit Arorae9e16b02010-08-03 10:15:20 +053061
Daniel Lezcano3d0aef42011-06-15 15:45:12 +020062 printf("%s\n", sensor->name);
Amit Arorae9e16b02010-08-03 10:15:20 +053063
Daniel Lezcano3d0aef42011-06-15 15:45:12 +020064 for (i = 0; i < sensor->nrtemps; i++)
Daniel Lezcanoe262b592011-10-20 13:49:27 +020065 printf(" %s %.1f °C/V\n", sensor->temperatures[i].name,
Daniel Lezcano3d0aef42011-06-15 15:45:12 +020066 (float)sensor->temperatures[i].temp / 1000);
Amit Arorae9e16b02010-08-03 10:15:20 +053067
Daniel Lezcano3d0aef42011-06-15 15:45:12 +020068 for (i = 0; i < sensor->nrfans; i++)
69 printf(" %s %d rpm\n", sensor->fans[i].name,
70 sensor->fans[i].rpms);
Amit Arora422c52f2010-12-02 16:22:29 +053071
Amit Arora17552782010-12-02 12:23:14 +053072 return 0;
73}
Daniel Lezcano3d0aef42011-06-15 15:45:12 +020074
75int sensor_dump(void)
76{
77 printf("\nSensor Information:\n");
78 printf("*******************\n\n");
79
80 return tree_for_each(sensor_tree, sensor_dump_cb, NULL);
81}
82
83static struct sensor_info *sensor_alloc(void)
84{
85 struct sensor_info *sensor;
86
87 sensor = malloc(sizeof(*sensor));
88 if (sensor)
89 memset(sensor, 0, sizeof(*sensor));
90
91 return sensor;
92}
93
94static int read_sensor_cb(struct tree *tree, void *data)
95{
96 DIR *dir;
97 int value;
98 struct dirent dirent, *direntp;
99 struct sensor_info *sensor = tree->private;
100
101 int nrtemps = 0;
102 int nrfans = 0;
103
104 dir = opendir(tree->path);
105 if (!dir)
106 return -1;
107
108 file_read_value(tree->path, "name", "%s", sensor->name);
109
110 while (!readdir_r(dir, &dirent, &direntp)) {
111
112 if (!direntp)
113 break;
114
115 if (direntp->d_type != DT_REG)
116 continue;
117
118 if (!strncmp(direntp->d_name, "temp", 4)) {
119
120 if (file_read_value(tree->path, direntp->d_name, "%d",
121 &value))
122 continue;
123
124 sensor->temperatures =
125 realloc(sensor->temperatures,
126 sizeof(struct temp_info) * (nrtemps + 1));
127 if (!sensor->temperatures)
128 continue;
129
130 strcpy(sensor->temperatures[nrtemps].name,
131 direntp->d_name);
132 sensor->temperatures[nrtemps].temp = value;
133
134 nrtemps++;
135 }
136
137 if (!strncmp(direntp->d_name, "fan", 3)) {
138
139 if (file_read_value(tree->path, direntp->d_name, "%d",
140 &value))
141 continue;
142
143 sensor->fans =
144 realloc(sensor->fans,
145 sizeof(struct temp_info) * (nrfans + 1));
146 if (!sensor->fans)
147 continue;
148
149 strcpy(sensor->fans[nrfans].name,
150 direntp->d_name);
151 sensor->fans[nrfans].rpms = value;
152
153 nrfans++;
154 }
155 }
156
157 sensor->nrtemps = nrtemps;
158 sensor->nrfans = nrfans;
159
160 closedir(dir);
161
162 return 0;
163}
164
Shaojie Sunc1462e72013-08-20 20:35:15 +0800165static int read_sensor_info(struct tree *tree)
166{
167 return tree_for_each(tree, read_sensor_cb, NULL);
168}
169
Daniel Lezcano3d0aef42011-06-15 15:45:12 +0200170static int fill_sensor_cb(struct tree *t, void *data)
171{
172 struct sensor_info *sensor;
173
174 sensor = sensor_alloc();
175 if (!sensor)
176 return -1;
177
178 t->private = sensor;
179
180 if (!t->parent)
181 return 0;
182
183 return read_sensor_cb(t, data);
184}
185
186static int fill_sensor_tree(void)
187{
188 return tree_for_each(sensor_tree, fill_sensor_cb, NULL);
189}
190
191static int sensor_filter_cb(const char *name)
192{
193 /* let's ignore some directories in order to avoid to be
194 * pulled inside the sysfs circular symlinks mess/hell
195 * (choose the word which fit better)
196 */
197 if (!strcmp(name, "subsystem"))
198 return 1;
199
200 if (!strcmp(name, "driver"))
201 return 1;
202
203 if (!strcmp(name, "hwmon"))
204 return 1;
205
206 if (!strcmp(name, "power"))
207 return 1;
208
209 return 0;
210}
211
Daniel Lezcano2e9df762011-06-15 15:45:12 +0200212static int sensor_display_cb(struct tree *t, void *data)
213{
214 struct sensor_info *sensor = t->private;
215 int *line = data;
216 char buf[1024];
217 int i;
218
219 if (!strlen(sensor->name))
220 return 0;
221
222 sprintf(buf, "%s", sensor->name);
223 display_print_line(SENSOR, *line, buf, 1, t);
224
225 (*line)++;
226
227 for (i = 0; i < sensor->nrtemps; i++) {
Daniel Lezcanoe262b592011-10-20 13:49:27 +0200228 sprintf(buf, " %-35s%.1f", sensor->temperatures[i].name,
Daniel Lezcano2e9df762011-06-15 15:45:12 +0200229 (float)sensor->temperatures[i].temp / 1000);
230 display_print_line(SENSOR, *line, buf, 0, t);
231 (*line)++;
232 }
233
234 for (i = 0; i < sensor->nrfans; i++) {
235 sprintf(buf, " %-35s%d rpm", sensor->fans[i].name,
236 sensor->fans[i].rpms);
237 display_print_line(SENSOR, *line, buf, 0, t);
238 (*line)++;
239 }
240
241 return 0;
242}
243
Daniel Lezcanofa453332011-06-21 00:57:08 +0200244static int sensor_print_header(void)
245{
246 char *buf;
247 int ret;
248
249 if (asprintf(&buf, "%-36s%s", "Name", "Value") < 0)
250 return -1;
251
Daniel Lezcano372ffba2011-06-21 00:57:08 +0200252 ret = display_column_name(buf);
Daniel Lezcanofa453332011-06-21 00:57:08 +0200253
254 free(buf);
255
256 return ret;
257}
258
Shaojie Sunc1462e72013-08-20 20:35:15 +0800259static int sensor_print_info(struct tree *tree)
Daniel Lezcano2e9df762011-06-15 15:45:12 +0200260{
261 int ret, line = 0;
262
263 display_reset_cursor(SENSOR);
264
Daniel Lezcanofa453332011-06-21 00:57:08 +0200265 sensor_print_header();
Daniel Lezcano2e9df762011-06-15 15:45:12 +0200266
Shaojie Sunc1462e72013-08-20 20:35:15 +0800267 ret = tree_for_each(tree, sensor_display_cb, &line);
Daniel Lezcano2e9df762011-06-15 15:45:12 +0200268
269 display_refresh_pad(SENSOR);
270
271 return ret;
272}
273
Shaojie Sunc1462e72013-08-20 20:35:15 +0800274static int sensor_display(bool refresh)
275{
Sanjay Singh Rawat96f6e052014-05-26 11:35:02 +0530276 if (sensor_error) {
277 display_message(SENSOR,
278 "error: path " SYSFS_SENSOR " not found");
279 return -2;
280 }
281
Shaojie Sunc1462e72013-08-20 20:35:15 +0800282 if (refresh && read_sensor_info(sensor_tree))
283 return -1;
284
285 return sensor_print_info(sensor_tree);
286}
287
Daniel Lezcanob301b082011-06-15 15:45:12 +0200288static struct display_ops sensor_ops = {
289 .display = sensor_display,
290};
291
Daniel Lezcano3d0aef42011-06-15 15:45:12 +0200292int sensor_init(void)
293{
Sanjay Singh Rawat96f6e052014-05-26 11:35:02 +0530294 int ret = 0;
295
296 ret = display_register(SENSOR, &sensor_ops);
297 if (!ret)
298 printf("error: sensor display register failed");
299
300 if (access(SYSFS_SENSOR, F_OK))
301 sensor_error = true; /* set the flag */
302
Daniel Lezcano25fc4a32011-08-25 15:46:13 +0200303 sensor_tree = tree_load(SYSFS_SENSOR, sensor_filter_cb, false);
Daniel Lezcano3d0aef42011-06-15 15:45:12 +0200304 if (!sensor_tree)
305 return -1;
306
Daniel Lezcanocaafece2011-06-27 22:59:17 +0200307 if (fill_sensor_tree())
308 return -1;
309
Sanjay Singh Rawat96f6e052014-05-26 11:35:02 +0530310 return ret;
Daniel Lezcano3d0aef42011-06-15 15:45:12 +0200311}