[PATCH 3/7] add support to display fields of memory mapped I/O registers with optional value decoding as defined by config files

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


From: Eric van Tassell <evt at evtM17x.(none)>

---
 Android.mk |    2 +-
 Makefile   |    2 +-
 mainloop.c |    2 +
 mmioreg.c  |   43 +++++-----
 mmioreg.h  |    3 +-
 regfield.c |  279 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 regfield.h |   52 +++++++++++
 utils.h    |    1 +
 8 files changed, 360 insertions(+), 24 deletions(-)
 create mode 100644 regfield.c
 create mode 100644 regfield.h

diff --git a/Android.mk b/Android.mk
index c6ec0d7..7bf67dc 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 \
+	powerdebug.c sensor.c clocks.c regulator.c gpio.c regfield.c\
 	display.c tree.c utils.c mainloop.c delimi.c mmioreg.c
 
 include $(BUILD_EXECUTABLE)
diff --git a/Makefile b/Makefile
index 71537c9..e7e3f20 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 gpio.o \
+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
 
 default: powerdebug
diff --git a/mainloop.c b/mainloop.c
index 02dda98..57fc4e7 100644
--- a/mainloop.c
+++ b/mainloop.c
@@ -18,6 +18,7 @@
 #include <unistd.h>
 #include <sys/epoll.h>
 #include "mainloop.h"
+#include "mmioreg.h"
 
 static int epfd = -1;
 static unsigned short nrhandler;
@@ -118,5 +119,6 @@ int mainloop_init(void)
 
 void mainloop_fini(void)
 {
+	memobj_close();
 	close(epfd);
 }
diff --git a/mmioreg.c b/mmioreg.c
index 6dab4f6..54ce24e 100644
--- a/mmioreg.c
+++ b/mmioreg.c
@@ -37,40 +37,41 @@ struct memobj devmem = {
 	.map_mask = 4096 - 1
 };
 
-void memobj_open(struct memobj *m)
+static void memobj_open(void)
 {
-	m->fd = open("/dev/mem", O_RDWR | O_SYNC);
-	if (m->fd == -1)
-		BAIL_OUT(("%s: failed to open %s\n", __func__, m->path));
+	devmem.fd = open("/dev/mem", O_RDWR | O_SYNC);
+	if (devmem.fd == -1)
+		BAIL_OUT(("%s: failed to open %s\n", __func__, devmem.path));
 }
 
-uint32_t memobj_readu32(struct memobj *m, uint32_t addr)
+uint32_t memobj_readu32(uint32_t addr)
 {
 	uint32_t ret;
 
-	if (m->fd == -1)
-		memobj_open(m);
+	if (devmem.fd == -1)
+		memobj_open();
 
-	if (m->last_map_req != addr) {
-		if (m->map_base != NULL)
-			munmap(m->map_base, m->map_size);
-		m->map_base = mmap(0,
-				   m->map_size,
+	if (devmem.last_map_req != addr) {
+		if (devmem.map_base != NULL)
+			munmap(devmem.map_base, devmem.map_size);
+		devmem.map_base = mmap(0,
+				   devmem.map_size,
 				   PROT_READ|PROT_WRITE, MAP_SHARED,
-				   m->fd,
-				   addr & ~m->map_mask);
-		if (m->map_base == (void *)-1)
+				   devmem.fd,
+				   addr & ~devmem.map_mask);
+		if (devmem.map_base == (void *)-1)
 			BAIL_OUT(("could not map system memory"));
-		m->last_map_req = addr;
+		devmem.last_map_req = addr;
 	}
-	ret = *((uint32_t *)(((uint32_t)m->map_base) + (addr & m->map_mask)));
+	ret = *((uint32_t *)
+		(((uint32_t)devmem.map_base) + (addr & devmem.map_mask)));
 	return ret;
 }
 
-static void memobj_close(struct memobj *m)
+void memobj_close(void)
 {
-	close(m->fd);
-	m->map_base = NULL;
-	m->last_map_req = 0;
+	close(devmem.fd);
+	devmem.map_base = NULL;
+	devmem.last_map_req = 0;
 }
 
diff --git a/mmioreg.h b/mmioreg.h
index 900b1fd..1757b10 100644
--- a/mmioreg.h
+++ b/mmioreg.h
@@ -23,4 +23,5 @@ struct memobj {
 };
 
 /* prototypes */
-uint32_t memobj_readu32(struct memobj *m, uint32_t addr);
+uint32_t memobj_readu32(uint32_t addr);
+void memobj_close(void);
diff --git a/regfield.c b/regfield.c
new file mode 100644
index 0000000..2e7e31c
--- /dev/null
+++ b/regfield.c
@@ -0,0 +1,279 @@
+/*******************************************************************************
+ * 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 "utils.h"
+#include "delimi.h"
+#include "regfield.h"
+#include "mmioreg.h"
+
+static struct decoder *decoder_new(char *name)
+{
+	struct decoder *d = (struct decoder *)calloc(1, sizeof(struct decoder));
+
+	if (!d)
+		return NULL;
+
+	d->name = name;
+	d->values = NULL;
+	d->num_values = 0;
+
+	return d;
+}
+
+#ifdef DEBUG_PARSE
+static void decoder_show(struct decoder *d)
+{
+	int i;
+
+	if (!d)
+		return;
+	printf("decoder: %s\n", d->name);
+	for (i = 0; i < d->num_values; i++)
+		printf("\t%d: %s\n", i, d->values[i]);
+}
+#endif /* DEBUG_PARSE */
+
+static void decoder_free(struct decoder *d)
+{
+	int i;
+
+	if (!d)
+		return;
+	if (d->name)
+		free(d->name);
+
+	for (i = 0; i < d->num_values; i++) {
+		if (d->values[i])
+			free(d->values[i]);
+	}
+	free(d);
+}
+
+static int decoder_add_value(struct decoder *d, char *value)
+{
+	char **tmp;
+
+	tmp = realloc(d->values, (d->num_values + 1) * sizeof(char *));
+
+	if (tmp == NULL)
+		return 0;
+
+	d->values = tmp;
+	d->values[d->num_values] = value;
+	d->num_values++;
+	return 1;
+}
+
+static struct field_def *field_new(char *name)
+{
+	struct field_def *f
+		= (struct field_def *)calloc(1, sizeof(struct field_def));
+
+	if (!f)
+		return NULL;
+
+	f->name = name;
+	return f;
+}
+
+static void field_show(struct field_def *f)
+{
+	if (!f)
+		return;
+	printf("%s\n", __func__);
+	printf("\t%s\n", f->name);
+	printf("\t0x%x\n", f->address);
+	printf("\t0x%x\n", f->shift);
+	printf("\t0x%x\n", f->mask);
+	printf("--------- decoder ---------\n");
+#ifdef DEBUG_PARSE
+	decoder_show(f->decoder);
+#endif
+}
+
+struct decoder_ctl decoder_ctl;
+
+char *field_decode(struct field_def *f)
+{
+	if (!f)
+		BAIL_OUT(("null field"));
+
+	if (f->value >= f->decoder->num_values)
+		return "out of range";
+
+	return f->decoder->values[f->value];
+}
+
+void field_read(struct field_def *f)
+{
+	f->value = memobj_readu32(f->address);
+	f->value = (f->value >> f->shift) & f->mask;
+}
+
+#ifdef DEBUG_PARSE
+static void decoder_ctl_show(struct decoder_ctl *dc)
+{
+	int i;
+
+	for (i = 0; i < dc->num_decoders; i++)
+#ifdef DEBUG_PARSE
+		decoder_show(dc->decoders[i]);
+#endif
+}
+#endif /* DEBUG_PARSE */
+
+static struct decoder *decoder_ctl_lookup_decoder(struct decoder_ctl *dc,
+						  char *name)
+{
+	int i;
+
+	if (!name)
+		return NULL;
+
+	for (i = 0; i < dc->num_decoders; i++) {
+		if (!strncmp(dc->decoders[i]->name, name, strlen(name)))
+			return dc->decoders[i];
+	}
+	return NULL;
+}
+
+static void decoder_ctl_free(struct decoder_ctl *dc)
+{
+	int i;
+
+	for (i = 0; i < dc->num_decoders; i++)
+		decoder_free(dc->decoders[i]);
+	free(dc->decoders);
+}
+
+static int decoder_ctl_add_decoder(struct decoder_ctl *dc, struct decoder *d)
+{
+
+	struct decoder **tmp;
+
+	tmp = realloc(dc->decoders,
+		      (dc->num_decoders + 1) * sizeof(struct decoder *));
+	if (tmp == NULL)
+		return 0;
+	dc->decoders = tmp;
+	dc->decoders[dc->num_decoders] = d;
+	dc->num_decoders++;
+	return 1;
+}
+
+void *parse_decoder(struct delim_iterator *delimi, char **name)
+{
+	struct decoder *decoder;
+	/* skip the first word, we already know it's "decoder" */
+	delimi_next(delimi);
+
+	decoder = decoder_new(delimi_aget_val(delimi));
+	delimi_next(delimi);
+	if (decoder == NULL)
+		return NULL;
+
+	/*
+	 * we're relaxed about errors in processing decoders,
+	 * if we can't decode -> just report raw value
+	 */
+	while (!delimi_empty(delimi)) {
+		if (!decoder_add_value(decoder, delimi_aget_val(delimi))) {
+			decoder_free(decoder);
+			return NULL;
+		}
+		delimi_next(delimi);
+	}
+
+	if (!decoder_ctl_add_decoder(&decoder_ctl, decoder)) {
+		decoder_ctl_free(&decoder_ctl);
+		return NULL;
+	}
+	return NULL;
+}
+
+void *parse_field(struct delim_iterator *delimi, char **name)
+{
+	char *verb, *fldname, *decoder_name;
+	struct field_def *f;
+	unsigned int address;
+	int shift, mask;
+	char *tmp;
+
+	/* skip the first word, we already know it's "field" */
+	delimi_next(delimi);
+
+	f = field_new(delimi_aget_val(delimi));
+	delimi_next(delimi);
+
+	tmp = delimi_aget_val(delimi);
+	if (!tmp)
+		return NULL;
+
+	sscanf(tmp, "%x", &f->address);
+	free(tmp);
+	delimi_next(delimi);
+
+	tmp = delimi_aget_val(delimi);
+	if (!tmp)
+		return NULL;
+
+	sscanf(tmp, "%x", &f->shift);
+	free(tmp);
+	delimi_next(delimi);
+
+	tmp = delimi_aget_val(delimi);
+	if (!tmp)
+		return NULL;
+
+	sscanf(tmp, "%x", &f->mask);
+	free(tmp);
+	delimi_next(delimi);
+
+	tmp = delimi_aget_val(delimi); /* decoder is optional */
+	if (strlen(tmp) != 0)
+		f->decoder = decoder_ctl_lookup_decoder(&decoder_ctl, tmp);
+	free(tmp);
+	*name = f->name;
+
+	return f;
+}
+
+static struct parser_descriptor parser_descriptors[2] = {
+	{
+		.verb = "field",
+		.parser = parse_field,
+	},
+	{
+		.verb = "decoder",
+		.parser = parse_decoder,
+	},
+};
+
+
+struct parser_ctl regfield_parsers = {
+	.num_parsers =  NUM_ELTS(parser_descriptors, struct parser_descriptor),
+	.descriptors = parser_descriptors
+};
diff --git a/regfield.h b/regfield.h
new file mode 100644
index 0000000..4fa6e8a
--- /dev/null
+++ b/regfield.h
@@ -0,0 +1,52 @@
+/*******************************************************************************
+ * 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 parser_descriptor {
+	char *verb;
+	void *(*parser)(struct delim_iterator *delimi, char **);
+};
+
+struct parser_ctl {
+	int num_parsers;
+	struct parser_descriptor *descriptors;
+};
+
+struct decoder {
+	char *name;
+	char **values;
+	unsigned char num_values;
+};
+
+struct decoder_ctl {
+	struct decoder **decoders;
+	unsigned char  num_decoders;
+};
+
+struct field_def {
+	char           *name;
+	unsigned int   address;
+	unsigned int   shift;
+	unsigned int   mask;
+	struct decoder *decoder;
+	uint32_t       value;
+};
+
+/* shared data */
+extern struct parser_ctl regfield_parsers;
+
+/* prototypes */
+char *field_decode(struct field_def *f);
+void field_read(struct field_def *f);
+void *parse_field(struct delim_iterator *delimi, char **name);
+void *parse_decoder(struct delim_iterator *delimi, char **name);
diff --git a/utils.h b/utils.h
index c5cec51..581e20d 100644
--- a/utils.h
+++ b/utils.h
@@ -23,6 +23,7 @@
 }
 #undef DEBUG_PARSE
 
+#define NUM_ELTS(vbl, type) (sizeof(vbl) / sizeof(type))
 /* prototypes */
 extern int file_read_value(const char *path, const char *name,
                            const char *format, void *value);
-- 
1.7.9.5




More information about the linaro-dev mailing list