/******************************************************************************* * 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 (IBM Corporation) * - initial API and implementation *******************************************************************************/ #ifndef _GNU_SOURCE #define _GNU_SOURCE #include #undef _GNU_SOURCE #endif #include #include #include #include #include #include #include #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); }