Sometime we are interested in following the symlinks, sometime not.
Signed-off-by: Daniel Lezcano daniel.lezcano@linaro.org --- clocks.c | 2 +- regulator.c | 2 +- sensor.c | 2 +- tree.c | 11 ++++++----- tree.h | 2 +- 5 files changed, 10 insertions(+), 9 deletions(-)
diff --git a/clocks.c b/clocks.c index 20a245c..364c0af 100644 --- a/clocks.c +++ b/clocks.c @@ -413,7 +413,7 @@ int clock_init(void) if (access(clk_dir_path, F_OK)) return -1;
- clock_tree = tree_load(clk_dir_path, NULL); + clock_tree = tree_load(clk_dir_path, NULL, false); if (!clock_tree) return -1;
diff --git a/regulator.c b/regulator.c index e9b01bb..55bd3e9 100644 --- a/regulator.c +++ b/regulator.c @@ -236,7 +236,7 @@ static struct display_ops regulator_ops = {
int regulator_init(void) { - reg_tree = tree_load(SYSFS_REGULATOR, regulator_filter_cb); + reg_tree = tree_load(SYSFS_REGULATOR, regulator_filter_cb, false); if (!reg_tree) return -1;
diff --git a/sensor.c b/sensor.c index e172f88..ff1e3dd 100644 --- a/sensor.c +++ b/sensor.c @@ -271,7 +271,7 @@ static struct display_ops sensor_ops = {
int sensor_init(void) { - sensor_tree = tree_load(SYSFS_SENSOR, sensor_filter_cb); + sensor_tree = tree_load(SYSFS_SENSOR, sensor_filter_cb, false); if (!sensor_tree) return -1;
diff --git a/tree.c b/tree.c index aefe0fe..d331c60 100644 --- a/tree.c +++ b/tree.c @@ -17,6 +17,7 @@ #include <stdio.h> #undef _GNU_SOURCE #include <stdlib.h> +#include <stdbool.h> #include <string.h> #include <dirent.h> #include <sys/types.h> @@ -111,7 +112,7 @@ static inline void tree_add_child(struct tree *parent, struct tree *child) * @filter : a callback to filter out the directories * Returns 0 on success, -1 otherwise */ -static int tree_scan(struct tree *tree, tree_filter_t filter) +static int tree_scan(struct tree *tree, tree_filter_t filter, bool follow) { DIR *dir; char *basedir, *newpath; @@ -152,7 +153,7 @@ static int tree_scan(struct tree *tree, tree_filter_t filter) if (ret) goto out_free_newpath;
- if (S_ISDIR(s.st_mode)) { + if (S_ISDIR(s.st_mode) || (S_ISLNK(s.st_mode) && follow)) {
ret = -1;
@@ -164,7 +165,7 @@ static int tree_scan(struct tree *tree, tree_filter_t filter)
tree->nrchild++;
- ret = tree_scan(child, filter); + ret = tree_scan(child, filter, follow); }
out_free_newpath: @@ -190,7 +191,7 @@ static int tree_scan(struct tree *tree, tree_filter_t filter) * Returns a tree structure corresponding to the root node of the * directory tree representation on success, NULL otherwise */ -struct tree *tree_load(const char *path, tree_filter_t filter) +struct tree *tree_load(const char *path, tree_filter_t filter, bool follow) { struct tree *tree;
@@ -198,7 +199,7 @@ struct tree *tree_load(const char *path, tree_filter_t filter) if (!tree) return NULL;
- if (tree_scan(tree, filter)) { + if (tree_scan(tree, filter, follow)) { tree_free(tree); return NULL; } diff --git a/tree.h b/tree.h index c7f3ca9..5c1c697 100644 --- a/tree.h +++ b/tree.h @@ -41,7 +41,7 @@ typedef int (*tree_cb_t)(struct tree *t, void *data);
typedef int (*tree_filter_t)(const char *name);
-extern struct tree *tree_load(const char *path, tree_filter_t filter); +extern struct tree *tree_load(const char *path, tree_filter_t filter, bool follow);
extern struct tree *tree_find(struct tree *tree, const char *name);
Add the enum definition we can rely on for the next patches.
Signed-off-by: Daniel Lezcano daniel.lezcano@linaro.org --- display.c | 1 + display.h | 2 +- 2 files changed, 2 insertions(+), 1 deletions(-)
diff --git a/display.c b/display.c index ebc4de6..f06387c 100644 --- a/display.c +++ b/display.c @@ -63,6 +63,7 @@ struct windata windata[] = { [CLOCK] = { .name = "Clocks" }, [REGULATOR] = { .name = "Regulators" }, [SENSOR] = { .name = "Sensors" }, + [GPIO] = { .name = "Gpio" }, };
static void display_fini(void) diff --git a/display.h b/display.h index 9e4e21a..035b2e9 100644 --- a/display.h +++ b/display.h @@ -13,7 +13,7 @@ * - initial API and implementation *******************************************************************************/
-enum { CLOCK, REGULATOR, SENSOR }; +enum { CLOCK, REGULATOR, SENSOR, GPIO };
struct display_ops { int (*display)(bool refresh);
Read the gpio directory structure where we will read the different data we are interested in.
Signed-off-by: Daniel Lezcano daniel.lezcano@linaro.org --- Makefile | 2 +- gpio.c | 103 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ gpio.h | 17 ++++++++++ 3 files changed, 121 insertions(+), 1 deletions(-) create mode 100644 gpio.c create mode 100644 gpio.h
diff --git a/Makefile b/Makefile index 8d41b24..2da9d67 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ MANDIR=/usr/share/man/man8 CFLAGS?=-O1 -g -Wall -Wshadow CC?=gcc
-OBJS = powerdebug.o sensor.o clocks.o regulator.o \ +OBJS = powerdebug.o sensor.o clocks.o regulator.o gpio.o \ display.o tree.o utils.o mainloop.o
default: powerdebug diff --git a/gpio.c b/gpio.c new file mode 100644 index 0000000..fc60d00 --- /dev/null +++ b/gpio.c @@ -0,0 +1,103 @@ +/******************************************************************************* + * 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" + +static struct tree *gpio_tree = NULL; + +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 inline int read_gpio_cb(struct tree *t, void *data) +{ + return 0; +} + +static int read_gpio_info(struct tree *tree) +{ + return 0; +} + +static int fill_gpio_cb(struct tree *t, void *data) +{ + return 0; +} + +static int fill_gpio_tree(void) +{ + return 0; +} + +int gpio_dump(void) +{ + return 0; +} + +/* + * Initialize the gpio framework + */ +int gpio_init(void) +{ + gpio_tree = tree_load(SYSFS_GPIO, NULL, false); + if (!gpio_tree) + return -1; + + if (fill_gpio_tree()) + return -1; + + return display_register(GPIO, &gpio_ops); +} diff --git a/gpio.h b/gpio.h new file mode 100644 index 0000000..38f035f --- /dev/null +++ b/gpio.h @@ -0,0 +1,17 @@ +/******************************************************************************* + * 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 + *******************************************************************************/ + +extern int gpio_init(void); +extern int gpio_dump(void);
Now we have the directory structure, we can address the different files and read their content in order to store them in the tree nodes.
Signed-off-by: Daniel Lezcano daniel.lezcano@linaro.org --- gpio.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 files changed, 70 insertions(+), 4 deletions(-)
diff --git a/gpio.c b/gpio.c index fc60d00..8e7499d 100644 --- a/gpio.c +++ b/gpio.c @@ -33,8 +33,27 @@
#define SYSFS_GPIO "/sys/class/gpio"
+struct gpio_info { + bool expanded; + int active_low; + int value; + int direction; + int edge; +} *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, 0, sizeof(*gi)); + + return gi; +} + static int gpio_display(bool refresh) { return 0; @@ -62,24 +81,71 @@ static struct display_ops gpio_ops = { .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 0; + return tree_for_each(tree, read_gpio_cb, NULL); }
static int fill_gpio_cb(struct tree *t, void *data) { - return 0; + 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 0; + return tree_for_each(gpio_tree, fill_gpio_cb, NULL); }
int gpio_dump(void) @@ -92,7 +158,7 @@ int gpio_dump(void) */ int gpio_init(void) { - gpio_tree = tree_load(SYSFS_GPIO, NULL, false); + gpio_tree = tree_load(SYSFS_GPIO, gpio_filter_cb, false); if (!gpio_tree) return -1;
Now we dump the output to the stdout.
Signed-off-by: Daniel Lezcano daniel.lezcano@linaro.org --- gpio.c | 45 ++++++++++++++++++++++++++++++++++++++++++--- 1 files changed, 42 insertions(+), 3 deletions(-)
diff --git a/gpio.c b/gpio.c index 8e7499d..562a11d 100644 --- a/gpio.c +++ b/gpio.c @@ -39,6 +39,7 @@ struct gpio_info { int value; int direction; int edge; + char *prefix; } *gpios_info;
static struct tree *gpio_tree = NULL; @@ -48,8 +49,10 @@ static struct gpio_info *gpio_alloc(void) struct gpio_info *gi;
gi = malloc(sizeof(*gi)); - if (gi) - memset(gi, 0, sizeof(*gi)); + if (gi) { + memset(gi, -1, sizeof(*gi)); + gi->prefix = NULL; + }
return gi; } @@ -148,11 +151,47 @@ static int fill_gpio_tree(void) return tree_for_each(gpio_tree, fill_gpio_cb, NULL); }
-int gpio_dump(void) +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 */
Let's create the command options parameters and plug the gpio code with the main code.
Signed-off-by: Daniel Lezcano daniel.lezcano@linaro.org --- powerdebug.c | 26 ++++++++++++++++++++++---- 1 files changed, 22 insertions(+), 4 deletions(-)
diff --git a/powerdebug.c b/powerdebug.c index b4575c4..cc9e871 100644 --- a/powerdebug.c +++ b/powerdebug.c @@ -24,6 +24,7 @@ #include "display.h" #include "clocks.h" #include "sensor.h" +#include "gpio.h" #include "mainloop.h" #include "powerdebug.h"
@@ -54,9 +55,10 @@ void version()
/* * Options: - * -r, --regulator : regulator + * -r, --regulator : regulators * -s, --sensor : sensors * -c, --clock : clocks + * -g, --gpio : gpios * -p, --findparents : clockname whose parents have to be found * -t, --time : ticktime * -d, --dump : dump @@ -70,6 +72,7 @@ static struct option long_options[] = { { "regulator", 0, 0, 'r' }, { "sensor", 0, 0, 's' }, { "clock", 0, 0, 'c' }, + { "gpio", 0, 0, 'g' }, { "findparents", 1, 0, 'p' }, { "time", 1, 0, 't' }, { "dump", 0, 0, 'd' }, @@ -84,6 +87,7 @@ struct powerdebug_options { bool regulators; bool sensors; bool clocks; + bool gpios; bool dump; unsigned int ticktime; int selectedwindow; @@ -101,7 +105,7 @@ int getoptions(int argc, char *argv[], struct powerdebug_options *options) while (1) { int optindex = 0;
- c = getopt_long(argc, argv, "rscp:t:dvVh", + c = getopt_long(argc, argv, "rscgp:t:dvVh", long_options, &optindex); if (c == -1) break; @@ -119,6 +123,10 @@ int getoptions(int argc, char *argv[], struct powerdebug_options *options) options->clocks = true; options->selectedwindow = CLOCK; break; + case 'g': + options->gpios = true; + options->selectedwindow = GPIO; + break; case 'p': options->clkname = strdup(optarg); if (!options->clkname) { @@ -149,8 +157,10 @@ int getoptions(int argc, char *argv[], struct powerdebug_options *options) }
/* No system specified to be dump, let's default to all */ - if (!options->regulators && !options->clocks && !options->sensors) - options->regulators = options->clocks = options->sensors = true; + if (!options->regulators && !options->clocks && + !options->sensors && !options->gpios) + options->regulators = options->clocks = + options->sensors = options->gpios = true;
if (options->selectedwindow == -1) options->selectedwindow = CLOCK; @@ -169,6 +179,9 @@ static int powerdebug_dump(struct powerdebug_options *options) if (options->sensors) sensor_dump();
+ if (options->gpios) + gpio_dump(); + return 0; }
@@ -234,6 +247,11 @@ int main(int argc, char **argv) options->sensors = false; }
+ if (gpio_init()) { + printf("failed to initialize gpios\n"); + options->gpios = false; + } + ret = options->dump ? powerdebug_dump(options) : powerdebug_display(options);
Show in ncurses mode the gpio informations.
Signed-off-by: Daniel Lezcano daniel.lezcano@linaro.org --- gpio.c | 130 +++++++++++++++++++++++++++++++++++++++++++++++++-------------- 1 files changed, 101 insertions(+), 29 deletions(-)
diff --git a/gpio.c b/gpio.c index 562a11d..f7d2a10 100644 --- a/gpio.c +++ b/gpio.c @@ -57,33 +57,6 @@ static struct gpio_info *gpio_alloc(void) 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 @@ -169,8 +142,21 @@ static int dump_gpio_cb(struct tree *t, void *data) 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); + printf("%s%s-- %s (", gpio->prefix, !t->next ? "`" : "", t->name); + + if (gpio->active_low != -1) + printf(" active_low:%d", gpio->active_low); + + if (gpio->value != -1) + printf(", value:%d", gpio->value); + + if (gpio->edge != -1) + printf(", edge:%d", gpio->edge); + + if (gpio->direction != -1) + printf(", direction:%d", gpio->direction); + + printf(" )\n");
return 0; } @@ -192,6 +178,92 @@ int gpio_dump(void) return ret; }
+static char *gpio_line(struct tree *t) +{ + struct gpio_info *gpio = t->private; + char *gpioline; + + if (asprintf(&gpioline, "%-20s %-10d %-10d %-10d %-10d", t-> name, + gpio->value, gpio->active_low, gpio->edge, gpio->direction) < 0) + return NULL; + + return gpioline; +} + +static int _gpio_print_info_cb(struct tree *t, void *data) +{ + int *line = data; + char *buffer; + + /* we skip the root node of the tree */ + if (!t->parent) + return 0; + + buffer = gpio_line(t); + if (!buffer) + return -1; + + display_print_line(GPIO, *line, buffer, 0, t); + + (*line)++; + + free(buffer); + + return 0; +} + +static int gpio_print_info_cb(struct tree *t, void *data) +{ + /* we skip the root node of the tree */ + if (!t->parent) + return 0; + + return _gpio_print_info_cb(t, data); +} + +static int gpio_print_header(void) +{ + char *buf; + int ret; + + if (asprintf(&buf, "%-20s %-10s %-10s %-10s %-10s", + "Name", "Value", "Active_low", "Edge", "Direction") < 0) + return -1; + + ret = display_column_name(buf); + + free(buf); + + return ret; +} + +static int gpio_print_info(struct tree *tree) +{ + int ret, line = 0; + + display_reset_cursor(GPIO); + + gpio_print_header(); + + ret = tree_for_each(tree, gpio_print_info_cb, &line); + + display_refresh_pad(GPIO); + + return ret; +} + +static int gpio_display(bool refresh) +{ + if (refresh && read_gpio_info(gpio_tree)) + return -1; + + return gpio_print_info(gpio_tree); +} + +static struct display_ops gpio_ops = { + .display = gpio_display, +}; + /* * Initialize the gpio framework */