/* * Copyright (c) 1995 Andrew McRae. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef lint static const char rcsid[] = "$Id: file.c,v 1.16 1998/04/25 18:10:10 hosokawa Exp $"; #endif /* not lint */ /* * Code cleanup, bug-fix and extension * by Tatsumi Hosokawa */ #include #include #include #include #include #include "cardd.h" static FILE *in; static int pushc, pusht; static int lineno; static char *filename; static char *keys[] = { "__EOF__", /* 1 */ "io", /* 2 */ "irq", /* 3 */ "memory", /* 4 */ "card", /* 5 */ "device", /* 6 */ "config", /* 7 */ "reset", /* 8 */ "ether", /* 9 */ "insert", /* 10 */ "remove", /* 11 */ "function", /* 12 */ "cardio", /* 13 */ "cardmem", /* 14 */ "ignirq", /* 15 */ #ifdef SLOT_ALLOC_IRQ "slot", /* 16 */ #endif /* SLOT_ALLOC_IRQ */ 0 }; #define KWD_EOF 1 #define KWD_IO 2 #define KWD_IRQ 3 #define KWD_MEMORY 4 #define KWD_CARD 5 #define KWD_DEVICE 6 #define KWD_CONFIG 7 #define KWD_RESET 8 #define KWD_ETHER 9 #define KWD_INSERT 10 #define KWD_REMOVE 11 #define KWD_FUNCTION 12 #define KWD_CARDIO 13 #define KWD_CARDMEM 14 #define KWD_IGNIRQ 15 #ifdef SLOT_ALLOC_IRQ #define KWD_SLOT 16 #endif /* SLOT_ALLOC_IRQ */ struct flags { char *name; int mask; }; static void parsefile(int); static char *getline(void); static char *next_tok(void); static int num_tok(void); static void error(char *); static int keyword(char *); static int irq_tok(int); static int config_tok(void); static int func_tok(void); static int ether_mac_tok(struct ether_mac *); static struct allocblk *ioblk_tok(int); static struct allocblk *memblk_tok(int); static struct driver *new_driver(char *); static struct card_io * cardio_tok(void); static struct card_mem * cardmem_tok(void); static void addcmd(struct cmd **); static void parse_card(int); static void delete_card(struct card *cp) { struct ether *etherp, *ether_next; struct card_config *configp, *config_next; struct cmd *cmdp, *cmd_next; /* free characters */ if (cp->manuf != NULL) free(cp->manuf); if (cp->version != NULL) free(cp->version); if (cp->add_info1 != NULL) free(cp->add_info1); if (cp->add_info2 != NULL) free(cp->add_info2); /* free structures */ for (etherp = cp->ether; etherp; etherp = ether_next) { struct ether_mac *macp, *next; ether_next = etherp->next; for (macp = etherp->ether_mac; macp; macp = next) { next = macp->next; free(macp); } free(etherp); } for (configp = cp->config; configp; configp = config_next) { struct card_io *iop, *io_next; struct card_mem *memp, *mem_next; config_next = configp->next; for (iop = configp->card_io; iop; iop = io_next) { io_next = iop->next; free(iop); } for (memp = configp->card_mem; memp; memp = mem_next) { mem_next = memp->next; free(memp); } free(configp); } for (cmdp = cp->insert; cmdp; cmdp = cmd_next) { cmd_next = cmdp->next; free(cmdp->line); free(cmdp); } for (cmdp = cp->remove; cmdp; cmdp = cmd_next) { cmd_next = cmdp->next; free(cmdp->line); free(cmdp); } free(cp); } /* * Read a file and parse the pcmcia configuration data. * After parsing, verify the links. */ void readfile(char *name, u_int irqmask) { int i; struct card *cp, *card_next; for (cp = cards; cp; cp = card_next) { card_next = cp->next; delete_card(cp); } cards = last_card = 0; in = fopen(name, "r"); if (in == NULL) { logerr(name); die("readfile"); } if (irqmask) for (i = 0; i < 16; i++) pool_irq[i] = ((irqmask & (1u << i)) != 0); parsefile(irqflag); for (i = 0; i < bitstr_size(IOPORTS); i++) io_avail[i] &= io_kern[i]; for (i = 0; i < bitstr_size(MEMBLKS); i++) mem_avail[i] &= mem_kern[i]; for (cp = cards; cp; cp = cp->next) { if (cp->config == 0) logmsg("warning: card %s(%s) has no valid configuration\n", cp->manuf, cp->version); } (void)fclose(in); in = NULL; #if 0 { char tmp[256]; char *p; p = &tmp[0]; *p = '\0'; /* for safety */ for (i = 0; i < 16; i++) { if (pool_irq[i]) { *p++ = ' '; if (i / 10) *p++ = '0' + (i / 10); *p++ = '0' + (i % 10); *p = '\0'; } } logmsg("irq pool:%s\n", tmp); } #endif } static void parsefile(int irqflag) { int i; struct allocblk *bp; #ifdef SLOT_ALLOC_IRQ int is_slot = 0; int slot = 0; /* quick and qirty hack for slot patch by nakagawa */ for (i=0; i < MAXSLOT; i++) { int j; pool_slots[i].flag = 0; pool_slots[i].pool_ioblks = 0; pool_slots[i].pool_mem = 0; for (j=0; j < 16; j++) pool_slots[i].pool_irq[j] = 0; } #endif /* SLOT_ALLOC_IRQ */ pushc = 0; lineno = 1; for (;;) switch (keyword(next_tok())) { case KWD_EOF: /* EOF */ return; case KWD_IO: /* reserved I/O blocks */ while ((bp = ioblk_tok(0)) != 0) { if (bp->size == 0 || bp->addr == 0) { free(bp); continue; } bit_nset(io_avail, bp->addr, bp->addr + bp->size - 1); #ifndef SLOT_ALLOC_IRQ bp->next = pool_ioblks; pool_ioblks = bp; #else /* SLOT_ALLOC_IRQ */ if (is_slot) { bp->next = pool_slots[slot].pool_ioblks; pool_slots[slot].pool_ioblks = bp; } else { bp->next = pool_ioblks; pool_ioblks = bp; } #endif /* SLOT_ALLOC_IRQ */ } pusht = 1; break; case KWD_IRQ: /* reserved irqs - deprecated */ while ((i = irq_tok(0)) > 0) { #ifndef SLOT_ALLOC_IRQ if (irqflag) pool_irq[i] = 1; #else /* SLOT_ALLOC_IRQ */ if (irqflag){ if (is_slot) { pool_slots[slot].pool_irq[i] = 1; } else { pool_irq[i] = 1; } } #endif /* SLOT_ALLOC_IRQ */ } pusht = 1; break; case KWD_IGNIRQ: /* ignored irqs */ while ((i = irq_tok(0)) > 0) pool_irq[i] = 0; pusht = 1; break; case KWD_MEMORY: /* reserved memory blocks. */ while ((bp = memblk_tok(0)) != 0) { if (bp->size == 0 || bp->addr == 0) { free(bp); continue; } bit_nset(mem_avail, MEM2BIT(bp->addr), MEM2BIT(bp->addr + bp->size)); #ifndef SLOT_ALLOC_IRQ bp->next = pool_mem; pool_mem = bp; #else /* SLOT_ALLOC_IRQ */ if (is_slot) { bp->next = pool_slots[slot].pool_mem; pool_slots[slot].pool_mem = bp; } else { bp->next = pool_mem; pool_mem = bp; } #endif /* SLOT_ALLOC_IRQ */ } pusht = 1; break; case KWD_CARD: /* Card definition. */ parse_card(DT_VERS); break; case KWD_FUNCTION: /* Function definition. */ parse_card(DT_FUNC); break; #ifdef SLOT_ALLOC_IRQ case KWD_SLOT: /* Slot definition. */ is_slot = 1; slot = num_tok(); pool_slots[slot].flag = 1; break; #endif /* SLOT_ALLOC_IRQ */ default: error("Syntax error"); pusht = 0; break; } } /* * Parse a card definition. */ static void parse_card(int deftype) { char *man, *vers, *tmp; char *add_info; struct card *cp; int i; int oemid, pcmciaid; struct card_config *confp, *lastp; struct ether_mac ether_mac; struct ether *ether; struct card_io *card_io, **ci; struct card_mem *card_mem, **cm; confp = lastp = 0; cp = xmalloc(sizeof(*cp)); cp->deftype = deftype; cp->ether = 0; switch (deftype) { case DT_VERS: oemid = pcmciaid = -1; oemid = num_tok(); if (oemid != -1) { pcmciaid = num_tok(); if (pcmciaid == -1) { pusht = 1; oemid = pcmciaid = -1; } } else { pusht = 1; } man = newstr(next_tok()); vers = newstr(next_tok()); #ifdef DEBUG printf("manufucturer: \"%s\"\n", man); printf("card version: \"%s\"\n", vers); #endif add_info = newstr(next_tok()); if (keyword(add_info)) { pusht = 1; free(add_info); cp->add_info1 = NULL; cp->add_info2 = NULL; } else { #ifdef DEBUG printf("addit. info1: \"%s\"\n", add_info); #endif cp->add_info1 = add_info; add_info = newstr(next_tok()); if (keyword(add_info)) { pusht = 1; free(add_info); cp->add_info2 = NULL; } else { #ifdef DEBUG printf("addit. info2: \"%s\"\n", add_info); #endif cp->add_info2 = add_info; } } cp->oemid = oemid; cp->pcmciaid = pcmciaid; cp->manuf = man; cp->version = vers; cp->func_id = 0; break; case DT_FUNC: cp->manuf = NULL; cp->version = NULL; cp->func_id = (u_char) func_tok(); break; default: fprintf(stderr, "parse_card: unknown deftype %d\n", deftype); exit(1); } cp->reset_time = 100; #if 1 cp->next = 0; if (!last_card) cards = last_card = cp; else { last_card->next = cp; last_card = cp; } #else cp->next = cards; cards = cp; #endif for (;;) { switch (keyword(next_tok())) { case KWD_CONFIG: /* config */ i = config_tok(); if (i == -1) { error("Illegal card config index"); break; } confp = xmalloc(sizeof(*confp)); man = next_tok(); confp->driver = new_driver(man); confp->irq = irq_tok(1); confp->flags = num_tok(); if (confp->flags == -1) { pusht = 1; confp->flags = 0; } #if 0 if (confp->irq < 0 || confp->irq > 15) #else /* quick hack: irq == 16 means PIO mode (hosokawa) */ if (confp->irq < 0 || confp->irq > 16) #endif { free(confp); break; } confp->index_type = confp->index = 0; if (i < 0) /* default: -2 -> 1, auto: -3 -> 2 */ confp->index_type = (i == -2) ? 1 : 2; else 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 KWD_RESET: /* reset */ i = num_tok(); if (i == -1) { error("Illegal card reset time"); break; } cp->reset_time = i; break; case KWD_ETHER: /* ether */ #ifdef orig cp->ether = num_tok(); if (cp->ether == -1) { error("Illegal ether address offset"); cp->ether = 0; } #else ether = xmalloc(sizeof(*ether)); ether->type = ETHTYPE_GENERIC; tmp = next_tok(); if (strcmp("attr2hex", tmp) == 0 || strcmp("megahertz", tmp) == 0) ether->type = ETHTYPE_ATTR2HEX; else if (strcmp("wavelan", tmp) == 0) ether->type = ETHTYPE_WAVELAN; else { pusht = 1; ether->attr = num_tok(); if (ether->attr == -1) { error("Illegal ether address offset"); free(ether); break; } } while (ether_mac_tok(ðer_mac) == 0) { struct ether_mac *em = xmalloc(sizeof(*em)); for (i = 0; i < 3; i++) em->addr[i] = ether_mac.addr[i]; em->next = ether->ether_mac; ether->ether_mac = em; } pusht = 1; ether->next = cp->ether; cp->ether = ether; #endif break; case KWD_INSERT: /* insert */ addcmd(&cp->insert); break; case KWD_REMOVE: /* remove */ addcmd(&cp->remove); break; case KWD_CARDIO: /* cardio */ card_io = cardio_tok(); if (!card_io) { error("Illegal cardio arguments"); break; } if (!confp) { error("No valid config index for cardio"); free(card_io); break; } for (ci = &confp->card_io; *ci; ci = &((*ci)->next)) ; *ci = card_io; break; case KWD_CARDMEM: /* cardmem */ card_mem = cardmem_tok(); if (!card_mem) { error("Illegal cardmem arguments"); break; } if (!confp) { error("No valid config index for cardmem"); free(card_mem); break; } for (cm = &confp->card_mem; *cm; cm = &((*cm)->next)) ; *cm = card_mem; break; default: pusht = 1; return; } } } /* * Generate a new driver structure. If one exists, use * that one after confirming the correct class. */ static 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); } /* * Parse one I/O block. */ static 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. */ static 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 '?'. */ static int irq_tok(int force) { int i; if (strcmp("?", next_tok()) == 0 && force) return (0); pusht = 1; if (strcmp("any", next_tok()) == 0 && force) return (0); pusht = 1; if (strcmp("pio", next_tok()) == 0 && force) return (16); pusht = 1; i = num_tok(); if (i > 0 && i < 16) return (i); if (force) error("Illegal card IRQ value"); return (-1); } /* * Config index token */ static int config_tok(void) { if (strcmp("default", next_tok()) == 0) return -2; pusht = 1; if (strcmp("auto", next_tok()) == 0) return -3; pusht = 1; return num_tok(); } /* * Function ID token */ static int func_tok(void) { if (strcmp("serial", next_tok()) == 0) return 2; pusht = 1; if (strcmp("fixed_disk", next_tok()) == 0) return 4; pusht = 1; return num_tok(); } /* * Ethernet address token */ static int ether_mac_tok(struct ether_mac *ether_mac) { unsigned char *t; int i, x; static int hex[] = {1, 1, 0, 1, 1, 0, 1, 1}; t = next_tok(); if (strlen(t) != 8) return -1; for (i = 0; i < 8; i++) if (!(hex[i] ? isxdigit(t[i]) : (t[i] == ':'))) return -1; for (i = 0; i < 3; i++) { sscanf(t + i * 3, "%x", &x); ether_mac->addr[i] = x; } return 0; } /* * Cardio token * cardio {|auto} */ static struct card_io * cardio_tok(void) { struct card_io * card_io = xmalloc(sizeof(*card_io)); if (strcmp("auto", next_tok()) == 0) card_io->addr = -1; /* wildcard */ else { pusht = 1; card_io->addr = num_tok(); if (card_io->addr == -1) goto err; } card_io->size = num_tok(); if (card_io->size == -1) goto err; #ifdef DEBUG if (verbose) printf("cardio:addr=%x size=%x\n", card_io->addr, card_io->size); #endif return card_io; err: /* parse error */ free(card_io); return NULL; } /* * Cardmem token * cardmem [] */ static struct card_mem * cardmem_tok(void) { struct card_mem * card_mem = xmalloc(sizeof(*card_mem)); if ((card_mem->addr = num_tok()) == -1) goto err; if ((card_mem->cardaddr = num_tok()) == -1) goto err; if ((card_mem->size = num_tok()) == -1) goto err; /* scan mem flags; use defaults if none exist */ card_mem->flags = num_tok(); if (card_mem->flags == -1) { pusht = 1; card_mem->flags = MDF_ACTIVE | MDF_16BITS; } #ifdef DEBUG if (verbose) printf("cardmem:addr=%x cardaddr=%x size=%x\n", card_mem->addr, card_mem->cardaddr, card_mem->size); #endif return card_mem; err: /* parse error */ free(card_mem); return NULL; } /* * search the table for a match. */ static int keyword(char *str) { char **s; int i = 1; for (s = keys; *s; s++, i++) if (strcmp(*s, str) == 0) return (i); return (0); } /* * addcmd - Append the command line to the list of * commands. */ static void addcmd(struct cmd **cp) { struct cmd *ncp; char *s = getline(); if (*s) { ncp = xmalloc(sizeof(*ncp)); ncp->line = s; while (*cp) cp = &(*cp)->next; *cp = ncp; } } static int last_char; static int get(void) { 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); } static void error(char *msg) { int c; pusht = 1; logmsg("%s: %s at line %d, near %s\n", filename, msg, lineno - (last_char == '\n'), next_tok()); if (last_char != '\n') while ((c = get()) != '\n' && c != EOF) ; } /* * 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. */ static int num_tok(void) { char *s = next_tok(), c; int val = 0, base; base = 10; c = *s++; if (c == '0') { base = 8; c = *s++; if (c == '\0') return 0; else 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++) != 0); return (val); } static char *_next_tok(void); static char * next_tok(void) { char *s = _next_tok(); #if 0 printf("Tok = %s\n", s); #endif return (s); } /* * get one token. Handles string quoting etc. */ static char * _next_tok(void) { 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; } case ' ': case '\t': /* Eat whitespace unless in a string. */ if (!instr) { if (p != buf) { *p++ = 0; return (buf); } } else *p++ = c; break; case '-': case '?': case '*': /* Special characters that are tokens on their own. */ 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. */ static char * getline(void) { 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)); }