static char SCCS_ID [] = "@(#)mkconf.c 2.30"; /* * Perkin-Elmer UNIX Configuration Utility * * * (C) 1980, Richard Miller * University of Wollongong * * There is code here to make a shell file to do the mknods * required for the devices, but it is not fully implemented, * and for that matter, it would be rather hard to handle all * the cases well. -- D Yost 11/22/81 */ #include "../h/local.h" #include "../h/dios.h" #include #include /* * Table describing device characteristics */ #define CDEV 01 /* is a character device */ #define BDEV 02 /* is a block device */ #define B_AND_CDEV (BDEV|CDEV) #define DEVAD 04 /* device addresses required */ #define CNTLAD 010 /* controller address required */ #define SELCHAD 020 /* selector channel address required */ #define SIZE 040 /* size specification required */ #define MAP 0100 /* logical device map required */ #define SPEEDS 0200 /* baud rate table required */ #define CONSDEV 0400 /* can be console device */ #define FSDEV 01000 /* can be file system device */ #define DREQ 02000 /* must be defined -- see struct req below */ #define DIOSAD 04000 /* DIOS addresses optional - 0 if not used */ #define TYPE 010000 /* type specification required */ #define LAYOUT 020000 /* layout specification required */ #define NAME 040000 /* name specification required */ #define PICT 0100000 /* picture specification required */ #define NMAP 8 /* max number of maps if DMAP */ /* There are two classes of required devices: * 1. Devices that appear in a list in the reqdev structure. * 2. A device that is required for some special device, such as swap, * in which case its DREQ flag is set by the occurence of the * special device. */ struct reqdev { char *rq_names; /* names of devices in this class */ int rq_def; /* 1 if any were defined */ }; struct reqdev reqdev[] = { { "msm d40 dsk" } , { "vdu" } , { "clock" } , { 0 } }; #define RQ_DISK 0 #define RQ_TTY 1 #define RQ_CLOCK 2 char null[] = "nulldev"; /* name of no-op fill-in routine */ char no[] = "nodev"; /* name of error fill-in routine */ char zero[] = "0"; /* null fill-in entry */ int zeromap[16] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; struct keyparm *findkey(); struct devconf { /* Static data */ char *d_name; /* external name */ int d_flags; /* device attributes - see #defines above */ int d_maxdev; /* maximum number of devices permitted (or 0 for no limit) */ int d_nccb; /* number of channel control blocks per dev */ char *d_bsw[6]; /* names of routines for bdevsw (if block device) */ char *d_csw[7]; /* names of routines for cdevsw (if character device) */ char *d_int[2]; /* names of interrupt handlers for even & odd address (character device), or for device & controller (block device) */ struct reqdev *d_req; /* required device class, if any */ /* be sure dev name occurs in reqdev list */ /* Input data */ #ifdef MAKEDEV char *d_devname; /* name in /dev */ #endif MAKEDEV char *d_reqby; /* if DREQ, what special device requires it */ int d_major; /* major device number (if both BDEV and CDEV, this is block device number) */ int d_defined; /* d_flags bits which have been defined */ int d_ndev; /* number of devices to be configured */ int *d_dev; /* list of device addresses */ int *d_cntl; /* array controller addresses */ union { /* channel address(es) */ int *d_selch; /* array of selch address */ int *d_dios; /* array of dios addresses */ } d_channel; union { int d_size; /* capacity for disks (ordinal ) */ int *d_type; /* array of disc types */ } d_disc; int *d_map; /* logical device map index for disks */ } devconf[] = { /*** The order is important here. /*** Change it, and you will have to /*** redo the nodes in /dev /*** because the major device numbers will be off /***/ /* Comms Mux, PALS or PASLA */ { "vdu", CDEV+DEVAD+DIOSAD+SPEEDS+CONSDEV, MAXVDU, 1, { 0 } , { "vduopen", "vduclose", "vduread", "vduwrite", "vduioctl", "vdustop", "vdu" } , { "vdurint", "vduxint" } , &reqdev[RQ_TTY] /* vdu must also be in this list */ } , /* Memory pseudo device */ { "mem", CDEV, 0, 0, { 0 } , { null, null, "mmread", "mmwrite", no, null, zero } , { 0 } , { 0 } , } , /* Cartridge disk - 2.5 or 10 Megabyte */ { "dsk", B_AND_CDEV+DEVAD+CNTLAD+SELCHAD+SIZE+FSDEV, 8, 0, { null, null, "dskstrategy", "dsktab", "BD_NORMAL" } , { null, null, "dskread", "dskwrite", no, null, zero } , { "dskintr", "cntlintr" } , { 0 } , } , /* Controlling terminal pseudo device */ { "tty", CDEV, 0, 0, { 0 } , { "syopen", null, "syread", "sywrite", "sysioctl", null, zero } , { 0 } , { 0 } , } , /* 1st Magnetic tape - 800 or 1600 bpi */ { "mt", B_AND_CDEV+DEVAD+SELCHAD, 4, 0, { "mtopen", "mtclose", "mtstrategy", "mtab", "BD_NORMAL" } , { "mtopen", "mtclose", "mtread", "mtwrite", "mtioctl", null, zero } , { "mtintr" } , { 0 } , } , /* Current loop interface */ { "cli", CDEV+DEVAD, 0, 0, { 0 } , { "cliopen", "cliclose", "cliread", "cliwrite", "cliioctl", null, "cli" } , { "cliint" } , { 0 } , } , /* 1st Line printer */ { "lp", CDEV+DEVAD, 1, 0, { 0 } , { "lpopen", "lpclose", no, "lpwrite", "lpioctl", null, zero } , { "lpint" } , { 0 } , } , /* MSM disk - 67 or 256 megabyte */ { "msm", B_AND_CDEV+DEVAD+CNTLAD+SELCHAD+NAME+TYPE+LAYOUT+PICT+FSDEV, 0, 0, { null, null, "msmstrategy", "msmtab", "BD_NORMAL" } , { null, null, "msmread", "msmwrite", no, null, zero } , { "msmintr" } , &reqdev[RQ_DISK] /* msm must also be in this list */ } , /* Synchronous data set adapter */ { "dsa", CDEV+DEVAD, 0, 2, { 0 } , { "dsaopen", "dsaclose", "dsaread", "dsawrite", "dsaioctl", "dsastop", "dsa" } , { "dsarint", "dsaxint" } , { 0 } , } , /* Multiplexed file pseudo device */ { "mx", CDEV, 0, 0, { 0 } , { "mxopen", "mxclose", "mxread", "mxwrite", "mxioctl", null, zero } , { 0 } , { 0 } , } , /* 40 megabyte disk */ { "d40", B_AND_CDEV+DEVAD+CNTLAD+SELCHAD+MAP+FSDEV, 4, 0, { null, null, "d40strategy", "d40tab", "BD_NORMAL" } , { null, null, "d40read", "d40write", no, null, zero } , { "d40intr", "d40cintr" } , &reqdev[RQ_DISK] /* d40 must also be in this list */ } , /* Precision clock */ { "clock", DEVAD, 1, 0, { 0 } , { 0 } , { "clock" } , &reqdev[RQ_CLOCK] /* clock must also be in this list */ } , /* 2nd Magnetic tape - 800 or 1600 bpi */ { "mta", B_AND_CDEV+DEVAD+SELCHAD, 4, 0, { "mtaopen", "mtaclose", "mtastrategy", "mtaab", "BD_NORMAL" } , { "mtaopen", "mtaclose", "mtaread", "mtawrite", "mtaioctl", null, zero } , { "mtaintr" } , { 0 } , } , /* 3rd Magnetic tape - 800 or 1600 bpi */ { "mtb", B_AND_CDEV+DEVAD+SELCHAD, 4, 0, { "mtbopen", "mtbclose", "mtbstrategy", "mtbab", "BD_NORMAL" } , { "mtbopen", "mtbclose", "mtbread", "mtbwrite", "mtbioctl", null, zero } , { "mtbintr" } , { 0 } , } , /* Undefined device #1, used for devices defined by users. */ { "ud1", B_AND_CDEV, 1, 0, { 0 } , { 0 } , { 0 } , } , /* Comms Mux, PALS or PASLA for simplex input */ { "sin", CDEV+DEVAD+DIOSAD+SPEEDS, 0, 1, { 0 } , { "sinopen", "sinclose", "sinread", null, "sinioctl", null, "sin" } , { "sinrint" } , /* no transmit interrupt */ { 0 } , } , /* megatek 7200 driver */ { "meg", CDEV+DEVAD+SELCHAD, 1, 0, { 0 }, { "megopen", "megclose", "megread", "megwrite", "megioctl", null, zero }, { "megintr" }, { 0 }, }, /* ptc Unet */ { "ptc",CDEV,0,0, { 0 } , { "ptcopen", "ptcclose", "ptcread", "ptcwrite", "ptyioctl", null, "pt_tty" } , { 0 } , { 0 } , } , /* pts Unet */ { "pts",CDEV,0,0, { 0 } , { "ptsopen", "ptsclose", "ptsread", "ptswrite", "ptyioctl", null, "pt_tty" } , { 0 } , { 0 } , } , /* up_ Unet */ { "up",CDEV,0,0, { 0 } , { "up_open", "up_close", "up_read", "up_write", "up_ioctl", null, zero } , { 0 } , { 0 } , } , /* uu_ Unet */ { "uu",CDEV,0,0, { 0 } , { "uu_open", "uu_close", "uu_read", "uu_write", "uu_ioctl", null, zero } , { 0 } , { 0 } , } , /* ud_ Unet */ { "ud",CDEV,0,0, { 0 } , { "ud_open", "ud_close", "ud_read", "ud_write", "ud_ioctl", null, zero } , { 0 } , { 0 } , } , /* Block Memory Device */ { "mm",BDEV+MAP+FSDEV,1,0, { "mmopen", "mmclose", "mmstrategy", "mmtab", "BD_NOCACHE" } , { 0 } , { 0 } , { 0 } , } , /* Line Interrupt */ { "li",CDEV+DEVAD,8,0, { 0 } , { "liopen", "liclose", "liread", no, "liioctl", null, zero } , { "liint" } , { 0 } , } , /* Digital I/O Module */ { "dio",CDEV+DEVAD,2,0, { 0 } , { "dioopen", "dioclose", no, "diowrite", "dioioctl", null, zero } , { "dioint" } , { 0 } , } , /* 2nd Line printer */ { "lpa", CDEV+DEVAD, 1, 0, { 0 } , { "lpaopen", "lpaclose", no, "lpawrite", "lpaioctl", null, zero } , { "lpaint" } , { 0 } , } , /* 3rd Line printer */ { "lpb", CDEV+DEVAD, 1, 0, { 0 } , { "lpbopen", "lpbclose", no, "lpbwrite", "lpbioctl", null, zero } , { "lpbint" } , { 0 } , } , /* Null name marks end of table */ { 0 } , }; /* * Table describing line disciplines */ struct lineconf { char *l_name; /* external name */ int l_include; /* include this discipline if not 0 */ int l_select; /* selectable via ioctl */ /* N.B. All entries with select=1 must precede those with select=0 */ char *l_lsw[10]; /* names of linesw entries */ } lineconf[] = { /* Standard tty driver */ { "tty", 1, 1, "ttyopen", null, "ttread", "ttwrite", no, "ttyinput", "ttyrend", null, "ttstart", null, } , /* Packet switch */ { "pack", 0, 1, "pkopen", "pkclose", "pkread", "pkwrite", "pkioctl", "pkrint", null, null, "pkxint", null, } , /* Multiplexed files */ { "mx", 0, 0, "mxopen", "mxclose", "mcread", "mcwrite", "mxioctl", null, null, null, null, null, } , /* Unet */ { "upk", 0, 0, "upkopen", "upkclose", "upkread", "upkwrite", "upkioctl", "upkrint", "upkrend", null, "upkstart", null } , /* Unet */ { "fpk", 0, 0, "upkopen", "upkclose", "upkread", "upkwrite", "upkioctl", "fpkrint", "fpkrend", null, "upkstart", null } , /* Null name marks end of table */ { 0 } , }; /* * Table for special device assignments */ struct spdev { char *s_name; /* external name */ int s_flag; /* d_flag type required */ int s_minor; /* minor device number */ struct devconf *s_dev; /* pointer to device description */ } spdev[] = { "root", FSDEV, 0, 0, "swap", FSDEV, 0, 0, "pipe", FSDEV, 0, 0, "cons", CONSDEV, 0, 0, 0 }; /* * Table for parsing main-level keywords */ #define K_REQ 1 /* definition required */ #define K_NUM 2 /* needs numeric parameter */ #define K_KEY 4 /* needs keyword parameter */ #define K_STR 8 /* needs string parameter */ #define K_NAME 16 /* needs name parameter */ #define K_UNET 32 /* dummy flag to force Punet */ int Pcpu(), Pmemory(), Ptotmem(), Pfloat(), Pdfloat(); int Pswaplo(), Pnswap(), Pdump(); int Ptimezone(), Pdaylight(); int Pndevs(); int Pserial(), Plicense(), Playout(); int Punet(); int Pmm(); struct keyparm { char *k_name; /* external name */ int k_flags; /* see #defines above */ int (*k_fn)(); /* routine to process keyword */ int k_defined; /* has been defined if nonzero */ } keyparm[] = { "cpu", K_REQ+K_NUM, Pcpu, 0, "memory", K_NUM, Pmemory, 0, "user-memory", K_NUM, Pmemory, 0, "total-memory", K_NUM, Ptotmem, 0, "float", K_KEY, Pfloat, 0, "dfloat", K_KEY, Pdfloat, 0, "wcs", 0, 0, 0, "timezone", K_REQ+K_NUM, Ptimezone, 0, "daylight", K_REQ+K_NUM, Pdaylight, 0, "swaplo", K_REQ+K_NUM, Pswaplo, 0, "nswap", K_REQ+K_NUM, Pnswap, 0, "dump", K_KEY, Pdump, 0, "lra", 0, 0, 0, "pic", 0, 0, 0, "ndevs", K_NUM, Pndevs, 0, "cpu-serial-number", K_REQ+K_STR, Pserial, 0, "license", K_REQ+K_STR, Plicense, 0, "layout", K_REQ+K_NAME, Playout, 0, "unet", K_UNET, Punet, 0, "mm", 0, Pmm, 0, 0 }; /* * Table for parsing device parameters */ int Pdev(), Pcntl(), Pselch(), Ptype(), Pname(), Psize(), Ppict(), Pmap(), Pspeeds(), Pdios(); struct devparm { char *p_name; /* external name */ int p_flag; /* d_flags value associated with this parm */ int (*p_fn)(); /* function to process this parm */ } devparm[] = { "dev", DEVAD, Pdev, "cntl", CNTLAD, Pcntl, "selch", SELCHAD, Pselch, "type", TYPE, Ptype, "name", NAME, Pname, "size", SIZE, Psize, "map", MAP, Pmap, "pict", PICT, Ppict, "speeds", SPEEDS, Pspeeds, "dios", DIOSAD, Pdios, 0 }; /* * Preprocessor #include files for c.c */ char *includes[] = { "../h/local.h", "../h/param.h", "../h/systm.h", "../h/buf.h", "../h/tty.h", "../h/conf.h", "../h/proc.h", "../h/text.h", "../h/file.h", "../h/inode.h", "../h/acct.h", "../h/dskmap.h", "../h/ccb.h", 0 }; /* * Other declarations for c.c */ char *junk[] = { "buf\tbfreelist", "acct\tacctbuf", "inode\t*acctp", 0 }; /* * Configuration data from input */ int *speeds; /* comm mux baud rates */ int nspeeds; /* number of entries in above */ int cpu; /* cpu model number */ int memory; /* maximum memory */ int totmem; /* total memory for seting up kernel seg regs */ int singlefloat; /* single precision floating point: 0=none, 1=hardware, 2=software */ int doublefloat; /* double precision floating point: as above */ int swaplo; /* origin of swap area */ int nswap; /* length of swap area */ int timezone; /* number of hours west of greenwich */ int daylight; /* whether or not daylight savings time */ char *dumpsw; /* dump routine */ int nccb; /* number of auto-driver 'channel' cntl blks */ int mx; /* nonzero if mx files included */ char serialnum[64]; /* cpu serial number */ char license[64]; /* license number */ #define MAXDEV 1024 /* Maximum number of device addresses */ int ndevs = 256; /* number of device addresses supported */ int highestdev; /* highest device address specified */ #ifdef CDEVMAJMAP char cdevmajmap[MAXDEV];/* map char device address => major device number */ /* dioses and selches have no major device number, so they */ /* appear as 0 in cdevmajmap */ /* This is currently not used */ #endif CDEVMAJMAP char devmap[MAXDEV]; /* map device address => minor device number */ char devint[MAXDEV]; /* map device address => interrupt table offset */ /* NOTE: only 64 (= 256/4) handlers can be handled by the present */ /* scheme. This is because when we write out the devint array */ /* we write out the array index of the handler times 4 */ #define MAXHANDLER 64 /* maximum number of interrupt routines */ #define SPURHANDLER 0 /* offset of built-in spurious entry */ #define SELCHOFFS 1 /* offset of built-in selch entry in table */ char *handler[MAXHANDLER] = { /* names of interrupt routines */ "spurint", /* offset 0 is unexpected interrupt */ "selchint", /* selector channel always included */ }; int nhandler = 2; /* number of interrupt routines */ #define MAXSELCH 16 /* max number of selches mkconf can handle */ #define MAXCNTRL 32 /* max number of selches mkconf can handle */ #define MAXDTYPE 16 #define MAXMAP 32 int diosoffs; /* offset of dios entry in table */ static int ndios; /* number of DIOSes */ static short diosaddr[MAXDIOS]; /* DIOS addresses */ static int nselch; /* number of selector channels */ static short selchaddr[MAXSELCH]; /* selector channel addresses */ int cntrloffs; static int ncntrl; /* number of controllers */ static short cntrladdr[MAXCNTRL]; /* controller addresses */ static short spindle[32]; static int nlayout =0; char mapname [32][16]; /* local array of map names */ char discname [32][16]; /* local array of disc names */ int *maplist [32]; /* pointers to maps */ /* * Files */ char *configfile; /* input file name */ char *cfile = "c.c"; /* C output file name */ char *sfile = "param.s"; /* as output file name */ #ifdef MAKEDEV char *mfile = "mkdev.sh"; /* mkdev shell output file name */ FILE *mfileno; #endif MAKEDEV /* * Input parsing information */ enum token_t { /* types of input token */ ENDFILE, KEYWORD, NUMERIC }; enum token_t token_type; /* type of next token on input file */ int token_value; /* value of token if numeric */ char token_key[64]; /* value of token if keyword */ int linenumber = 0; /* current input line number */ /* * Shorthand macros */ #define match(a) !strcmp(a, token_key) /* * mkconf [ -c cfile ] [ -s sfile ] [ config ] * * Read configuration description in config file (default stdin). * Produce cfile (default "c.c") containing device driver information, * sfile (default "param.s") containing conditional assembly parameters, #ifdef MAKEDEV * and mfile (default mkdev.sh) shell file to make entries in /dev #endif MAKEDEV */ main(argc, argv) char **argv; { /* * Obey arguments */ while (--argc > 0) { argv++; if (argv[0][0] == '-') switch (argv[0][1]) { case 'c': /* change cfile */ if (--argc <= 0) error("Missing cfile name"); cfile = *++argv; break; #ifdef MAKEDEV case 'm': /* change mfile */ if (--argc <= 0) error("Missing sfile name"); mfile = *++argv; break; #endif MAKEDEV case 's': /* change sfile */ if (--argc <= 0) error("Missing sfile name"); sfile = *++argv; break; default: error("Unknown argument %s", *argv); break; } else configfile = *argv; } /* * Read config file and store data in internal form */ if (configfile && freopen(configfile, "r", stdin) == NULL) error("Can't open %s", configfile); linenumber = 1; /* start line numbering for error messages */ token(); while (getconfig()) ; linenumber = 0; /* turn off line numbers for error messages */ /* * Check validity of data and compute remaining parameters */ mkconf(); #ifdef MAKEDEV /* * Make mkdev.sh file */ if ((mfileno = fopen(mfile, "w")) == NULL) error("Can't write %s", mfile); #endif MAKEDEV /* * Make C file */ if (freopen(cfile, "w", stdout) == NULL) error("Can't write %s", cfile); putcfile(); /* * Make as file */ if (freopen(sfile, "w", stdout) == NULL) error("Can't write %s", sfile); putsfile(); exit(0); } /* * Make "c.c" file * * Contains #includes * bdevsw, cdevsw and linesw tables * device assignments for root, swap, pipes * other configuration variables * device driver configuration information */ putcfile() { register struct devconf *dp; register struct lineconf *lp; register int major, i; register int nldisp = 0; int ii; printf ("/* from \"%s\" */\n\n", configfile ? configfile : "standard input"); /* * #includes */ { register char **pp; for (pp = includes; *pp; pp++) printf("#include \"%s\"\n", *pp); } /* * Declarations for char switch routines */ printf("\nint %s(), %s();\n", no, null); for (dp = devconf; dp->d_name; dp++) { if ((dp->d_flags&BDEV) && dp->d_ndev > 0) { register char *sep = "int\t"; for (i = 0; i < 3; i++) { if (dp->d_bsw[i] != no && dp->d_bsw[i] != null) { printf("%s%s()", sep, dp->d_bsw[i]); sep = ", "; } } printf(";\n"); if (dp->d_bsw[3] != zero) printf("struct buf %s;\n", dp->d_bsw[3]); } } /* * bdevsw */ printf("\nstruct bdevsw bdevsw[] = {\n"); for (major = 0, dp = devconf; dp->d_name; dp++) { if (!(dp->d_flags&BDEV)) continue; if (dp->d_ndev > 0) { printf("\t%s, %s, %s, ", dp->d_bsw[0], dp->d_bsw[1], dp->d_bsw[2]); if (dp->d_bsw[3] == zero) printf("0,"); else printf("&%s,", dp->d_bsw[3]); printf(" %s,", dp->d_bsw[4]); } else printf("\tnodev, nodev, nodev, 0, 0,"); printf("\t/* %s = %d */\n", dp->d_name, major); putmfile(dp,major,BDEV); dp->d_major = major; major++; } printf("\t0\n};\n\n"); /* * declarations for char switch routines */ for (dp = devconf; dp->d_name; dp++) { if ((dp->d_flags&CDEV) && dp->d_ndev > 0) { register char *sep = "int\t"; for (i = 0; i < 6; i++) { if (dp->d_csw[i] != no && dp->d_csw[i] != null) { printf("%s%s()", sep, dp->d_csw[i]); sep = ", "; } } printf(";\n"); if (dp->d_csw[6] != zero){ if (!strcmp(dp->d_name,"ptc")){ printf("struct tty %s[];\n", dp->d_csw[6]); continue; } if (!strcmp(dp->d_name,"pts")) continue; printf("struct tty %s[%d];\n", dp->d_csw[6], dp->d_ndev); } } } /* * cdevsw */ printf("\nstruct cdevsw cdevsw[] = {\n"); for (major = 0, dp = devconf; dp->d_name; dp++) { if (!(dp->d_flags&CDEV)) continue; if (dp->d_ndev > 0) { printf("\t%s, %s, %s, %s, %s, %s, %s,", dp->d_csw[0], dp->d_csw[1], dp->d_csw[2], dp->d_csw[3], dp->d_csw[4], dp->d_csw[5], dp->d_csw[6]); } else printf("\tnodev, nodev, nodev, nodev, nodev, nodev, 0,"); printf("\t/* %s = %d */\n", dp->d_name, major); putmfile(dp,major,CDEV); if (!(dp->d_flags & BDEV)) { register int i; dp->d_major = major; #ifdef CDEVMAJMAP /* fill in the cdevmajmap[] array */ if (dp->d_dev) for (i = 0; i < dp->d_ndev; ++i) cdevmajmap[dp->d_dev[i]] = major; #endif CDEVMAJMAP } major++; } printf("\t0\n};\n\n"); /* * Definitions for linesw */ for (lp = lineconf; lp->l_name; lp++) { if (lp->l_include) { register char *sep = "int\t"; for (i = 0; i < 10; i++) if (lp->l_lsw[i] != no && lp->l_lsw[i] != null) { printf("%s%s()", sep, lp->l_lsw[i]); sep = ", "; } printf(";\n"); } } /* * linesw */ printf("\nstruct linesw linesw[] = {\n"); for (major = 0, lp = lineconf; lp->l_name; lp++) { if (lp->l_include) { for (i = 0; i < 10; i++) { printf(i==0? "\t": i==5? ",\n\t\t": ", "); printf("%s", lp->l_lsw[i]); } printf(",\t/* %s = %d */\n", lp->l_name, major); if (lp->l_select) nldisp++; major++; } } printf("\t0\n};\n\nint nldisp = %d;\n", nldisp); if (!mx) /* force loading of fake mx routines */ printf("int\tmpxchan();\nint\t(*ldmpx)() = mpxchan;\n"); /* * Special device assignments */ { register struct spdev *sp; for (sp = spdev; sp->s_name; sp++) { printf("dev_t\t%sdev = makedev(%d, %d);\n", sp->s_name, sp->s_dev->d_major, sp->s_minor); } } /* * Assorted configuration variables */ printf("daddr_t\tswplo\t= %d;\nint\tnswap\t= %d;\n", swaplo, nswap); if(memory != 0 && totmem != 0 && memory > totmem) memory = totmem; if (memory == 0) memory = totmem; printf("caddr_t\tmemtop\t= %d;\n", memory); if (totmem == 0) totmem = memory; printf("caddr_t\ttotmem\t= %d;\n", totmem); if(strcmp(dumpsw,"none")) printf("\nint\t%s();\nint\t(*dumpsw)() = %s;\n\n", dumpsw, dumpsw); else printf("\nint\t(*dumpsw)() = nulldev;\n\n"); printf("int\ttimezone = %d;\nint\tdaylight = %d;\n", timezone, daylight); { register char **pp; for (pp = junk; *pp; pp++) printf("struct\t%s;\n", *pp); } printf("char\tserialnum[32] = \"%.32s\";\n", serialnum); printf("char\tlicense[32] = \"%.32s\";\n", license); /* * Driver configuration data */ for (dp = devconf; dp->d_name; dp++) /* output device if ndev>0 or the dev is mm and not defined */ if (dp->d_ndev > 0 || dp->d_ndev == -999) { if (dp->d_flags & DEVAD) { if (dp->d_maxdev != 1 || !strcmp(dp->d_name,"vdu")) printf("int\tn%s = %d;\n", dp->d_name, dp->d_ndev); printf("char\t%saddr[] = {", dp->d_name); for (i = 0; i < dp->d_ndev; i++) printf("%s0x%02x,", i&07 ? " " : "\n\t", dp->d_dev[i]); printf("\n};\n"); } if (dp->d_nccb) { printf("struct ccb *%sccb = &ccb[%d];\n", dp->d_name, nccb); nccb += dp->d_ndev * dp->d_nccb; } if (dp->d_flags & DIOSAD) { printf("int\t%sdios[] = {", dp->d_name); for (i = 0; i < dp->d_ndev; i++) printf("%s0x%02x,", i&07 ? " " : "\n\t", dp->d_channel.d_dios[i]); printf("\n};\n"); } if (dp->d_flags & SPEEDS) { printf("char\t%srate[][4] = {", dp->d_name); for (i = 0; i < nspeeds; i++) printf("%sB%d,", i&03 ? " " : "\n\t", speeds[i]); printf("\n};\n"); } if (dp->d_flags & CNTLAD){ printf("char\t%scntl[] = {", dp->d_name); for (i = 0; i < dp->d_ndev; i++) printf("%s0x%02x,", i&07 ? " " : "\n\t", dp->d_cntl[i]); printf("\n};\n"); } if (dp->d_flags & SELCHAD){ printf("int\t%sselch[] = {", dp->d_name); for (i = 0; i < dp->d_ndev; i++) printf("%s0x%02x,", i&07 ? " " : "\n\t", dp->d_channel.d_selch[i]); printf("\n};\n"); } if (dp->d_flags & TYPE){ printf("char\t%stype[] = {", dp->d_name); for (i = 0; i < dp->d_ndev; i++) printf("%s%d,", i&07 ? " " : "\n\t", dp->d_disc.d_type[i]); printf("\n};\n"); for( i = 0; i < dp->d_ndev; i++ ) spindle[i] = devmap[dp->d_dev[i]]; printf("char\t%sspindle[] = {", dp->d_name); for (i = 0; i < dp->d_ndev; i++) printf("%s%d,", i&07 ? " " : "\n\t", spindle[i]); printf("\n};\n"); } if (dp->d_flags & SIZE) printf("int\t%ssize = %d;\n", dp->d_name, dp->d_size); if (dp->d_flags & MAP) { printf("int\t%smap[] = {", dp->d_name); for (i = 0; i < 16; i++) printf("%s%8d,", i&01 ? "\t" : "\n\t", dp->d_map[i]); printf("\n};\n"); } if (dp->d_flags & PICT){ printf("char\t%smap[] = {", dp->d_name); for (i = 0; i < dp->d_ndev; i++) printf("%s%d,", i&07 ? " " : "\n\t", dp->d_map[i]); printf("\n};\n"); } if (dp->d_flags & LAYOUT) { printf("int\t%slayout[][16] = {", dp->d_name); for (ii = 0; ii < nlayout; ii++){ printf("\n{"); for (i = 0; i < 16; i++) printf("%s%8d,", i&01 ? "\t" : "\n\t", maplist[ii][i]); printf("\n},\n"); } printf("\n};\n"); } } /* * diosaddr[] = dios address table, indexed by dios minor device */ printf("\nshort\tdiosaddr[] = {\n\t"); for (i = 0; i < ndios; ++i) printf("0x%03x, ", diosaddr[i]); printf("\n};\n"); /* * file locking hook */ printf("\nstruct\tlocklist locklist[NFLOCKS];\n"); #ifdef CDEVMAJMAP /* * cdevmajmap[] = table of major device numbers, * indexed by device address */ printf("\nchar\tcdevmajmap[] = {"); for (i = 0; i < ndevs; i++) { if (i & 017) putchar (' '); else printf ("\n /* %3x */ ", i); printf("%2d,", cdevmajmap[i] & 0xff); } printf("\n};\n"); #endif CDEVMAJMAP /* * devmap[] = table of minor device numbers, indexed by device address */ printf("\nchar\tdevmap[] = {"); for (i = 0; i < ndevs; i++) { if (i & 017) putchar (' '); else printf ("\n /* %3x */ ", i); printf("%2d,", devmap[i] & 0xff); } printf("\n};\n"); /* * devint[] */ printf("\nchar\tdevint[] = {"); for (i = 0; i < ndevs; i++) { if (i & 017) putchar (' '); else printf ("\n /* %3x */ ", i); printf("%2d,", devint[i] * sizeof handler[0]); } printf("\n};\n"); /* * handler table */ { register char *sep = "int\t"; for (i = 0; i < nhandler; i++) { printf("%s%s()", sep, handler[i]); if (i%6 == 5) sep = ";\nint\t"; else sep = ", "; } } printf(";\n\nint\t(*handler[])() = {\n"); for (i = 0; i < nhandler; i++) printf("\t%s,\n", handler[i]); printf("};\n"); } /* * Make mkdev.sh file */ putmfile(dp,major,flag) register struct devconf *dp; int major,flag; { #ifdef MAKEDEV register int minor; int type; if (dp->d_ndev <= 0) return; type = dp->d_flags; if (type & PICT) { if (flag & BDEV){ for (minor = 0; minor < dp->d_ndev * NMAP; ++minor) { fprintf (mfileno,"/etc/mknod /dev/%s%c b %d %d\n", discname[minor >> 3], "abcdefg "[minor & 7], major, minor); } } else { for (minor = 0; minor < dp->d_ndev * NMAP; ++minor) { fprintf (mfileno,"/etc/mknod /dev/r%s%c c %d %d\n", discname[minor >> 3], "abcdefg "[minor & 7], major, minor); } } } if( (!strcmp(dp->d_name,"vdu")) && type &CDEV ){ for (minor = 0; minor < dp->d_ndev; ++minor) { fprintf (mfileno,"/etc/mknod /dev/tty%d c %d %d\n", minor, major, minor); } } if( (!strncmp(dp->d_name, "mt", 2)) ){ int num = 0; if(!strcmp(dp->d_name, "mta")) num = 4; if(!strcmp(dp->d_name, "mtb")) num = 8; if (flag & BDEV){ for (minor = 0; minor < dp->d_ndev; ++minor) { fprintf (mfileno,"/etc/mknod /dev/mt%d b %d %d\n", num+minor, major, minor); } for (minor = 0; minor < dp->d_ndev; ++minor) { fprintf (mfileno,"/etc/mknod /dev/mmt%d b %d %d\n", num+minor, major, minor+4); } } else { for (minor = 0; minor < dp->d_ndev; ++minor) { fprintf (mfileno,"/etc/mknod /dev/rmt%d c %d %d\n", num+minor, major, minor); } for (minor = 0; minor < dp->d_ndev; ++minor) { fprintf (mfileno,"/etc/mknod /dev/rmmt%d c %d %d\n", num+minor, major, minor+4); } } } #endif MAKEDEV } /* * Find entry in keyword table * It had better be there! */ struct keyparm * findkey(name) register char *name; { register struct keyparm *kp; for (kp = keyparm; kp->k_name; kp++) if (!strcmp(kp->k_name, name)) return(kp); abort(); /* NOTREACHED */ } /* * Make "param.s" file * * Contains parameters for conditional assembly of UNIX kernel routines */ putsfile() { putparm("M3200", (cpu == 3220) || (cpu == 3240)); putparm("M3240", cpu == 3240); putparm("FPREGS", singlefloat == 1); putparm("DPREGS", doublefloat == 1); putparm("SPFPT", singlefloat == 2); putparm("DPFPT", doublefloat == 2); putparm("NCCB", nccb); putparm("WCS", findkey("wcs")->k_defined); putparm("LRA", (cpu == 3220) || (cpu == 3240) || findkey("lra")->k_defined); putparm("PIC", findkey("pic")->k_defined); putparm("NDEVS", ndevs); } /* * Equate assembly parameter name to value */ putparm(name, value) char *name; { printf("%s\tequ\t%d\n", name, value); } /* * Check validity of input data and generate internal parameters */ mkconf() { register struct devconf *dp; int mem; char p[50]; /* * Check that all required main keywords are defined */ { register struct keyparm *kp; mem = 0; /* have not seen any memory params yet */ for (kp = keyparm; kp->k_name; kp++) { if ((kp->k_flags & K_REQ) && !kp->k_defined) error("%s not specified", kp->k_name); strcpy(p,kp->k_name); /* * if the param is a memory parameter and it * has been defined then increment mem variable. * If no memory gets defined then an error is * raised. */ if( (!strcmp(p,"memory") || !strcmp(p,"user-memory") || !strcmp(p,"total-memory")) && kp->k_defined) mem++; /* * if the param is for the shared memory driver * "mm" check to see if its been defined by calling * its routine. In this configuration a declaration * for mmmap must be given so that mem.c doesn't * croak. */ if(!strcmp(p, "mm")) (*kp->k_fn)(); } if(!mem) error("No memory parameter specified"); } /* * Check that special device assignments have been defined */ { register struct spdev *sp; for (sp = spdev; sp->s_name; sp++) if (sp->s_dev == 0) error("%s device not specified", sp->s_name); } /* * Check at least one in each class of required device is specified */ { register struct reqdev *rq; for (rq = reqdev; rq->rq_names; rq++) if (rq->rq_def == 0) error("must specify at least one: %s", rq->rq_names); } /* * Device processing */ for (dp = devconf; dp->d_name; dp++) { register struct devparm *pp; /* * Check that required devices & parameters are defined */ if (dp->d_ndev == 0) { if (dp->d_flags & DREQ) error("%s not defined. Required by %s", dp->d_name, dp->d_reqby); continue; } for (pp = devparm; pp->p_name; pp++) if ((dp->d_flags & pp->p_flag) && ! (dp->d_defined & pp->p_flag)) { if (dp->d_flags & DIOSAD) { /* default to no dioses */ getlist (&dp->d_ndev, &dp->d_channel.d_dios, 0); } else error("%s not specified for %s", pp->p_name, dp->d_name); } /* * Remember interrupt information */ if (dp->d_flags & DEVAD) { register int i; register int int0, int1; int0 = mkhandler(dp->d_int[0]); if (dp->d_int[1]) int1 = mkhandler(dp->d_int[1]); else int1 = SPURHANDLER; for (i = 0; i < dp->d_ndev; i++) { register int dev = dp->d_dev[i]; mkintvec(dev, int0); if( devmap[dev] == 0 ) devmap[dev] = i; if ( (dp->d_flags&(B_AND_CDEV)) == CDEV && int1 != SPURHANDLER) { if (dev & 01) error("%s addresses must be even", dp->d_name); mkintvec(dev + 1, int1); devmap[dev + 1] = i; } } if (dp->d_flags & CNTLAD) mkcntrl(dp); if (dp->d_flags & SELCHAD) mkselch(dp); if (dp->d_flags & DIOSAD) mkdios(dp); } } } /* * Add a name to the interrupt handler table * * Return handler[] index */ mkhandler(name) char *name; { handler[nhandler] = name; if (++nhandler > MAXHANDLER) error("Interrupt table overflow"); return nhandler - 1; } /* * Add an address to the coltroller address table (if not already present) * Also record 'minor device number' and interrupt handler for controller address */ mkcntrl(dp) register struct devconf *dp; { register int i; register int address; register int ind; for (ind = 0; ind < dp->d_ndev; ++ind) { /* see if we know about this cntrl already */ address = dp->d_cntl[ind]; for (i = 0; i < ncntrl; i++) if (cntrladdr[i] == address) goto next; cntrladdr[i] = address; if (i == 0) cntrloffs = mkhandler("msmcintr"); devmap[address] = i; devint[address] = cntrloffs; ++ncntrl; next: continue; } } mkselch(dp) register struct devconf *dp; { register int i; register int address; register int ind; for (ind = 0; ind < dp->d_ndev; ++ind) { /* see if we know about this selch already */ address = dp->d_channel.d_selch[ind]; for (i = 0; i < nselch; i++) if (selchaddr[i] == address) goto next; selchaddr[i] = address; devmap[address] = i; devint[address] = SELCHOFFS; ++nselch; next: continue; } } /* * Add an address to the dios address table (if not already present) * Also record 'minor device number' and interrupt handler for dios address */ mkdios(dp) register struct devconf *dp; { register int i; register int address; register int ind; for (ind = 0; ind < dp->d_ndev; ++ind) { /* if address is 0, this is not a real dios, * but a place holder, so don't put it in the table */ if (!(address = dp->d_channel.d_dios[ind])) continue; /* see if we know about this dios already */ if (address & 0x3F) error ("%s: dios address least significant 6 bits must be 0", dp->d_name); if (!(dp->d_dev[ind] & 0x3F)) error ("%s: least significant 6 address bits of device on dios can't be 0", dp->d_name); if ((address & 0x3C0) != (dp->d_dev[ind] & 0x3C0)) error ("%s: dios and device upper bits don't match", dp->d_name); for (i = 0; i < ndios; i++) if (diosaddr[i] == address) goto next; diosaddr[i] = address; if (i == 0) diosoffs = mkhandler("diosint"); devmap[address] = i; devint[address] = diosoffs; ++ndios; next: continue; } } /* * Put interrupt handler table offset into interrupt table for given device * * Check that addresses are not reassigned */ mkintvec(address, offset) { if (devint[address] == offset){ printf("WARRING!! device address 0x%02x already used\n", address); return; } else { if(devint[address] != 0) error("device address 0x%02x reassigned", address); } devint[address] = offset; } /* * Get the next complete configuration entry from the input file * * Returns 0 at end of file */ getconfig() { register struct devconf *dp; register struct keyparm *kp; register struct spdev *sp; /* * First thing must be a keyword */ switch (token_type) { case ENDFILE: return(0); case NUMERIC: error("Extraneous numeric data"); return(0); case KEYWORD: break; default: abort(); } /* * Check for device declaration */ for (dp = devconf; dp->d_name; dp++) { if (match(dp->d_name)) { token(); while (getdevice(dp)) ; if (dp->d_req) dp->d_req->rq_def = 1; if (!(dp->d_flags & DEVAD)) dp->d_ndev = 1; /* * Some device names are also line discipline names */ getline(dp->d_name); return(1); } } /* * Check for line discipline declaration */ if (getline(token_key)) { token(); return(1); } /* * Check for special device assignment */ for (sp = spdev; sp->s_name; sp++) { if (match(sp->s_name)) { token(); if (token_type != KEYWORD) error("%s requires device name", sp->s_name); for (dp = devconf; dp->d_name; dp++) { if (match(dp->d_name)) { token(); if (!(dp->d_flags & sp->s_flag)) error("%s is wrong type of device", dp->d_name); sp->s_dev = dp; dp->d_flags |= DREQ; dp->d_reqby = sp->s_name; if (token_type != NUMERIC) error("missing minor device number"); sp->s_minor = token_value; token(); break; } } if (dp->d_name == 0) error("unknown device %s", token_key); return(1); } } /* * Check for other main-level keywords */ for (kp = keyparm; kp->k_name; kp++) { if (match(kp->k_name)) { token(); getkey(kp); kp->k_defined = 1; return(1); } } error("Unknown keyword %s", token_key); /* NOTREACHED */ } /* * Process a single main-level non-device entry */ getkey(kp) register struct keyparm *kp; { if (kp->k_flags & K_NUM) { if (token_type != NUMERIC) error("%s requires a numeric parameter", kp->k_name); (*kp->k_fn)(); token(); } else if (kp->k_flags & K_KEY) { if (token_type != KEYWORD) error("%s requires a keyword parameter", kp->k_name); (*kp->k_fn)(); token(); } else if (kp->k_flags & K_STR) { (*kp->k_fn)(); token(); } else if (kp->k_flags & K_NAME) { (*kp->k_fn)(); } else if (kp->k_flags & K_UNET) { (*kp->k_fn)(); } } /* * Main keyword parameter routines */ Pcpu() { /* so far, there are basically only 3 types of cpus 832, 3220, 3240 */ switch (token_value) { case 732: case 832: cpu = 832; break; case 3220: cpu = 3220; break; case 3210: case 3230: case 3240: case 3250: cpu = 3240; break; default: error("Unknown CPU model %d", token_value); } } Pmemory() { if (token_value < 128*1024) error("Sorry, not enough memory to run UNIX"); if ( cpu == 3240 ){ if (token_value > 16*1024*1024-65536) error("Sorry, a maximumum of 15936K memory currently supported"); } else { if (token_value > 15*65536 ) error("Sorry, a maximumum of 960K memory currently supported"); } memory = token_value; } Ptotmem() { if (token_value < 128*1024) error("Sorry, not enough memory to run UNIX"); if ( cpu == 3240 ){ if (token_value > 16*1024*1024-65536) error("Sorry, a maximumum of 15936K memory currently supported"); } else { if (token_value > 15*65536 ) error("Sorry, a maximumum of 960K memory currently supported"); } totmem = token_value; } Pfloat() { if (match("hard")) singlefloat = 1; else if (match("soft")) singlefloat = 2; else error("'hard' or 'soft' expected"); } Pdfloat() { if (match("hard")) doublefloat = 1; else if (match("soft")) doublefloat = 2; else error("'hard' or 'soft' expected"); } Pswaplo() { swaplo = token_value; } Pnswap() { nswap = token_value; } Pdump() { if (match("mt")) dumpsw = "mtdump"; else if (match("dsk")) dumpsw = "dskdump"; else if (match("none")) dumpsw = "none"; else error("%s not a dump device", token_key); } Pndevs() { switch (ndevs = token_value) { case 256: case 512: case 1024: return; } error("ndevs must be 256, 512, or 1024"); } Pserial() { strcpy (serialnum, token_key); } Plicense() { strcpy (license, token_key); } /* * This routine gets called when no mm device is given * in the conf file. However in order to appease mem.c * a dummy mmmap must be given in c.c. To do this ndev * is set to -999 and this will allow putcfile to output * a mmmap to c.c. */ Pmm() { register struct devconf *dp; for(dp=devconf; dp->d_name; dp++) if(!strcmp(dp->d_name, "mm")) { if(dp->d_defined & MAP) /* return if already defined */ return; dp->d_defined |= MAP; dp->d_ndev = -999; dp->d_map = &zeromap; } } Punet() { register struct devconf *dp; register struct lineconf *lp; for ( dp = devconf; dp->d_name; dp++) { if ((!strcmp(dp->d_name,"pts")) || (!strcmp(dp->d_name,"ptc")) || (!strcmp(dp->d_name,"up" )) || (!strcmp(dp->d_name,"uu" )) || (!strcmp(dp->d_name,"ud" )) ){ dp->d_ndev++; } } for ( lp = lineconf; lp->l_name; lp++) { if (!strcmp(lp->l_name,"upk") || !strcmp(lp->l_name,"fpk")) { lp->l_include++; lp->l_select++; } } } /* * Get next entry in input description of a device * * Check that parameter is permitted for this device type * Call routine to process parameter * Returns 0 for failure */ getdevice(dp) register struct devconf *dp; { register struct devparm *pp; for (pp = devparm; pp->p_name; pp++) { if (match(pp->p_name)) { token(); if (!(dp->d_flags & pp->p_flag)) error("%s not permitted for %s", pp->p_name, dp->d_name); (*pp->p_fn)(dp); dp->d_defined |= pp->p_flag; return(1); } } return(0); } /* * Device parameter routines */ Pdev(dp) register struct devconf *dp; { getlist(&dp->d_ndev, &dp->d_dev, 1); if (dp->d_maxdev && dp->d_ndev > dp->d_maxdev) error("Too many device addresses for %s", dp->d_name); chkdevaddr (dp->d_dev, dp->d_ndev); } Pcntl(dp) register struct devconf *dp; { int ncntl; getlist(&ncntl, &dp->d_cntl, 1); if (ncntl > dp->d_ndev) error("Too many controler addresses for %s", dp->d_name); if (ncntl < dp->d_ndev) error("%s must have as many controler entries as devices", dp->d_name); chkdevaddr (dp->d_cntl, ncntl); } Pselch(dp) register struct devconf *dp; { int ndevselch; getlist(&ndevselch, &dp->d_channel.d_selch, 1); if (ndevselch > dp->d_ndev) error("Too many selch addresses for %s", dp->d_name); if (ndevselch < dp->d_ndev) error("%s must have as many selch entries as devices", dp->d_name); chkdevaddr (dp->d_channel.d_selch, ndevselch); } Pdios(dp) register struct devconf *dp; { int ndevdios; getlist(&ndevdios, &dp->d_channel.d_dios, 1); if (ndevdios > dp->d_ndev) error("Too many dios addresses for %s", dp->d_name); if (ndevdios < dp->d_ndev) error("%s must have as many dios entries as devices", dp->d_name); chkdevaddr (dp->d_channel.d_dios, ndevdios); } Psize(dp) register struct devconf *dp; { register int size; size = getnum(); if (!strcmp(dp->d_name, "dsk")) { switch (size) { case 10: case 10*1024*1024: dp->d_disc.d_size = 1; return; case 2: case 2*1024*1024: dp->d_disc.d_size = 0; return; } } else { if ( !strcmp(dp->d_name, "ud1" ) ) { switch (size) { case 67: case 67*1024*1024: dp->d_disc.d_size = 0; return; case 256: case 256*1024*1024: dp->d_disc.d_size = 1; return; } } } error("incorrect size for %s", dp->d_name); } Ptype(dp) register struct devconf *dp; { int i; int ntype = MAXDTYPE; getlist(&dp->d_ndev, &dp->d_disc.d_type, 0); if ( !strcmp(dp->d_name, "msm")){ for ( i=0; i < dp->d_ndev; i++ ){ if ( match( "d67" ) || match( "D67" ) ){ dp->d_disc.d_type[i] = 0; goto next; } if ( match( "d256" ) || match( "D256" ) ){ dp->d_disc.d_type[i] = 1; goto next; } if ( match( "c13r" ) || match( "C13R" ) || match( "C13r" ) || match( "c13R" ) ){ dp->d_disc.d_type[i] = 2; goto next; } if( match( "c13f" ) || match( "C13F" ) || match( "C13f" ) || match( "c13F" ) ){ dp->d_disc.d_type[i] = 3; goto next; } if ( match( "c40f" ) || match( "C40F" ) || match( "C40f" ) || match( "c40F" ) ){ dp->d_disc.d_type[i] = 4; goto next; } if ( match( "c67f" ) || match( "C67F" ) || match( "C67f" ) || match( "c67F" ) ){ dp->d_disc.d_type[i] = 5; goto next; } if ( match( "udd" ) || match( "UDD" ) ){ dp->d_disc.d_type[i] = 6; goto next; } error("incorrect type for %s %s", dp->d_name,token_key); break; next: token(); } return; } } Pmap(dp) register struct devconf *dp; { int nmap; getlist(&nmap, &dp->d_map, 1); if (nmap != 16) error("%s map must have 16 entries", dp->d_name); } Ppict(dp) register struct devconf *dp; { int nmap = MAXMAP; int i,ii; int j=0; getlist(&nmap, &dp->d_map, 0); for ( ii=0; iid_ndev; ii++ ){ for (i=0; i<=nlayout; i++){ if ( !strcmp(mapname[i],token_key) ) break; } if ( !(i < nlayout) ) error("%s not defined in layout",token_key); dp->d_map[ii] = i; token(); j++; } if (j != dp->d_ndev) error("%s map must have %d entries", dp->d_name,dp->d_ndev); } Playout() { int layout,i; for (i=0; id_ndev; i++){ for ( ii=0; iid_ndev) error("name must have %d entries", dp->d_ndev); } Pspeeds() { getlist(&nspeeds, &speeds, 1); if (nspeeds & 03) error("must define 4 speeds per port"); } Ptimezone() { timezone = token_value * 60; } Pdaylight() { daylight = token_value; } /* * If key is name of a line discipline, mark it for inclusion * * Return 0 if not found * make special note of "mx" discipline, to prevent loading of fakemx */ getline(key) char *key; { register struct lineconf *lp; for (lp = lineconf; lp->l_name; lp++) { if (!strcmp(key, lp->l_name)) { lp->l_include = 1; if (!strcmp(key, "mx")) mx = 1; return(1); } } return(0); } /* * Get a list of (one or more) input numbers * * Return indirectly in *length the number of addresses read, and in *list * a pointer to the array of integer values read * The space for the list is allocated using sbrk */ getlist(length, list, inpflg) int *length; int **list; int inpflg; /* 1 if from input, 0 if zero-fill */ { extern int end[]; static int *avail = end; /* top of available memory */ static int *next = end; /* next available word */ register int len = 0; *list = next; if (!inpflg) { /* fill out a list with zeroes */ len = *length; while (--len >= 0) { if (next >= avail) { avail += 64; if (brk(avail) != 0) error("Out of memory"); } *next++ = 0; } return; } if (token_type != NUMERIC) error("Numeric item expected"); while (token_type == NUMERIC) { if (next >= avail) { avail += 64; if (brk(avail) != 0) error("Out of memory"); } *next++ = token_value; len++; token(); } *length = len; } /* * Get a number from the input * * Return its value * Check that not more than one number is supplied */ getnum() { register retval; if (token_type != NUMERIC) error("Numeric item required"); retval = token_value; token(); if (token_type == NUMERIC) error("Only one numeric item expected"); return(retval); } int tokenroom; /* how many characters we can take */ char *tokenptr; /* where to put input characters */ /* * Get the next input token * * Skip white space * Skip comments (from '*' to end of line) * Read the next token (non-white-space string) * Set token_type to: * ENDFILE - no more input * NUMERIC - integer (may be preceded by 0 or 0x for octal * or hex, followed by K or M for kilo- or mega-) * may be negative. * - store value in token_value * KEYWORD - anything else * - store keyword string in token_key */ token() { register int c; int sign; tokenroom = sizeof(token_key); tokenptr = token_key; skipspace(); sign = 1; if (feof(stdin) || (c = getchar()) == EOF) { /* no more input */ token_type = ENDFILE; return; } if (c == '-') { sign = -1; putp(c); if (feof(stdin) || (c = getchar()) == EOF) error ("Malformed number"); } if (isdigit(c)) { /* a number */ register int accum = 0, base = 10; if (c == '0') { putp(c); c = getchar(); if (c == 'x' || c == 'X') { putp(c); c = getchar(); base = 16; } else base = 8; } for (;;) { int num; if (isdigit(c)) num = c - '0'; else if (c >= 'a' && c <= 'f') num = c - ('a'-10); else if (c >= 'A' && c <= 'F') num = c - ('A'-10); else break; if (num >= base) goto string; accum *= base; accum += num; putp(c); c = getchar(); } if (c == 'k' || c == 'K') { putp(c); c = getchar(); accum *= 1024; } else if (c == 'm' || c == 'M') { putp(c); c = getchar(); accum *= 1024*1024; } else if (!isspace(c)) goto string; ungetc(c, stdin); token_type = NUMERIC; token_value = sign < 0 ? -accum : accum; } else { /* a keyword */ string: while (!(isspace(c)) && c != EOF) { putp (c); c = getchar(); } token_type = KEYWORD; ungetc(c, stdin); } putp ('\0'); } putp (chr) int chr; { *tokenptr++ = chr; if (--tokenroom <= 0) error("Impossibly long word"); } /* * Skip space and comments on the input file * Also keep track of line numbers */ skipspace() { register int c; for (;;) { c = getchar(); if (c == '*') while ((c = getchar()) != '\n') ; if (c == '\n') linenumber++; else if (!(isspace(c))) break; } if (c != EOF) ungetc(c, stdin); } chkdevaddr (list, num) int *list; int num; { for (; --num >= 0; ++list) { if (*list > ndevs) error ("device address larger than ndevs"); if (highestdev < *list) highestdev = *list; } } /* * Print error message and exit */ /* VARARGS 1 */ error(msg, a1, a2) char *msg; char *a1, *a2; { if (linenumber != 0) fprintf(stderr, "Line %d: ", linenumber); fprintf(stderr, msg, a1, a2); fprintf(stderr, "\n"); exit(1); }