blob: 562a11d7f35d37fe6e10fd080cad53d4b6856457 [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:
* Daniel Lezcano <daniel.lezcano@linaro.org> (IBM Corporation)
* - initial API and implementation
*******************************************************************************/
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#include <stdio.h>
#undef _GNU_SOURCE
#endif
#include <mntent.h>
#include <string.h>
#include <stdbool.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/param.h>
#include <sys/stat.h>
#include "powerdebug.h"
#include "display.h"
#include "tree.h"
#include "utils.h"
#define SYSFS_GPIO "/sys/class/gpio"
struct gpio_info {
bool expanded;
int active_low;
int value;
int direction;
int edge;
char *prefix;
} *gpios_info;
static struct tree *gpio_tree = NULL;
static struct gpio_info *gpio_alloc(void)
{
struct gpio_info *gi;
gi = malloc(sizeof(*gi));
if (gi) {
memset(gi, -1, sizeof(*gi));
gi->prefix = NULL;
}
return gi;
}
static int gpio_display(bool refresh)
{
return 0;
}
static int gpio_select(void)
{
return 0;
}
static int gpio_find(const char *name)
{
return 0;
}
static int gpio_selectf(void)
{
return 0;
}
static struct display_ops gpio_ops = {
.display = gpio_display,
.select = gpio_select,
.find = gpio_find,
.selectf = gpio_selectf,
};
static int gpio_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, "device"))
return 1;
if (!strcmp(name, "subsystem"))
return 1;
if (!strcmp(name, "driver"))
return 1;
/* we want to ignore the gpio chips */
if (strstr(name, "chip"))
return 1;
/* we are not interested by the power value */
if (!strcmp(name, "power"))
return 1;
return 0;
}
static inline int read_gpio_cb(struct tree *t, void *data)
{
struct gpio_info *gpio = t->private;
file_read_value(t->path, "active_low", "%d", &gpio->active_low);
file_read_value(t->path, "value", "%d", &gpio->value);
file_read_value(t->path, "edge", "%d", &gpio->edge);
file_read_value(t->path, "direction", "%d", &gpio->direction);
return 0;
}
static int read_gpio_info(struct tree *tree)
{
return tree_for_each(tree, read_gpio_cb, NULL);
}
static int fill_gpio_cb(struct tree *t, void *data)
{
struct gpio_info *gpio;
gpio = gpio_alloc();
if (!gpio)
return -1;
t->private = gpio;
/* we skip the root node but we set it expanded for its children */
if (!t->parent) {
gpio->expanded = true;
return 0;
}
return read_gpio_cb(t, data);
}
static int fill_gpio_tree(void)
{
return tree_for_each(gpio_tree, fill_gpio_cb, NULL);
}
static int dump_gpio_cb(struct tree *t, void *data)
{
struct gpio_info *gpio = t->private;
struct gpio_info *pgpio;
if (!t->parent) {
printf("/\n");
gpio->prefix = "";
return 0;
}
pgpio = t->parent->private;
if (!gpio->prefix)
if (asprintf(&gpio->prefix, "%s%s%s", pgpio->prefix,
t->depth > 1 ? " ": "", t->next ? "|" : " ") < 0)
return -1;
printf("%s%s-- %s (active_low:%d)\n",
gpio->prefix, !t->next ? "`" : "", t->name, gpio->active_low);
return 0;
}
int dump_gpio_info(void)
{
return tree_for_each(gpio_tree, dump_gpio_cb, NULL);
}
int gpio_dump(void)
{
int ret;
printf("\nGpio Tree :\n");
printf("***********\n");
ret = dump_gpio_info();
printf("\n\n");
return ret;
}
/*
* Initialize the gpio framework
*/
int gpio_init(void)
{
gpio_tree = tree_load(SYSFS_GPIO, gpio_filter_cb, false);
if (!gpio_tree)
return -1;
if (fill_gpio_tree())
return -1;
return display_register(GPIO, &gpio_ops);
}