/*
	@(#)main.c	1.27	(3/4/85 16:44:55)
*/

#include "standalone.h"
#include "sys/config.h"

#ifndef RF360
#ifndef CWC43
#ifndef CWC38		/* Atasi */
#ifndef	CWC21
#ifndef	MSC21
#ifndef	MSC10
	#define	MSC10
#endif
#endif
#endif
#endif
#endif
#endif

#ifdef RF360
#define RF
#endif
#ifdef CWC43
#define CWC
#endif
#ifdef CWC38		/* Atasi */
#define CWC
#endif
#ifdef CWC21
#define CWC
#endif
#ifdef MSC21
#define MSC
#endif
#ifdef MSC10
#define MSC
#endif

#define CWCLITES_VA	(MBIOBASE + 0x00F0)	/* Disk lights base address. */
#define	BELL 0x7

#ifdef PANEL
int noconsole;
int button;				/* Control panel push buttons */
int keypos;				/* Control panel key position */
#endif PANEL

char	cmdbuf[132];
char	command[16];
char	drivernm[16];
char	filename[64];

static	int	buflen;
static	int	bufidx;
static	int	filsysno = 0;

static	int	driver, drive, nbpt, ntpc, ncpd, dp1, dp2, dp3, dp4, fssb, fseb;

struct	{
	char	driver;
	char	filsys;
	int	fssb;
	int	fseb;
	}	dfm[] =	{{DIOB_CFC,   0,      0,   1231},
#ifdef RF360
			 {DIOB_RF,    0,     45,  15299},
#endif
#ifdef CWC43
			 {DIOB_CWC,   0,    102,  13871},
#endif
#ifdef CWC38	/* Atasi */
 			 {DIOB_CWC,   0,    119,  13685},
#endif
#ifdef CWC21
			 {DIOB_CWC,   0,    136,  12511},
#endif
#ifdef MSC21
			 {DIOB_MSC,   0,      0,  15231},
#endif
#ifdef MSC10
			 {DIOB_MSC,   0,      0,   6463},
#endif
			 {       0,   0,      0,      0}};



char   *msg1[]={
"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",
#ifdef	RF360
"boot: Callan Data Systems UNISTAR UNIX boot program (version 4.2 360MB)",
#endif
#ifdef	CWC43
#ifndef RF
"boot: Callan Data Systems UNISTAR UNIX boot program (version 4.2 43MB)",
#endif RF
#endif
#ifdef	CWC38		/* Atasi */
"boot: Callan Data Systems UNISTAR UNIX boot program (version 4.2, 38MB)",
#endif
#ifdef	CWC21
"boot: Callan Data Systems UNISTAR UNIX boot program (version 4.2 21MB)",
#endif
#ifdef	MSC21
"boot: Callan Data Systems UNISTAR UNIX boot program (version 4.2 21MB)",
#endif
#ifdef	MSC10
"boot: Callan Data Systems UNISTAR UNIX boot program (version 4.2 10MB)",
#endif
"",
"boot: Press <RETURN> to load UNIX, or type a ? followed by <RETURN> for help.\n",
0};

char *msg2[] = {"\nThe following commands are available:\n",
	        "     <RETURN> Boots `unix' from the default Winchester disk.",
                "     f        Boots `unix' from the Callan floppy disk.",
#ifdef MSC
                "     msc      Boots `unix' from the MSC-9205 Winchester disk.",
#endif
                "     b        Boots files using supplied parameters.",
		"     list     Lists files in root directory of specified file system.",
#ifdef CWC43
		"     ships    Move hard disk arms to power-off landing area.",
#else
		"     ship     Moves hard disk arm to power-off landing area.",
		"     ships    Like ship, but for multiple drives.",
#endif
#ifdef ENTERMON
		"     monitor  Enters the on-board monitor PROM.",
#endif
#ifdef CD68K
		"     diagnose Enters the on-board diagnostic PROM.",
#endif
		"",
                "Supplied parameters are of the format:\n",
                "       cmd  drivernm(drive_args,filesys_args)filename",
		"drive_args are of the format:",
		"       drive_number  OR  [driveno,nbpt,ntpc,ncpd,dp1,dp2,dp3,dp4]",
		"filesys_args are of the format:",
		"       filesystem_number  OR  [filesys_start_block,filesys_end_block]",
		"",
#ifdef RF360
                "EXAMPLE:    b rf([0,45,20,842,1,1,0,0],[45,15299])unix",
#endif
#ifdef CWC43
                "EXAMPLE:    b cwc([0,17,6,830,0,0,0,0],[102,13871])unix",
#endif
#ifdef CWC38	/* Atasi */
                "EXAMPLE:    b cwc([0,17,7,645,0,0,0,0],[119,13685])unix",
#endif
#ifdef CWC21
                "EXAMPLE:    b cwc([0,17,8,320,0,0,0,0],[136,12511])unix",
#endif
#ifdef MSC21
                "EXAMPLE:    b msc([0,16,8,320,4,0,0,0],[0,15231])unix",
#endif
#ifdef MSC10
                "EXAMPLE:    b msc([0,16,4,306,4,0,0,0],[0,6463])unix",
#endif
		"",
		0};


wait4ret ()
{	char buffer[128];

	printf("boot: Press <RETURN> to continue: ");
	getlin(buffer, "", -1);
}

/* Determines if c is a legal filename char */
isalpha(c)
register char  c;
{
	if ('A' <= c  &&  c <= 'Z'  ||  'a' <= c  &&  c <= 'z')
	    return (1);
	else
	    switch (c)
	    {
		case ',':
		case '(': case ')':
		case '[': case ']':
			return (0);
		default:
			if (c > ' ')
				return 1;
			else
				return 0;
	    }
}

isdigit(c)
register char  c;
{
	return ('0' <= c  &&  c <= '9');
}

eatwhite()
{
	register char  c;

	while (bufidx < buflen)
	    {
	    c = cmdbuf[bufidx];
	    if ('\041' <= c  &&  c <= '\176')
		{
		return(c);
		}
	    bufidx++;
	    }
	return(0);
}

eatnumber(oldvalue)
int  oldvalue;
{
	register char c;
	register int  value;

	value = 0;
	eatwhite();
	c = cmdbuf[bufidx];
	if (c == ',')
	    {
	    bufidx++;
	    return(oldvalue);
	    }
	if (!isdigit(c))
	    {
	    error(1,"Syntax error: Need digit or ',', column %d\n",bufidx+1);
	    return(0);
	    }
	while (bufidx < buflen)
	    {
	    c = cmdbuf[bufidx];
	    if (isdigit(c))
		{
		value *= 10;
		value += c - '0';
		bufidx++;
		}
	    else
		{
		break;
		}
	    }
	eatwhite();	/* Eat any between last digit and ',' */
	if (cmdbuf[bufidx] == ',')
	    {
	    bufidx++;
	    }
	return(value);
}
eatword(tobuf)
register char  *tobuf;
{
	register char   c;

	while (bufidx < buflen)
	    {
	    if (isalpha(c = cmdbuf[bufidx])  ||  isdigit(c))
		{
		*tobuf++ = c;
		bufidx++;
		}
	    else
		{
		break;
		}
	    }
	*tobuf = '\0';
}

eatascii(tobuf)
register char  *tobuf;
{
	register char   c;

	while (bufidx < buflen)
	    {
	    c = cmdbuf[bufidx];
	    if ('\041' <= c  &&  c <= '\176')
		{
		*tobuf++ = c;
		bufidx++;
		}
	    else
		{
		break;
		}
	    }
	*tobuf = '\0';
}

bufmore()
{
	eatwhite();
	if (bufidx < buflen)
	    return(1);
	else
	    return(0);
}

ludrvrnm(name)
register char  *name;
{
	if (strcmp(name,"f")  ||  strcmp(name,"cfc"))
	    {
	    driver = DIOB_CFC;
	    strcpy(name,drivernm);
	    drive = 0;
	    nbpt  = 8;
	    ntpc  = 2;
	    ncpd  = 77;
	    dp1   = 0;
	    dp2   = 0;
	    dp3   = 0;
	    dp4   = 0;
	    fssb  = 0;
	    fseb  = 1231;
	    }
#ifdef RF
#ifdef RF360
	else if (strcmp(name,"s")  ||  strcmp(name,"rf"))
	    {
	    driver = DIOB_RF;
	    strcpy(name,drivernm);
	    drive = 0;
	    nbpt  = 45;
	    ntpc  = 20;
	    ncpd  = 842;
	    dp1   = 1;			/* Interleave factor */
	    dp2   = 1;			/* Drive type: 0,1, or 2 */
	    dp3   = 0;
	    dp4   = 0;
	    fssb  = 45;
	    fseb = 15299;
	    }
#endif RF360
#endif RF
#ifdef CWC
	else if (strcmp(name,"w")  ||  strcmp(name,"cwc"))
	    {
	    driver = DIOB_CWC;
	    strcpy(name,drivernm);
	    drive = 0;
	    nbpt  = 17;
#ifdef CWC43
	    ntpc  = 6;
	    ncpd  = 830;
#endif
#ifdef CWC38		/* Atasi */
 	    ntpc  = 7;
 	    ncpd  = 645;
#endif
#ifdef CWC21
	    ntpc  = 8;
	    ncpd  = 320;
#endif
	    dp1   = 0;
	    dp2   = 0;
	    dp3   = 0;
	    dp4   = 0;
#ifdef CWC43
	    fssb  = 102;
	    fseb = 13871;
#endif
#ifdef CWC38		/* Atasi */
 	    fssb  = 119;
 	    fseb = 13685;
#endif
#ifdef CWC21
	    fssb  = 136;
	    fseb = 12511;
#endif
	    }
#endif
#ifdef MSC
#ifdef CWC
	else if (strcmp(name,"msc"))
#else  CWC
	else if (strcmp(name,"w")  ||  strcmp(name,"msc"))
#endif CWC
	    {
	    driver = DIOB_MSC;
	    strcpy(name,drivernm);
	    drive = 0;
	    nbpt  = 16;
#ifdef MSC21
	    ntpc  = 8;
	    ncpd  = 320;
#endif
#ifdef MSC10
	    ntpc  = 4;
	    ncpd  = 306;
#endif
	    dp1   = 4;
	    dp2   = 0;
	    dp3   = 0;
	    dp4   = 0;
	    fssb  = 0;
#ifdef MSC21
	    fseb = 15231;
#endif
#ifdef MSC10
	    fseb  = 6463;
#endif
	    }
#endif MSC
	else
	    {
	    error(2,"Unknown driver name `%s'.\n",name);
	    }
}
parseit()
{
	register char  c;
	register int   i;
	char	       word1[80];
	char	       word2[80];
	char	       word3[80];

	eatwhite();
	eatascii(command);
	if (bufmore())
	    {
	    if (isalpha(cmdbuf[bufidx]))	/* Driver name or filename? */
	        {
	        eatword(word1);
	        if (!bufmore())			/* No more, must be filename. */
		    {
		    strcpy(word1,filename);
		    return;
		    }
	        else				/* More, must be driver name. */
		    {
		    strcpy(word1,drivernm);
		    ludrvrnm(drivernm);
		    }
	        }
	    /* eat and convert driver name */
	    if (cmdbuf[bufidx++] != '(')
		{
		error(3,"Syntax error: Expecting a `(', column %d\n",bufidx+1);
		return;
		}
	    eatwhite();				/* Eat space between ( [ */
	    if (cmdbuf[bufidx] == '[')		/* Is drive specifications */
		{
		bufidx++;
		drive = eatnumber(drive);
		nbpt  = eatnumber(nbpt);
		ntpc  = eatnumber(ntpc);
		ncpd  = eatnumber(ncpd);
		dp1   = eatnumber(dp1);
		dp2   = eatnumber(dp2);
		dp3   = eatnumber(dp3);
		dp4   = eatnumber(dp4);
		eatwhite();
		if (cmdbuf[bufidx] == ']')
		    {
		    bufidx++;
		    }
		else
		    {
		    error(4,"Syntax error: Need a ']', column %d\n",bufidx+1);
		    }
		eatwhite();
		if (cmdbuf[bufidx] == ',')
		    {
		    bufidx++;
		    }
		else
		    {
		    error(5,"Syntax error: Need ',', column %d\n",bufidx+1);
		    }
		}
	    else if (isdigit(cmdbuf[bufidx]))	/* Is numeric driver number */
		{
		drive = eatnumber(drive);
		}
	    else
		{
		error(6,"Syntax error: Need digit or `[', col=%d\n",bufidx+1);
		return;
		}
	    /* O.K., have now handled the drive specifications */
	    /* Will now handle the file system specifications  */
	    c = eatwhite();
	    if (c == '[')
		{
		bufidx++;
		fssb = eatnumber(fssb);
		fseb = eatnumber(fseb);
		eatwhite();
		if (cmdbuf[bufidx] == ']')
		    {
		    bufidx++;
		    }
		else
		    {
		    error(7,"Syntax error: Need a ']', column %d\n",bufidx+1);
		    }
		}
	    else if (isdigit(c))
		{
		filsysno = eatnumber(0);
		for (i = 0;  dfm[i].driver;  i++)
		    {
		    if (dfm[i].driver == driver && dfm[i].filsys == filsysno)
			{
			fssb = dfm[i].fssb;
			fseb = dfm[i].fseb;
			break;
			}
		    }
		if (!dfm[i].driver)
		    {
		    error(8,"Filesystem number (%d) not in table.",filsysno);
		    }
		}
	    else if (c == ',')		/* Comma default, eat it */
		{
		bufidx++;
		}
	    else if (c == ')')		/* Not specified default */
		{
		}
	    else
		{
		error(9,"Syntax error: Need digit or `[', col=%d\n",bufidx+1);
		return;
		}
	    c = eatwhite();
	    if (c == ')')
		{
		bufidx++;
		}
	    else
		{
		error(10,"Syntax error: Need ')', col=%d\n",bufidx+1);
		}
	    if (bufmore())
		{
		eatascii(filename);
		}
	    }
}

msgsout(nblanks,messages)
register int nblanks;
register char *messages[];
{
	register int i;

	for (i = 0;  messages[i];  i++)
	{
		while (nblanks-- >= 0)
			putchar(' ');
		printf("%s\n", messages[i]);
	}
}

loadunix(file, flag)
register FILE *file;
{
	register int magic, tsize, dsize, bsize;
	register caddr_t start, caddr;
	register int count;

#ifdef PANEL
	cpdputs("Loading "); cpdputs(filename); cpdputch('\n', 1);
#endif PANEL
	magic = getw(file);
	tsize = getw(file);
	dsize = getw(file);
	bsize = getw(file);
	getw(file);
	getw(file);
	getw(file);
	caddr = start = (caddr_t)getw(file);
	printf("boot: Loading %s at 0x%x.\n",filename,start);
	printf("boot: text size is %6d 0x%5x.\n",tsize,tsize);
	for (count = 0;  count < tsize;  count++)
	    *caddr++ = getc(file);

	printf("boot: data size is %6d 0x%5x.\n",dsize,dsize);
	for (count = 0;  count < dsize;  count++)
	    *caddr++ = getc(file);

	printf("boot: bss size is %6d 0x%5x.\n",bsize,bsize);
	for (count = 0;  count < bsize;  count++)
	    *caddr++ = 0;

	printf("boot: total size is %6d 0x%5x.\n", tsize+dsize+bsize,
	       tsize+dsize+bsize);

#ifdef PANEL
	cpdputs("* Unistar 300 *\n");
#endif PANEL

#ifdef ENTERMON
	if (flag)
	{
		printf("boot: Type <RETURN> to start at 0x%x\n", start);
		getlin(cmdbuf,"",-1);
		if (cmdbuf[0] != '\0')
			( (int (*)()) 0x2002fa) ();
	}
#endif
	( (int (*)()) start) ();
}

main()
{
	register int i;
	register char *s;
	FILE file;

#ifdef CWC
	iocheck (CWCLITES_VA, 0);
#endif
	while (1)
	{
#ifdef	    RF360
#ifdef CWC
	    /* Check for existence of SMD controller board.  If it exists, we
	     * assume the SMD disk also exists, and we attempt to boot from 
	     * it in the default case.  If it doesn't exist, then we try to
	     * boot from a Winchester disk in the default case.  This scheme
	     * is to allow the same set of PROMs to be used on any Unistar 300
	     * with a CD68K CPU.
	     */
	    if (iocheck(RF50CMDP_VA, -1) >= 0)	/* SMD exists */
	    {
		    strcpy("rf",drivernm);
		    filsysno = 0;
		    command[0] = '\0';
		    driver = DIOB_RF;
		    drive  = 0;
		    nbpt   = 45;
		    ntpc   = 20;
		    ncpd   = 842;
		    dp1    = 1;			/* This is interleave factor */
		    dp2    = 1;			/* Drive type: 0,1, or 2 */
		    dp3    = 0;
		    dp4    = 0;
		    fssb   = 45;
		    fseb   = 15299;
	    }
	    else		/* SMD doesn't exist.  Try a Winchester */
	    {
#ifdef CWC43
		    strcpy("cwc",drivernm);
		    filsysno = 0;
		    command[0] = '\0';
		    driver = DIOB_CWC;
		    drive  = 0;
		    nbpt   = 17;
		    ntpc   = 6;
		    ncpd   = 830;
		    dp1    = 0;
		    dp2    = 0;
		    dp3    = 0;
		    dp4    = 0;
		    fssb   = 102;
		    fseb   = 13871;
#endif CWC43
	    }
#else CWC
	    strcpy("rf",drivernm);
	    filsysno = 0;
	    command[0] = '\0';
	    driver = DIOB_RF;
	    drive  = 0;
	    nbpt   = 45;
	    ntpc   = 20;
	    ncpd   = 842;
	    dp1    = 1;			/* This is interleave factor */
	    dp2    = 1;			/* Drive type: 0,1, or 2 */
	    dp3    = 0;
	    dp4    = 0;
	    fssb   = 45;
	    fseb   = 15299;
#endif CWC
#endif RF360
#ifdef	    CWC43
#ifndef RF
	    strcpy("cwc",drivernm);
	    filsysno = 0;
	    command[0] = '\0';
	    driver = DIOB_CWC;
	    drive  = 0;
	    nbpt   = 17;
	    ntpc   = 6;
	    ncpd   = 830;
	    dp1    = 0;
	    dp2    = 0;
	    dp3    = 0;
	    dp4    = 0;
	    fssb   = 102;
	    fseb   = 13871;
#endif RF
#endif
#ifdef	    CWC38		/* Atasi */
 	    strcpy("cwc",drivernm);
 	    filsysno = 0;
 	    command[0] = '\0';
 	    driver = DIOB_CWC;
 	    drive  = 0;
 	    nbpt   = 17;
 	    ntpc   = 7;
 	    ncpd   = 645;
 	    dp1    = 0;
 	    dp2    = 0;
 	    dp3    = 0;
 	    dp4    = 0;
 	    fssb   = 119;
 	    fseb   = 13685;
#endif
#ifdef	    CWC21
	    strcpy("cwc",drivernm);
	    filsysno = 0;
	    command[0] = '\0';
	    driver = DIOB_CWC;
	    drive  = 0;
	    nbpt   = 17;
	    ntpc   = 8;
	    ncpd   = 320;
	    dp1    = 0;
	    dp2    = 0;
	    dp3    = 0;
	    dp4    = 0;
	    fssb   = 136;
	    fseb   = 12511;
#endif
#ifdef	    MSC21
	    strcpy("msc",drivernm);
	    filsysno = 0;
	    command[0] = '\0';
	    driver = DIOB_MSC;
	    drive  = 0;
	    nbpt   = 16;
	    ntpc   = 8;
	    ncpd   = 320;
	    dp1    = 4;
	    dp2    = 0;
	    dp3    = 0;
	    dp4    = 0;
	    fssb   = 0;
	    fseb = 15231;
#endif
#ifdef	    MSC10
	    strcpy("msc",drivernm);
	    filsysno = 0;
	    command[0] = '\0';
	    driver = DIOB_MSC;
	    drive  = 0;
	    nbpt   = 16;
	    ntpc   = 4;
	    ncpd   = 320;
	    dp1    = 4;
	    dp2    = 0;
	    dp3    = 0;
	    dp4    = 0;
	    fssb   = 0;
	    fseb   = 6463;
#endif
	    sleep(1);
#ifdef PANEL
	    cpdputs("boot:\n");
	    noconsole = 0;
#endif PANEL
	    filename[0] = '\0';
	    msgsout(0,msg1);
	    printf("boot: ");		/* Main prompt */
#ifdef PANEL
	    keypos = cpdkeypos();
	    /* Allow chance to boot from front panel */
	    if (keypos == KEY_MAINT)
	    {
		getkeylin(cmdbuf, -1);
		if (noconsole)
		{
		    panelboot(&file);
		    continue;
		}
	    }
	    else
		getlin(cmdbuf, "", 30);
#endif PANEL
#ifdef PM68K
	    getlin (cmdbuf, "", 30);
#endif
	    bufidx = 0;
	    buflen = strlen(cmdbuf);
	    parseit();

	    /* Interpret commands */
	    if (strcmp(command,"?"))
	    {
		msgsout(6,msg2);
	    }
	    else if (strcmp(command,"\0"))	/* user just types <RETURN>, */
	    {					/* or times-out */
		/* He gets all the defaults */
		if (!filename[0]) strcpy("unix", filename);
		i = open(filename,&file,driver,drive,
                     nbpt,ntpc,ncpd,dp1,dp2,dp3,dp4,fssb,fseb);
		if (!i) loadunix(&file, 0);
	    }
	    else if (strcmp(command,"f"))
	    {
		if (!filename[0]) strcpy("unix", filename);
		i = open(filename,&file,DIOB_CFC,0,8,2,77,0,0,0,0,0,1231);
		if (!i) loadunix(&file, 1);
	    }
	    else if (strcmp(command,"b"))
	    {
		if (!filename[0]) strcpy("unix", filename);
	        s = "boot: Driver ";
	        printf("%s name ..................... `%s'\n",s,drivernm);
	        printf("%s number ................... %d\n",s,drive);
	        s = "boot: Number of ";
	        printf("%s blocks per track ...... %d\n",s,nbpt);
	        printf("%s tracks per cylinder ... %d\n",s,ntpc);
	        printf("%s cylinders per drive ... %d\n",s,ncpd);
	        s = "boot: Disk controller parameter ";
	        printf("%s 1 ..... %d\n%s 2 ..... %d\n",s,dp1,s,dp2);
	        printf("%s 3 ..... %d\n%s 4 ..... %d\n",s,dp3,s,dp4);
	        s = "boot: Filesystem ";
	        printf("%s number ............... %d\n",s,filsysno);
	        printf("%s starting block ....... %d\n",s,fssb);
	        printf("%s ending block ......... %d\n",s,fseb);
	        printf("boot: Filename ........................ `%s'\n",filename);
		printf("boot: Correct? (y or n): ");
		getlin(cmdbuf,"y",-1);
		if (cmdbuf[0] == 'y' || cmdbuf[0] == 'Y' || cmdbuf[0] == '\0')
		    {
		    i = open(filename,&file,driver,drive,
                         nbpt,ntpc,ncpd,dp1,dp2,dp3,dp4,fssb,fseb);
		    if (!i) loadunix(&file, 1);
		    }
	    }
#ifndef CWC43
#ifndef CWC38		/* Atasi */
	    else if (strcmp(command,"ship"))
	    {
#ifdef	CWC21
		cwcship(0,320);
#endif
#ifdef	MSC21
		mscship(0,320);
#endif
#ifdef	MSC10
		mscship(0,320);
#endif
		printf("boot: .... Ship is done, power off.\n");
		while (1) ;
	    }
#endif	CWC38
#endif	CWC43
	    else if (strcmp(command,"ships"))
	    {
		while (1)
		    {
		    printf("boot: .... drive number    (normally   0)? ");
	            getlin(cmdbuf,"",-1);
		    if (cmdbuf[0] == '\0')
			{
			break;
			}
	            bufidx = 0;
	            buflen = strlen(cmdbuf);
		    drive = eatnumber(0);
#ifdef CWC43
		    printf("boot: .... cylinder number (normally 830)? ");
	            getlin(cmdbuf,"830",-1);
#endif
#ifdef CWC38	/* Atasi */
 		    printf("boot: .... cylinder number (normally 645)? ");
 	            getlin(cmdbuf,"645",-1);
#endif
#ifdef CWC21
		    printf("boot: .... cylinder number (normally 320)? ");
	            getlin(cmdbuf,"320",-1);
#endif
		    if (cmdbuf[0] == '\0')
			{
			break;
			}
	            bufidx = 0;
	            buflen = strlen(cmdbuf);
		    ncpd = eatnumber(0);
#ifdef	CWC
		    cwcship(drive,ncpd);
#else CWC
#ifdef	MSC
		    mscship(drive,ncpd);
#endif CWC
#endif MSC
		    }
		}
#ifdef ENTERMON
	    else if (strcmp(command,"monitor"))
	    {
		( (int (*)()) 0x2002fa) ();
	    }
#endif
#ifdef FASTBOOT
	    else if (strcmp(command,"x"))
	    {
		ffboot();
	    }
#endif
#ifdef CD68K
	    else if (strcmp(command,"diagnose"))
	    {
		callprom (0);
	    }
#endif
	    else if (strcmp(command, "list"))		/* List files */
	    {
		/* Open default file system */
		if (!filename[0]) strcpy("/", filename); /* Default directory */
		strcpy("list", file.file_buf);
		i = open(filename,&file,driver,drive,
                     nbpt,ntpc,ncpd,dp1,dp2,dp3,dp4,fssb,fseb);
		if (!i) list(&file);
		file.file_buf[0] = '\0';
	    }
	    else
	    {
		printf("boot: Unknown command <%s>, try again or type in ? ",
		       command);
		printf("for help.\n");
	    }
	    wait4ret ();
	}
}

#define	 LCOLS	4
/* List files */
list(file)
FILE *file;
{
    struct direct dir;
    register int i, j, col;

    col = 1;
    putchar('\n');
    while (read(file, &dir, sizeof (dir)) == sizeof (dir))
    {
	if (dir.d_ino)
	{
	    col++;
	    for (i=0; i < 14; i++)
		if (dir.d_name[i])
		    putchar(dir.d_name[i]);
		else
		    break;
	    for (j=i; j < 20; j++)
		putchar(' ');
	    if (col > LCOLS)
	    {	col = 1;
		putchar('\n');
	    }
	}
    }
    if (col != 1)
	putchar('\n');
}

#ifdef CD68K
callprom (code)			/* Call a subroutine in PROM 0 */
int		code;		/* Code to indicate which routine */
{
/*
	The diagnostic PROM contains a table which is pointed at by
	location 0x200004.  The table is an array of pointers to subroutines.
	The array is unusual in that it is indexed by negative numbers, with
	entry number -1 being the first.

	Suppose the PROM contains the following entries:

	0x200004:	0x200800		Pointer to table

	0x2007F8:	0x200900		Pointer to subr # 2
	0x2007FC:	0x200A00		Pointer to subr # 1

	In C, we might declare these as follows:

	Subroutines 1 and 2, at 0x200A00 and 0x200900 respectively, are

		(int (*) ()) 0x200A00

	and can be called with

		((int (*) ()) 0x200900) ();

	Then the table entry at 0x200800 is declared as

		(int (**) ()) 0x200800

	and used as

		((int (**) ()) 0x200800)[-1] ();

	Finally, location 0x200004 can be declared as

		(int (***) ()) 0x200004

	and used as

		(*(int (***) ()) 0x200004)[-1] ();
*/
	register int	(***subtbl) () = (int (***) ()) 0x200004;
	register int	(*subr) ();

	if ((subr = (*subtbl)[-1 - code]) != 0)
	    return (*subr) ();
	return -1;
}
#endif

#ifdef PANEL
getkeylin(buffer, waitcnt)
register char *buffer;
register int waitcnt;
{
    register int i, c;

    i = 0;
    printf("      ");
    while ((c=getchar(15000)) != '\n')
    {
	if (keypos == KEY_MAINT  &&  waitcnt >= 0) /* Stop countdown if maint */
	{   waitcnt = -1;
	    printf ("\010\010\010\010\010    ");
	}
	if (c == -2)
	{
	    if (button > 0)		/* A button was pressed */
	    {   noconsole = 1;
		return;
	    }
	    else
		continue;
	}
	if (c == '\b')
	{
	    if (i == 0)
		{
		printf("\007");
		}
	    else
		{
		printf("\b \b");
		i--;
		}
	}
	else if (c < '\040'  ||  keypos == KEY_ON)
	{
	    putchar('\007');
	}
	else
	{
	    putchar(c);
	    buffer[i++] = c;
	    waitcnt = -1;
	}
    }
    c = i;
    while (--c >= 0)
	putchar ('\010');
    printf("\010\010\010\010\010    ");
    putchar('\n');
    buffer[i] = '\0';
}

panelboot(file)
FILE *file;
{   register int c, i, j, magic, nprogs = 0;
    struct direct dir;
    char progs[100][15];

    cpdputs("Press EXECUTE to boot, SELECT to skip\n");

    /* Open root directory */
    strcpy("/", filename);
    strcpy("list", file->file_buf);
    i = open(filename,file,driver,drive,
	    nbpt,ntpc,ncpd,dp1,dp2,dp3,dp4,fssb,fseb);
    file->file_buf[0] = '\0';
    if (i)
    {   printf("boot: open of `/' failed\n");
        cpdputs("open of `/' failed\n");
	return;
    }

    cpdputch(BELL_OFF);		/* Turn off bell */

    while (read(file, &dir, sizeof (dir)) == sizeof (dir))
    {
	if (dir.d_ino)
	{
	    magic = getmagic(dir.d_ino, file);
	    if ((magic != 0405) && (magic != 0407) && (magic != 0410) && (magic != 0411))
		continue;
	    for (i=0; i < 14; i++)
		if (dir.d_name[i])
		    progs[nprogs][i] = dir.d_name[i];
		else
		    break;
	    progs[nprogs++][i] = '\0';
	}
    }

    sleep(1);
    j = nprogs;
    while (j-- > 0)
    {
	i = 0;
	while (c=progs[j][i++])
	    cpdputch(c, 1);
	cpdputch('?', 1);
	cpdputch('\n', 1);
	cpdputch(BELL_ON, 1); cpdputch(BELL, 1); cpdputch(BELL_OFF, 1);
	while (1)
	{   c = cpdgetch(1);	/* wait for front panel input */
	    if (c == 'S') 	/* skip to next program */
		break;
	    else if (c == '0') 	/* skip to previous program */
	    {	j += 2;
		if (j > nprogs) j = 1;
		break;
	    }
	    else if (c == 'E')
	    {	
		cpdputch(BELL_ON, 1); cpdputch(BELL, 1);
		strcpy(&progs[j][0], filename);
		i = open(filename,file,driver,drive,
		     nbpt,ntpc,ncpd,dp1,dp2,dp3,dp4,fssb,fseb);
		if (!i) loadunix(file, 1);
		return;
	    }
	}
	if (j == 0)
	    j = nprogs;
    }
}

getmagic(inodeno, file)
register int inodeno;
FILE *file;
{
	struct dinode inode;
	FILE dfile;

	bytefill(&dfile,0,sizeof(FILE));
	bcopy(&file->file_diob,&dfile.file_diob,sizeof(dfile.file_diob));
	getinode(inodeno,&inode,&dfile.file_diob);
	bcopy(&inode,&dfile.file_ino,sizeof(dfile.file_ino));
	dfile.file_cblk = -1;
	dfile.file_i1b = -1;
	dfile.file_i2b = -1;
	dfile.file_i3b = -1;
	return (getw(&dfile));
}

cpdputs(s)
register char *s;
{   register int c;
    while (c = *s++)
	cpdputch(c, 1);
}
#endif PANEL
