summaryrefslogtreecommitdiffstats
path: root/usr.sbin/pccard/pccardd/file.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/pccard/pccardd/file.c')
-rw-r--r--usr.sbin/pccard/pccardd/file.c873
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));
+}
OpenPOWER on IntegriCloud