From: Eric van Tassell <evt@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);