SysIII/usr/src/cmd/config/config.vax.c

Compare this file to the similar file:
Show the results in this format:

#include "stdio.h"
#define	TSIZE	50		/* maximum configuration table size */
#define	DSIZE	50		/* maximum device table size */
#define	ASIZE	20		/* maximum alias table size */
#define MSIZE	100		/* maximum address map table size */
#define	PSIZE	32		/* maximum keyword table size */
#define	BSIZE	16		/* maximum block device table size */
#define	CSIZE	50		/* maximum character device table size */
#define ONCE	128		/* allow only one specification of device */
#define NOCNT	64		/* suppress device count field */
#define SUPP	32		/* suppress interrupt vector (on print) */
#define REQ	16		/* required device */
#define	BLOCK	8		/* block type device */
#define	CHAR	4		/* character type device */
#define	FLT	2		/* interrupt vector in range 0300 - 0774 */
#define	FIX	1		/* interrupt vector in range 0 - 0274 */
#define INIT	64		/* initialization routine exists */
#define PWR	32		/* power fail routine exists */
#define	OPEN	16		/* open routine exists */
#define	CLOSE	8		/* close routine exists */
#define	READ	4		/* read routine exists */
#define	WRITE	2		/* write routine exists */
#define	IOCTL	1		/* ioctl routine exists */

struct	t	{
	char	*devname;	/* pointer to device name */
	short	vector;		/* interrupt vector location */
	unsigned short address;	/* device address */
	short	buslevel;	/* bus request level */
	short	addrsize;	/* number of bytes at device address */
	short	vectsize;	/* number of bytes for interrupt vector */
	short	type;		/* ONCE,NOCNT,SUPP,REQ,BLOCK,CHAR,FLT,FIX  */
	char	*handler;	/* pointer to interrupt handler */
	short	count;		/* sequence number for this device */
	short	blk;		/* major device number if block type device */
	short	chr;		/* major device number if char. type device */
	short	mlt;		/* number of devices on controller */
}	table	[TSIZE];

struct	t2	{
	char	dev[9];		/* device name */
	short	vsize;		/* interrupt vector size */
	short	asize;		/* device address size */
	short	type2;		/* ONCE,NOCNT,SUPP,REQ,BLOCK,CHAR,FLT,FIX  */
	short	block;		/* major device number if block type device */
	short	charr;		/* major device number if char. type device */
	short	mult;		/* maximum number of devices per controller */
	short	busmax;		/* maximum allowable bus request level */
	short	mask;		/* device mask indicating existing handlers */
	char	hndlr[5];	/* handler name */
	short	dcount;		/* number of controllers present */
	char	entries[3][9];	/* conf. structure definitions */
	short	acount;		/* number of devices */
}	devinfo	[DSIZE];

struct	t3	{
	char	new[9];		/* alias of device */
	char	old[9];		/* reference name of device */
}	alias	[ASIZE];

struct	map	{
	unsigned short start;	/* starting unibus address */
	short	length;		/* gap length */
}	map[MSIZE] =
{
	0160000, 017570
};

struct	t4	{
	char	indef[21];		/* input parameter keyword */
	char	oudef[21];		/* output definition symbol */
	char	value[21];		/* actual parameter value */
	char	defval[21];		/* default parameter value */
}	parms	[PSIZE];

struct	t	*lowptr[128];		/* low core double-word pointers */
struct	t2	*bdevices[BSIZE];	/* pointers to block devices */
struct	t2	*cdevices[CSIZE];	/* pointers to char. devices */
struct	t	*p;			/* configuration table pointer */
struct	t2	*q;			/* master device table pointer */
struct	t3	*r;			/* alias table pointer */
struct	t4	*kwdptr;		/* keyword table pointer */
struct	t	*locate();
struct	t2	*find();
struct	t4	*lookup();
char	*uppermap();

short	power	= 0;	/* power fail restart flag */
short	eflag	= 0;	/* error in configuration */
short	tflag	= 0;	/* table flag */
short	bmax	= -1;	/* dynamic max. major device number for block device */
short	cmax	= -1;	/* dynamic max. major device number for char. device */
short	blockex	= 0;	/* dynamic end of block device table */
short	charex	= 0;	/* dynamic end of character device table */
short	subv	= 0;	/* low core double-word subscript */
short	subtmp	= 0;	/* temporary; for subscripting */
short	abound	= -1;	/* current alias table size */
short	dbound	= -1;	/* current device table size */
short	tbound	= -1;	/* current configuration table size */
short	pbound	= -1;	/* current keyword table size */
short	mbound	= 0;	/* current address map table size */
short	rtmaj	= -1;	/* major device number for root device */
short	swpmaj	= -1;	/* major device number for swap device */
short	pipmaj	= -1;	/* major device number for pipe device */
short	dmpmaj	= -1;	/* major device number for dump device */
short	rtmin	= -1;	/* minor device number for root device */
short	swpmin	= -1;	/* minor device number for swap device */
short	pipmin	= -1;	/* minor device number for pipe device */
short	dmpmin	= -1;	/* minor device number for dump device */
long	swplo	= -1;	/* low disc address for swap area */
short	nswap	= -1;	/* number of disc blocks in swap area */
FILE	*fdconf;	/* configuration file descriptor */
FILE	*fdlow;		/* low core file descriptor */
char	*dmphndlr;	/* pointer to dump handler routine */
char	*mfile;		/* master device file */
char	*cfile;		/* output configuration table file */
char	*lfile;		/* output low core file */
char	*infile;	/* input configuration file */
char	line[101];	/* input line buffer area */
char	dump[81];	/* trap filler for dump routine */
char	pwrbuff[513];	/* power fail routine buffer */
char	initbuff[513];	/* initialization routine buffer */
char	xbuff[101];	/* buffer for external symbol definitions */
char	d[9];		/* buffer area */
char	capitals[9];	/* buffer area */
short	vec;		/* specified interrupt vector */
unsigned short add;	/* specified device address */
short	bl;		/* specified bus level */
short	ml;		/* specified device multiplicity */

char	*opterror =		/* option error message */
{
	"Option re-specification\n"
};

char	*sdev[] = {
	"dm11",
	"hisdm",
	NULL
};

main(argc,argv) 
int argc;
char *argv[];
{
	register i, l;
	register FILE *fd;
	int number;
	char input[21], buff[9], c, symbol[21];
	char *argv2;
	struct t *pt;
	argc--;
	argv++;
	argv2 = argv[0];
	argv++;
/*
 * Scan off the 'c', 'l', 'm', and 't' options.
 */
	while ((argc > 1) && (argv2[0] == '-')) {
		for (i=1; (c=argv2[i]) != NULL; i++) {
			switch (c) {
/*
 * Output configuration file specification
 */
			case 'c':	if (cfile) {
						printf (opterror);
						exit(1);
					}
					cfile = argv[0];
					argv++;
					argc--;
					break;
/*
 * Output univec file specification
 */
			case 'l':	if (lfile) {
						printf (opterror);
						exit(1);
					}
					lfile = argv[0];
					argv++;
					argc--;
					break;
/*
 * Input master table specification
 */
			case 'm':	if (mfile) {
						printf (opterror);
						exit(1);
					}
					mfile = argv[0];
					argv++;
					argc--;
					break;
/*
 * Table flag
 */
			case 't':	tflag++;
					break;

			default:	printf ("Unknown option\n");
					exit(1);
			}
		}
		argc--;
		argv2 = argv[0];
		argv++;
	}
	if (argc != 1) {
		printf ("Usage: config [-t][-l file][-c file][-m file] file\n");
		exit(1);
	}
/*
 * Set up defaults for unspecified files.
 */
	if (cfile == 0)
		cfile = "conf.c";
	if (lfile == 0)
		lfile = "univec.c";
	if (mfile == 0)
		mfile = "/etc/master";
	infile = argv2;
	fd = fopen (infile,"r");
	if (fd == NULL) {
		printf ("Open error for file -- %s\n",infile);
		exit(1);
	}
/*
 * Open configuration file and set modes.
 */
	fdconf = fopen (cfile,"w");
	if (fdconf == NULL) {
		printf ("Open error for file -- %s\n",cfile);
		exit(1);
	}
	chmod (cfile,0644);
/*
 * Print configuration file heading.
 */
	fprintf (fdconf,"/*\n *  Configuration information\n */\n\n\n");
	p = table;
/*
 * Read in the master device table and the alias table.
 */
	file();
/*
 * Start scanning the input.
 */
	while (fgets(line,100,fd) != NULL) {
		if (line[0] == '*')
			continue;
		l = sscanf(line,"%20s",input);
		if (l == 0) {
			error ("Incorrect line format");
			continue;
		}
		if (equal(input,"root")) {
/*
 * Root device specification
 */
			l = sscanf(line,"%*8s%8s%o",buff,&number);
			if (l != 2) {
				error ("Incorrect line format");
				continue;
			}
			if ((pt=locate(buff)) == 0) {
				error ("No such device");
				continue;
			}
			if ((pt->type & BLOCK) == 0) {
				error ("Not a block device");
				continue;
			}
			if (number > 255) {
				error ("Invalid minor device number");
				continue;
			}
			if (rtmin >= 0) {
				error ("Root re-specification");
				continue;
			}
			rtmin = number;
			rtmaj = pt->blk;
		}
		else
		    if (equal(input,"swap")) {
/*
 * Swap device specification
 */
			l = sscanf(line,"%*8s%8s%o%ld%hd",
					buff,&number,
					&swplo,&nswap);
			if (l != 4) {
				error ("Incorrect line format");
				continue;
			}
			if ((pt=locate(buff)) == 0) {
				error ("No such device");
				continue;
			}
			if ((pt->type & BLOCK) == 0) {
				error ("Not a block device");
				continue;
			}
			if (number > 255) {
				error ("Invalid minor device number");
				continue;
			}
			if (swpmin >= 0) {
				error ("Swap re-specification");
				continue;
			}
			if (nswap < 1) {
				error ("Invalid nswap");
				continue;
			}
			if (swplo < 0) {
				error ("Invalid swplo");
				continue;
			}
			swpmin = number;
			swpmaj = pt->blk;
		}
		else
		    if (equal(input,"pipe")) {
/*
 * Pipe device specification
 */
			l = sscanf(line,"%*8s%8s%o",buff,&number);
			if (l != 2) {
				error ("Incorrect line format");
				continue;
			}
			if ((pt=locate(buff)) == 0) {
				error ("No such device");
				continue;
			}
			if ((pt->type & BLOCK) == 0) {
				error ("Not a block device");
				continue;
			}
			if (number > 255) {
				error ("Invalid minor device number");
				continue;
			}
			if (pipmin >= 0) {
				error ("Pipe re-specification");
				continue;
			}
			pipmin = number;
			pipmaj = pt->blk;
		}
		else
		    if (equal(input,"dump")) {
/*
 * Dump device specification
 */
			l = sscanf(line,"%*8s%8s%o",buff,&number);
			if (l != 2) {
				error ("Incorrect line format");
				continue;
			}
			if ((pt=locate(buff)) == 0) {
				error ("No such device");
				continue;
			}
			if ((pt->type & BLOCK) == 0) {
				error ("Not a block device");
				continue;
			}
			if (number > 255) {
				error ("Invalid minor device number");
				continue;
			}
			if (dmpmin >= 0) {
				error ("Dump re-specification");
				continue;
			}
			dmpmin = number;
			dmpmaj = pt->blk;
			dmphndlr = pt->handler;
		}
		else {
/*
 * Device or parameter specification other than root, swap, pipe, or dump.
 * If power fail recovery is specified, remember it.
 */
			kwdptr = lookup(input);
			if (kwdptr) {
				l = sscanf(line,"%20s%20s",input,symbol);
				if (l != 2) {
					error ("Incorrect line format");
					continue;
				}
				if (strlen(kwdptr->value)) {
					error ("Parameter re-specification");
					continue;
				}
				if (equal(input,"power") && equal(symbol,"1"))
					power++;
				strcpy(kwdptr->value,symbol);
				continue;
			}
			l = sscanf(line,"%8s%ho%ho%hd%hd",d,&vec,&add,&bl,&ml);
			if (l < 4) {
				error ("Incorrect line format");
				continue;
			}
/*
 * Does such a device exist, and if so, do we allow its specification?
 */
			if ((q=find(d)) == 0) {
				error ("No such device");
				continue;
			}
			if ((q->type2 & ONCE) && (locate(d))) {
				error ("Only one specification allowed");
				continue;
			}
/*
 * Is the address valid?
 */
			if (q->asize) {
				if (add % 2) {
					error ("Address alignment");
					continue;
				}
				if (add < 0160000) {
					error ("Invalid address");
					continue;
				}
				if (addrcheck(add,q->asize)) {
					error ("Address collision");
					continue;
				}
			}
			else {
				if (add) {
					error ("Address not null");
					continue;
				}
			}
/*
 * If the vector size field is non-zero, process as a regular device.
 */
			if (q->vsize) {
/*
 * Is the interrupt vector on an appropriate boundary?
 */
				if (vec%q->vsize) {
					error ("Vector alignment");
					continue;
				}
/*
 * Is the interrupt vector in low core?
 */
				if (vec<0 || vec>0774) {
					error ("Vector not in low core range");
					continue;
				}
				switch (q->type2 & (FIX|FLT)) {
/*
 * This interrupt vector should be in the 0 - 0274 range.
 */
				case FIX:
					if (vec > 0274) {
						error ("Vector not in 0-0274 range");
						continue;
					}
					break;
/*
 * This interrupt vector should be in the 0300 - 0774 range.
 */
				case FLT:
					if (vec < 0300) {
						error ("Vector not in 0300-0774 range");
						continue;
					}
					break;
				}
/*
 * Is the bus request level a valid one for this device?
 */
				if (bl<4 || bl>q->busmax) {
					error ("Invalid bus level");
					continue;
				}
/*
 * Get the double-word offset for the interrupt vector.
 */
				subv = vec/4;
/*
 * Make sure the interrupt vector is free.
 */
				if (lowptr[subv]) {
					error ("Vector allocated");
					continue;
				}
				if (q->vsize == 8) {
					if (lowptr[subv+1]) {
						error ("Vector collision");
						continue;
					}
				}
			}
/*
 * Device is not interrupt driven, so interrupt vector and
   bus request levels should be zero.
 */
			else {
				if (vec) {
					error ("Interrupt vector not null");
					continue;
				}
				if (bl) {
					error ("Bus level not null");
					continue;
				}
				subv = 0;
			}
/*
 * See if the optional device multiplier was specified, and if so, see
 * if it is a valid one.
 */
			if (l == 5) {
				if ((ml > q->mult) || (ml < 1)) {
					error ("Invalid device multiplier");
					continue;
				}
			}
/*
 * Multiplier not specified, so take a default value from master device table.
 */
			else
				ml = q->mult;
/*
 * Fill in the contents of the configuration table node for this device.
 */
			enterdev(vec,add,bl,ml,d);
		}
	}
/*
 * Make sure that the root, swap, pipe and dump devices were specified.
 * Set up default values for tunable things where applicable.
 */
	if (rtmaj < 0) {
		printf ("root device not specified\n");
		eflag++;
	}
	if (swpmaj < 0) {
		printf ("swap device not specified\n");
		eflag++;
	}
	if (pipmaj < 0) {
		printf ("pipe device not specified\n");
		eflag++;
	}
	if (dmpmaj < 0) {
		printf ("dump device not specified\n");
		eflag++;
	}
	for (kwdptr=parms; kwdptr<= &parms[pbound]; kwdptr++) {
		if (strlen(kwdptr->value) == 0) {
			if (strlen(kwdptr->defval) == 0) {
				printf ("%s not specified\n",kwdptr->indef);
				eflag++;
			}
			strcpy(kwdptr->value,kwdptr->defval);
		}
	}
/*
 * See if configuration is to be terminated.
 */
	if (eflag) {
		printf ("\nConfiguration aborted.\n");
		exit (1);
	}
/*
 * Configuration is okay, so write the two files and quit.
 */
	for (q=devinfo; q<= &devinfo[dbound]; q++) {
		if (q->type2 & REQ) {
			if (!(locate(q->dev))) {
				enterdev(0,0,0,q->mult,q->dev);
			}
		}
	}

	prtconf();
	prtlow();
	exit(0);
}

/*
 * This routine writes out the univec program.
 */
prtlow()
{
	register int i;
	register struct t *ptr;
	register struct t *ktemp;
/*
 * Open univec file and set modes.
 */
	fdlow = fopen (lfile,"w");
	if (fdlow == NULL) {
		printf ("Open error for file -- %s\n",lfile);
		exit(1);
	}
	chmod (lfile,0644);
/*
 * Print some headings.
 */
	fprintf (fdlow,"/* Unibus vector table */\n\n");
	fprintf (fdlow,"#define	NULL	(int *)0\n");
	fprintf (fdlow,"#define	D0	0x00000000\n");
	fprintf (fdlow,"#define	D1	0x08000000\n");
	fprintf (fdlow,"#define	D2	0x10000000\n");
	fprintf (fdlow,"#define	D3	0x18000000\n");
	fprintf (fdlow,"#define	D4	0x20000000\n");
	fprintf (fdlow,"#define	D5	0x28000000\n");
	fprintf (fdlow,"#define	D6	0x30000000\n");
	fprintf (fdlow,"#define	D7	0x38000000\n");
	fprintf (fdlow,"\n/* Interrupt Service Routine addresses */\n");
/*
 * Go through configuration table and print out all required handler references.
 * For devices that are not interrupt driven, and those that have the
 * SUPP bit on, the printing of the handler name is suppressed.
 */
	for (ptr= table; ptr->devname!=0; ptr++) {
		if (ptr->count == 0) {
			if ((ptr->type & SUPP) || (ptr->vectsize == 0))
				continue;
			if (ptr->vectsize == 4) {
				fprintf (fdlow,"extern %sintr();\n",
					ptr->handler);
			}
			else {
				fprintf (fdlow,"extern %srint(), %sxint();\n",
					ptr->handler,
					ptr->handler);
			}
		}
	}
/*
 * Go through low core in double-word increments.
 */
	fprintf (fdlow,"int *UNIvec[128] = {\n");
	for (i=0; i<128; i++) {
		ktemp = lowptr[i];
/*
 * If the pointer is 0, set vector up for stray interrupt catcher.
 */
		if (ktemp == 0)
			fprintf (fdlow,"\tNULL,\n");
		else {
			fprintf (fdlow,"/* %o */\n",i*4);
/*
 * Pointer refers to a device, so set up the handler routine address with
 * the bus level and device sequence number, unless SUPP bit is on.
 */
			ptr = ktemp;
			if (ptr->vectsize == 8) {
				if (ptr->type & SUPP) {
					fprintf (fdlow,"\tNULL,\n");
					fprintf (fdlow,"\tNULL,\n");
				}
				else {
					fprintf (fdlow,"\t(int *)((int)%srint+D%d),\n",
						ptr->handler,
						ptr->count);
					fprintf (fdlow,"\t(int *)((int)%sxint+D%d),\n",
						ptr->handler,
						ptr->count);
				}
				i++;
			}
			else {
				if (ptr->type & SUPP) {
					fprintf (fdlow,"\tNULL,\n");
				}
				else {
					fprintf (fdlow,"\t(int *)((int)%sintr+D%d),\n",
						ptr->handler,
						ptr->count);
				}
			}
		}
	}
	fprintf (fdlow,"};\n");
}

/*
 * This routine is used to read in the master device table and the
 * alias table.  In the master device file, these two tables are separated
 * by a line that contains an asterisk in column 1.  
 */
file() 
{
	register l;
	register FILE *fd;
	fd = fopen(mfile,"r");
	if (fd == NULL) {
		printf ("Open error for file -- %s\n",mfile);
		exit(1);
	}
	q = devinfo;
	
	while (fgets(line,100,fd) != NULL) {
/*
 * Check for the delimiter that indicates the beginning of the
 * alias table entries.
 */
		if (line[0] == '$')
			break;
/*
 * Check for comment.
 */
		if (line[0] == '*')
			continue;
		dbound++;
		if (dbound == DSIZE) {
			printf ("Device table overflow\n");
			exit(1);
		}
		l = sscanf(line,"%8s%hd%ho%ho%4s%hd%hd%hd%hd%hd%8s%8s%8s",
			q->dev,&(q->vsize),&(q->mask),&(q->type2),
			q->hndlr,&(q->asize),&(q->block),
			&(q->charr),&(q->mult),&(q->busmax),
			q->entries[0],q->entries[1],q->entries[2]);
		if (l < 10) {
			printf ("%s\nDevice parameter count\n",line);
			exit(1);
		}
		if (q->type2 & REQ) {
			if (q->vsize || q->asize || q->busmax) {
				printf ("%s\nParameter inconsistency\n",line);
				exit(1);
			}
		}
/*
 * Update the ends of the block and character device tables.
 */
		if (q->type2 & BLOCK)
			if ((blockex = max(blockex,q->block)) >= BSIZE) {
				printf ("%s\nBad major device number\n",line);
				exit(1);
			}
		if (q->type2 & CHAR)
			if ((charex = max(charex,q->charr)) >= CSIZE) {
				printf ("%s\nBad major device number\n",line);
				exit(1);
			}
		q++;
	}
	r = alias;
	while (fgets(line,100,fd) != NULL) {
/*
 * Check for the delimiter that indicates the beginning of the
 * keyword table entries.
 */
		if (line[0] == '$')
			break;
/*
 * Check for comment.
 */
		if (line[0] == '*')
			continue;
		abound++;
		if (abound == ASIZE) {
			printf ("Alias table overflow\n");
			exit(1);
		}
		l = sscanf(line,"%8s%8s",r->new,r->old);
		if (l < 2) {
			printf ("%s\nAlias parameter count\n",line);
			exit(1);
		}
		r++;
	}
	kwdptr = parms;
	while (fgets(line,100,fd) != NULL) {
/*
 * Check for comment.
 */
		if (line[0] == '*')
			continue;
		pbound++;
		if (pbound == PSIZE) {
			printf ("Keyword table overflow\n");
			exit(1);
		}
		l = sscanf(line,"%20s%20s%20s",kwdptr->indef,
			kwdptr->oudef,kwdptr->defval);
		if (l < 2) {
			printf ("%s\nTunable parameter count\n",line);
			exit(1);
		}
		if (l == 2)
			*(kwdptr->defval) = NULL;
		kwdptr++;
	}
	return;
}

/*
 * This routine compares two null terminated strings for equality.
 */
equal(s1,s2)
register char *s1, *s2;
{
	while (*s1++ == *s2) {
		if (*s2++ == 0)
			return(1);
	}
	return(0);
}

/*
 * This routine is used to print a configuration time error message
 * and then set a flag indicating a contaminated configuration.
 */
error(message)
char *message;
{
	printf ("%s%s\n\n",line,message);
	eflag++;
	return;
}

/*
 * This routine is used to search through the master device table for
 * some specified device.  If the device is found, we return a pointer to 
 * the device.  If the device is not found, we search the alias table for
 * this device.  If the device is not found in the alias table, we return a
 * zero.  If the device is found, we change its name to the reference name of
 * the device and re-initiate the search for this new name in the master
 * device table.
 */
struct t2 *
find(device)
char *device;
{
	register struct t2 *q;
	register struct t3 *r;
	for (;;) {
/*
 * Search the master device table for the specified device.
 */
		for (q=devinfo; q<= &devinfo[dbound]; q++) {
			if (equal(device,q->dev))
				return(q);
		}
/*
 * Since the device was not found in the master device table,
 * we now search through the alias table.
 */
		for (r=alias; r<= &alias[abound]; r++) {
			if (equal(device,r->new)) {
				device = r->old;
				break;
			}
		}
/*
 * See if the device was found in the alias table. If it wasn't, return a 0.
 */
		if (r > &alias[abound])
			return(0);
/*
 * It was found in the alias table, so we change its name back to the
 * reference name of the device and re-initiate the master device table search.
 */
	}
}

/*
 * This routine is used to set the character and/or block table pointers
 * to point to an entry of the master device table.
 */
setq()
{
	register struct t2 *ptr;
/*
 * Do a switch on the type of device.
 */
	switch (q->type2 & (BLOCK|CHAR)) {
/*
 * Device is not a block or character device.
 */
	case 0:	break;
/*
 * Device is a character type device.
 */
	case CHAR:
		subtmp = q->charr;
		ptr = cdevices[subtmp];
		if (ptr) {
			if (!equal(ptr->dev,q->dev)) {
				charex++;
				if (charex == CSIZE) {
					printf("Character table overflow\n");
					exit(1);
				}
				q->charr = subtmp = charex;
			}
		}
		cdevices[subtmp] = q;
		cmax = max (cmax,subtmp);
		break;
/*
 * Device is a block type device.
 */
	case BLOCK:
		subtmp = q->block;
		ptr = bdevices[subtmp];
		if (ptr) {
			if (!equal(ptr->dev,q->dev)) {
				blockex++;
				if (blockex == BSIZE) {
					printf ("Block table overflow\n");
					exit(1);
				}
				q->block = subtmp = blockex;
			}
		}
		bdevices[subtmp] = q;
		bmax = max (bmax,subtmp);
		break;
/*
 * Device is both a character and block type device.
 */
	case BLOCK|CHAR:
		subtmp = q->charr;
		ptr = cdevices[subtmp];
		if (ptr) {
			if (!equal(ptr->dev,q->dev)) {
				charex++;
				if (charex == CSIZE) {
					printf("Character table overflow\n");
					exit(1);
				}
				q->charr = subtmp = charex;
			}
		}
		cdevices[subtmp] = q;
		cmax = max (cmax,subtmp);
		subtmp = q->block;
		ptr = bdevices[subtmp];
		if (ptr) {
			if (!equal(ptr->dev,q->dev)) {
				blockex++;
				if (blockex == BSIZE) {
					printf ("Block table overflow\n");
					exit(1);
				}
				q->block = subtmp = blockex;
			}
		}
		bdevices[subtmp] = q;
		bmax = max (bmax,subtmp);
		break;
	}
	return;
}

/*
 * This routine writes out the configuration file (C program.)
 */
prtconf()
{
	register i, j, counter;
	short k;
	char *sname;
	struct t2 *ptr;
/*
 * Print some headings.
 */
	fprintf (fdconf,"\n");
	for (kwdptr=parms; kwdptr<= &parms[pbound]; kwdptr++) {
		fprintf (fdconf,"#define\t%s\t%s\n",
			kwdptr->oudef, kwdptr->value);
	}
	fprintf (fdconf,"\n#include\t\"sys/param.h\"\n");
	fprintf (fdconf,"#include\t\"sys/io.h\"\n");
	fprintf (fdconf,"#include\t\"sys/space.h\"\n");
	fprintf (fdconf,"#include\t\"sys/conf.h\"\n");
	fprintf (fdconf,"#include\t\"sys/uba.h\"\n\n");

/*
 * Print the extern statement for the nodev and nulldev entries.
 */
	fprintf (fdconf,"extern nodev(), nulldev();\n");

/*
 * Search the configuration table and generate an extern statement for
 * any routines that are needed.
 */
	for (p=table; p<= &table[tbound]; p++) {
		if (p->count)
			continue;
		switch (p->type & (BLOCK|CHAR)) {
		case CHAR:
			q = find(p->devname);
			sprintf (xbuff,"extern ");
			if (q->mask & OPEN) {
				strcat (xbuff,q->hndlr);
				strcat (xbuff,"open(), ");
			}
			if (q->mask & CLOSE) {
				strcat (xbuff,q->hndlr);
				strcat (xbuff,"close(), ");
			}
			if (q->mask & READ) {
				strcat (xbuff,q->hndlr);
				strcat (xbuff,"read(), ");
			}
			if (q->mask & WRITE) {
				strcat (xbuff,q->hndlr);
				strcat (xbuff,"write(), ");
			}
			if (q->mask & IOCTL) {
				strcat (xbuff,q->hndlr);
				strcat (xbuff,"ioctl(), ");
			}
			if (q->mask & PWR)
				if (power) {
					strcat (xbuff,q->hndlr);
					strcat (xbuff,"clr(), ");
				}
			if (q->mask & INIT) {
				strcat (xbuff,q->hndlr);
				strcat (xbuff,"init(), ");
			}
			xbuff[strlen(xbuff)-2] = ';';
			xbuff[strlen(xbuff)-1] = NULL;
			fprintf (fdconf,"%s\n",xbuff);
			break;
		case BLOCK:
			fprintf (fdconf,"extern %sopen(), %sclose(), %sstrategy();\n",
				p->handler,p->handler,p->handler);
			fprintf (fdconf,"extern struct iobuf %stab;\n", p->handler);
			break;
		case BLOCK|CHAR:
			q = find(p->devname);
			sprintf (xbuff,"extern %sopen(), %sclose(), ",
				q->hndlr,q->hndlr);
			if (q->mask & READ) {
				strcat (xbuff,q->hndlr);
				strcat (xbuff,"read(), ");
			}
			if (q->mask & WRITE) {
				strcat (xbuff,q->hndlr);
				strcat (xbuff,"write(), ");
			}
			if (q->mask & IOCTL) {
				strcat (xbuff,q->hndlr);
				strcat (xbuff,"ioctl(), ");
			}
			if (q->mask & PWR)
				if (power) {
					strcat (xbuff,q->hndlr);
					strcat (xbuff,"clr(), ");
				}
			if (q->mask & INIT) {
				strcat (xbuff,q->hndlr);
				strcat (xbuff,"init(), ");
			}
			strcat (xbuff,q->hndlr);
			strcat (xbuff,"strategy();");
			fprintf (fdconf,"%s\n",xbuff);
			fprintf (fdconf,"extern struct iobuf %stab;\n", q->hndlr);
			break;
		}
	}

	fprintf (fdconf,"\nstruct bdevsw bdevsw[] = {\n");
/*
 * Go through block device table and indicate addresses of required routines.
 * If a particular device is not present, fill in "nodev" entries.
 */
	for (i=0; i<=bmax; i++) {
		ptr = bdevices[i];
		fprintf (fdconf,"/*%2d*/\t",i);
		if (ptr) {
			fprintf (fdconf,"%sopen,\t%sclose,\t%sstrategy,\t&%stab,\n",
				ptr->hndlr,
				ptr->hndlr,
				ptr->hndlr,
				ptr->hndlr);
		}
		else {
			fprintf (fdconf,"nodev, \tnodev, \tnodev, \t0, \n");
		}
	}
	fprintf (fdconf,"};\n\n");
	fprintf (fdconf,"struct cdevsw cdevsw[] = {\n");
/*
 * Go through character device table and indicate addresses of required
 * routines, or indicate "nulldev" if routine is not present.  If a 
 * particular device is not present, fill in "nodev" entries.
 */
	for (j=0; j<=cmax; j++) {
		ptr = cdevices[j];
		fprintf (fdconf,"/*%2d*/",j);
		if (ptr) {
			if (ptr->mask & OPEN)
				fprintf (fdconf,"\t%sopen,",ptr->hndlr);
			else
				fprintf (fdconf,"\tnulldev,");
			if (ptr->mask & CLOSE)
				fprintf (fdconf,"\t%sclose,",ptr->hndlr);
			else
				fprintf (fdconf,"\tnulldev,");
			if (ptr->mask & READ)
				fprintf (fdconf,"\t%sread,",ptr->hndlr);
			else
				fprintf (fdconf,"\tnodev, ");
			if (ptr->mask & WRITE)
				fprintf (fdconf,"\t%swrite,",ptr->hndlr);
			else
				fprintf (fdconf,"\tnodev, ");
			if (ptr->mask & IOCTL)
				fprintf (fdconf,"\t%sioctl,\n",ptr->hndlr);
			else
				fprintf (fdconf,"\tnodev, \n");
		}
		else
			fprintf (fdconf,"\tnodev, \tnodev, \tnodev, \tnodev, \tnodev,\n");
	}
/*
 * Print out block and character device counts, root, swap, and dump device
 * information, and the swplo, and nswap values.
 */
	fprintf (fdconf,"};\n\n");
	fprintf (fdconf,"int\tbdevcnt = %d;\nint\tcdevcnt = %d;\n\n",i,j);
	fprintf (fdconf,"dev_t\trootdev = makedev(%d, %d);\n",rtmaj,rtmin);
	fprintf (fdconf,"dev_t\tpipedev = makedev(%d, %d);\n",pipmaj,pipmin);
	fprintf (fdconf,"dev_t\tdumpdev = makedev(%d, %d);\n",dmpmaj,dmpmin);
	fprintf (fdconf,"dev_t\tswapdev = makedev(%d, %d);\n",swpmaj,swpmin);
	fprintf (fdconf,"daddr_t\tswplo = %lu;\nint\tnswap = %d;\n\n",swplo,nswap);
/*
 * Initialize the power fail and init handler buffers.
 */
	sprintf (pwrbuff,"\nint\t(*pwr_clr[])() = \n{\n");
	sprintf (initbuff,"\nint\t(*dev_init[])() = \n{\n");
/*
 * Go through the block device table, ignoring any zero entries.
 * Add power fail and init handler entries to the buffers as appropriate.
 */
	if (tflag)
		printf ("Block Devices\nmajor\tdevice\thandler\tcount\n");
	for (i=0; i<=bmax; i++) {
		if ((q=bdevices[i]) == 0)
			continue;
		if (power)
			if (q->mask & PWR)
				sprintf (&pwrbuff[strlen(pwrbuff)],"\t%sclr,\n",q->hndlr);
		if (q->mask & INIT)
				sprintf (&initbuff[strlen(initbuff)],"\t&%sinit,\n",q->hndlr);
		counter = 0;
/*
 * For each of these devices, go through the configuration table and
 * look for matches. For each match, print the device address, and keep
 * a count of the number of matches.
 */
		fprintf (fdconf,"\n");
		if (q->asize)
			fprintf (fdconf,"int\t%s_addr[] = {\n",q->hndlr);
		for (p=table; p<= &table[tbound]; p++) {
			if (equal(q->dev,p->devname)) {
				if (q->asize)
					fprintf(fdconf,"\tUBA_DEV+%.7o,\n",p->address);
				counter += p->mlt;
			}
		}
		if (q->asize)
			fprintf (fdconf,"};\n");
		if (!(q->type2 & NOCNT))
			fprintf (fdconf,"int\t%s_cnt = %d;\n",
				q->hndlr,counter);
		if (tflag)
			printf ("%2d\t%s\t%s\t%2d\n",i,q->dev,q->hndlr,counter);
		q->acount = counter;
/*
 * Print any required structure definitions.
 */
		for (j=0; j<3; j++) {
			if (*(q->entries[j]) != NULL)
				fprintf (fdconf,"struct\t%s\t%s_%s[%d];\n",
					q->entries[j],q->hndlr,
					q->entries[j],counter);
		}
	}
/*
 * Go through the character device table, ignoring any zero entries,
 * as well as those that are not strictly character devices.
 * Add power fail and init handler entries to the buffers as appropriate.
 */
	if (tflag)
		printf ("Character Devices\nmajor\tdevice\thandler\tcount\n");
	for (i=0; i<=cmax; i++) {
		if ((q=cdevices[i]) == 0)
			continue;
		if ((q->type2 & (BLOCK|CHAR)) != CHAR) {
			if (tflag)
				printf ("%2d\t%s\t%s\t%2d\n",i,q->dev,q->hndlr,q->acount);
			continue;
		}
		if (power)
			if (q->mask & PWR)
				sprintf (&pwrbuff[strlen(pwrbuff)],"\t%sclr,\n",q->hndlr);
		if (q->mask & INIT)
				sprintf (&initbuff[strlen(initbuff)],"\t&%sinit(),\n",q->hndlr);
		counter = 0;
/*
 * For each of these devices, go through the configuration table and
 * look for matches. For each match, print the device address, and keep
 * a count of the number of matches.
 */
		fprintf (fdconf,"\n");
		if (q->asize)
			fprintf (fdconf,"int\t%s_addr[] = {\n",q->hndlr);
		for (p=table; p<= &table[tbound]; p++) {
			if (equal(q->dev,p->devname)) {
				if (q->asize)
					fprintf(fdconf,"\tUBA_DEV+%.7o,\n",p->address);
				counter += p->mlt;
			}
		}
		if (q->asize)
			fprintf (fdconf,"};\n");
		if (!(q->type2 & NOCNT))
			fprintf (fdconf,"int\t%s_cnt = %d;\n",
				q->hndlr,counter);
		if (tflag)
			printf ("%2d\t%s\t%s\t%2d\n",i,q->dev,q->hndlr,counter);
/*
 * Print any required structure definitions.
 */
		for (j=0; j<3; j++) {
			if (*(q->entries[j]) != NULL)
				fprintf (fdconf,"struct\t%s\t%s_%s[%d];\n",
					q->entries[j],q->hndlr,
					q->entries[j],counter);
		}
	}
/*
 * Repeat this swill for the weirdo devices.
 */
	for (k=0; (sname=sdev[k]) != NULL; k++)
		if (locate(sname)) {
			q = find(sname);
			counter = 0;
			fprintf (fdconf,"\nint\t%s_addr[] = {\n",q->hndlr);
			for (p=table; p<= &table[tbound]; p++) {
				if (equal (p->devname,sname)) {
					fprintf (fdconf,"\tUBA_DEV+%.7o,\n",p->address);
					counter += p->mlt;
				}
			}
			fprintf (fdconf,"};\n");
			if (!(q->type2 & NOCNT))
				fprintf (fdconf,"int\t%s_cnt = %d;\n",
					q->hndlr,counter);
			for (j=0; j<3; j++) {
				if (*(q->entries[j]) != NULL)
					fprintf (fdconf,"struct\t%s\t%s_%s[%d];\n",
						q->entries[j],q->hndlr,
						q->entries[j],counter);
			}
		}
/*
 * Write out NULL entry into power fail and init buffers.
 * Then write the buffers out into the configuration file.
 */
	sprintf (&pwrbuff[strlen(pwrbuff)],"\t(int (*)())0\n};\n");
	sprintf (&initbuff[strlen(initbuff)],"\t(int (*)())0\n};\n");
	fprintf (fdconf,"%s",pwrbuff);
	fprintf (fdconf,"%s",initbuff);
	return;
}

max(a,b)
int a, b;
{
	return (a>b ? a:b);
}

/*
 * This routine is used to search the configuration table for some
 * specified device.  If the device is found we return a pointer to
 * that device.  If the device is not found, we search the alias
 * table for this device.  If the device is not found in the alias table
 * we return a zero.  If the device is found, we change its name to
 * the reference name of the device and re-initiate the search for this
 * new name in the configuration table.
 */

struct t *
locate(device)
char *device;
{
	register struct t *p;
	register struct t3 *r;
	for (;;) {
/*
 * Search the configuration table for the specified device.
 */
		for (p=table; p<= &table[tbound]; p++) {
			if (equal(device,p->devname))
				return(p);
		}
/*
 * Since the device was not found in the configuration table, we now
 * search through the alias table.
 */
		for (r=alias; r<= &alias[abound]; r++) {
			if (equal(device,r->new)) {
				device = r->old;
				break;
			}
		}
/*
 * See if the device was found in the alias table. If it wasn't, return a 0.
 */
		if (r > &alias[abound])
			return(0);
/*
 * It was found in alias table, so we change its name back to the
 * reference name of the device and re-initiate the configuration
 * table search.
 */
	}
}

/*
 * This routine is used to search the parameter table
 * for the keyword that was specified in the configuration.  If the
 * keyword cannot be found in this table, a value of zero is returned.
 * If the keyword is found, a pointer to that entry is returned.
 */
struct t4 *
lookup(keyword)
char *keyword;
{
	register struct t4 *kwdptr;
	for (kwdptr=parms; kwdptr<= &parms[pbound]; kwdptr++) {
		if (equal(keyword,kwdptr->indef))
			return (kwdptr);
	}
	return(0);
}

/*
 * This routine is used to map lower case alphabetics into upper case.
 */
char *
uppermap(device,caps)
char *device;
char *caps;
{
	register char *ptr;
	register char *ptr2;
	ptr2 = caps;
	for (ptr=device; *ptr!=NULL; ptr++) {
		if ('a' <= *ptr && *ptr <= 'z')
			*ptr2++ = *ptr + 'A' - 'a';
		else
			*ptr2++ = *ptr;
	}
	*ptr2 = NULL;
	return (caps);
}

/*
 * This routine enters the device in the configuration table.
 */
enterdev(vec,add,bl,ml,name)
int	vec, bl, ml;
unsigned	add;
char	*name;
{
	tbound++;
	if (tbound == TSIZE) {
		printf ("Configuration table overflow\n");
		exit(1);
	}
/*
 * Write upper case define statement and sequence number for device.
 */
	fprintf (fdconf,"#define\t%s_%d 1\n",
		uppermap (name,capitals),
		q->dcount);
	if (q->vsize)
		setlow(vec);
	setq();
	p->devname = q->dev;
	p->vector = vec;
	p->address = add;
	p->buslevel = bl;
	p->addrsize = q->asize;
	p->vectsize = q->vsize;
	p->type = q->type2;
	p->handler = q->hndlr;
	p->count = q->dcount;
	p->mlt = ml;
	p->blk = q->block;
	p->chr = q->charr;
	p++;
	q->dcount++;
	return;
}

/*
 * This routine enters the appropriate pointer for the device
 * into low core.
 */
setlow(vec)
int vec;
{
	subv = vec/4;
	if (q->vsize == 8)
		lowptr[subv+1] = p;
	lowptr[subv] = p;
	return;
}

addrcheck(add,size)
unsigned short add;
short size;
{
	register struct map *mp;
	register struct map *hold;

	for (mp= &map[mbound]; mp >= map; mp--) {
		if (add >= mp->start) {
			if ((add+size) > (mp->start+mp->length))
				return(1);
			if ((add == mp->start) &&
				((size+add)==(mp->start+mp->length))) {
				mbound--;
				while (mp <= &map[mbound]) {
					mp->start = (mp+1)->start;
					mp->length = (mp+1)->length;
					mp++;
				}
				return(0);
			}
			if (add == mp->start) {
				mp->start += size;
				mp->length -= size;
				return(0);
			}
			if ((size + add) == (mp->start + mp->length)) {
				mp->length -= size;
				return(0);
			}
			hold = mp;
			if ((mbound + 1) == MSIZE) {
				printf ("Address map table overflow\n");
				exit(1);
			}
			for (mp= &map[mbound]; mp >= hold; mp--) {
				(mp+1)->start = mp->start;
				(mp+1)->length = mp->length;
			}
			mp++;
			mp->length = add - mp->start;
			(mp+1)->start = size + add;
			(mp+1)->length = (mp+1)->length-(size+add)+mp->start;
			mbound++;
			return(0);
		}
	}
	return(1);
}