blob: ff1e3dd6503f32a07fb37d4c53e1046d08f8b95a [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;
34
35struct temp_info {
36 char name[NAME_MAX];
37 int temp;
38};
39
40struct fan_info {
41 char name[NAME_MAX];
42 int rpms;
43};
44
45struct sensor_info {
46 char name[NAME_MAX];
47 struct temp_info *temperatures;
48 struct fan_info *fans;
49 short nrtemps;
50 short nrfans;
51};
52
53static int sensor_dump_cb(struct tree *tree, void *data)
Amit Arorae9e16b02010-08-03 10:15:20 +053054{
Daniel Lezcano3d0aef42011-06-15 15:45:12 +020055 int i;
56 struct sensor_info *sensor = tree->private;
Amit Arorae9e16b02010-08-03 10:15:20 +053057
Daniel Lezcano3d0aef42011-06-15 15:45:12 +020058 if (!strlen(sensor->name))
59 return 0;
Amit Arorae9e16b02010-08-03 10:15:20 +053060
Daniel Lezcano3d0aef42011-06-15 15:45:12 +020061 printf("%s\n", sensor->name);
Amit Arorae9e16b02010-08-03 10:15:20 +053062
Daniel Lezcano3d0aef42011-06-15 15:45:12 +020063 for (i = 0; i < sensor->nrtemps; i++)
64 printf(" %s %.1f °C\n", sensor->temperatures[i].name,
65 (float)sensor->temperatures[i].temp / 1000);
Amit Arorae9e16b02010-08-03 10:15:20 +053066
Daniel Lezcano3d0aef42011-06-15 15:45:12 +020067 for (i = 0; i < sensor->nrfans; i++)
68 printf(" %s %d rpm\n", sensor->fans[i].name,
69 sensor->fans[i].rpms);
Amit Arora422c52f2010-12-02 16:22:29 +053070
Amit Arora17552782010-12-02 12:23:14 +053071 return 0;
72}
Daniel Lezcano3d0aef42011-06-15 15:45:12 +020073
74int sensor_dump(void)
75{
76 printf("\nSensor Information:\n");
77 printf("*******************\n\n");
78
79 return tree_for_each(sensor_tree, sensor_dump_cb, NULL);
80}
81
82static struct sensor_info *sensor_alloc(void)
83{
84 struct sensor_info *sensor;
85
86 sensor = malloc(sizeof(*sensor));
87 if (sensor)
88 memset(sensor, 0, sizeof(*sensor));
89
90 return sensor;
91}
92
93static int read_sensor_cb(struct tree *tree, void *data)
94{
95 DIR *dir;
96 int value;
97 struct dirent dirent, *direntp;
98 struct sensor_info *sensor = tree->private;
99
100 int nrtemps = 0;
101 int nrfans = 0;
102
103 dir = opendir(tree->path);
104 if (!dir)
105 return -1;
106
107 file_read_value(tree->path, "name", "%s", sensor->name);
108
109 while (!readdir_r(dir, &dirent, &direntp)) {
110
111 if (!direntp)
112 break;
113
114 if (direntp->d_type != DT_REG)
115 continue;
116
117 if (!strncmp(direntp->d_name, "temp", 4)) {
118
119 if (file_read_value(tree->path, direntp->d_name, "%d",
120 &value))
121 continue;
122
123 sensor->temperatures =
124 realloc(sensor->temperatures,
125 sizeof(struct temp_info) * (nrtemps + 1));
126 if (!sensor->temperatures)
127 continue;
128
129 strcpy(sensor->temperatures[nrtemps].name,
130 direntp->d_name);
131 sensor->temperatures[nrtemps].temp = value;
132
133 nrtemps++;
134 }
135
136 if (!strncmp(direntp->d_name, "fan", 3)) {
137
138 if (file_read_value(tree->path, direntp->d_name, "%d",
139 &value))
140 continue;
141
142 sensor->fans =
143 realloc(sensor->fans,
144 sizeof(struct temp_info) * (nrfans + 1));
145 if (!sensor->fans)
146 continue;
147
148 strcpy(sensor->fans[nrfans].name,
149 direntp->d_name);
150 sensor->fans[nrfans].rpms = value;
151
152 nrfans++;
153 }
154 }
155
156 sensor->nrtemps = nrtemps;
157 sensor->nrfans = nrfans;
158
159 closedir(dir);
160
161 return 0;
162}
163
164static int fill_sensor_cb(struct tree *t, void *data)
165{
166 struct sensor_info *sensor;
167
168 sensor = sensor_alloc();
169 if (!sensor)
170 return -1;
171
172 t->private = sensor;
173
174 if (!t->parent)
175 return 0;
176
177 return read_sensor_cb(t, data);
178}
179
180static int fill_sensor_tree(void)
181{
182 return tree_for_each(sensor_tree, fill_sensor_cb, NULL);
183}
184
185static int sensor_filter_cb(const char *name)
186{
187 /* let's ignore some directories in order to avoid to be
188 * pulled inside the sysfs circular symlinks mess/hell
189 * (choose the word which fit better)
190 */
191 if (!strcmp(name, "subsystem"))
192 return 1;
193
194 if (!strcmp(name, "driver"))
195 return 1;
196
197 if (!strcmp(name, "hwmon"))
198 return 1;
199
200 if (!strcmp(name, "power"))
201 return 1;
202
203 return 0;
204}
205
Daniel Lezcano2e9df762011-06-15 15:45:12 +0200206static int sensor_display_cb(struct tree *t, void *data)
207{
208 struct sensor_info *sensor = t->private;
209 int *line = data;
210 char buf[1024];
211 int i;
212
213 if (!strlen(sensor->name))
214 return 0;
215
216 sprintf(buf, "%s", sensor->name);
217 display_print_line(SENSOR, *line, buf, 1, t);
218
219 (*line)++;
220
221 for (i = 0; i < sensor->nrtemps; i++) {
222 sprintf(buf, " %-35s%.1f °C", sensor->temperatures[i].name,
223 (float)sensor->temperatures[i].temp / 1000);
224 display_print_line(SENSOR, *line, buf, 0, t);
225 (*line)++;
226 }
227
228 for (i = 0; i < sensor->nrfans; i++) {
229 sprintf(buf, " %-35s%d rpm", sensor->fans[i].name,
230 sensor->fans[i].rpms);
231 display_print_line(SENSOR, *line, buf, 0, t);
232 (*line)++;
233 }
234
235 return 0;
236}
237
Daniel Lezcanofa453332011-06-21 00:57:08 +0200238static int sensor_print_header(void)
239{
240 char *buf;
241 int ret;
242
243 if (asprintf(&buf, "%-36s%s", "Name", "Value") < 0)
244 return -1;
245
Daniel Lezcano372ffba2011-06-21 00:57:08 +0200246 ret = display_column_name(buf);
Daniel Lezcanofa453332011-06-21 00:57:08 +0200247
248 free(buf);
249
250 return ret;
251}
252
Daniel Lezcanod577aaa2011-06-21 00:57:08 +0200253static int sensor_display(bool refresh)
Daniel Lezcano2e9df762011-06-15 15:45:12 +0200254{
255 int ret, line = 0;
256
257 display_reset_cursor(SENSOR);
258
Daniel Lezcanofa453332011-06-21 00:57:08 +0200259 sensor_print_header();
Daniel Lezcano2e9df762011-06-15 15:45:12 +0200260
261 ret = tree_for_each(sensor_tree, sensor_display_cb, &line);
262
263 display_refresh_pad(SENSOR);
264
265 return ret;
266}
267
Daniel Lezcanob301b082011-06-15 15:45:12 +0200268static struct display_ops sensor_ops = {
269 .display = sensor_display,
270};
271
Daniel Lezcano3d0aef42011-06-15 15:45:12 +0200272int sensor_init(void)
273{
Daniel Lezcano25fc4a32011-08-25 15:46:13 +0200274 sensor_tree = tree_load(SYSFS_SENSOR, sensor_filter_cb, false);
Daniel Lezcano3d0aef42011-06-15 15:45:12 +0200275 if (!sensor_tree)
276 return -1;
277
Daniel Lezcanocaafece2011-06-27 22:59:17 +0200278 if (fill_sensor_tree())
279 return -1;
280
281 return display_register(SENSOR, &sensor_ops);
Daniel Lezcano3d0aef42011-06-15 15:45:12 +0200282}