Home | History | Annotate | Download | only in modules
      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) */
     46 static 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 
     62 static 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 
     89 static 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 
    108 static 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 
    178 int 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