/* ----------------------------------------------------------------------- * * * 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 #include #include #include #include #include #include #include #include #include #ifdef DEBUG # define dprintf printf #else # define dprintf(...) ((void)0) #endif #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; }