blob: bd8c354991f2fa3a667de6d74a0e210fd8bf2f93 [file] [log] [blame]
/*******************************************************************************
* Copyright (C) 2010, Linaro Limited.
*
* This file is part of PowerDebug.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Amit Arora <amit.arora@linaro.org> (IBM Corporation)
* - initial API and implementation
*******************************************************************************/
#define _GNU_SOURCE
#include <stdio.h>
#undef _GNU_SOURCE
#include <sys/types.h>
#include <stdbool.h>
#include <dirent.h>
#include <string.h>
#include <stdlib.h>
#include "powerdebug.h"
#include "display.h"
#include "sensor.h"
#include "tree.h"
#include "utils.h"
#define SYSFS_SENSOR "/sys/class/hwmon"
static struct tree *sensor_tree;
struct temp_info {
char name[NAME_MAX];
int temp;
};
struct fan_info {
char name[NAME_MAX];
int rpms;
};
struct sensor_info {
char name[NAME_MAX];
struct temp_info *temperatures;
struct fan_info *fans;
short nrtemps;
short nrfans;
};
static int sensor_dump_cb(struct tree *tree, void *data)
{
int i;
struct sensor_info *sensor = tree->private;
if (!strlen(sensor->name))
return 0;
printf("%s\n", sensor->name);
for (i = 0; i < sensor->nrtemps; i++)
printf(" %s %.1f °C/V\n", sensor->temperatures[i].name,
(float)sensor->temperatures[i].temp / 1000);
for (i = 0; i < sensor->nrfans; i++)
printf(" %s %d rpm\n", sensor->fans[i].name,
sensor->fans[i].rpms);
return 0;
}
int sensor_dump(void)
{
printf("\nSensor Information:\n");
printf("*******************\n\n");
return tree_for_each(sensor_tree, sensor_dump_cb, NULL);
}
static struct sensor_info *sensor_alloc(void)
{
struct sensor_info *sensor;
sensor = malloc(sizeof(*sensor));
if (sensor)
memset(sensor, 0, sizeof(*sensor));
return sensor;
}
static int read_sensor_cb(struct tree *tree, void *data)
{
DIR *dir;
int value;
struct dirent dirent, *direntp;
struct sensor_info *sensor = tree->private;
int nrtemps = 0;
int nrfans = 0;
dir = opendir(tree->path);
if (!dir)
return -1;
file_read_value(tree->path, "name", "%s", sensor->name);
while (!readdir_r(dir, &dirent, &direntp)) {
if (!direntp)
break;
if (direntp->d_type != DT_REG)
continue;
if (!strncmp(direntp->d_name, "temp", 4)) {
if (file_read_value(tree->path, direntp->d_name, "%d",
&value))
continue;
sensor->temperatures =
realloc(sensor->temperatures,
sizeof(struct temp_info) * (nrtemps + 1));
if (!sensor->temperatures)
continue;
strcpy(sensor->temperatures[nrtemps].name,
direntp->d_name);
sensor->temperatures[nrtemps].temp = value;
nrtemps++;
}
if (!strncmp(direntp->d_name, "fan", 3)) {
if (file_read_value(tree->path, direntp->d_name, "%d",
&value))
continue;
sensor->fans =
realloc(sensor->fans,
sizeof(struct temp_info) * (nrfans + 1));
if (!sensor->fans)
continue;
strcpy(sensor->fans[nrfans].name,
direntp->d_name);
sensor->fans[nrfans].rpms = value;
nrfans++;
}
}
sensor->nrtemps = nrtemps;
sensor->nrfans = nrfans;
closedir(dir);
return 0;
}
static int fill_sensor_cb(struct tree *t, void *data)
{
struct sensor_info *sensor;
sensor = sensor_alloc();
if (!sensor)
return -1;
t->private = sensor;
if (!t->parent)
return 0;
return read_sensor_cb(t, data);
}
static int fill_sensor_tree(void)
{
return tree_for_each(sensor_tree, fill_sensor_cb, NULL);
}
static int sensor_filter_cb(const char *name)
{
/* let's ignore some directories in order to avoid to be
* pulled inside the sysfs circular symlinks mess/hell
* (choose the word which fit better)
*/
if (!strcmp(name, "subsystem"))
return 1;
if (!strcmp(name, "driver"))
return 1;
if (!strcmp(name, "hwmon"))
return 1;
if (!strcmp(name, "power"))
return 1;
return 0;
}
static int sensor_display_cb(struct tree *t, void *data)
{
struct sensor_info *sensor = t->private;
int *line = data;
char buf[1024];
int i;
if (!strlen(sensor->name))
return 0;
sprintf(buf, "%s", sensor->name);
display_print_line(SENSOR, *line, buf, 1, t);
(*line)++;
for (i = 0; i < sensor->nrtemps; i++) {
sprintf(buf, " %-35s%.1f", sensor->temperatures[i].name,
(float)sensor->temperatures[i].temp / 1000);
display_print_line(SENSOR, *line, buf, 0, t);
(*line)++;
}
for (i = 0; i < sensor->nrfans; i++) {
sprintf(buf, " %-35s%d rpm", sensor->fans[i].name,
sensor->fans[i].rpms);
display_print_line(SENSOR, *line, buf, 0, t);
(*line)++;
}
return 0;
}
static int sensor_print_header(void)
{
char *buf;
int ret;
if (asprintf(&buf, "%-36s%s", "Name", "Value") < 0)
return -1;
ret = display_column_name(buf);
free(buf);
return ret;
}
static int sensor_display(bool refresh)
{
int ret, line = 0;
display_reset_cursor(SENSOR);
sensor_print_header();
ret = tree_for_each(sensor_tree, sensor_display_cb, &line);
display_refresh_pad(SENSOR);
return ret;
}
static struct display_ops sensor_ops = {
.display = sensor_display,
};
int sensor_init(void)
{
sensor_tree = tree_load(SYSFS_SENSOR, sensor_filter_cb, false);
if (!sensor_tree)
return -1;
if (fill_sensor_tree())
return -1;
return display_register(SENSOR, &sensor_ops);
}