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 daniel.lezcano@linaro.org * - *******************************************************************************/ + ******************************************************************************/
/* * 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 daniel.lezcano@linaro.org (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