1/* ----------------------------------------------------------------------- * 2 * 3 * Copyright 2005-2008 H. Peter Anvin - All Rights Reserved 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation, Inc., 53 Temple Place Ste 330, 8 * Boston MA 02111-1307, USA; either version 2 of the License, or 9 * (at your option) any later version; incorporated herein by reference. 10 * 11 * ----------------------------------------------------------------------- */ 12 13/* 14 * ethersel.c 15 * 16 * Search for an Ethernet card with a known PCI signature, and run 17 * the corresponding Ethernet module. 18 * 19 * To use this, set up a syslinux config file like this: 20 * 21 * PROMPT 0 22 * DEFAULT ethersel.c32 23 * # DEV [DID xxxx:yyyy[/mask]] [RID zz-zz] [SID uuuu:vvvv[/mask]] commandline 24 * # ... 25 * 26 * DID = PCI device ID 27 * RID = Revision ID (range) 28 * SID = Subsystem ID 29 */ 30 31#include <inttypes.h> 32#include <stdio.h> 33#include <ctype.h> 34#include <stdlib.h> 35#include <string.h> 36#include <console.h> 37#include <sys/pci.h> 38#include <com32.h> 39#include <syslinux/boot.h> 40#include <syslinux/config.h> 41#include <dprintf.h> 42 43#define MAX_LINE 512 44 45/* Check to see if we are at a certain keyword (case insensitive) */ 46static int looking_at(const char *line, const char *kwd) 47{ 48 const char *p = line; 49 const char *q = kwd; 50 51 while (*p && *q && ((*p ^ *q) & ~0x20) == 0) { 52 p++; 53 q++; 54 } 55 56 if (*q) 57 return 0; /* Didn't see the keyword */ 58 59 return *p <= ' '; /* Must be EOL or whitespace */ 60} 61 62static char *get_did(char *p, uint32_t * idptr, uint32_t * maskptr) 63{ 64 unsigned long vid, did, m1, m2; 65 66 *idptr = -1; 67 *maskptr = 0xffffffff; 68 69 vid = strtoul(p, &p, 16); 70 if (*p != ':') 71 return p; /* Bogus ID */ 72 did = strtoul(p + 1, &p, 16); 73 74 *idptr = (did << 16) + vid; 75 76 if (*p == '/') { 77 m1 = strtoul(p + 1, &p, 16); 78 if (*p != ':') { 79 *maskptr = (m1 << 16) | 0xffff; 80 } else { 81 m2 = strtoul(p + 1, &p, 16); 82 *maskptr = (m1 << 16) | m2; 83 } 84 } 85 86 return p; 87} 88 89static char *get_rid_range(char *p, uint8_t * rid_min, uint8_t * rid_max) 90{ 91 unsigned long r0, r1; 92 93 p = skipspace(p + 3); 94 95 r0 = strtoul(p, &p, 16); 96 if (*p == '-') { 97 r1 = strtoul(p + 1, &p, 16); 98 } else { 99 r1 = r0; 100 } 101 102 *rid_min = r0; 103 *rid_max = r1; 104 105 return p; 106} 107 108static struct match *parse_config(const char *filename) 109{ 110 char line[MAX_LINE], *p; 111 FILE *f; 112 struct match *list = NULL; 113 struct match **ep = &list; 114 struct match *m; 115 116 if (!filename) 117 filename = syslinux_config_file(); 118 119 f = fopen(filename, "r"); 120 if (!f) 121 return list; 122 123 while (fgets(line, sizeof line, f)) { 124 p = skipspace(line); 125 126 if (!looking_at(p, "#")) 127 continue; 128 p = skipspace(p + 1); 129 130 if (!looking_at(p, "dev")) 131 continue; 132 p = skipspace(p + 3); 133 134 m = malloc(sizeof(struct match)); 135 if (!m) 136 continue; 137 138 memset(m, 0, sizeof *m); 139 m->rid_max = 0xff; 140 141 for (;;) { 142 p = skipspace(p); 143 144 if (looking_at(p, "did")) { 145 p = get_did(p + 3, &m->did, &m->did_mask); 146 } else if (looking_at(p, "sid")) { 147 p = get_did(p + 3, &m->sid, &m->sid_mask); 148 } else if (looking_at(p, "rid")) { 149 p = get_rid_range(p + 3, &m->rid_min, &m->rid_max); 150 } else { 151 char *e; 152 153 e = strchr(p, '\n'); 154 if (*e) 155 *e = '\0'; 156 e = strchr(p, '\r'); 157 if (*e) 158 *e = '\0'; 159 160 m->filename = strdup(p); 161 if (!m->filename) 162 m->did = -1; 163 break; /* Done with this line */ 164 } 165 } 166 167 dprintf("DEV DID %08x/%08x SID %08x/%08x RID %02x-%02x CMD %s\n", 168 m->did, m->did_mask, m->sid, m->sid_mask, 169 m->rid_min, m->rid_max, m->filename); 170 171 *ep = m; 172 ep = &m->next; 173 } 174 175 return list; 176} 177 178int main(int argc, char *argv[]) 179{ 180 struct match *list, *match; 181 struct pci_domain *pci_domain; 182 183 pci_domain = pci_scan(); 184 185 if (pci_domain) { 186 list = parse_config(argc < 2 ? NULL : argv[1]); 187 188 match = find_pci_device(pci_domain, list); 189 190 if (match) 191 syslinux_run_command(match->filename); 192 } 193 194 /* On error, return to the command line */ 195 fputs("Error: no recognized network card found!\n", stderr); 196 return 1; 197} 198