diff options
Diffstat (limited to 'contrib/syslinux-4.02/com32/modules/ethersel.c')
-rw-r--r-- | contrib/syslinux-4.02/com32/modules/ethersel.c | 210 |
1 files changed, 210 insertions, 0 deletions
diff --git a/contrib/syslinux-4.02/com32/modules/ethersel.c b/contrib/syslinux-4.02/com32/modules/ethersel.c new file mode 100644 index 0000000..f586e83 --- /dev/null +++ b/contrib/syslinux-4.02/com32/modules/ethersel.c @@ -0,0 +1,210 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2005-2008 H. Peter Anvin - All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +/* + * ethersel.c + * + * Search for an Ethernet card with a known PCI signature, and run + * the corresponding Ethernet module. + * + * To use this, set up a syslinux config file like this: + * + * PROMPT 0 + * DEFAULT ethersel.c32 + * # DEV [DID xxxx:yyyy[/mask]] [RID zz-zz] [SID uuuu:vvvv[/mask]] commandline + * # ... + * + * DID = PCI device ID + * RID = Revision ID (range) + * SID = Subsystem ID + */ + +#include <inttypes.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <console.h> +#include <sys/pci.h> +#include <com32.h> +#include <syslinux/boot.h> +#include <syslinux/config.h> + +#ifdef DEBUG +# define dprintf printf +#else +# define dprintf(...) ((void)0) +#endif + +static char *skipspace(char *p) +{ + while (*p && *p <= ' ') + p++; + + return p; +} + +#define MAX_LINE 512 + +/* Check to see if we are at a certain keyword (case insensitive) */ +static int looking_at(const char *line, const char *kwd) +{ + const char *p = line; + const char *q = kwd; + + while (*p && *q && ((*p ^ *q) & ~0x20) == 0) { + p++; + q++; + } + + if (*q) + return 0; /* Didn't see the keyword */ + + return *p <= ' '; /* Must be EOL or whitespace */ +} + +static char *get_did(char *p, uint32_t * idptr, uint32_t * maskptr) +{ + unsigned long vid, did, m1, m2; + + *idptr = -1; + *maskptr = 0xffffffff; + + vid = strtoul(p, &p, 16); + if (*p != ':') + return p; /* Bogus ID */ + did = strtoul(p + 1, &p, 16); + + *idptr = (did << 16) + vid; + + if (*p == '/') { + m1 = strtoul(p + 1, &p, 16); + if (*p != ':') { + *maskptr = (m1 << 16) | 0xffff; + } else { + m2 = strtoul(p + 1, &p, 16); + *maskptr = (m1 << 16) | m2; + } + } + + return p; +} + +static char *get_rid_range(char *p, uint8_t * rid_min, uint8_t * rid_max) +{ + unsigned long r0, r1; + + p = skipspace(p + 3); + + r0 = strtoul(p, &p, 16); + if (*p == '-') { + r1 = strtoul(p + 1, &p, 16); + } else { + r1 = r0; + } + + *rid_min = r0; + *rid_max = r1; + + return p; +} + +static struct match *parse_config(const char *filename) +{ + char line[MAX_LINE], *p; + FILE *f; + struct match *list = NULL; + struct match **ep = &list; + struct match *m; + + if (!filename) + filename = syslinux_config_file(); + + f = fopen(filename, "r"); + if (!f) + return list; + + while (fgets(line, sizeof line, f)) { + p = skipspace(line); + + if (!looking_at(p, "#")) + continue; + p = skipspace(p + 1); + + if (!looking_at(p, "dev")) + continue; + p = skipspace(p + 3); + + m = malloc(sizeof(struct match)); + if (!m) + continue; + + memset(m, 0, sizeof *m); + m->rid_max = 0xff; + + for (;;) { + p = skipspace(p); + + if (looking_at(p, "did")) { + p = get_did(p + 3, &m->did, &m->did_mask); + } else if (looking_at(p, "sid")) { + p = get_did(p + 3, &m->sid, &m->sid_mask); + } else if (looking_at(p, "rid")) { + p = get_rid_range(p + 3, &m->rid_min, &m->rid_max); + } else { + char *e; + + e = strchr(p, '\n'); + if (*e) + *e = '\0'; + e = strchr(p, '\r'); + if (*e) + *e = '\0'; + + m->filename = strdup(p); + if (!m->filename) + m->did = -1; + break; /* Done with this line */ + } + } + + dprintf("DEV DID %08x/%08x SID %08x/%08x RID %02x-%02x CMD %s\n", + m->did, m->did_mask, m->sid, m->sid_mask, + m->rid_min, m->rid_max, m->filename); + + *ep = m; + ep = &m->next; + } + + return list; +} + +int main(int argc, char *argv[]) +{ + struct match *list, *match; + struct pci_domain *pci_domain; + + openconsole(&dev_null_r, &dev_stdcon_w); + pci_domain = pci_scan(); + + if (pci_domain) { + list = parse_config(argc < 2 ? NULL : argv[1]); + + match = find_pci_device(pci_domain, list); + + if (match) + syslinux_run_command(match->filename); + } + + /* On error, return to the command line */ + fputs("Error: no recognized network card found!\n", stderr); + return 1; +} |