diff options
Diffstat (limited to 'usr.sbin/pccard/pccardd/file.c')
-rw-r--r-- | usr.sbin/pccard/pccardd/file.c | 873 |
1 files changed, 873 insertions, 0 deletions
diff --git a/usr.sbin/pccard/pccardd/file.c b/usr.sbin/pccard/pccardd/file.c new file mode 100644 index 0000000..769fafc --- /dev/null +++ b/usr.sbin/pccard/pccardd/file.c @@ -0,0 +1,873 @@ +/* + * Decode pcmciad file. + */ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include "cardd.h" + +static FILE *in; +static int pushc, pusht; +static int lineno; +static char *filename; + +static char *keys[] = + { + "io", /* 1 */ + "irq", /* 2 */ + "memory", /* 3 */ + "card", /* 4 */ + "device", /* 5 */ + "config", /* 6 */ + "__EOF__", /* 7 */ + "reset", /* 8 */ + "ether", /* 9 */ + "insert", /* 10 */ + "remove", /* 11 */ + "iosize", /* 12 */ + "memsize", /* 13 */ + 0 + }; + +struct flags + { + char *name; + int mask; + }; + +void parsefile(); +char *token(); +char *getline(); +char *next_tok(); +int num_tok(); +void error(char *); +int keyword(char *); +struct allocblk *ioblk_tok(int); +struct allocblk *memblk_tok(int); +int irq_tok(int); +void setflags(struct flags *, int *); +struct driver *new_driver(char *); + +/* + * Read a file and parse the pcmcia configuration data. + * After parsing, verify the links. + */ +readfile(char *name) +{ +struct card *cp; +struct driver *drvp; + + in = fopen(name, "r"); + if (in == 0) + { + perror(name); + exit(1); + } + parsefile(); + for (cp = cards; cp; cp = cp->next) + { + if (cp->config == 0) +fprintf(stderr, "warning: card %s(%s) has no valid configuration\n", + cp->manuf, cp->version); + } +} +void +parsefile() +{ +int i; +char *s; +struct allocblk *bp; + + pushc = 0; + lineno = 1; + for(;;) + switch(keyword(next_tok())) + { + default: + error("Syntax error"); + pusht = 0; + break; + case 7: + return; +/* + * reserved I/O blocks + */ + case 1: + while (bp = ioblk_tok(0)) + { + if (bp->size == 0 || bp->addr == 0) + { + free(bp); + continue; + } + bit_nset(io_avail, bp->addr, bp->addr+bp->size-1); + bp->next = pool_ioblks; + pool_ioblks = bp; + } + pusht = 1; + break; +/* + * reserved irqs + */ + case 2: + while ((i = irq_tok(0)) > 0) + pool_irq[i] = 1; + pusht = 1; + break; +/* + * reserved memory blocks. + */ + case 3: + while (bp = memblk_tok(0)) + { + if (bp->size == 0 || bp->addr == 0) + { + free(bp); + continue; + } + bit_nset(mem_avail, MEM2BIT(bp->addr), + MEM2BIT(bp->addr+bp->size)-1); + bp->next = pool_mem; + pool_mem = bp; + } + pusht = 1; + break; +/* + * Card definition. + */ + case 4: + parse_card(); + break; +/* + * Device description + */ +#if 0 + case 5: + parse_device(); + break; +#endif + } +} +/* + * Parse a card definition. + */ +parse_card() +{ +char *man, *vers; +struct card *cp; +int i; +struct card_config *confp, *lastp; + + man = newstr(next_tok()); + vers = newstr(next_tok()); + cp = xmalloc(sizeof(*cp)); + cp->manuf = man; + cp->version = vers; + cp->reset_time = 50; + cp->next = cards; + cards = cp; + for (;;) + { + switch(keyword(next_tok())) + { + default: + pusht = 1; + return; + case 8: + i = num_tok(); + if (i == -1) + { + error("Illegal card reset time"); + break; + } + cp->reset_time = i; + break; + case 6: + i = num_tok(); + if (i == -1) + { + error("Illegal card config index"); + break; + } + confp = xmalloc(sizeof(*confp)); + man = next_tok(); + confp->driver = new_driver(man); + confp->irq = num_tok(); + confp->flags = num_tok(); + if (confp->flags == -1) + { + pusht = 1; + confp->flags = 0; + } + if (confp->irq < 0 || confp->irq > 15) + { + error("Illegal card IRQ value"); + break; + } + confp->index = i & 0x3F; +/* + * If no valid driver for this config, then do not save + * this configuration entry. + */ + if (confp->driver) + { + if (cp->config == 0) + cp->config = confp; + else + { + for (lastp = cp->config; lastp->next; + lastp = lastp->next) + ; + lastp->next = confp; + } + } + else + free(confp); + break; + case 9: + cp->ether = num_tok(); + if (cp->ether == -1) + { + error("Illegal ether address offset"); + cp->ether = 0; + } + break; + case 10: + addcmd(&cp->insert); + break; + case 11: + addcmd(&cp->remove); + break; + } + } +} +/* + * Generate a new driver structure. If one exists, use + * that one after confirming the correct class. + */ +struct driver * +new_driver(char *name) +{ +struct driver *drvp; +char *p; + + for (drvp = drivers; drvp; drvp = drvp->next) + if (strcmp(drvp->name, name)==0) + return(drvp); + drvp = xmalloc(sizeof(*drvp)); + drvp->next = drivers; + drivers = drvp; + drvp->name = newstr(name); + drvp->kernel = newstr(name); + p = drvp->kernel; + while (*p++) + if (*p >= '0' && *p <= '9') + { + drvp->unit = atoi(p); + *p = 0; + break; + } +#ifdef DEBUG + if (verbose) + printf("Drv %s%d created\n", drvp->kernel, drvp->unit); +#endif + return(drvp); +} +#if 0 +/* + * Parse the device description. + */ +parse_device() +{ +enum drvclass type = drvclass_tok(); +struct device *dp; +static struct device *lastp; + + if (type == drv_none) + { + error("Unknown driver class"); + return; + } + dp = xmalloc(sizeof(*dp)); + dp->type = type; + if (devlist == 0) + devlist = dp; + else + lastp->next = dp; + lastp = dp; + for (;;) + switch(keyword(next_tok())) + { + default: + pusht = 1; + return; + case 10: + addcmd(&dp->insert); + break; + case 11: + addcmd(&dp->remove); + break; + } +} +/* + * Parse the driver description. + */ +parse_driver() +{ +char *name, *dev, *p; +struct driver *dp; +static struct driver *lastp; +int i; +struct allocblk *bp; +static struct flags io_flags[] = +{ +{ "ws", 0x01 }, +{ "16bit", 0x02 }, +{ "cs16", 0x04 }, +{ "zerows", 0x08 }, +{ 0, 0 } +}; +static struct flags mem_flags[] = +{ +{ "16bit", 0x01 }, +{ "zerows", 0x02 }, +{ "ws0", 0x04 }, +{ "ws1", 0x08 }, +{ 0, 0 } +}; + + name = newstr(next_tok()); + dev = newstr(next_tok()); + type = drvclass_tok(); + if (type == drv_none) + { + error("Unknown driver class"); + return; + } + dp = xmalloc(sizeof(*dp)); + dp->name = name; + dp->kernel = dev; + dp->type = type; + dp->unit = -1; + dp->irq = -1; +/* + * Check for unit number in driver name. + */ + p = dev; + while (*p++) + if (*p >= '0' && *p <= '9') + { + dp->unit = atoi(p); + *p = 0; + break; + } + if (dp->unit < 0) + error("Illegal kernel driver unit"); +/* + * Place at end of list. + */ + if (lastp == 0) + drivers = dp; + else + lastp->next = dp; + lastp = dp; + for (;;) + switch(keyword(next_tok())) + { + default: + pusht = 1; + return; + case 1: + bp = ioblk_tok(1); + if (bp) + { + setflags(io_flags, &bp->flags); + if (dp->io) + { + error("Duplicate I/O spec"); + free(bp); + } + else + { + bit_nclear(io_avail, bp->addr, + bp->addr+bp->size-1); + dp->io = bp; + } + } + break; + case 2: + dp->irq = irq_tok(1); + if (dp->irq > 0) + pool_irq[i] = 0; + break; + case 3: + bp = memblk_tok(1); + if (bp) + { + setflags(mem_flags, &bp->flags); + if (dp->mem) + { + error("Duplicate memory spec"); + free(bp); + } + else + { + bit_nclear(mem_avail, + MEM2BIT(bp->addr), + MEM2BIT(bp->addr+bp->size)-1); + dp->mem = bp; + } + } + break; + case 10: + addcmd(&dp->insert); + break; + case 11: + addcmd(&dp->remove); + break; +/* + * iosize - Don't allocate an I/O port, but specify + * a size for the range of ports. The actual port number + * will be allocated dynamically. + */ + case 12: + i = num_tok(); + if (i <= 0 || i > 128) + error("Illegal iosize"); + else + { + int flags = 0; + setflags(io_flags, &flags); + if (dp->io) + error("Duplicate I/O spec"); + else + { + dp->io = xmalloc(sizeof(*dp->io)); + dp->io->flags = flags; + dp->io->size = i; + } + } + break; + case 13: + i = num_tok(); + if (i <= 0 || i > 256*1024) + error("Illegal memsize"); + else + { + int flags = 0; + setflags(mem_flags, &flags); + if (dp->mem) + error("Duplicate memory spec"); + else + { + dp->mem = xmalloc(sizeof(*dp->mem)); + dp->mem->flags = flags; + dp->mem->size = i; + } + } + break; + } +} +/* + * drvclass_tok - next token is expected to + * be a driver class. + */ +enum drvclass +drvclass_tok() +{ +char *s = next_tok(); + + if (strcmp(s, "tty")==0) + return(drv_tty); + else if (strcmp(s, "net")==0) + return(drv_net); + else if (strcmp(s, "bio")==0) + return(drv_bio); + else if (strcmp(s, "null")==0) + return(drv_null); + return(drv_none); +} +#endif /* 0 */ +/* + * Parse one I/O block. + */ +struct allocblk * +ioblk_tok(int force) +{ +struct allocblk *io; +int i, j; + + if ((i = num_tok()) >= 0) + { + if (strcmp("-", next_tok()) || (j = num_tok()) < 0 || j < i) + { + error("I/O block format error"); + return(0); + } + io = xmalloc(sizeof(*io)); + io->addr = i; + io->size = j - i + 1; + if (j > IOPORTS) + { + error("I/O port out of range"); + if (force) + { + free(io); + io = 0; + } + else + io->addr = io->size = 0; + } + return(io); + } + if (force) + error("Illegal or missing I/O block spec"); + return(0); +} +/* + * Parse a memory block. + */ +struct allocblk * +memblk_tok(int force) +{ +struct allocblk *mem; +int i, j; + + if ((i = num_tok()) >= 0) + if ((j = num_tok()) < 0) + error("Illegal memory block"); + else + { + mem = xmalloc(sizeof(*mem)); + mem->addr = i & ~(MEMUNIT-1); + mem->size = (j + MEMUNIT - 1) & ~(MEMUNIT-1); + if (i < MEMSTART || (i + j) > MEMEND) + { + error("Memory address out of range"); + if (force) + { + free(mem); + mem = 0; + } + else + mem->addr = mem->size = 0; + } + return(mem); + } + if (force) + error("Illegal or missing memory block spec"); + return(0); +} +/* + * IRQ token. Must be number > 0 && < 16. + * If force is set, IRQ must exist, and can also be '?'. + */ +int +irq_tok(int force) +{ +int i; + + if (strcmp("?", next_tok())==0 && force) + return(0); + pusht = 1; + i = num_tok(); + if (i > 0 && i < 16) + return(i); + if (force) + error("Illegal IRQ value"); + return(-1); +} +/* + * search the table for a match. + */ +int +keyword(char *str) +{ +char **s; +int i = 1; + + for (s = keys; *s; s++, i++) + if (strcmp(*s, str)==0) + return(i); + return(0); +} + +/* + * Set/clear flags + */ +void +setflags(struct flags *flags, int *value) +{ +char *s; +struct flags *fp; +int set = 1; + + do { + s = next_tok(); + if (*s == '!') + { + s++; + set = 0; + } + for (fp = flags; fp->name; fp++) + if (strcmp(s, fp->name)==0) + { + if (set) + *value |= fp->mask; + else + *value &= ~fp->mask; + break; + } + } while (fp->name); + pusht = 1; +} +/* + * addcmd - Append the command line to the list of + * commands. + */ +addcmd(struct cmd **cp) +{ +char *s = getline(); +struct cmd *ncp; + + if (*s) + { + ncp = xmalloc(sizeof(*ncp)); + ncp->line = s; + while (*cp) + cp = &(*cp)->next; + *cp = ncp; + } +} +void +error(char *msg) +{ + pusht = 1; + fprintf(stderr, "%s: %s at line %d, near %s\n", + filename, msg, lineno, next_tok()); + pusht = 1; +} +int last_char; + +int +get() +{ +int c; + + if (pushc) + c = pushc; + else + c = getc(in); + pushc = 0; + while (c == '\\') + { + c = getc(in); + switch(c) + { + case '#': + return(last_char = c); + case '\n': + lineno++; + c = getc(in); + continue; + } + pushc = c; + return('\\'); + } + if (c == '\n') + lineno++; + if (c == '#') + { + while (get() != '\n') + ; + return(last_char = '\n'); + } + return(last_char = c); +} +/* + * num_tok - expecting a number token. If not a number, + * return -1. + * Handles octal (who uses octal anymore?) + * hex + * decimal + * Looks for a 'k' at the end of decimal numbers + * and multiplies by 1024. + */ +int +num_tok() +{ +char *s = next_tok(), c; +int val=0, base, term=0; + + base = 10; + c = *s++; + if (c == '0') + { + base = 8; + c = *s++; + if (c == 'x' || c == 'X') + { + c = *s++; + base = 16; + } + } + do { + switch(c) + { + case 'k': + case 'K': + if (val && base == 10 && *s == 0) + return(val * 1024); + return(-1); + default: + return(-1); + case '0': case '1': + case '2': case '3': + case '4': case '5': + case '6': case '7': + val = val * base + c - '0'; + break; + + case '8': case '9': + if (base == 8) + return(-1); + else + val = val * base + c - '0'; + break; + case 'a': case 'b': + case 'c': case 'd': + case 'e': case 'f': + if (base == 16) + val = val * base + c - 'a' + 10; + else + return(-1); + break; + case 'A': case 'B': + case 'C': case 'D': + case 'E': case 'F': + if (base == 16) + val = val * base + c - 'A' + 10; + else + return(-1); + break; + } + } while (c = *s++); + return(val); +} +char *_next_tok(); +char * +next_tok() +{ +char *s = _next_tok(); +#if 0 + printf("Tok = %s\n", s); +#endif + return(s); +} +/* + * get one token. Handles string quoting etc. + */ +char * +_next_tok() +{ +static char buf[1024]; +char *p = buf, instr = 0; +int c; + + if (pusht) + { + pusht = 0; + return(buf); + } + for(;;) + { + c = get(); + switch(c) + { + default: + *p++ = c; + break; + case '"': + if (instr) + { + *p++ = 0; + return(buf); + } + instr = 1; + break; + case '\n': + if (instr) + { + error("Unterminated string"); + break; + } +/* + * Eat whitespace unless in a string. + */ + case ' ': + case '\t': + if (!instr) + { + if (p!=buf) + { + *p++ = 0; + return(buf); + } + } + else + *p++ = c; + break; +/* + * Special characters that must be tokens on their own. + */ + case '-': + case '?': + case '*': + if (instr) + *p++ = c; + else + { + if (p != buf) + pushc = c; + else + *p++ = c; + *p++ = 0; + return(buf); + } + break; + case EOF: + if (p != buf) + { + *p++ = 0; + return(buf); + } + strcpy(buf, "__EOF__"); + return(buf); + } + } +} + +/* + * get the rest of the line. If the + * last character scanned was a newline, then + * return an empty line. If this isn't checked, then + * a getline may incorrectly return the next line. + */ +char * +getline() +{ +char buf[1024], *p = buf; +int c, i = 0; + + if (last_char == '\n') + return(newstr("")); + do { + c = get(); + } while (c == ' ' || c == '\t'); + for (;c != '\n' && c != EOF; c = get()) + if (i++ < sizeof(buf)-10) + *p++ = c; + *p = 0; + return(newstr(buf)); +} |