/*
 * Copyright (c) 1983 Regents of the University of California.
 * All rights reserved. The Berkeley Software License Agreement
 * specifies the terms and conditions for redistribution.
 */
/* $Header:mkioconf.c 12.0$ */
/* $ACIS:mkioconf.c 12.0$ */
/* $Source: /ibm/acis/usr/src/etc/config/RCS/mkioconf.c,v $ */

#ifndef lint
static char *rcsid = "$Header:mkioconf.c 12.0$";
#endif

#ifndef lint
static char sccsid[] = "@(#)mkioconf.c	2.9 (Berkeley) 8/11/83";
#endif

#include <stdio.h>
#include "y.tab.h"
#include "config.h"

/*
 * build the ioconf.c file
 */
char	*qu();
char	*intv();

#if MACHINE_VAX
vax_ioconf()
{
	register struct device *dp, *mp, *np;
	register int uba_n, slave;
	FILE *fp;

	fp = fopen(path("ioconf.c"), "w");
	if (fp == 0) {
		perror(path("ioconf.c"));
		exit(1);
	}
	fprintf(fp, "#include \"../machine/pte.h\"\n");
	fprintf(fp, "#include \"../h/param.h\"\n");
	fprintf(fp, "#include \"../h/buf.h\"\n");
	fprintf(fp, "#include \"../h/map.h\"\n");
	fprintf(fp, "#include \"../h/vm.h\"\n");
	fprintf(fp, "\n");
	fprintf(fp, "#include \"../vaxmba/mbavar.h\"\n");
	fprintf(fp, "#include \"../vaxuba/ubavar.h\"\n\n");
	fprintf(fp, "\n");
	fprintf(fp, "#define C (caddr_t)\n\n");
	/*
	 * First print the mba initialization structures
	 */
	if (seen_mba) {
		for (dp = dtab; dp != 0; dp = dp->d_next) {
			mp = dp->d_conn;
			if (mp == 0 || mp == TO_NEXUS ||
			    !eq(mp->d_name, "mba"))
				continue;
			fprintf(fp, "extern struct mba_driver %sdriver;\n",
			    dp->d_name);
		}
		fprintf(fp, "\nstruct mba_device mbdinit[] = {\n");
		fprintf(fp, "\t/* Device,  Unit, Mba, Drive, Dk */\n");
		for (dp = dtab; dp != 0; dp = dp->d_next) {
			mp = dp->d_conn;
			if (dp->d_unit == QUES || mp == 0 ||
			    mp == TO_NEXUS || !eq(mp->d_name, "mba"))
				continue;
			if (dp->d_addr) {
				printf("can't specify csr address on mba for %s%d\n",
				    dp->d_name, dp->d_unit);
				continue;
			}
			if (dp->d_vec != 0) {
				printf("can't specify vector for %s%d on mba\n",
				    dp->d_name, dp->d_unit);
				continue;
			}
			if (dp->d_drive == UNKNOWN) {
				printf("drive not specified for %s%d\n",
				    dp->d_name, dp->d_unit);
				continue;
			}
			if (dp->d_slave != UNKNOWN) {
				printf("can't specify slave number for %s%d\n",
				    dp->d_name, dp->d_unit);
				continue;
			}
			fprintf(fp, "\t{ &%sdriver, %d,   %s,",
				dp->d_name, dp->d_unit, qu(mp->d_unit));
			fprintf(fp, "  %s,  %d },\n",
				qu(dp->d_drive), dp->d_dk);
		}
		fprintf(fp, "\t0\n};\n\n");
		/*
		 * Print the mbsinit structure
		 * Driver Controller Unit Slave
		 */
		fprintf(fp, "struct mba_slave mbsinit [] = {\n");
		fprintf(fp, "\t/* Driver,  Ctlr, Unit, Slave */\n");
		for (dp = dtab; dp != 0; dp = dp->d_next) {
			/*
			 * All slaves are connected to something which
			 * is connected to the massbus.
			 */
			if ((mp = dp->d_conn) == 0 || mp == TO_NEXUS)
				continue;
			np = mp->d_conn;
			if (np == 0 || np == TO_NEXUS ||
			    !eq(np->d_name, "mba"))
				continue;
			fprintf(fp, "\t{ &%sdriver, %s",
			    mp->d_name, qu(mp->d_unit));
			fprintf(fp, ",  %2d,    %s },\n",
			    dp->d_unit, qu(dp->d_slave));
		}
		fprintf(fp, "\t0\n};\n\n");
	}
	/*
	 * Now generate interrupt vectors for the unibus
	 */
	for (dp = dtab; dp != 0; dp = dp->d_next) {
		if (dp->d_vec != 0) {
			struct idlst *ip;
			mp = dp->d_conn;
			if (mp == 0 || mp == TO_NEXUS ||
			    !eq(mp->d_name, "uba"))
				continue;
			fprintf(fp,
			    "extern struct uba_driver %sdriver;\n",
			    dp->d_name);
			fprintf(fp, "extern ");
			ip = dp->d_vec;
			for (;;) {
				fprintf(fp, "X%s%d()", ip->id, dp->d_unit);
				ip = ip->id_next;
				if (ip == 0)
					break;
				fprintf(fp, ", ");
			}
			fprintf(fp, ";\n");
			fprintf(fp, "int\t (*%sint%d[])() = { ", dp->d_name,
			    dp->d_unit, dp->d_unit);
			ip = dp->d_vec;
			for (;;) {
				fprintf(fp, "X%s%d", ip->id, dp->d_unit);
				ip = ip->id_next;
				if (ip == 0)
					break;
				fprintf(fp, ", ");
			}
			fprintf(fp, ", 0 } ;\n");
		}
	}
	fprintf(fp, "\nstruct uba_ctlr ubminit[] = {\n");
	fprintf(fp, "/*\t driver,\tctlr,\tubanum,\talive,\tintr,\taddr */\n");
	for (dp = dtab; dp != 0; dp = dp->d_next) {
		mp = dp->d_conn;
		if (dp->d_type != CONTROLLER || mp == TO_NEXUS || mp == 0 ||
		    !eq(mp->d_name, "uba"))
			continue;
		if (dp->d_vec == 0) {
			printf("must specify vector for %s%d\n",
			    dp->d_name, dp->d_unit);
			continue;
		}
		if (dp->d_addr == 0) {
			printf("must specify csr address for %s%d\n",
			    dp->d_name, dp->d_unit);
			continue;
		}
		if (dp->d_drive != UNKNOWN || dp->d_slave != UNKNOWN) {
			printf("drives need their own entries; dont ");
			printf("specify drive or slave for %s%d\n",
			    dp->d_name, dp->d_unit);
			continue;
		}
		if (dp->d_flags) {
			printf("controllers (e.g. %s%d) ",
			    dp->d_name, dp->d_unit);
			printf("don't have flags, only devices do\n");
			continue;
		}
		fprintf(fp,
		    "\t{ &%sdriver,\t%d,\t%s,\t0,\t%sint%d, C 0%o },\n",
		    dp->d_name, dp->d_unit, qu(mp->d_unit),
		    dp->d_name, dp->d_unit, dp->d_addr);
	}
	fprintf(fp, "\t0\n};\n");
/* unibus devices */ 
	fprintf(fp, "\nstruct uba_device ubdinit[] = {\n");
	fprintf(fp,
"\t/* driver,  unit, ctlr,  ubanum, slave,   intr,    addr,    dk, flags*/\n");
	for (dp = dtab; dp != 0; dp = dp->d_next) {
		mp = dp->d_conn;
		if (dp->d_unit == QUES || dp->d_type != DEVICE || mp == 0 ||
		    mp == TO_NEXUS || mp->d_type == MASTER ||
		    eq(mp->d_name, "mba"))
			continue;
		np = mp->d_conn;
		if (np != 0 && np != TO_NEXUS && eq(np->d_name, "mba"))
			continue;
		np = 0;
		if (eq(mp->d_name, "uba")) {
			if (dp->d_vec == 0) {
				printf("must specify vector for device %s%d\n",
				    dp->d_name, dp->d_unit);
				continue;
			}
			if (dp->d_addr == 0) {
				printf("must specify csr for device %s%d\n",
				    dp->d_name, dp->d_unit);
				continue;
			}
			if (dp->d_drive != UNKNOWN || dp->d_slave != UNKNOWN) {
				printf("drives/slaves can be specified ");
				printf("only for controllers, ");
				printf("not for device %s%d\n",
				    dp->d_name, dp->d_unit);
				continue;
			}
			uba_n = mp->d_unit;
			slave = QUES;
		} else {
			if ((np = mp->d_conn) == 0) {
				printf("%s%d isn't connected to anything ",
				    mp->d_name, mp->d_unit);
				printf(", so %s%d is unattached\n",
				    dp->d_name, dp->d_unit);
				continue;
			}
			uba_n = np->d_unit;
			if (dp->d_drive == UNKNOWN) {
				printf("must specify ``drive number'' ");
				printf("for %s%d\n", dp->d_name, dp->d_unit);
				continue;
			}
			/* NOTE THAT ON THE UNIBUS ``drive'' IS STORED IN */
			/* ``SLAVE'' AND WE DON'T WANT A SLAVE SPECIFIED */
			if (dp->d_slave != UNKNOWN) {
				printf("slave numbers should be given only ");
				printf("for massbus tapes, not for %s%d\n",
				    dp->d_name, dp->d_unit);
				continue;
			}
			if (dp->d_vec != 0) {
				printf("interrupt vectors should not be ");
				printf("given for drive %s%d\n",
				    dp->d_name, dp->d_unit);
				continue;
			}
			if (dp->d_addr != 0) {
				printf("csr addresses should be given only ");
				printf("on controllers, not on %s%d\n",
				    dp->d_name, dp->d_unit);
				continue;
			}
			slave = dp->d_drive;
		}
		fprintf(fp, "\t{ &%sdriver,  %2d,   %s,",
		    eq(mp->d_name, "uba") ? dp->d_name : mp->d_name, dp->d_unit,
		    eq(mp->d_name, "uba") ? " -1" : qu(mp->d_unit));
		fprintf(fp, "  %s,    %2d,   %s, C 0%-6o,  %d,  0x%x },\n",
		    qu(uba_n), slave, intv(dp), dp->d_addr, dp->d_dk,
		    dp->d_flags);
	}
	fprintf(fp, "\t0\n};\n");
	(void) fclose(fp);
}
#endif

#if MACHINE_SUN
sun_ioconf()
{
	register struct device *dp, *mp;
	register int slave;
	FILE *fp;

	fp = fopen(path("ioconf.c"), "w");
	if (fp == 0) {
		perror(path("ioconf.c"));
		exit(1);
	}
	fprintf(fp, "#include \"../h/param.h\"\n");
	fprintf(fp, "#include \"../h/buf.h\"\n");
	fprintf(fp, "#include \"../h/map.h\"\n");
	fprintf(fp, "#include \"../h/vm.h\"\n");
	fprintf(fp, "\n");
	fprintf(fp, "#include \"../sundev/mbvar.h\"\n");
	fprintf(fp, "\n");
	fprintf(fp, "#define C (caddr_t)\n\n");
	fprintf(fp, "\n");
	/*
	 * Now generate interrupt vectors for the Multibus
	 */
	for (dp = dtab; dp != 0; dp = dp->d_next) {
		if (dp->d_pri != 0) {
			mp = dp->d_conn;
			if (mp == 0 || mp == TO_NEXUS ||
			    !eq(mp->d_name, "mb"))
				continue;
			fprintf(fp, "extern struct mb_driver %sdriver;\n",
			    dp->d_name);
		}
	}
	/*
	 * Now spew forth the mb_cinfo structure
	 */
	fprintf(fp, "\nstruct mb_ctlr mbcinit[] = {\n");
	fprintf(fp, "/*\t driver,\tctlr,\talive,\taddr,\tintpri */\n");
	for (dp = dtab; dp != 0; dp = dp->d_next) {
		mp = dp->d_conn;
		if (dp->d_type != CONTROLLER || mp == TO_NEXUS || mp == 0 ||
		    !eq(mp->d_name, "mb"))
			continue;
		if (dp->d_pri == 0) {
			printf("must specify priority for %s%d\n",
			    dp->d_name, dp->d_unit);
			continue;
		}
		if (dp->d_addr == 0) {
			printf("must specify csr address for %s%d\n",
			    dp->d_name, dp->d_unit);
			continue;
		}
		if (dp->d_drive != UNKNOWN || dp->d_slave != UNKNOWN) {
			printf("drives need their own entries; ");
			printf("dont specify drive or slave for %s%d\n",
			    dp->d_name, dp->d_unit);
			continue;
		}
		if (dp->d_flags) {
			printf("controllers (e.g. %s%d) don't have flags, ");
			printf("only devices do\n",
			    dp->d_name, dp->d_unit);
			continue;
		}
		fprintf(fp, "\t{ &%sdriver,\t%d,\t0,\tC 0x%x,\t%d },\n",
		    dp->d_name, dp->d_unit, dp->d_addr, dp->d_pri);
	}
	fprintf(fp, "\t0\n};\n");
	/*
	 * Now we go for the mb_device stuff
	 */
	fprintf(fp, "\nstruct mb_device mbdinit[] = {\n");
	fprintf(fp,
"\t/* driver,  unit, ctlr,  slave,   addr,    pri,    dk, flags*/\n");
	for (dp = dtab; dp != 0; dp = dp->d_next) {
		mp = dp->d_conn;
		if (dp->d_unit == QUES || dp->d_type != DEVICE || mp == 0 ||
		    mp == TO_NEXUS || mp->d_type == MASTER ||
		    eq(mp->d_name, "mba"))
			continue;
		if (eq(mp->d_name, "mb")) {
			if (dp->d_pri == 0) {
				printf("must specify vector for device %s%d\n",
				    dp->d_name, dp->d_unit);
				continue;
			}
			if (dp->d_addr == 0) {
				printf("must specify csr for device %s%d\n",
				    dp->d_name, dp->d_unit);
				continue;
			}
			if (dp->d_drive != UNKNOWN || dp->d_slave != UNKNOWN) {
				printf("drives/slaves can be specified only ");
				printf("for controllers, not for device %s%d\n",
				    dp->d_name, dp->d_unit);
				continue;
			}
			slave = QUES;
		} else {
			if (mp->d_conn == 0) {
				printf("%s%d isn't connected to anything, ",
				    mp->d_name, mp->d_unit);
				printf("so %s%d is unattached\n",
				    dp->d_name, dp->d_unit);
				continue;
			}
			if (dp->d_drive == UNKNOWN) {
				printf("must specify ``drive number'' for %s%d\n",
				   dp->d_name, dp->d_unit);
				continue;
			}
			/* NOTE THAT ON THE UNIBUS ``drive'' IS STORED IN */
			/* ``SLAVE'' AND WE DON'T WANT A SLAVE SPECIFIED */
			if (dp->d_slave != UNKNOWN) {
				printf("slave numbers should be given only ");
				printf("for massbus tapes, not for %s%d\n",
				    dp->d_name, dp->d_unit);
				continue;
			}
			if (dp->d_pri != 0) {
				printf("interrupt priority should not be ");
				printf("given for drive %s%d\n",
				    dp->d_name, dp->d_unit);
				continue;
			}
			if (dp->d_addr != 0) {
				printf("csr addresses should be given only");
				printf("on controllers, not on %s%d\n",
				    dp->d_name, dp->d_unit);
				continue;
			}
			slave = dp->d_drive;
		}
		fprintf(fp,
"\t{ &%sdriver,  %2d,   %s,    %2d,   C 0x%x, %d,  %d,  0x%x },\n",
		    eq(mp->d_name, "mb") ? dp->d_name : mp->d_name, dp->d_unit,
		    eq(mp->d_name, "mb") ? " -1" : qu(mp->d_unit),
		    slave, dp->d_addr, dp->d_pri, dp->d_dk, dp->d_flags);
	}
	fprintf(fp, "\t0\n};\n");
	(void) fclose(fp);
}
#endif

#if MACHINE_IBM370

#define NOTUSED 0
#define	MAX_CHAN	16

#define	getCtlr(a) \
	(chnlInfo[((a)&0x1f00)>>8].locators[((a)&0xf0)>>4]->locations[(a)&0xf].controller)

struct unit {
    struct unit *next;
    struct device *device;
    int ordinal;
};

struct locator {
    struct locator *next;
    int ordinal;
    struct location {
	struct unit *controller;	/* Pointer to controller */
	struct unit *device;		/* Pointer to device */
    } locations[16];
};

struct chnlInfo {
    char *name;
    struct locator *locators[16];
} chnlInfo[MAX_CHAN];

struct driverInfo {
    struct driverInfo *next;	/* link */
    char *name;		/* "name" of this driver (eg: "fd") */
    int		units[32];
};

static struct driverInfo *driverHead = 0;

static struct locator
	*headLocator = 0,
	*tailLocator = 0;

static struct unit
	*headCtlr = 0,
	*tailCtlr = 0,
	*headDevice = 0,
	*tailDevice = 0;

static int
	nextLocator = 0,
	nextCtlr = 0,
	nextDevice = 0;

int bits[32] = {
    0x80000000, 0x40000000, 0x20000000, 0x10000000,
    0x08000000, 0x04000000, 0x02000000, 0x01000000,
    0x00800000, 0x00400000, 0x00200000, 0x00100000,
    0x00080000, 0x00040000, 0x00020000, 0x00010000,
    0x00008000, 0x00004000, 0x00002000, 0x00001000,
    0x00000800, 0x00000400, 0x00000200, 0x00000100,
    0x00000080, 0x00000040, 0x00000020, 0x00000010,
    0x00000008, 0x00000004, 0x00000002, 0x00000001 };

#define	BIT_CHK(di,n)	((di)->units[(n)/32]&bits[(n)%32])
#define	BIT_ON(di,n)	(di)->units[(n)/32] |= bits[(n)%32]
#define	BIT_OFF(di,n)	(di)->units[(n)/32] &= ~bits[(n)%32]

char *
savestr(string)
char *string;
{
    char *saved;
    int n = strlen(string)+1;

    saved = malloc(n);
    if (saved == 0) {
	return 0;
    } else {
	bcopy(string, saved, n);
	return saved;
    }
}

static void
makedevice(dp)
struct device *dp;
{
    struct locator **loclocator;
    struct locator **firstlocator, **lastlocator;
    struct location *firstlocation, *lastlocation;
    struct location *location;
    struct chnlInfo *channel;
    struct unit *device;
    struct device *ndp;
    int i;
    int currentAddress;
    int lastAddress;

    if (dp->d_conn && (dp->d_conn->d_type != MASTER)) {
	struct unit *controller;

	controller = getCtlr(dp->d_addr);
	ndp = controller->device;
	if ((dp->d_addr < ndp->d_addr) ||
		((dp->d_addr+dp->d_pri) > (ndp->d_addr+ndp->d_pri))) {
	    fprintf(stderr, "Device %s%d at 0x%x",
				    dp->d_name, dp->d_unit, dp->d_addr);
	    if (dp->d_pri != 1) {
		fprintf(stderr, " for %d devices", dp->d_pri);
	    }
	    fprintf(stderr,
		":\n\ttoo many units for controller %s%d (0x%03x-0x%03x).\n",
		ndp->d_name, ndp->d_unit, ndp->d_addr,
		ndp->d_addr+ndp->d_pri-1);
	    dp->d_pri = ndp->d_addr+ndp->d_pri-dp->d_addr;
	}
    }

    channel = chnlInfo+((dp->d_addr&0xf00)>>8);

    firstlocator = channel->locators+((dp->d_addr&0x0f0)>>4);
    lastlocator = channel->locators+(((dp->d_addr+dp->d_pri-1)&0xf0)>>4);
    currentAddress = dp->d_addr;
    lastAddress = dp->d_addr+dp->d_pri-1;
    for (loclocator = firstlocator; loclocator <= lastlocator; loclocator++) {
	if (*loclocator == 0) {
	    *loclocator = (struct locator *) malloc(sizeof **loclocator);
	    if (*loclocator == 0) {
		fprintf(stderr, "No memory for locator block.\n");
		exit(1);
	    }
	    if (headLocator) {
		tailLocator->next = *loclocator;
		tailLocator = *loclocator;
	    } else {
		tailLocator = headLocator = *loclocator;
	    }
	    (*loclocator)->next = 0;
	    (*loclocator)->ordinal = ++nextLocator;
	    for (location = (*loclocator)->locations;
			location < ((*loclocator)+16)->locations; location++) {
		location->controller = NOTUSED;
		location->device = NOTUSED;
	    }
	}
	firstlocation = (*loclocator)->locations+(currentAddress&0xf);
	if ((lastAddress&~0xf) == (currentAddress&~0xf)) {
	    i = lastAddress&0xf;
	} else {
	    i = 0xf;
	}
	lastlocation = (*loclocator)->locations+i;
	for (location = firstlocation; location <= lastlocation; location++) {
	    if (location->device != NOTUSED) {
		ndp = location->device->device;
		fprintf(stderr, "Device %s%d at 0x%03x for %d:\n",
			    dp->d_name, dp->d_unit, dp->d_addr, dp->d_pri);
		fprintf(stderr, "\tintersects with %s%d at 0x%03x for %d.\n",
			ndp->d_name, ndp->d_unit, ndp->d_addr, ndp->d_pri);
	    } else {
		device = (struct unit *) malloc(sizeof *device);
		if (device == 0) {
		    fprintf(stderr, "No memory for device block.\n");
		    exit(1);
		}
		location->device = device;
		device->device = dp;
		device->ordinal = ++nextDevice;
		device->next = 0;
		if (tailDevice) {
		    tailDevice->next = device;
		    tailDevice = device;
		} else {
		    tailDevice = headDevice = device;
		}
	    }
	    currentAddress++;
	}
    }
}

static void
makectlr(dp)
struct device *dp;
{
    struct locator **loclocator;
    struct locator **firstlocator, **lastlocator;
    struct location *firstlocation, *lastlocation;
    struct location *location;
    struct chnlInfo *channel;
    struct unit *controller;
    struct device *ndp;
    int i;
    int currentAddress;
    int lastAddress;
    int intEncountered = 0;

    if (((dp->d_addr&0x0ff) + dp->d_pri-1)&0x100) {
	fprintf(stderr, "Controller %s%d at 0x%x for %d devices:\n",
				dp->d_name, dp->d_unit, dp->d_addr, dp->d_pri);
	fprintf(stderr, "\ttoo many units (extends past end of channel).\n");
	dp->d_pri = 0x100-(dp->d_addr&0xff);
    }
    channel = chnlInfo+((dp->d_addr&0xf00)>>8);

    controller = (struct unit *) malloc(sizeof *controller);
    if (controller == 0) {
	fprintf(stderr, "No memory for controller block.\n");
	exit(1);
    }
    controller->device = dp;
    controller->ordinal = ++nextCtlr;
    controller->next = 0;
    if (tailCtlr) {
	tailCtlr->next = controller;
	tailCtlr = controller;
    } else {
	tailCtlr = headCtlr = controller;
    }

    firstlocator = channel->locators+((dp->d_addr&0x0f0)>>4);
    lastlocator = channel->locators+(((dp->d_addr+dp->d_pri-1)&0xf0)>>4);
    currentAddress = dp->d_addr;
    lastAddress = dp->d_addr+dp->d_pri-1;
    for (loclocator = firstlocator; loclocator <= lastlocator; loclocator++) {
	if (*loclocator == 0) {
	    *loclocator = (struct locator *) malloc(sizeof **loclocator);
	    if (*loclocator == 0) {
		fprintf(stderr, "No memory for locator block.\n");
		exit(1);
	    }
	    if (headLocator) {
		tailLocator->next = *loclocator;
		tailLocator = *loclocator;
	    } else {
		tailLocator = headLocator = *loclocator;
	    }
	    (*loclocator)->next = 0;
	    (*loclocator)->ordinal = ++nextLocator;
	    for (location = (*loclocator)->locations;
			location < ((*loclocator)+16)->locations; location++) {
		location->controller = NOTUSED;
		location->device = NOTUSED;
	    }
	}
	firstlocation = (*loclocator)->locations+(currentAddress&0xf);
	if ((lastAddress&~0xf) == (currentAddress&~0xf)) {
	    i = lastAddress&0xf;
	} else {
	    i = 0xf;
	}
	lastlocation = (*loclocator)->locations+i;
	for (location = firstlocation; location <= lastlocation; location++) {
	    if (location->controller != NOTUSED) {
		if ((dp->d_type != DEVICE) && !intEncountered) {
		    intEncountered = 1;
		    ndp = location->controller->device;
		    fprintf(stderr, "Controller %s%d at 0x%03x for %d:\n",
				dp->d_name, dp->d_unit, dp->d_addr, dp->d_pri);
		    fprintf(stderr,
			    "\tintersects with %s%d at 0x%03x for %d.\n",
			    ndp->d_name, ndp->d_unit, ndp->d_addr, ndp->d_pri);
		}
	    } else {
		location->controller = controller;
	    }
	    currentAddress++;
	}
    }
}

static struct driverInfo *
getDriver(name, create)
char *name;
int  create;
{
    struct driverInfo *di, *last;

    for (di = driverHead; di != 0; di = di->next) {
	if (eq(name, di->name)) {
	    return di;
	}
	last = di;
    }
    if (create) {
	di = (struct driverInfo *) malloc(sizeof *di);
	if (di == 0) {
	    fprintf(stderr, "config: No more room for driver info.\n");
	    return 0;
	}
	di->next = 0;
	di->name = savestr(name);
	bzero((char *)di->units, sizeof di->units);
	if (driverHead) {
	    last->next = di;
	} else {
	    driverHead = di;
	}
    }
    return di;
}

#define	intersects(la,ha,lb,hb)	(!(((ha)<(lb))||((hb)<(la))))

ibm370_ioconf()
{
    register struct device *dp, *mp;
    struct device *ndp;
    FILE *fp;
    struct driverInfo *di;
    struct unit *ctlr, *device;
    register int i, j;
    struct locator *locator;
    struct location *firstlocation, *location, *lastlocation;

    fp = fopen(path("ioconf.c"), "w");
    if (fp == 0) {
	perror(path("ioconf.c"));
	exit(1);
    }

    fprintf(fp,"#include \"../ibm370/ioconf.h\"\n\n\n");
    /*
     * First things first:  figure out the names of the
     * device attach routines we will be calling.
     */
    for (dp = dtab; dp != 0; dp = dp->d_next) {
	if (dp->d_type == DEVICE) {
	    if (getDriver(dp->d_name, 1) == 0) {
		fprintf(stderr,
			"config: no space for device driver structures!\n");
		return;
	    }
	}
    }
    for (di = driverHead; di; di = di->next) {
	fprintf(fp, "extern int\t%sattach();\n", di->name);
    }
    /*
     * Here the DEVICE records are set up
     */

    fprintf(fp, "\n\n/* name, unit, address, busy, qfirst, qlast,");
    fprintf(fp, " active, interrupt, attach, flags */\n");
    fprintf(fp, "\nstruct ios_device ios_devices[] = {\n");
    for (dp = dtab; dp != 0; dp = dp->d_next) {
	mp = dp->d_conn;
	if (dp->d_pri == 0) {
	    dp->d_pri = 1;
	}
	if (dp->d_type == CONTROLLER) {
	    makectlr(dp);
	} else if (dp->d_type == DEVICE) {
	    if (!mp) {
		fprintf(stderr, "Device %s%d at address 0x%03x:",
			    dp->d_name, dp->d_unit, dp->d_addr);
		fprintf(stderr,
			    "  must connect to a channel or a controller.\n");
		continue;
	    }
	    if (mp->d_type != MASTER) {
		ctlr = getCtlr(dp->d_addr);
		if (ctlr == 0) {
		    fprintf(stderr, "%s %s%d at addresss 0x%03x!\n",
			    "Couldn't find controller for device",
			    dp->d_name, dp->d_unit, dp->d_addr);
		    continue;
		}
		if ((mp->d_name != ctlr->device->d_name)
			    || (mp->d_unit != ctlr->device->d_unit)) {
		    ndp = ctlr->device;
		    fprintf(stderr, "Device %s%d at address 0x%03x",
				    dp->d_name, dp->d_unit, dp->d_addr);
		    fprintf(stderr, " is in the address\n");
		    fprintf(stderr,
				"\trange of controller %s%d (0x%03x-0x%03x),\n",
				ndp->d_name, ndp->d_unit,
				ndp->d_addr, ndp->d_addr+ndp->d_pri-1);
		    fprintf(stderr,
				"\tbut is not connected to that controller.\n");
		    continue;
		}
	    }
	    makedevice(dp);
	    di = getDriver(dp->d_name, 0);
	    for (i=0; i<dp->d_pri; i++) {
		if (BIT_CHK(di, dp->d_unit+i)) {
		    fprintf(stderr,
			"Duplicate unit %s%d encountered at 0x%03x",
				dp->d_name, dp->d_unit+i, dp->d_addr+i);
		    if ((dp->d_pri-i) > 1) {
			fprintf(stderr, " (%d units ignored)", dp->d_pri-i);
		    }
		    fprintf(stderr, ".\n");
		    break;
		} else {
		    BIT_ON(di, dp->d_unit+i);
		}
		fprintf(fp,
		"\t{ \"%s\", %d, 0x%03x, 0, 0, 0, 0, 0, %sattach, 0x%x },\n",
		    dp->d_name, dp->d_unit+i, dp->d_addr+i,
		    dp->d_name, dp->d_flags);
	    }
	}
    }
    fprintf(fp, "\t0\n};\n");
    fprintf(fp,"\nstruct ios_controller ios_controllers[] = {\n");
    for (ctlr = headCtlr; ctlr; ctlr = ctlr->next) {
	ndp = ctlr->device;
	fprintf(fp, "\t{ \"%s\", %d, 0x%03x, 0x%03x, 0, 0, 0},\n",
	    ndp->d_name, ndp->d_unit, ndp->d_addr, ndp->d_addr+ndp->d_pri-1);
    }
    fprintf(fp,"};\n");

    fprintf(fp, "\nstruct ios_locator ios_locators[] = {\n");
    for (locator = headLocator; locator; locator = locator->next) {
	firstlocation = locator->locations;
	lastlocation = locator->locations
		+(sizeof locator->locations/sizeof locator->locations[0])-1;
	fprintf(fp, "    {{");
	for (location = firstlocation; location <= lastlocation; location++) {
	    if (location->controller == NOTUSED) {
		fprintf(fp,  "\t{                   0,\t");
	    } else {
		fprintf(fp, "\t{ &ios_controllers[%d],\t",
					location->controller->ordinal-1);
	    }
	    if (location->device == NOTUSED) {
		fprintf(fp,  "               0 },\n");
	    } else {
		fprintf(fp, " &ios_devices[%d] },\n",
					location->device->ordinal-1);
	    }
	}
	fprintf(fp, "    }},\n");
    }
    fprintf(fp,"\n};\n");
    fprintf(fp,"\nstruct ios_channel ios_channels[16] = {\n");
    for (i=0; i<16; i++) {
	fprintf(fp,"\t{ 0, 0, 0,\n\t\t{");
	for (j=0; j<16; j++) {
	    if (chnlInfo[i].locators[j] == NOTUSED) {
		fprintf(fp,  "                0, ");
	    } else {
		fprintf(fp, " &ios_locators[%d], ",
					chnlInfo[i].locators[j]->ordinal-1);
	    }
	    if (((j & 0x1) == 1) && (j != 15)) {
		fprintf(fp,"\n\t\t ");
	    }
	}
	fprintf(fp,"\n\t\t}\n\t},\n\n");
    }
    fprintf(fp,"\n};\n");

    for (dp = dtab; dp != 0; dp = dp->d_next) {
	    /*
	     * XXX
	     *
	     * To make the headers come out correctly, we adjust the count,
	     * and make channels point at -1 (both are justified, somewhat,
	     * by mkheaders.c).
	     */
	switch (dp->d_type) {
	case DEVICE:
	    dp->d_unit += (dp->d_pri-1);
	    break;
	default:
	    break;
	}
    }
    for (di = driverHead; di;) {
	struct driverInfo *dinext;

	if (di->name) {
	    free(di->name);
	}
	dinext = di->next;
	free((char *)di);
	di = dinext;
    }
    for (locator = headLocator; locator; locator = locator->next) {
	struct locator *next;

	next = locator->next;
	free((char *)locator);
	locator = next;
    }
    for (ctlr = headCtlr; ctlr; ctlr = ctlr->next) {
	struct unit *next;

	next = ctlr->next;
	free((char *)ctlr);
	ctlr = next;
    }
    for (device = headDevice; device; device = device->next) {
	struct unit *next;

	next = device->next;
	free((char *)device);
	device = next;
    }
    (void) fclose(fp);
}
#endif

#if MACHINE_IBM032
ibm032_ioconf()
{
	register struct device *dp, *mp;
	register int slave;
	FILE *fp;

	fp = fopen(path("ioconf.c"), "w");
	if (fp == 0) {
		perror(path("ioconf.c"));
		exit(1);
	}
	fprintf(fp, "#include \"../h/param.h\"\n");
	fprintf(fp, "#include \"../h/buf.h\"\n");
	fprintf(fp, "#include \"../h/map.h\"\n");
	fprintf(fp, "#include \"../h/vm.h\"\n");
	fprintf(fp, "\n");
	fprintf(fp, "#include \"../machineio/ioccvar.h\"\n");
	fprintf(fp, "\n");
	fprintf(fp, "#define C (caddr_t)\n\n");
	fprintf(fp, "\n");

	fprintf (fp, "struct     iocc_hd iocc_hd[] = {{C 0xF0000000,}};\n");
	/*
	 * Now generate interrupt vectors for the  Winnerbus
	 */
	for (dp = dtab; dp != 0; dp = dp->d_next) {
		if (dp->d_pri != 0) {
			mp = dp->d_conn;
			if (mp == 0 || mp == TO_NEXUS ||
			    !eq(mp->d_name, "iocc"))
				continue;
			fprintf(fp, "extern struct iocc_driver %sdriver;\n",
			    dp->d_name);
		}
	}
	/*
	 * Now spew forth the iocc_cinfo structure
	 */
	fprintf(fp, "\nstruct iocc_ctlr iocccinit[] = {\n");
	fprintf(fp, "/*\t driver,\tctlr,\talive,\taddr,\tintpri */\n");
	for (dp = dtab; dp != 0; dp = dp->d_next) {
		mp = dp->d_conn;
		if (dp->d_type != CONTROLLER || mp == TO_NEXUS || mp == 0 ||
		    !eq(mp->d_name, "iocc"))
			continue;
		if (dp->d_pri == 0) {
			if (dp->d_unit != QUES)
				printf("must specify priority for %s%d\n",
				    dp->d_name, dp->d_unit);
			continue;
		}
		if (dp->d_addr == 0) {
			printf("must specify csr address for %s%d\n",
			    dp->d_name, dp->d_unit);
			continue;
		}
		if (dp->d_drive != UNKNOWN || dp->d_slave != UNKNOWN) {
			printf("drives need their own entries; ");
			printf("dont specify drive or slave for %s%d\n",
			    dp->d_name, dp->d_unit);
			continue;
		}
		if (dp->d_flags) {
			printf("controllers (e.g. %s%d) don't have flags, ");
			printf("only devices do\n",
			    dp->d_name, dp->d_unit);
			continue;
		}
		fprintf(fp, "\t{ &%sdriver,\t%d,\t0,\tC 0x%x,\t%d },\n",
		    dp->d_name, dp->d_unit, dp->d_addr, dp->d_pri);
	}
	fprintf(fp, "\t0\n};\n");
	/*
	 * Now we go for the iocc_device stuff
	 */
	fprintf(fp, "\nstruct iocc_device ioccdinit[] = {\n");
	fprintf(fp,
"\t/* driver,  unit, ctlr,  slave,   addr,    pri,    dk, flags*/\n");
	for (dp = dtab; dp != 0; dp = dp->d_next) {
		mp = dp->d_conn;
		if (dp->d_unit == QUES || dp->d_type != DEVICE || mp == 0 ||
		    mp == TO_NEXUS || mp->d_type == MASTER ||
		    eq(mp->d_name, "iocca"))
			continue;
		if (eq(mp->d_name, "iocc")) {
			if (dp->d_pri == 0) {
				printf("must specify vector for device %s%d\n",
				    dp->d_name, dp->d_unit);
				continue;
			}
			if (dp->d_addr == 0) {
				printf("must specify csr for device %s%d\n",
				    dp->d_name, dp->d_unit);
				continue;
			}
			if (dp->d_drive != UNKNOWN || dp->d_slave != UNKNOWN) {
				printf("drives/slaves can be specified only ");
				printf("for controllers, not for device %s%d\n",
				    dp->d_name, dp->d_unit);
				continue;
			}
			slave = QUES;
		} else {
			if (mp->d_conn == 0) {
				printf("%s%d isn't connected to anything, ",
				    mp->d_name, mp->d_unit);
				printf("so %s%d is unattached\n",
				    dp->d_name, dp->d_unit);
				continue;
			}
			if (dp->d_drive == UNKNOWN) {
				printf("must specify ``drive number'' for %s%d\n",
				   dp->d_name, dp->d_unit);
				continue;
			}
			/* NOTE THAT ON THE UNIBUS ``drive'' IS STORED IN */
			/* ``SLAVE'' AND WE DON'T WANT A SLAVE SPECIFIED */
			if (dp->d_slave != UNKNOWN) {
				printf("slave numbers should be given only ");
				printf("for massbus tapes, not for %s%d\n",
				    dp->d_name, dp->d_unit);
				continue;
			}
			if (dp->d_pri != 0) {
				printf("interrupt priority should not be ");
				printf("given for drive %s%d\n",
				    dp->d_name, dp->d_unit);
				continue;
			}
			if (dp->d_addr != 0) {
				printf("csr addresses should be given only");
				printf("on controllers, not on %s%d\n",
				    dp->d_name, dp->d_unit);
				continue;
			}
			slave = dp->d_drive;
		}
		fprintf(fp,
"\t{ &%sdriver,  %2d,   %s,    %2d,   C 0x%x, %d,  %d,  0x%x },\n",
		    eq(mp->d_name, "iocc") ? dp->d_name : mp->d_name, dp->d_unit,
		    eq(mp->d_name, "iocc") ? " -1" : qu(mp->d_unit),
		    slave, dp->d_addr, dp->d_pri, dp->d_dk, dp->d_flags);
	}
	fprintf(fp, "\t0\n};\n");
	(void) fclose(fp);
}
#endif

char *intv(dev)
	register struct device *dev;
{
	static char buf[20];

	if (dev->d_vec == 0)
		return ("     0");
	return (sprintf(buf, "%sint%d", dev->d_name, dev->d_unit));
}

char *
qu(num)
{

	if (num == QUES)
		return ("'?'");
	if (num == UNKNOWN)
		return (" -1");
	return (sprintf(errbuf, "%3d", num));
}
