diff --git a/.gitignore b/.gitignore index c94f592..1b2f4df 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,8 @@ fexc bin2fex fex2bin +bootinfo fel +pio *.o *.swp diff --git a/Makefile b/Makefile index d9301fb..761704b 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ CC = gcc CFLAGS = -g -O0 -Wall -Wextra CFLAGS += -std=c99 -D_POSIX_C_SOURCE=200112L -TOOLS = fexc bin2fex fex2bin bootinfo fel +TOOLS = fexc bin2fex fex2bin bootinfo fel pio MISC_TOOLS = phoenix_info diff --git a/pio.c b/pio.c new file mode 100644 index 0000000..e54dc74 --- /dev/null +++ b/pio.c @@ -0,0 +1,150 @@ +/* needs _BSD_SOURCE for htole and letoh */ +#define _BSD_SOURCE + +#include +#include +#include +#include +#include + +#include + +#define PIO_REG_SIZE 0x228 /*0x300*/ +#define PIO_PORT_SIZE 0x24 + +#define errf(...) fprintf(stderr, __VA_ARGS__) + +static inline int _read(int fd, char *buf, size_t l) +{ + ssize_t rc = 0; + while (l > 0) { + rc = read(fd, buf, l); + if (rc >= 0) + break; + else if (rc < 0 && errno != EINTR) { + errf("read: %s\n", strerror(errno)); + break; + } + } + + return rc; +} + +static int read_fixed_stdin(char *buf, size_t wanted) +{ + ssize_t rc; + char eof; + + while (wanted > 0) { + rc = _read(0, buf, wanted); + if (rc > 0) { + wanted -= rc; + buf += rc; + } else if (rc == 0) { + errf("read: input too small\n"); + goto fail; + } else if (rc < 0) { + goto fail; + } + } + + if (_read(0, &eof, 1) == 0) + return 1; + + errf("read: input too large\n"); +fail: + return 0; +} + +struct pio_status { + int mul_sel; + int pull; + int drv_level; + int data; +}; + +#define PIO_REG_CFG(B, N, I) ((B) + (N)*0x24 + ((I)<<2) + 0x00) +#define PIO_REG_DLEVEL(B, N, I) ((B) + (N)*0x24 + ((I)<<2) + 0x14) +#define PIO_REG_PULL(B, N, I) ((B) + (N)*0x24 + ((I)<<2) + 0x1C) +#define PIO_REG_DATA(B, N) ((B) + (N)*0x24 + 0x10) + +#define LE32TOH(X) le32toh(*((uint32_t*)(X))) + +static int pio_get(const char *buf, uint32_t port, uint32_t port_num, struct pio_status *pio) +{ + uint32_t val; + uint32_t port_num_func, port_num_pull; + uint32_t offset_func, offset_pull; + + port_num_func = port_num >> 3; + offset_func = ((port_num - (port_num_func << 3)) << 2); + + port_num_pull = port_num >> 4; + offset_pull = ((port_num - (port_num_pull << 4)) << 1); + + /* func */ + val = LE32TOH(PIO_REG_CFG(buf, port, port_num_func)); + pio->mul_sel = (val>>offset_func) & 0x07; + + /* pull */ + val = LE32TOH(PIO_REG_PULL(buf, port, port_num_pull)); + pio->pull = (val>>offset_pull) & 0x03; + + /* dlevel */ + val = LE32TOH(PIO_REG_DLEVEL(buf, port, port_num_pull)); + pio->drv_level = (val>>offset_pull) & 0x03; + + /* i/o data */ + if (pio->mul_sel > 1) + pio->data = -1; + else { + val = LE32TOH(PIO_REG_CFG(buf, port, port_num_func)); + pio->data = (val >> port_num) & 0x01; + } + return 1; +} + +static void print(const char *buf) +{ + int port, i; + struct pio_status pio; + for (port=0; port < 10 /*PIO_REG_SIZE/0x24*/; port++) { + for (i=0; i<28; i++) { + if (pio_get(buf, port, i, &pio)) { + printf("P%c%d", 'A'+port, i+1); + printf("<%x>", pio.mul_sel); + printf("<%x>", pio.pull); + printf("<%x>", pio.drv_level); + if (pio.data >= 0) + printf("<%x>", pio.data); + + fputc('\n', stdout); + } + } + } +} +static int read_and_print(void) +{ + char buf[PIO_REG_SIZE]; + + if (read_fixed_stdin(buf, PIO_REG_SIZE)) { + print(buf); + return 0; + } + return -1; +} + +static inline int usage(const char *argv0) +{ + fprintf(stderr, "usage: %s print < PIO\n", argv0); + return 1; +} + +int main(int argc, char **argv) +{ + if (argc == 2 && (strncmp("print", argv[1], 5) == 0)) + return read_and_print(); + else + return usage(argv[0]); +} +