/* ----------------------------------------------------------------------- * * * 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 #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_device_list pci_device_list; struct pci_bus_list pci_bus_list; openconsole(&dev_null_r, &dev_stdcon_w); pci_scan(&pci_bus_list,&pci_device_list); list = parse_config(argc < 2 ? NULL : argv[1]); match = find_pci_device(&pci_device_list,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; }