From: Eric van Tassell <evt@evtM17x.(none)>
---
Android.mk | 4 +-
Makefile | 4 +-
dirtree.c | 149 ++++++++++++++++++++++++++++++++++++++++++++
dirtree.h | 22 +++++++
display.c | 12 ++++
display.h | 4 +-
powerdebug.c | 1 +
tree.c | 28 +++++++++
tree.h | 11 +++-
tree_mgr.c | 197 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
tree_mgr.h | 25 ++++++++
utils.c | 58 +++++++++++++++++
utils.h | 3 +
13 files changed, 511 insertions(+), 7 deletions(-)
create mode 100644 dirtree.c
create mode 100644 dirtree.h
create mode 100644 tree_mgr.c
create mode 100644 tree_mgr.h
diff --git a/Android.mk b/Android.mk
index 7bf67dc..d67317f 100644
--- a/Android.mk
+++ b/Android.mk
@@ -28,7 +28,7 @@ LOCAL_C_INCLUDES += external/stlport/stlport/ \
external/ncurses/include/ncurses
LOCAL_SRC_FILES += \
- powerdebug.c sensor.c clocks.c regulator.c gpio.c regfield.c\
- display.c tree.c utils.c mainloop.c delimi.c mmioreg.c
+ powerdebug.c sensor.c clocks.c regulator.c gpio.c regfield.c dirtree.c \
+ display.c tree.c utils.c mainloop.c delimi.c mmioreg.c tree_mgr.c
include $(BUILD_EXECUTABLE)
diff --git a/Makefile b/Makefile
index e7e3f20..b04749e 100644
--- a/Makefile
+++ b/Makefile
@@ -4,8 +4,8 @@ MANDIR=/usr/share/man/man8
CFLAGS?=-O1 -g -Wall -Wshadow
CC?=gcc
-OBJS = powerdebug.o sensor.o clocks.o regulator.o gpio.o regfield.o\
- display.o tree.o utils.o mainloop.o delimi.o mmioreg.o
+OBJS = powerdebug.o sensor.o clocks.o regulator.o gpio.o regfield.o dirtree.o \
+ display.o tree.o utils.o mainloop.o delimi.o mmioreg.o tree_mgr.o
default: powerdebug
diff --git a/dirtree.c b/dirtree.c
new file mode 100644
index 0000000..a630f14
--- /dev/null
+++ b/dirtree.c
@@ -0,0 +1,149 @@
+/*******************************************************************************
+ * Copyright (C) 2012, 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:
+ * Eric van Tassell
+ * - 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 <ctype.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include "display.h"
+#include "tree.h"
+#include "utils.h"
+#include "delimi.h"
+#include "dirtree.h"
+#include "regfield.h"
+
+/*
+ * This function takes the path to a config file that defines the heirarchy
+ * of memory mapped registers. ex: root -> power-domain -> register -> field
+ *
+ * This approach is taken to avoid creating tons of architecture specific
+ * debugfs files
+ *
+ * @tree : a path to the topmost directory path
+ * Returns a tree structure corresponding to the root node of the
+ * directory tree representation on success, NULL otherwise
+ */
+struct tree *tree_load_file(const char *cfg_file_path)
+{
+ struct tree *tree;
+ struct tree *node_stack[MAX_TREE_DEPTH];
+ struct tree *node;
+ int sp = 0;
+ FILE *fp;
+ char buf[MAX_LINE_LENGTH];
+ char *cfg_field;
+ char new_path[MAX_LINE_LENGTH];
+ struct tree *(*alloc)(const char *path, int depth);
+ void (*add_child)(struct tree *parent, struct tree *child);
+ struct delim_iterator *delimi;
+ struct parser_ctl *parser_ctl = ®field_parsers;
+
+ get_tree_cbs(&alloc, &add_child);
+ if ((alloc == NULL) || (add_child == NULL))
+ BAIL_OUT(("cannnot determine alloc or add_child callbacks"));
+
+ memset(node_stack, 0, sizeof(node_stack));
+
+ tree = alloc("/", sp);
+ if (!tree)
+ return NULL;
+
+ node_stack[sp] = tree;
+
+ fp = fopen(cfg_file_path, "r");
+ if (!fp)
+ BAIL_OUT(("Cannot open config file: %s\n", cfg_file_path));
+
+ memset(buf, 0, sizeof(buf));
+
+ while (fgets(buf, sizeof(buf), fp)) {
+ if (*buf == '#')
+ continue;
+ delimi = delimi_new(buf, ',');
+ if (delimi == NULL)
+ BAIL_OUT(("NULL delim_iterator_t *"));
+
+ if (!strncmp(buf, "push", strlen("push"))) {
+ char path[MAX_LINE_LENGTH];
+
+ if (sp == MAX_TREE_DEPTH - 1) {
+ printf("push - max tree depth reached\n");
+ exit(0);
+ }
+
+ memset(path, 0, sizeof(path));
+ sscanf(buf, "push, %s\n", path);
+ if (sp == 0)
+ sprintf(new_path, "%s%s",
+ node_stack[sp]->path,
+ path);
+ else
+ sprintf(new_path,
+ "%s/%s",
+ node_stack[sp]->path,
+ path);
+
+ sp++;
+ node_stack[sp] = alloc(new_path, sp);
+ add_child(node_stack[sp - 1], node_stack[sp]);
+ } else if (!strncmp(buf, "pop", strlen("pop"))) {
+ if (sp == 0) {
+ printf("illegal - cant pop the root node\n");
+ exit(0);
+ }
+ sp--;
+ } else {
+ int i;
+ int parser_found = 0;
+
+ for (i = 0; i < parser_ctl->num_parsers; i++) {
+ struct parser_descriptor *pd;
+
+ pd = &(parser_ctl->descriptors[i]);
+ if (!strncmp(buf, pd->verb, strlen(pd->verb))) {
+ void *pvdata;
+ char *name;
+
+ parser_found = 1;
+ pvdata = (pd->parser)(delimi, &name);
+ if (pvdata) {
+ sprintf(new_path, "%s/%s",
+ node_stack[sp]->path,
+ name);
+ node = alloc(new_path, sp + 1);
+ if (!node)
+ BAIL_OUT(("NULL node"));
+
+ node->private = pvdata;
+ add_child(node_stack[sp], node);
+ }
+ break;
+ }
+ }
+ if (!parser_found)
+ BAIL_OUT(("illegal config line:%s\n", buf));
+ }
+ delimi_free(delimi);
+ memset(buf, 0, sizeof(buf));
+ }
+ return tree;
+}
diff --git a/dirtree.h b/dirtree.h
new file mode 100644
index 0000000..57abb98
--- /dev/null
+++ b/dirtree.h
@@ -0,0 +1,22 @@
+/*******************************************************************************
+ * Copyright (C) 2012, 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:
+ * Eric van Tassell
+ * - initial API and implementation
+
******************************************************************************/
+
+#define MAX_TREE_DEPTH 8
+#define MAX_LINE_LENGTH 255
+
+typedef void (*p_parser)(struct delim_iterator *, char **);
+
+/* prototypes */
+struct tree *tree_load_file(const char *cfg_file_path);
diff --git a/display.c b/display.c
index f06387c..fcb4ec1 100644
--- a/display.c
+++ b/display.c
@@ -24,6 +24,7 @@
#include "mainloop.h"
#include "regulator.h"
#include "display.h"
+#include "utils.h"
enum { PT_COLOR_DEFAULT = 1,
PT_COLOR_HEADER_BAR,
@@ -52,6 +53,7 @@ struct windata {
WINDOW *pad;
struct display_ops *ops;
struct rowdata *rowdata;
+ void *pvdata;
char *name;
int nrdata;
int scrolling;
@@ -600,3 +602,13 @@ int display_register(int win, struct display_ops *ops)
return 0;
}
+
+int display_register_ex(int win, struct display_ops *ops, void *v)
+{
+ if (display_register(win, ops))
+ return -1;
+
+ windata[win].pvdata = v;
+ printf("%s: win = %d, v = %p\n", __func__, win, v);
+ return 0;
+}
diff --git a/display.h b/display.h
index 6362a48..d469a66 100644
--- a/display.h
+++ b/display.h
@@ -13,10 +13,9 @@
* - initial API and implementation
*******************************************************************************/
-enum { CLOCK, REGULATOR, SENSOR, GPIO };
-
struct display_ops {
int (*display)(bool refresh);
+ int (*display_ex)(bool refresh, void *v);
int (*select)(void);
int (*find)(const char *);
int (*selectf)(void);
@@ -31,6 +30,7 @@ extern void *display_get_row_data(int window);
extern int display_init(int wdefault);
extern int display_register(int win, struct display_ops *ops);
+extern int display_register_ex(int win, struct display_ops *ops, void *v);
extern int display_column_name(const char *line);
#define NAME_MAX 255
diff --git a/powerdebug.c b/powerdebug.c
index cc9e871..0f15b38 100644
--- a/powerdebug.c
+++ b/powerdebug.c
@@ -27,6 +27,7 @@
#include "gpio.h"
#include "mainloop.h"
#include "powerdebug.h"
+#include "utils.h"
void usage(void)
{
diff --git a/tree.c b/tree.c
index d331c60..d4ada79 100644
--- a/tree.c
+++ b/tree.c
@@ -229,6 +229,34 @@ int tree_for_each(struct tree *tree, tree_cb_t cb, void
*data)
}
/*
+ * provide callbacks to allow external tree composers to be built without
+ * polluting this file with application specific code
+ */
+void get_tree_cbs(struct tree *(**alloc)(const char *path, int depth),
+ void (**add_child)(struct tree *parent, struct tree *child))
+{
+ if ((alloc == NULL) || (add_child == NULL))
+ return;
+ *alloc = tree_alloc;
+ *add_child = tree_add_child;
+}
+
+/* same as above but pass an integer to each cb */
+int tree_for_each_ex(struct tree *tree, tree_cb_ex_t cb, void *data, int ix)
+{
+ if (!tree)
+ return 0;
+
+ if (cb(tree, data, ix))
+ return -1;
+
+ if (tree_for_each_ex(tree->child, cb, data, ix))
+ return -1;
+
+ return tree_for_each_ex(tree->next, cb, data, ix);
+}
+
+/*
* This function will go over the tree passed as parameter at the reverse
* order and will call the callback passed as parameter for each.
* @tree : the lower node where we begin to browse the tree at the reverse
diff --git a/tree.h b/tree.h
index 5c1c697..9a6649c 100644
--- a/tree.h
+++ b/tree.h
@@ -11,7 +11,7 @@
* Author:
* Daniel Lezcano <[email protected]>
*
-
*******************************************************************************/
+
******************************************************************************/
/*
* Structure describing a node of the clock tree
@@ -40,6 +40,7 @@ struct tree {
typedef int (*tree_cb_t)(struct tree *t, void *data);
typedef int (*tree_filter_t)(const char *name);
+typedef int (*tree_cb_ex_t)(struct tree *t, void *data, int ix);
extern struct tree *tree_load(const char *path, tree_filter_t filter, bool
follow);
@@ -47,8 +48,16 @@ extern struct tree *tree_find(struct tree *tree, const char
*name);
extern int tree_for_each(struct tree *tree, tree_cb_t cb, void *data);
+extern int tree_for_each_ex(struct tree *tree,
+ tree_cb_ex_t cb,
+ void *data,
+ int ix);
+
extern int tree_for_each_reverse(struct tree *tree, tree_cb_t cb, void *data);
extern int tree_for_each_parent(struct tree *tree, tree_cb_t cb, void *data);
extern int tree_finds(struct tree *tree, const char *name, struct tree ***ptr);
+
+void get_tree_cbs(struct tree *(**alloc)(const char *path, int depth),
+ void (**add_child)(struct tree *parent, struct tree *child));
diff --git a/tree_mgr.c b/tree_mgr.c
new file mode 100644
index 0000000..9588a2a
--- /dev/null
+++ b/tree_mgr.c
@@ -0,0 +1,197 @@
+/*******************************************************************************
+ * Copyright (C) 2012, 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:
+ * Eric van Tassell
+ * - 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 <ctype.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include "display.h"
+#include "tree_mgr.h"
+#include "tree.h"
+#include "utils.h"
+#include "delimi.h"
+#include "dirtree.h"
+#include "regfield.h"
+
+static int tree_mgr_dump_cb(struct tree *t, void *data)
+{
+ int i;
+ if (t->depth == 0)
+ return 0;
+
+ for (i = 1; i < t->depth; i++)
+ printf("\t");
+ printf("%s\n", t->name);
+ if (t->private) {
+ struct field_def *f = (struct field_def *) t->private;
+
+ for (i = 1; i < t->depth; i++)
+ printf("\t");
+ if (f->decoder)
+ printf("\t0x%x(%s)\n", f->value, field_decode(f));
+ else
+ printf("\t0x%x\n", f->value);
+ }
+ return 0;
+}
+
+int tree_mgr_dump(struct tree_mgr *t)
+{
+ printf("%s", t->dump_header);
+
+ return tree_for_each(t->tree, tree_mgr_dump_cb, NULL);
+}
+
+static int tree_mgr_read_cb(struct tree *t, void *data)
+{
+ if (!t)
+ BAIL_OUT(("bad tree"));
+
+ field_read((struct field_def *) t->private);
+ return 0;
+}
+
+static int tree_mgr_fill_cb(struct tree *t, void *data)
+{
+ if (t->private)
+ return tree_mgr_read_cb(t, data);
+ else
+ return 0;
+}
+
+#ifdef DEBUG_PARSE
+static int tree_mgr_dump_debug_cb(struct tree *t, void *data)
+{
+ printf("%s: name = %s, depth = %d, private = %p, path = %s\n",
+ __func__,
+ t->name,
+ t->depth,
+ t->private,
+ t->path);
+ return 0;
+}
+#endif /* DEBUG_PARSE */
+
+static int tree_mgr_fill_tree(struct tree_mgr *t)
+{
+ return tree_for_each(t->tree, tree_mgr_fill_cb, NULL);
+}
+
+#ifdef DEBUG_PARSE
+static int tree_mgr_debug_dump_tree(struct tree *t)
+{
+ return tree_for_each(t, tree_mgr_dump_debug_cb, NULL);
+}
+#endif /* DEBUG_PARSE */
+
+static int tree_mgr_display_cb(struct tree *t, void *data, int ix)
+{
+ int *line = data;
+ char *buf;
+ int i;
+ struct field_def *f = (struct field_def *) t->private;
+
+ if (t == NULL)
+ BAIL_OUT(("bad tree"));
+ if (t->private == NULL)
+ return 0; /* only display register fields */
+
+ if (f->decoder)
+ asprintf(&buf, "%25s %-8x(%s)",
+ t->path, f->value, field_decode(f));
+ else
+ asprintf(&buf, "%25s %-8x", t->path, f->value);
+ display_print_line(ix, *line, buf, 1, t);
+
+ (*line)++;
+
+ return 0;
+}
+
+static int tree_mgr_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 tree_mgr_display(bool refresh, void *v)
+{
+ int ret, line = 0;
+ struct tree_mgr *tm = (struct tree_mgr *) v;
+ struct tree *t;
+
+ if (!tm)
+ BAIL_OUT(("bad tree_mgr"));
+ t = tm->tree;
+ if (!t)
+ BAIL_OUT(("bad tree"));
+
+ display_reset_cursor(tm->ix);
+
+ tree_mgr_print_header();
+
+ ret = tree_for_each_ex(t, tree_mgr_display_cb, &line, tm->ix);
+
+ display_refresh_pad(tm->ix);
+
+ return ret;
+}
+
+static struct display_ops tree_mgr_ops = {
+ .display_ex = tree_mgr_display,
+};
+
+struct tree_mgr *tree_mgr_new(int ix, char *hdr_str)
+{
+ struct tree_mgr *t = calloc(1, sizeof(struct tree_mgr));
+
+ if (!t)
+ BAIL_OUT(("failed to allocated struct tree_mgr"));
+
+ t->tree = tree_load_file(get_cfg_file(ix));
+ t->dump_header = hdr_str;
+ t->ix = ix;
+
+#ifdef DEBUG_PARSE
+ tree_mgr_debug_dump_tree(t->tree);
+#endif /* DEBUG_PARSE */
+
+ if (!t->tree)
+ BAIL_OUT(("failed to allocate tree"));
+
+ if (tree_mgr_fill_tree(t))
+ return NULL;
+
+ if (display_register_ex(ix, &tree_mgr_ops, (void *)t))
+ BAIL_OUT(("display_register_ex failed"));
+ return t;
+}
+
diff --git a/tree_mgr.h b/tree_mgr.h
new file mode 100644
index 0000000..d692e1f
--- /dev/null
+++ b/tree_mgr.h
@@ -0,0 +1,25 @@
+/*******************************************************************************
+ * Copyright (C) 2012, 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:
+ * Eric van Tassell
+ * - initial API and implementation
+
******************************************************************************/
+
+
+struct tree_mgr {
+ int ix;
+ struct tree *tree;
+ char *dump_header;
+};
+
+/* prototypes */
+struct tree_mgr *tree_mgr_new(int ix, char *hdr_str);
+extern int tree_mgr_dump(struct tree_mgr *t);
diff --git a/utils.c b/utils.c
index 0e95f05..35a61a5 100644
--- a/utils.c
+++ b/utils.c
@@ -11,12 +11,17 @@
* Contributors:
* Daniel Lezcano <[email protected]> (IBM Corporation)
* - initial API and implementation
+ * Eric van Tassell
+ * - minor additions
*******************************************************************************/
#define _GNU_SOURCE
#include <stdio.h>
#undef _GNU_SOURCE
#include <stdlib.h>
+#include "utils.h"
+#include "delimi.h"
+#include "regfield.h"
/*
* This functions is a helper to read a specific file content and store
@@ -65,3 +70,56 @@ char *strchrnul(char *str, char delim)
tmp = str + strlen(str) - 1;
return tmp;
}
+
+static char *get_omap4_config_file(int ix)
+{
+ switch (ix) {
+ case PWRDM:
+ return"pwrdm.regdefs.omap4";
+ case VDD:
+ return"vdd.regdefs.omap4";
+ default:
+ return NULL;
+ }
+}
+
+static int is_omap4(void)
+{
+ uint32_t omap4_ids[] = {
+ 0x0B85202F, /* OMAP4430 ES1.0 */
+ 0x1B85202F, /* OMAP4430 ES2.0 */
+ 0x3B95C02F, /* OMAP4430 ES2.1 */
+ 0x4B95C02F, /* OMAP4430 ES2.2 */
+ 0x6B95C02F /* OMAP4430 ES2.3 */
+ };
+
+ struct field_def omap4_id_code = {
+ .name = "ID_CODE",
+ .address = 0x4A002204,
+ .shift = 0,
+ .mask = 0xffffffff
+ };
+
+ uint32_t i;
+
+ field_read(&omap4_id_code);
+
+ for (i = 0; i < sizeof(omap4_ids) / sizeof(uint32_t); i++) {
+ if (omap4_ids[i] == omap4_id_code.value)
+ return 1;
+ }
+ return 0;
+}
+
+char *get_cfg_file(int ix)
+{
+ char *ret = NULL;
+
+ if (is_omap4())
+ ret = get_omap4_config_file(ix);
+ else
+ BAIL_OUT(("unknown SOC, cannot determine config file"));
+
+ printf("%s: ret = %s\n", __func__, ret);
+ return ret;
+}
diff --git a/utils.h b/utils.h
index 581e20d..d4b7ece 100644
--- a/utils.h
+++ b/utils.h
@@ -15,6 +15,8 @@
#ifndef __UTILS_H
#define __UTILS_H
+enum { CLOCK, REGULATOR, SENSOR, PWRDM, VDD, GPIO};
+
#define BAIL_OUT(x) \
{ \
printf x; \
@@ -29,4 +31,5 @@ extern int file_read_value(const char *path, const char *name,
const char *format, void *value);
char *strchrnul(char *str, char delim);
+char *get_cfg_file(int ix);
#endif
--
1.7.9.5
_______________________________________________
linaro-dev mailing list
[email protected]
http://lists.linaro.org/mailman/listinfo/linaro-dev