Mercurial > ~darius > hgwebdir.cgi > hwmon
diff pcmon/pcmonhelper.c @ 0:c34b37680055 default tip
Inital commit of random SuperIO code.
author | Daniel O'Connor <darius@dons.net.au> |
---|---|
date | Thu, 20 Oct 2011 16:48:24 +1030 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pcmon/pcmonhelper.c Thu Oct 20 16:48:24 2011 +1030 @@ -0,0 +1,252 @@ +#define _WITH_GETLINE + +#include <stdio.h> +#include <errno.h> +#include <string.h> +#include <fcntl.h> +#include <stdlib.h> +#include <sys/types.h> +#include <machine/cpufunc.h> +#include <unistd.h> + +/* Prototypes */ +void ec_outb(uint16_t base, uint8_t adr, uint8_t val); +uint8_t ec_inb(uint16_t base, uint8_t adr); +void ec_run(uint16_t base); +void freeargs(char **args, size_t nargs); +void splitline(char *line, char ***args, size_t *nargs); +void superio_enter(uint16_t base, char type); +void superio_exit(uint16_t base, char type); +uint8_t superio_inb(uint8_t base, uint8_t adr); +void superio_outb(uint16_t base, uint8_t adr, uint8_t val); +void usage(char *name); + +void +usage(char *name) { + fprintf(stderr, + "Bad usage\n" + "\t%s [-b base] [-t type]\n" + "\n" + "Read/write registers in the EC function of Winbond/ITE parts\n" + "base is the base address for the chip (default: 0x2e)\n" + "type is the chip type (i = ITE, w = WinBond)\n", name); + exit(1); +} + +int +main(int argc, char **argv) { + int fd, base, ch, ecbase, devid; + char *progname, type; + + type = 'w'; + base = 0x2e; + + progname = argv[0]; + + while ((ch = getopt(argc, argv, "b:t:")) != -1) { + switch (ch) { + case 'b': + base = strtol(optarg, NULL, 0) & 0xffff; + break; + + case 't': + if (optarg[0] != 'w' && optarg[0] != 'i') { + fprintf(stderr, "type must be w or i\n\n"); + usage(progname); + } + + type = optarg[0]; + break; + + default: + usage(progname); + break; + } + } + argc -= optind; + argv += optind; + + if (argc != 0) + usage(progname); + + if ((fd = open("/dev/io", O_RDWR)) == -1) { + fprintf(stderr, "Can't open /dev/io: %s\n", strerror(errno)); + exit(1); + } + + /* Enter extended function mode */ + superio_enter(base, type); + + /* Check device ID */ + devid = superio_inb(base, 0x20) << 8 | superio_inb(base, 0x21); + printf("Device ID = 0x%04x\n", devid); + if (devid != 0x8720) { + fprintf(stderr, "Device ID mismatch\n"); + superio_exit(base, type); + exit(1); + } + + /* Select EC config registers */ + superio_outb(base, 0x7, 4); + + /* Determine EC base address */ + ecbase = superio_inb(base, 0x60) << 8; + ecbase |= superio_inb(base, 0x61); + + /* Exit extended function mode */ + superio_exit(base, type); + + ec_run(ecbase); + exit(0); +} + +/* Enter extended function mode */ +void +superio_enter(uint16_t base, char type) { + if (type == 'w') { + outb(base, 0x87); + outb(base, 0x87); + } else { + outb(base, 0x87); + outb(base, 0x01); + outb(base, 0x55); + outb(base, 0x55); + } +} + +/* Exit extended function mode */ +void +superio_exit(uint16_t base, char type) { + if (type == 'w') { + outb(base, 0xaa); + outb(base, 0xaa); + } else { + outb(base, 0x02); + outb(base, 0x02); + } +} + +void +superio_outb(uint16_t base, uint8_t adr, uint8_t val) { + outb(base, adr); + outb(base + 1, val); +} + +uint8_t +superio_inb(uint8_t base, uint8_t adr) { + outb(base, adr); + return(inb(base + 1)); +} + +void +ec_outb(uint16_t base, uint8_t adr, uint8_t val) { + outb(base + 5, adr); + outb(base + 6, val); +} + +uint8_t +ec_inb(uint16_t base, uint8_t adr) { + outb(base + 5, adr); + return(inb(base + 6)); +} + +void +ec_run(uint16_t base) { + char *line = NULL, **args = NULL, *p; + size_t llen = 0, nargs; + long tmp; + uint8_t adr, val; + + printf("EC base address = 0x%04x\n", base); + printf("EC Vendor ID = 0x%02x\n", ec_inb(base, 0x58)); + printf("EC Core ID = 0x%02x\n", ec_inb(base, 0x5b)); + + while (1) { + if (getline(&line, &llen, stdin) == -1) + break; + + /* Snip trailing new line*/ + *rindex(line, '\n')= '\0'; + + splitline(line, &args, &nargs); + + if (nargs != 2 && nargs != 3) { + printf("Unable to parse line\n"); + continue; + } + + tmp = strtol(args[1], &p, 0); + if (p == args[1]) { + printf("Unable to parse address\n"); + continue; + } + if (tmp < 0 || tmp > 255) { + printf("Address out of range\n"); + continue; + } + adr = tmp; + + if (!strcmp("read", args[0])) { + if (nargs != 2) { + printf("Bad usage of read command\n"); + continue; + } + + printf("0x%02x -> 0x%02x\n", adr, ec_inb(base, adr)); + } else if (!strcmp("write", args[0])) { + if (nargs != 3) { + printf("Bad usage of write command\n"); + continue; + } + tmp = strtol(args[2], &p, 0); + if (p == args[1]) { + printf("Unable to parse value\n"); + continue; + } + if (tmp < 0 || tmp > 255) { + printf("Value out of range\n"); + continue; + } + val = tmp; + ec_outb(base, adr, val); + printf("0x%02x <- 0x%02x\n", adr, val); + } else { + printf("Unable to parse line\n"); + } + } + free(line); +} + +void +splitline(char *line, char ***args, size_t *nargs) { + char *token; + + freeargs(*args, *nargs); + *args = NULL; + *nargs = 0; + + while ((token = strsep(&line, " ")) != NULL) { + *args = realloc(*args, sizeof(char *) * (*nargs + 1)); + if (args == NULL) { + fprintf(stderr, "Unable to allocate memory\n"); + exit(1); + } + + (*args)[*nargs] = malloc(strlen(token) + 1); + strcpy((*args)[*nargs], token); + + (*nargs)++; + } +} + +void +freeargs(char **args, size_t nargs) { + int i; + + if (args != NULL) { + for (i = 0; i < nargs; i++) + free(args[i]); + free(args); + } +} +