[PATCH 4/7] largest commit of this series. Provide an instance of the tree abstraction used by powerdebug core that is built by parsing a config file instead of walking a debugfs tree as, for example, the sensor functionality does

evttxl at gmail.com evttxl at gmail.com
Sat Jun 30 19:27:50 UTC 2012


From: Eric van Tassell <evt at 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 = &regfield_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 at 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 at 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
-- 
1.7.9.5




More information about the linaro-dev mailing list