1
0
Files
irix-657m-src/irix/cmd/lboot/subr.c
2022-09-29 17:59:04 +03:00

2107 lines
44 KiB
C
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* All Rights Reserved */
/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T */
/* The copyright notice above does not evidence any */
/* actual or intended publication of such source code. */
#ident "$Revision: 2.77 $"
#include <sys/types.h>
#include <a.out.h>
#define edt kernel_edt
#define vme_intrs kernel_vme_intrs
#define iospace kernel_iospace
#include <sys/edt.h>
#include <sys/vmereg.h>
#undef edt
#undef vme_intrs
#undef iospace
#include <sys/sysmacros.h>
#include <errno.h>
#include <ctype.h>
#include <sys/stat.h>
#include <sys/syssgi.h>
#include <sys/pio.h>
#include <limits.h>
#include <stdio.h>
#include <paths.h>
#include "lboot.h"
#include "boothdr.h"
extern char any_error; /* any error seen in master.d */
extern int noprobe;
/* _PATH_LS is only defined on 6.5 and beyond */
#ifdef _PATH_LS
#define __PATH_LS _PATH_LS
#else
#define __PATH_LS "/sbin/ls"
#endif
#define probe_base 3
struct t_edt {
kernptr_t t_base, t_base2, t_base3;
char *v_ifcn;
uint_t e_bustype;
uint_t e_adap;
uint_t e_ctlr;
unsigned char v_vec;
unsigned char v_ipl;
unsigned char v_unit;
struct lboot_iospace e_space[4];
int cpusyscall;
int cpuintr;
char *probe_path;
};
/*
* Static function declarations for this file
*/
static char *do_kernel(int, char **, dev_t *);
static char *do_device_admin(int,char **,dev_t *);
static char *do_driver_admin(int,char **,dev_t *);
static char *do_devicefile(int, char **, char **);
static char *do_exclude(int, char **, dev_t *);
static char *do_include(int, char **, dev_t *);
static char *do_use(int, char **, dev_t *);
static char *do_rootdevice(int, char **, dev_t *);
static char *do_dumpdevice(int, char **, dev_t *);
static char *do_swapdevice(int, char **, dev_t *);
static char *do_vector(int, char **, dev_t *);
static char *do_ccopts(int, char **, dev_t *);
static char *do_cc(int, char **, dev_t *);
static char *do_ldopts(int, char **, dev_t *);
static char *do_ld(int, char **, dev_t *);
static char *do_ipl(int, char **, dev_t *);
static char *do_nointr(int, char **, dev_t *);
static char *do_noprobe(int, char **, dev_t *);
static char *do_link(int, char **, dev_t *);
static char *do_version(int, char **, dev_t *);
static char *interpret(char *);
static boolean numeric(int *, char *);
static int parse_base(char *, struct t_edt *, int);
static void gen_entry(char *, struct t_edt *);
static int parse_system_file(char *);
void epc_module(char *, struct t_edt *);
/*
* IBUS data structure
*/
#define MAX_IBUS_ADAPS 60
int ibus_numadaps;
ibus_t ibus_adapters[MAX_IBUS_ADAPS];
/*
* Process system files. If etcsystem is a directory, then read and parse
* all files in that directory.
*/
int /* number of errors found */
parse_system(void)
{
struct stat stb;
struct dirent **systems;
char system_path[PATH_MAX];
int i, errcnt, nentries;
if (stat(etcsystem, &stb) == -1) {
error(ER7, etcsystem);
return 1;
}
if (S_ISDIR(stb.st_mode)) {
/* sort directory contents alphabetically */
if ((nentries = scandir(etcsystem, &systems, sys_select, alphasort)) < 0) {
error(ER7, etcsystem);
return 1;
}
errcnt = 0;
for (i = 0; i < nentries; i++) {
strcpy(system_path, etcsystem);
strcat(system_path, "/");
strcat(system_path, systems[i]->d_name);
errcnt += parse_system_file(system_path);
free(systems[i]);
}
free(systems);
} else
errcnt = parse_system_file(etcsystem);
return errcnt;
}
/*
* Select files that look like system files
*/
int
sys_select(struct dirent *d)
{
struct stat stb;
char system_path[PATH_MAX];
/*
* Make sure pathname doesn't get too long
* ("+2" accounts for extra "/" and NULL byte)
*/
if (strlen(etcsystem) + strlen(d->d_name) + 2 >
PATH_MAX) {
fprintf(stderr, "%s/%s: pathname too long\n",
etcsystem, d->d_name);
return 0;
}
strcpy(system_path, etcsystem);
strcat(system_path, "/");
strcat(system_path, d->d_name);
/*
* Skip subdirectories and other non-regular files.
* This is so we don't try to interpret ".", "..",
* "RCS", "SCCS", etc., as system files.
*/
if (stat(system_path, &stb) == -1) {
error(ER7, system_path);
return 0;
}
if (!S_ISREG(stb.st_mode))
return 0;
/*
* Legal system files end in ".sm", skip all others.
* This makes sure we don't try to process SCCS "s."
* files, RCS ",v" files, etc.
*/
if (!suffix(d->d_name, "sm"))
return 0;
return 1;
}
/*
* Read an individual system file, parse and extract all the necessary
* information.
*/
static int
parse_system_file(char *systemfile)
{
register FILE *stream;
char line[4096];
register char *msg;
register lineno = 1;
int error_cnt = 0;
if ((stream=fopen(systemfile,"r")) == 0) {
error(ER7, systemfile);
return 1;
}
while (fgets(line,sizeof(line),stream) != NULL) {
if (strlen(line) >= sizeof(line)-1) {
error(ER53, systemfile, lineno, "too long");
error_cnt++;
continue;
}
if (line[0] != '*'
&& !blankline(line)
&& (msg=interpret(line)) != NULL) {
error(ER53, systemfile, lineno, msg);
error_cnt++;
}
++lineno;
}
(void)fclose(stream);
return error_cnt|any_error;
}
/*
* Interpret(line)
*
* Interpret the line from the /etc/system file
*/
struct syntax {
char *keyword;
char *(*process)(int, char **, dev_t *);
dev_t *argument;
};
static struct syntax syntax[] ={
{ "KERNEL", do_kernel, 0, },
{ "DEVICE_ADMIN",do_device_admin,0},
{ "DRIVER_ADMIN",do_driver_admin,0},
{ "EXCLUDE", do_exclude, 0, },
{ "INCLUDE", do_include, 0, },
{ "USE", do_use, 0 },
{ "DUMPDEV", do_dumpdevice, 0, },
{ "ROOTDEV", do_rootdevice, 0 },
{ "SWAPDEV", do_swapdevice, 0 },
{ "VECTOR", do_vector, 0 },
{ "CCOPTS", do_ccopts, 0 },
{ "CC", do_cc, 0 },
{ "LDOPTS", do_ldopts, 0 },
{ "LD", do_ld, 0 },
{ "IPL", do_ipl, 0},
{ "NOINTR", do_nointr, 0},
{ "NOPROBE", do_noprobe, 0},
{ "VERSION", do_version, 0},
{ "LINKMODULES", do_link, 0},
{ "TUNE-TAG", do_tunetag, 0},
0
};
static char *
interpret(char *line)
{
register int argc;
char *argv[256];
register struct syntax *p;
argc = parse(argv,sizeof(argv)/sizeof(argv[0]),line);
if (argc > sizeof(argv)/sizeof(argv[0]))
return("line too long");
if (argc == 0)
return(NULL);
if (argc <= 2 || *argv[1] != ':')
return("syntax error");
for (p=syntax; p->keyword; ++p) {
if (0 == strcmp(*argv,p->keyword))
return((*(p->process))(argc-2, &argv[2], (dev_t *) p->argument));
}
return("syntax error");
}
/*
* Parse(argv, sizeof(argv), line)
*
* Parse a line from the /etc/system file; argc is returned, and argv is
* initialized with pointers to the elements of the line. The contents
* of the line are destroyed.
*/
int
parse(char **argv, unsigned sizeof_argv, char *line)
{
register char **argvp = argv;
register char **maxvp = argv + sizeof_argv;
register c;
while (c = *line) {
switch (c) {
/*
* white space
*/
case ' ':
case '\t':
case '\r':
*line++ = '\0';
line += strspn(line," \t\r");
continue;
/*
* special characters
*/
case ':':
*line = '\0';
*argvp++ = ":";
++line;
break;
case ',':
*line = '\0';
*argvp++ = ",";
++line;
break;
case '(':
*line = '\0';
*argvp++ = "(";
++line;
break;
case ')':
*line = '\0';
*argvp++ = ")";
++line;
break;
case '?':
*line = '\0';
*argvp++ = "?";
++line;
break;
case '=':
*line = '\0';
*argvp++ = "=";
++line;
break;
case '*':
*line = '\0';
*argvp++ = "*";
++line;
break;
/*
* quotes unparsed
*/
case '"':
*line ='\0';
*argvp++ = ++line;
while(*line != '"') line++;
*line = '\0';
line++;
break;
/*
* end of line
*/
case '\n':
*line = '\0';
*argvp = NULL;
return((int)(argvp - argv));
/*
* words and numbers
*/
default:
*argvp++ = line;
line += strcspn(line,":,()?= \t\r\n");
break;
}
/*
* don't overflow the argv array
*/
if (argvp >= maxvp)
return(sizeof_argv + 1);
}
*argvp = NULL;
return((int)(argvp - argv));
}
/*
* Blankline(line)
*
* Return TRUE if the line is entirely blank or null; return FALSE otherwise.
*/
boolean
blankline(char *line)
{
return(strspn(line," \t\r\n") == strlen(line));
}
/*
* Numeric(assign, string)
*
* If the string is a valid numeric string, then set *assign to its numeric
* value and return TRUE; otherwise return FALSE.
*/
static boolean
numeric(int *assign, char *string)
{
register int value;
char *next;
value = (int)strtoul(string, &next, 0);
if (*next)
/*
* bad number
*/
return(FALSE);
*assign = value;
return(TRUE);
}
/*
* Do_??????(argc, argv, optional)
*
* Handle the processing for each type of line in /etc/system
*/
/*
* KERNEL: master
*/
/* ARGSUSED */
static char *
do_kernel(int argc, char **argv, dev_t *dummyvar)
{
if (argc > 1)
return("syntax error");
if (kernel_master)
return("duplicate KERNEL specification");
kernel_master=mymalloc( strlen(*argv) + 1);
(void) strcpy(kernel_master,*argv);
if ((kernel.opthdr = mkboot(kernel_master)) == 0)
return("not a master file");
if (!(kernel.opthdr->flag & KOBJECT))
return("not a kernel master file");
return(NULL);
}
/*
* EXCLUDE: driver ...
*/
/* ARGSUSED */
static char *
do_exclude(int argc, char **argv, dev_t *dummyvar)
{
while (argc-- > 0) {
if (*argv[0] != ',')
exclude(*argv);
++argv;
}
return(NULL);
}
/*
* INCLUDE: driver(optional-number) ...
*/
/* ARGSUSED */
static char *
do_include(int argc, char **argv, dev_t *dummyvar)
{
register char *p;
int n;
register struct driver *dp;
while (argc > 0) {
if (*argv[0] == ',') {
--argc;
++argv;
continue;
}
p = *argv;
n = 1;
if (argc >= 4 && *argv[1] == '(') {
if (*argv[3] != ')')
return("syntax error");
if (! numeric(&n, argv[2]))
return("count must be numeric");
argc -= 3;
argv += 3;
}
else
if (*p == '(' || *p == ')')
return("syntax error");
dp = searchdriver(p);
if (!dp || !dp->dname) {
if (dp) {
fprintf(stderr,"Warning: no object file %s%s or %s%s for INCLUDED subsystem %s\n",
dp->mname, ".o", dp->mname, ".a", dp->mname);
error (ER2, dp->mname);
}
} else
include(p, n);
--argc;
++argv;
}
return(NULL);
}
/*
* USE: driver(optional-number) ...
* If we can find the driver, include it. Otherwise, exclude it.
*/
/* ARGSUSED */
static char *
do_use(int argc, char **argv, dev_t *dummyvar)
{
register char *p;
int n;
register struct driver *dp;
int incr = 0;
while (argc > 0) {
if (*argv[0] == ',') {
--argc;
++argv;
continue;
}
p = *argv;
n = 1;
if (argc >= 4 && *argv[1] == '(') {
if (*argv[3] != ')')
return("syntax error");
if (! numeric(&n, argv[2]))
return("count must be numeric");
argc -= 3;
argv += 3;
}
else
if (*p == '(' || *p == ')')
return("syntax error");
--argc;
++argv;
if (argc > 0 && EQUAL("exprobe", argv[0])) {
if (argc == 1 || !EQUAL("=", argv[1]))
return ("USE: exprobe: syntax error");
if (incr = exprobe_parse(argc, argv)) {
argc -= incr;
argv += incr;
} else
return ("USE: exprobe: syntax error");
}
dp = searchdriver(p);
if (!dp || !dp->dname) {
exclude(p);
} else if (incr) {
if (exprobe())
include(p, n);
} else {
include(p, n);
}
if (incr) {
free_Vtuple_list();
incr = 0;
}
}
return(NULL);
}
/*
* NOPROBE: 1|0
*/
/* ARGSUSED */
static char *
do_noprobe(int argc, char **argv, dev_t *dummyvar)
{
char *p;
if (argc != 1)
return("NOPROBE syntax error");
noprobe = (int)strtoul(*argv, &p, 0);
if (*p != '\0')
return("NOPROBE syntax error");
return(0);
}
/*
* LINKMODULES: 1|0
*/
/* ARGSUSED */
static char *
do_link(int argc, char **argv, dev_t *dummyvar)
{
char *p;
int dolink;
if (argc != 1)
return("LINKMODULES syntax error");
dolink = (int)strtoul(*argv, &p, 0);
if (*p != '\0')
return("LINKMODULES syntax error");
Dolink = dolink;
return(0);
}
/*
* IPL: level, cpu#
* build the array cpuipl[]
*/
/* ARGSUSED */
static char *
do_ipl(int argc, char **argv, dev_t *dummyvar)
{
register int cpu, ipl;
char *p;
if (argc % 2 || argc == 0)
return("IPL syntax error");
while (argc) {
ipl = (int)strtoul(*argv, &p, 0);
if (*p != '\0' || ipl >= MAXIPL)
return("IPL syntax error");
cpu = (int)strtoul(*(argv+1), &p, 0);
if (*p != '\0')
return("IPL syntax error");
argc -= 2;
argv += 2;
if (cpuipl[ipl] != (char)-1 && cpuipl[ipl] != cpu)
error(ER104, ipl);
else
cpuipl[ipl] = cpu;
}
return(0);
}
#define NOINTR_MAX 128
cpuid_t nointr_list[NOINTR_MAX];
int nointr_count = 0;
/*
* NOINTR: cpu#
* build the nointr list
*/
/* ARGSUSED */
static char *
do_nointr(int argc, char **argv, dev_t *dummyvar)
{
register cpuid_t cpu;
char *p;
if (argc == 0)
return("NOINTR syntax error");
/* TBD: Might be nice if we accepted a range of cpus... */
while (argc) {
cpu = (cpuid_t)strtoul(*argv, &p, 0);
if ((*p != '\0') || (cpu < 1) )
error(ER109, cpu);
argc -= 1;
argv += 1;
if (nointr_count >= NOINTR_MAX)
return("NOINTR too many cpus");
nointr_list[nointr_count++] = cpu;
}
return(0);
}
/*
* TUNE-TAG:
*/
/* ARGSUSED */
char *
do_tunetag(int argc, char **argv, dev_t *dummyvar)
{
if (argc < 1)
return("TUNE-TAG: tag [tag ...]");
while (argc-- && (tune_num < MAXTAGS))
tune_tag[tune_num++] = strdup(*argv++);
if (argc > 0)
return("Too many tags");
return NULL;
}
/*
* VERSION:
*/
/* ARGSUSED */
static char *
do_version(int argc, char **argv, dev_t *dummyvar)
{
char *p;
if (argc != 1)
return("VERSION: #");
if (system_version != -1)
return("more than one VERSION line");
system_version = (int)strtoul(*argv, &p, 0);
if (*p != '\0' || system_version <= 0)
return("not a valid number after VERSION:");
if (system_version > MAX_VERSION)
return(MAX_VERSION_MSG);
if (system_version < MIN_VERSION)
return(MAX_VERSION_MSG);
return(0);
}
/*
* Handle { path } syntax in ROOTDEV/SWAPDEV/DUMPDEV specs.
*/
static char *
do_devicefile(int argc, char **argv, char **devpath)
{
if (argc == 1) {
if (devpath)
*devpath = strdup(*argv);
return(NULL);
}
return ("syntax error");
}
/*
* ROOTDEV: { path }
*/
/* ARGSUSED */
static char *
do_rootdevice(int argc, char **argv, dev_t *dummyvar)
{
return (do_devicefile(argc, argv, &bootrootfile));
}
/*
* SWAPDEV: { path } swplo nswap
*/
/* ARGSUSED */
static char *
do_swapdevice(int argc, char **argv, dev_t *dummyvar)
{
register char *p;
int temp;
if (argc == 3) {
/*
* path swplo nswap
*
* swapdev = path
* swplo = number
* nswap = number
*/
if (*argv[1] == '=')
/*
* internal prompt response
*/
{
if (0 == strcmp("swapdev",argv[0]))
return(do_devicefile(1, &argv[2],
&bootswapfile));
if (0 == strcmp("swplo",argv[0])) {
if (! numeric(&temp,argv[2]))
return("must be numeric");
swplo = temp;
}
if (0 == strcmp("nswap",argv[0]))
if (! numeric(&nswap,argv[2]))
return("must be numeric");
return(NULL);
}
if ((p=do_devicefile(1,argv,&bootswapfile)) != NULL)
return(p);
--argc;
++argv;
} else
return("syntax error");
if (! numeric(&temp,argv[0]))
return("must be numeric");
swplo = temp;
if (! numeric(&nswap,argv[1]))
return("must be numeric");
return(NULL);
}
/*
* DUMPDEV: { path }
*/
/*ARGSUSED*/
static char *
do_dumpdevice(int argc, char **argv, dev_t *device)
{
return (do_devicefile(argc, argv, &bootdumpfile));
}
#define freet(t) \
if ((t).v_ifcn) free ((t).v_ifcn);
/*
* VECTOR: bustype module [intr] [ipl vector unit base] [probe [probe_size]]
*/
/* ARGSUSED */
static char *
do_vector(int argc, char **argv, dev_t *dummyvar)
{
paddr_t probe_addr = 0;
int probe_size = 4;
int probe_iospace = 0;
int unit = 0;
int fd;
char pbuf[16];
struct t_edt t_edt;
char *mod_name = 0;
int incr = 0;
int esincr = 0;
int i, adapters;
char *type;
static char errbuf[128];
bzero(&t_edt, sizeof(t_edt));
/* default to -1 */
t_edt.v_ipl = -1;
t_edt.e_adap = 0;
t_edt.cpusyscall = -1;
t_edt.cpuintr = -1;
while (argc > 0) {
if (EQUAL("bustype",argv[0])) {
if (!EQUAL("=",argv[1]) || argc < 2) {
freet(t_edt);
return("VECTOR: bustype = ???");
}
if (EQUAL("VME",argv[2]))
t_edt.e_bustype = ADAP_VME;
else if (EQUAL("GFX",argv[2]))
t_edt.e_bustype = ADAP_GFX;
else if (EQUAL("SCSI",argv[2]))
t_edt.e_bustype = ADAP_SCSI;
else if (EQUAL("LOCAL",argv[2]))
t_edt.e_bustype = ADAP_LOCAL;
else if (EQUAL("GIO",argv[2]))
t_edt.e_bustype = ADAP_GIO;
else if (EQUAL("EISA",argv[2]))
t_edt.e_bustype = ADAP_EISA;
else if (EQUAL("IBUS",argv[2]))
t_edt.e_bustype = ADAP_IBUS;
else if (EQUAL("EPC",argv[2]))
t_edt.e_bustype = ADAP_EPC;
else if (EQUAL("DANG",argv[2]))
t_edt.e_bustype = ADAP_DANG;
else if (EQUAL("PCI",argv[2]))
t_edt.e_bustype = ADAP_PCI;
else
t_edt.e_bustype = ADAP_NULL;
argc -= 3, argv += 3;
} else if (EQUAL("module",argv[0])) {
if (!EQUAL("=",argv[1]) || argc < 2) {
freet(t_edt);
return("VECTOR: module = ???");
}
mod_name=argv[2];
argc -= 3, argv += 3;
} else if (EQUAL("intr",argv[0])) {
if (!(EQUAL("=",argv[1])) || (argc < 2)) {
freet(t_edt);
return("VECTOR: intr = ???");
}
t_edt.v_ifcn=strcpy(mymalloc(strlen(argv[2])+1),argv[2]);
argc -= 3, argv += 3;
} else if (EQUAL("ipl",argv[0])) {
if (!(EQUAL("=",argv[1])) || (argc < 2)) {
freet(t_edt);
return("VECTOR: ipl = ???");
}
if( t_edt.e_bustype != ADAP_VME ) {
freet(t_edt);
return("VECTOR: VME doesn't support old style vector line");
}
t_edt.v_ipl = (unsigned char)strtoul(argv[2], 0, 0);
argc -= 3, argv += 3;
} else if (EQUAL("vector",argv[0])) {
if (!(EQUAL("=",argv[1])) || (argc < 2)) {
freet(t_edt);
return("VECTOR: vector = ???");
}
t_edt.v_vec = (unsigned char)strtoul(argv[2], 0, 0);
argc -= 3, argv += 3;
} else if (EQUAL("unit",argv[0])) {
if (!(EQUAL("=",argv[1])) || (argc < 2)) {
freet(t_edt);
return("VECTOR: unit = ???");
}
if( t_edt.e_bustype == ADAP_VME ) {
freet(t_edt);
return("VECTOR: VME doesn't support unit=");
}
unit = TRUE;
t_edt.v_unit = (unsigned char)strtoul(argv[2], 0, 0);
argc -= 3, argv += 3;
} else if (EQUAL("ctlr",argv[0])) {
if (!(EQUAL("=",argv[1])) || (argc < 2)) {
freet(t_edt);
return("VECTOR: ctlr = ???");
}
t_edt.e_ctlr = (uint_t)strtoul(argv[2], 0, 0);
argc -= 3, argv += 3;
} else if (EQUAL("adapter",argv[0])) {
if (!(EQUAL("=",argv[1])) || (argc < 2)) {
freet(t_edt);
return("VECTOR: adapter = ???");
}
if (EQUAL("*",argv[2])) {
t_edt.e_adap = (uint_t)-1;
} else
t_edt.e_adap = (uint_t)strtoul(argv[2], 0, 0);
argc -= 3, argv += 3;
} else if (EQUAL("slot", argv[0])) {
if (!(EQUAL("=",argv[1])) || (argc < 2)) {
freet(t_edt);
return("VECTOR: slot = ???");
}
if (t_edt.e_adap != 0) {
freet(t_edt);
return("VECTOR: slot: adapter already set");
}
t_edt.e_adap = (uint_t)strtoul(argv[2], 0, 0) << IBUS_SLOTSHFT;
argc -= 3; argv += 3;
} else if (EQUAL("ioa", argv[0])) {
if (!(EQUAL("=", argv[1])) || (argc < 2)) {
freet(t_edt);
return("VECTOR: ioa = ???");
}
t_edt.e_adap |= (strtoul(argv[2], 0, 0) & IBUS_IOAMASK);
argc -= 3; argv += 3;
} else if (EQUAL("base",argv[0])) {
if (!(EQUAL("=",argv[1])) || (argc < 2)) {
freet(t_edt);
return("VECTOR: base = ???");
}
t_edt.t_base = (kernptr_t)strtoull(argv[2], 0, 0);
argc -= 3, argv += 3;
} else if (EQUAL("base2",argv[0])) {
if (!(EQUAL("=",argv[1])) || (argc < 2)) {
freet(t_edt);
return("VECTOR: base2 = ???");
}
t_edt.t_base2 = (kernptr_t)strtoull(argv[2], 0, 0);
argc -= 3, argv += 3;
} else if (EQUAL("base3",argv[0])) {
if (!(EQUAL("=",argv[1])) || (argc < 2)) {
freet(t_edt);
return("VECTOR: base3 = ???");
}
t_edt.t_base3 = (kernptr_t)strtoull(argv[2], 0, 0);
argc -= 3, argv += 3;
} else if (EQUAL("iospace",argv[0])) {
if (argc >= 9 && EQUAL("=",argv[1]) &&
EQUAL("(", argv[2]) && EQUAL(")",argv[8])) {
type=strcpy(mymalloc(strlen(argv[3])+1),argv[3]);
if (parse_base(type, &t_edt, 0)) {
freet(t_edt);
sprintf(errbuf, "VECTOR: ios type= %s", type);
return errbuf;
}
t_edt.e_space[0].ios_iopaddr =
strtoul(argv[5], 0, 0);
if (*argv[7] != '*')
t_edt.e_space[0].ios_size =
strtoul(argv[7], 0, 0);
free(type);
argc -= 9, argv += 9;
} else {
freet(t_edt);
return("VECTOR: iospace = ???");
}
} else if (EQUAL("iospace2",argv[0])) {
if (argc >= 9 && EQUAL("=",argv[1]) &&
EQUAL("(", argv[2]) && EQUAL(")",argv[8])) {
type=strcpy(mymalloc(strlen(argv[3])+1),argv[3]);
if (parse_base(type, &t_edt, 1)) {
freet(t_edt);
sprintf(errbuf, "VECTOR: ios type= %s", type);
return errbuf;
}
t_edt.e_space[1].ios_iopaddr =
strtoul(argv[5], 0, 0);
if (*argv[7] != '*')
t_edt.e_space[1].ios_size =
strtoul(argv[7], 0, 0);
free(type);
argc -= 9, argv += 9;
} else {
freet(t_edt);
return("VECTOR: iospace2 = ???");
}
} else if (EQUAL("iospace3",argv[0])) {
if (argc >= 9 && EQUAL("=",argv[1]) &&
EQUAL("(", argv[2]) && EQUAL(")",argv[8])) {
type=strcpy(mymalloc(strlen(argv[3])+1),argv[3]);
if (parse_base(type, &t_edt, 2)) {
freet(t_edt);
sprintf(errbuf, "VECTOR: ios type= %s", type);
return errbuf;
}
t_edt.e_space[2].ios_iopaddr =
strtoul(argv[5], 0, 0);
if (*argv[7] != '*')
t_edt.e_space[2].ios_size =
strtoul(argv[7], 0, 0);
free(type);
argc -= 9, argv += 9;
} else {
freet(t_edt);
return("VECTOR: iospace3 = ???");
}
} else if (EQUAL("probe",argv[0])) {
if (!(EQUAL("=",argv[1])) || (argc < 2)) {
freet(t_edt);
return("VECTOR: probe = ???");
}
probe_addr = strtoul(argv[2], 0, 0);
argc -= 3, argv += 3;
} else if (EQUAL("probe_size",argv[0])) {
if (!(EQUAL("=",argv[1])) || (argc < 2)) {
freet(t_edt);
return("VECTOR: probe_size = ???");
}
probe_size = (int)strtoul(argv[2], 0, 0);
argc -= 3, argv += 3;
} else if (EQUAL("exprobe",argv[0])) {
if (!EQUAL("=",argv[1])) {
freet(t_edt);
return ("VECTOR: exprobe: syntax error");
}
if (incr = exprobe_parse(argc, argv)) {
argc -= incr;
argv += incr;
} else {
freet(t_edt);
return ("VECTOR: exprobe: syntax error");
}
} else if (EQUAL("exprobe_space",argv[0])) {
if (!EQUAL("=",argv[1])) {
freet(t_edt);
return ("VECTOR: exprobe_space: syntax error");
}
if (esincr = exprobesp_parse(argc, argv,
t_edt.e_bustype)) {
argc -= esincr;
argv += esincr;
} else {
freet(t_edt);
return ("VECTOR: exprobe_space: syntax error");
}
} else if (EQUAL("probe_space",argv[0])) {
if (argc >= 9 && EQUAL("=",argv[1]) &&
EQUAL("(", argv[2]) && EQUAL(")",argv[8])) {
type=strcpy(mymalloc(strlen(argv[3])+1),argv[3]);
if (parse_base(type, &t_edt, probe_base)) {
freet(t_edt);
sprintf(errbuf, "VECTOR: ios type= %s", type);
return errbuf;
}
t_edt.e_space[probe_base].ios_iopaddr =
strtoul(argv[5], 0, 0);
if (*argv[7] != '*')
t_edt.e_space[probe_base].ios_size =
strtoul(argv[7], 0, 0);
probe_iospace = 1;
free(type);
argc -= 9, argv += 9;
} else {
freet(t_edt);
return("VECTOR: probe_space = ???");
}
} else if (EQUAL("syscallcpu", argv[0])) {
if (argc >= 3 && EQUAL("=", argv[1])) {
char *c;
for(c = argv[2]; *c; c++)
if (!isdigit(*c))
goto syscallcpuerr;
t_edt.cpusyscall = atoi(argv[2]);
argc -= 3;
argv += 3;
}
else {
syscallcpuerr:
freet(t_edt);
return("VECTOR: syscallcpu = ???");
}
} else if (EQUAL("intrcpu", argv[0])) {
if (argc >= 3 && EQUAL("=", argv[1])) {
char *c;
for(c = argv[2]; *c; c++)
if (!isdigit(*c))
goto intrcpuerr;
t_edt.cpuintr = atoi(argv[2]);
argc -= 3;
argv += 3;
}
else {
intrcpuerr:
freet(t_edt);
return("VECTOR: intrcpu = ???");
}
} else if (EQUAL("probe_path", argv[0])) {
if (!EQUAL("=",argv[1]) || argc < 2) {
freet(t_edt);
return("VECTOR: probe_path = ???");
}
if (strlen(argv[2]) > MAXPATHLEN) {
freet(t_edt);
return("VECTOR: probe_path pathname too long.");
}
t_edt.probe_path = (char *)malloc(MAXPATHLEN);
if (t_edt.probe_path == NULL) {
freet(t_edt);
return("VECTOR:probe_path no memory left");
}
strcpy(t_edt.probe_path, argv[2]);
argc -= 3, argv += 3;
} else {
freet(t_edt);
sprintf(errbuf, "VECTOR: unknown specifier %s", argv[0]);
return errbuf;
}
}
if (!mod_name)
return("VECTOR: missing module name");
if ((t_edt.v_vec) && (t_edt.e_adap == (uint_t)-1))
return("VECTOR: vector is hardwired, but adapter is unknow???");
/* If the probe path is specified, check to see if it exists
* in the system. If not, don't configure. */
if (t_edt.probe_path != NULL) {
char command[MAXPATHLEN + 40]; /* 40 is sort of random */
sprintf(command, "%s -d %s > /dev/null 2> /dev/null",
__PATH_LS, t_edt.probe_path);
if (!system(command))
gen_entry(mod_name, &t_edt);
else
return NULL;
}
/*
* For wildcards other than DANG chips, we will iterate over
* all possible adapters here.
*/
if (t_edt.e_adap == (uint_t)-1 && t_edt.e_bustype != ADAP_DANG) {
i = 0;
adapters = (int)syssgi(SGI_CONFIG, ADAP_READ, t_edt.e_bustype);
}
else {
i = t_edt.e_adap;
adapters = i+1;
}
for ( ; i < adapters; i++ ) {
t_edt.e_adap = i;
/* XXX syssgi() should be modify to give the number of
* DANG chips, and edt_init() in kern/os/main.c
* should be changed to get the number of DANG chips
* from readadapters(), and then here and above should
* generate separate EDT entries for each DANG chip.
*
* Until then, let the drivers to all of the work of
* scanning for their boards.
*/
if (t_edt.e_bustype == ADAP_DANG && i == -1)
t_edt.e_adap = 0;
/* perform old style probe */
if (probe_addr) {
fd = open("/dev/kmem", O_RDONLY);
if (fd < 0)
error(ER2, "/dev/kmem");
if (0 > lseek(fd, (off_t)probe_addr & LBOOT_LSEEK_MASK, 0))
error(ER2, "/dev/kmem");
if (probe_size != read(fd, pbuf, probe_size)) {
if (Verbose)
printf("%s, unit %d probe failed\n",
mod_name,
((unit == 0) ? t_edt.e_ctlr:t_edt.v_unit));
(void)close(fd);
freet(t_edt);
/*
* stub-out missing hardware
*/
(void)searchdriver(mod_name);
continue;
}
if (Verbose)
printf("probed %s unit %d\n", mod_name,
((unit == 0) ? t_edt.e_ctlr:t_edt.v_unit));
(void)close(fd);
}
/* perform new style probe space */
if ((noprobe == 0) && (probe_iospace == 1) ) {
if (syssgi(SGI_IOPROBE, t_edt.e_bustype, i,
&t_edt.e_space[probe_base], IOPROBE_READ, 0)) {
if (Verbose)
printf("%s, adapter %d probe space failed\n",
mod_name, i);
/*
* stub-out missing hardware
*/
(void)searchdriver(mod_name);
continue;
} else {
if (Verbose)
printf("probe spaced %s adapter %d\n",
mod_name, i);
}
}
/* perform old sytle extended probe */
if (incr) {
if (!exprobe()) {
if (Verbose)
printf("%s, unit %d exprobe failed\n",
mod_name,
((unit == 0)
? t_edt.e_ctlr
: t_edt.v_unit));
freet(t_edt);
/*
* stub-out missing hardware
*/
(void)searchdriver(mod_name);
continue;
}
if (Verbose)
printf("exprobed %s unit %d\n", mod_name,
((unit == 0)
? t_edt.e_ctlr
: t_edt.v_unit));
}
/* perform new style extended probe */
if ((noprobe == 0) && esincr) {
if( !exprobesp(i,t_edt.e_bustype) ) {
if (Verbose)
printf("%s, adapter %d exprobe space failed\n",
mod_name, i);
/*
* stub-out missing hardware
*/
(void)searchdriver(mod_name);
continue;
}
if (Verbose)
printf("exprobe spaced %s adapter %d\n",
mod_name, i);
}
if (t_edt.e_bustype == ADAP_EPC)
epc_module(mod_name, &t_edt);
else
gen_entry(mod_name, &t_edt);
}
/* free up extended probe lists */
if (incr)
free_Vtuple_list();
if (esincr)
free_Ntuple_list();
return(NULL);
}
static void
gen_entry(char *mod_name, struct t_edt *t_edt)
{
struct driver *dp = 0;
struct master *mp;
struct lboot_vme_intrs *vp;
struct lboot_edt *ep;
int i;
int maxnctl;
int adap;
dp = searchdriver(mod_name);
if (!dp || !dp->dname) {
if (t_edt->v_ifcn)
free (t_edt->v_ifcn);
if (Verbose)
printf("Driver not found for %s device\n", mod_name);
return;
}
mp = dp->opthdr;
dp->flag |= INEDT;
/*
* Enforce some slightly obscure semantics regarding nctl: the
* number of controllers should never be less than the maximum
* unit number probed (plus 1). Then, drivers can use the ##C
* hook, without fear of a unit #1 with no unit #0.
*/
if (noprobe == 0) {
adap = (int)syssgi(SGI_CONFIG, ADAP_READ, t_edt->e_bustype);
if (t_edt->e_adap == -1)
maxnctl = max(t_edt->e_ctlr * adap + t_edt->e_adap + 1,
t_edt->v_unit + 1);
else
maxnctl = max(t_edt->e_ctlr + 1, t_edt->v_unit + 1);
dp->nctl = max(dp->nctl, maxnctl);
} else {
maxnctl = max(t_edt->e_ctlr + 1, t_edt->v_unit+1);
dp->nctl = max(dp->nctl+1, maxnctl);
}
/*
* see if there is edt structure existant to which to attach this
*/
for (ep=dp->edtp; ep; ep=ep->e_next) {
if (t_edt->t_base == ep->e_space[0].ios_vaddr
&& t_edt->t_base2 == ep->e_space[1].ios_vaddr
&& t_edt->t_base3 == ep->e_space[2].ios_vaddr
&& t_edt->e_ctlr == ep->e_ctlr
&& t_edt->e_adap == ep->e_adap)
break;
}
if (!ep) {
ep = (struct lboot_edt *)mycalloc(sizeof(struct lboot_edt),1);
ep->e_next = dp->edtp;
dp->edtp = ep;
ep->e_bus_type = t_edt->e_bustype;
ep->e_adap = t_edt->e_adap;
ep->e_ctlr = t_edt->e_ctlr;
for (i=0; i < NBASE; i++)
ep->e_space[i] = t_edt->e_space[i];
if (t_edt->t_base)
ep->e_space[0].ios_vaddr = t_edt->t_base;
if (t_edt->t_base2)
ep->e_space[1].ios_vaddr = t_edt->t_base2;
if (t_edt->t_base3)
ep->e_space[2].ios_vaddr = t_edt->t_base3;
vp = (struct lboot_vme_intrs *)ep;
if (t_edt->cpusyscall >= 0) {
ep->v_cpusyscall = t_edt->cpusyscall;
ep->v_setcpusyscall = 1;
}
else
ep->v_setcpusyscall = 0;
if (t_edt->cpuintr >= 0) {
ep->v_cpuintr = t_edt->cpuintr;
ep->v_setcpuintr = 1;
}
else
ep->v_setcpuintr = 0;
} else {
for (vp=(struct lboot_vme_intrs *)ep; vp->v_next; vp=vp->v_next)
continue;
}
/*
* funny case -- an edt without a interrupt routine
* we build the edt with a null vme_intrs pointer
*/
if (!t_edt->v_vec && (t_edt->v_ipl == (uchar_t)-1))
return;
vp->v_next = (struct lboot_vme_intrs *)mycalloc(sizeof(struct lboot_vme_intrs),1);
vp = vp->v_next;
if (t_edt->v_ifcn) {
vp->v_vname = t_edt->v_ifcn;
} else {
/*
* use prefix|"intr" if interrupt function not specified
* use tag|"intr" if interrupt function not specified ???
*/
vp->v_vname = concat(mp->prefix, "intr");
}
vp->v_vec = t_edt->v_vec;
vp->v_brl = t_edt->v_ipl;
vp->v_unit = t_edt->v_unit;
return;
}
struct {
char *mod_name;
int mod_num;
} mod_names[] = {
{ "epcserial", EPC_SERIAL },
{ "epcether", EPC_ETHER },
{ "", 0 }
};
void
epc_module(char *module, struct t_edt *t_edt)
{
ibus_t *ib = &ibus_adapters[ibus_numadaps++];
int i;
for (i = 0; mod_names[i].mod_num != 0; i++) {
if (strcasecmp(mod_names[i].mod_name, module) == 0)
break;
}
if (mod_names[i].mod_num == 0) {
printf("Error: Invalid EPC module name: '%s'\n",
module);
myexit(1);
}
ib->ibus_module = mod_names[i].mod_num;
ib->ibus_unit = t_edt->v_unit;
ib->ibus_adap = t_edt->e_adap;
ib->ibus_ctlr = t_edt->e_ctlr;
ib->ibus_proc = -1;
}
int
get_base(int bustype, char *type)
{
switch (bustype) {
case ADAP_VME:
if (EQUAL("A16NP",type))
return PIOMAP_A16N;
else if (EQUAL("A16S",type))
return PIOMAP_A16S;
else if (EQUAL("A24NP",type))
return PIOMAP_A24N;
else if (EQUAL("A24S",type))
return PIOMAP_A24S;
else if (EQUAL("A32NP",type))
return PIOMAP_A32N;
else if (EQUAL("A32S",type))
return PIOMAP_A32S;
else if (EQUAL("A64",type))
return PIOMAP_A64;
else
return(-1);
case ADAP_EISA:
if (EQUAL("EISAIO",type))
return PIOMAP_EISA_IO;
else if (EQUAL("EISAMEM",type))
return PIOMAP_EISA_MEM;
else
return -1;
case ADAP_LOCAL:
if (EQUAL("LANRAM",type))
return LAN_RAM;
else if (EQUAL("LANIO",type))
return LAN_IO;
else if (EQUAL("ETMEM",type))
return ET_MEM;
else if (EQUAL("ETIO",type))
return ET_IO;
else
return(-1);
case ADAP_IBUS:
if (EQUAL("FCI",type))
return PIOMAP_FCI;
else
return(-1);
case ADAP_DANG:
if (EQUAL("DANG",type))
return PIOMAP_FCI;
else
return(-1);
case ADAP_PCI:
if (EQUAL("PCIID",type))
return PIOMAP_PCI_ID;
else
return(-1);
}
return -1;
}
static int
parse_base(char *type, struct t_edt *t_edt, int nbase)
{
int val;
val = get_base(t_edt->e_bustype,type);
if( val == -1 )
return -1;
t_edt->e_space[nbase].ios_type = val;
return(0);
}
/*
* recombine parts of "parsed" string
*/
static char *
unparse(int argc, char **argv)
{
char *s;
s = 0;
while (argc--) {
s = concat_free(s, argv[0]);
/* combine isolated '=' and ',' with neighbors */
while (argc && (argv[1][0] == '=' || argv[1][0] == ',' ||
argv[1][0] == ':')) {
argv++; argc--;
s = concat_free(s, argv[0]);
if (argc) {
argv++; argc--;
s = concat_free(s, argv[0]);
}
}
argv++;
s = concat_free(s, " ");
}
return s;
}
/*
* recombine parts of "parsed" command, and add toolpath to the right part
* If we see TOOLROOT=xxx before the command, then do not fiddle with
* the command. Otherwise, add toolpath when we first see the command.
*/
static char *
unparse_cmd(int argc, char **argv, char *cmd)
{
char *s;
int clen, l;
clen = (int)strlen(cmd);
s = 0;
while (argc--) {
if (0 != cmd
&& (l = (int)strlen(argv[0])-clen) >= 0
&& !strcmp(cmd,argv[0]+l)) {
cmd = concat(toolpath,argv[0]);
s = concat_free(s, cmd);
cmd = 0;
} else {
s = concat_free(s, argv[0]);
}
/* combine isolated '=' and ',' with neighbors */
if (argc
&& (argv[1][0] == '=' || argv[1][0] == ',')) {
if (0 != cmd
&& !strcmp("TOOLROOT",argv[0])
&& argv[1][0] == '=')
cmd = 0;
argv++; argc--;
s = concat_free(s, argv[0]);
if (argc) {
argv++; argc--;
s = concat_free(s, argv[0]);
}
}
argv++;
s = concat_free(s, " ");
}
return s;
}
/*
* CC: strings...
*/
/* ARGSUSED */
static char *
do_cc(int argc, char **argv, dev_t *dummyvar)
{
if (cc)
return("CC already specified");
cc = unparse_cmd(argc, argv, "cc");
return(0);
}
/*
* CCOPTS: strings...
*
* ``deparse'' CCOPTS string into ccopts[]
*/
/* ARGSUSED */
static char *
do_ccopts(int argc, char **argv, dev_t *dummyvar)
{
if (ccopts)
return("CCOPTS already specified");
ccopts = unparse(argc,argv);
return(NULL);
}
/*
* LD: strings...
*/
/* ARGSUSED */
static char *
do_ld(int argc, char **argv, dev_t *dummyvar)
{
if (ld)
return("LD already specified");
ld = unparse_cmd(argc, argv, "ld");
return(0);
}
/*
* LDOPTS: strings...
*
* ``deparse'' LDOPTS string into ldopts[]
*/
/* ARGSUSED */
static char *
do_ldopts(int argc, char **argv, dev_t *dummyvar)
{
if (ldopts)
return("LDOPTS already specified");
while (argc--) {
if (EQUAL(argv[0],"-o") && argc>0) {
ldopts = concat_free(ldopts, argv[0]);
ldopts = concat_free(ldopts, " ");
argv++;
argc--;
if (argv[0][0] != '/') {
ldopts = concat_free(ldopts, cwd_slash);
}
}
ldopts = concat_free(ldopts, argv[0]);
while (argc && argv[1][0] == ',') {
argv++, argc--;
ldopts = concat_free(ldopts, argv[0]);
if (argc) {
argv++; argc--;
ldopts = concat_free(ldopts, argv[0]);
}
}
ldopts = concat_free(ldopts, " ");
argv++;
}
return(NULL);
}
/*
* Read with error checking; if an I/O error occurs, quit.
*/
void
read_and_check(int fildes, char *fname, char *buf, unsigned nbyte)
{
register ssize_t rbyte;
if ((rbyte = read(fildes,buf,nbyte)) < 0)
error(ER2, fname);
if (rbyte != nbyte)
error(ER2, fname);
}
/*
* Function(prefix, name, symbol)
*
* Test whether the symbol is prefix-name
*/
boolean
function(char *prefix, char *name, char *symbol)
{
register size_t len = strlen(prefix);
return(0 == strncmp(prefix,symbol,len) &&
0 == strcmp(name,&symbol[len]));
}
/*
* Suffix (string, suffix)
* Given "string" and 'suffix', suffix()
* returns true if "string" ends with .suffix
*/
int
suffix(char *string, char *suf)
{
char *dotpos;
if ((dotpos = strrchr(string, '.')) == NULL)
return(0);
if (EQUAL(++dotpos, suf))
return(1);
return(0);
}
/*
**
** Figure out which processor this driver should be locked into
** default is 0, if no info was given
**
** if the driver has an edt structure with an ipl level, then the cpu to
** lock this driver on is given from the array cpuipl[]
**
** Error checking
** 1. if one edt entry that wish to send intr to a particular cpu then
** for a processor locked driver, the driver has to be locked on to
** that cpu and all other edt entries of this driver
** must also send their intr to that cpu regardless of their IRQ level
**
** 2. if there are two edt entries of the same IRQ with conflicting intr
** destinations then the error is unrecoverable. The user has to reconfig
** the system file.
**
** 3. One driver can have multiple edt entries, each might be configured
** for a diffrent ipl levels, ea ipl level can be locked on a different cpu
**
** This check is done by intrlock_sanity_check() later across all drivers
** after lock_on_cpu() was done on all processor locked drivers
*/
int
lock_on_cpu(struct master *mp, struct driver *dp)
{
struct lboot_edt *edtp; /* pointer to edt structure */
char cpu = -1;
int ipl;
struct lboot_vme_intrs *intrs;
if (dp->flag & INEDT) {
/*
** if driver has edt structure with a valid ipl level
** select the edt entry with a valid ipl and set v_cpuintr
** based on the cpuipl[] array
*/
for (edtp = dp->edtp; edtp; edtp = edtp->e_next) {
intrs = edtp->v_next;
if (!intrs || intrs->v_brl == (unsigned char)-1)
continue;
ipl = intrs->v_brl;
cpu = cpuipl[ipl];
/* if was not specified then default to 0 */
if (cpu == (char)-1) {
cpuipl[ipl] = 0;
cpu = 0;
}
edtp->v_cpuintr = cpu;
edtp->v_setcpuintr = 1;
}
}
/*
** by now all the edt entries of the driver are set up with
** the given info from the system file
** lets do some error checking
*/
if (mp->sema == S_PROC) {
/*
** if driver is of processor locking type, then
** all edt entries's ipl levels must be locked to the same
** cpu.
*/
/* use earlier result if there is any */
if (cpu == (char)-1)
cpu = 0;
/* if driver has no edt list then done */
if (!(dp->flag & INEDT))
goto lock_done;
/* now go thru. the edt list of the driver again and make sure
** that all edt's ipl levels are locked to the same cpu
*/
for (edtp = dp->edtp; edtp; edtp = edtp->e_next) {
intrs = edtp->v_next;
if (!intrs || intrs->v_brl == (unsigned char)-1)
continue;
if (edtp->v_cpuintr != cpu) {
error(ER106,
dp->mname,intrs->v_brl,edtp->v_cpuintr);
}
}
goto lock_done;
}
/* regular driver just return -1 */
cpu = -1;
lock_done:
return(cpu);
}
/*
** If there are two edt entries of the same IRQ with conflicting intr
** destinations then the error is unrecoverable. The user has to reconfig
** the system file.
*/
void
intrlock_sanity_check(void)
{
struct driver *dp;
struct lboot_edt *ep;
struct dcpu {
char cpu;
char *mname;
} cpu_of_irq[MAXIPL], *cpuirq;
int iplcount = 0;
int i;
struct lboot_vme_intrs *intrs;
/* IRQ start from 0*/
for (i=0; i<MAXIPL; i++) {
cpu_of_irq[i].cpu = -1;
cpu_of_irq[i].mname = 0;
}
/*
** go thru all driver, for ea IRQ level look for first edt entry
** with matching IRQ and v_setcpuintr set
*/
for (dp = driver; dp; dp = dp->next) {
for (ep = dp->edtp; ep; ep = ep->e_next) {
intrs = ep->v_next;
if (intrs && (intrs->v_brl != (unsigned char)-1) &&
ep->v_setcpuintr &&
cpu_of_irq[intrs->v_brl].cpu == (char)-1) {
cpuirq = &cpu_of_irq[intrs->v_brl];
cpuirq->cpu = ep->v_cpuintr;
cpuirq->mname = dp->mname;
iplcount++;
if (iplcount == MAXIPL)
break;
}
}
if (iplcount == MAXIPL)
break;
}
/* now go thru all driver, check out every edt entries to make sure
** that no edt entries with the same IRQ can have different intr
** destinations.
*/
for (dp = driver; dp; dp = dp->next) {
for (ep = dp->edtp; ep; ep = ep->e_next) {
intrs = ep->v_next;
if (!intrs || intrs->v_brl == (unsigned char)-1)
continue;
/* is this edt's intr IRQ locked to a particular cpu */
if (cpu_of_irq[intrs->v_brl].cpu != (char)-1) {
/* can this edt intr destination still
** be moved around?
*/
cpuirq = &cpu_of_irq[intrs->v_brl];
if (!ep->v_setcpuintr) {
ep->v_cpuintr = cpuirq->cpu;
ep->v_setcpuintr = 1;
}
else if (ep->v_cpuintr != cpuirq->cpu) {
if (!strcmp(dp->mname,cpuirq->mname))
error(ER102, dp->mname, ep->v_cpuintr);
else
error(ER103, intrs->v_brl,dp->mname,ep->v_cpuintr,cpuirq->mname,cpuirq->cpu);
}
}
}
}
}
static int dev_first_call = 1;
static int drv_first_call = 1;
/*
* Called at exit to get rid of the device admin .c file.
*/
void
cleanup_dev_admin(void)
{
char cmd[1024];
sprintf(cmd, "rm -f %s\n", tmp_dev_admin_dot_c);
system(cmd);
}
/*
* Called at exit to get rid of the driver admin .c file.
*/
void
cleanup_drv_admin(void)
{
char cmd[1024];
sprintf(cmd, "rm -f %s\n", tmp_drv_admin_dot_c);
system(cmd);
}
/*
* create the device administration info table in master.c
* this function processes a single device / driver administration
* directive in the system.gen file. basically it parses the various
* fields in the directive and builds the equivalent entries in the
* static device administration info table.
*/
char *
do_device_admin(int argc,char **argv,dev_t *devp)
{
char **p = argv;
char *name;
FILE *fp;
devp = devp; /* satisfy the compiler */
/* make sure that we have atleast 3 arguments corr. to
* <parameter-name> = <parameter-value>
*/
if (argc < 3)
return NULL;
if (dev_first_call) {
dev_first_call = 0;
if ((fp=fopen(tmp_dev_admin_dot_c,"w")) == NULL) {
fprintf(stderr, "lboot: unable to create %s.\n",
tmp_dev_admin_dot_c);
exit (1);
}
/* Make sure the file gets removed. */
atexit(cleanup_dev_admin);
generate_dev_admin_table_head(fp);
generate_dev_admin_table_tail(fp);
} else {
if ((fp = fopen(tmp_dev_admin_dot_c,"r+")) == NULL)
return NULL;
fseek64(fp,0,SEEK_END); /* skip over all the previous
* material in temporary dev_admin.c
* file
*/
}
if (*p)
name = *p;
/* skip over the device / driver name */
p++;
argc--;
fseek64(fp,-(long)DAT_DEV_TAILLEN,SEEK_END);
/* for each <parameter> = < value> sequence iterate */
while (argc) {
p = device_admin(name,p,&argc,fp);
}
generate_dev_admin_table_tail(fp);
fflush(fp);
fclose(fp);
return NULL;
}
/*
* create the driver administration info table in master.c
* this function processes a single device / driver administration
* directive in the system.gen file. basically it parses the various
* fields in the directive and builds the equivalent entries in the
* static driver administration info table.
*/
char *
do_driver_admin(int argc,char **argv,dev_t *devp)
{
char **p = argv;
char *name;
FILE *fp;
devp = devp; /* satisfy the compiler */
/* make sure that we have atleast 3 arguments corr. to
* <parameter-name> = <parameter-value>
*/
if (argc < 3)
return NULL;
if (drv_first_call) {
drv_first_call = 0;
if ((fp=fopen(tmp_drv_admin_dot_c,"w")) == NULL) {
fprintf(stderr, "lboot: unable to create %s.\n",
tmp_drv_admin_dot_c);
exit (1);
}
/* Make sure the file gets removed. */
atexit(cleanup_drv_admin);
generate_drv_admin_table_head(fp);
generate_drv_admin_table_tail(fp);
} else {
if ((fp = fopen(tmp_drv_admin_dot_c,"r+")) == NULL)
return NULL;
fseek64(fp,0,SEEK_END); /* skip over all the previous
* material in temporary drv_admin.c
* file
*/
}
if (*p)
name = *p;
/* skip over the device / driver name */
p++;
argc--;
fseek64(fp,-(long)DAT_DRV_TAILLEN,SEEK_END);
/* for each <parameter> = < value> sequence iterate */
while (argc) {
p = device_admin(name,p,&argc,fp);
}
generate_drv_admin_table_tail(fp);
fflush(fp);
fclose(fp);
return NULL;
}