/* hdx.c */

/*
 * Atari Hard Disk Installation Utility
 * Copyright 1988 Atari Corp.
 *
 * Associated files
 *	hdx.rsc		resource file
 *	wincap		hard disk database (text file)
 *
 *	hdx.h		object tree definitions
 *	defs.h		constant definitions
 *	part.h		ST structure definitions
 *	ipart.h		IBM structure definitions
 *
 *	hdx.c		top level, user interface (this file)
 *	epart.c		edit partition sizes
 *	fmt.c		disk formatting
 *	part.c		partition reading/writing
 *	sect.c		sector reading, writing, zeroing
 *	string.c	string functions (matching, concat, ...)
 *	assist.c	markbad(), zero()
 *	wincap.c	hard disk parameter / partition size database
 *	st.c		random ST functions (delay, reboot, ...)
 *
 *----
 * 8-Nov-1988  jye. change and add some codes so that can be used for extended
 *					and big partition.
 * 13-Jun-1989 jye. Change and add some codes so that HDX can be deal with
 *				    acsi and scsi drives.
 * 22-Jan-1990 jye. Change the HDX so that we don't have to put a informations
 *					of a drive into the Wincap file.
 * 13-Mar-1990 jye. change the HDX to a genetic one so that the user don't
 *					need know what kind of drive.
 * 20-Jul-1990 jye. change the interface about the unit select. In the new 
 *					interface, user tells the type of drive is acsi or scsi,
 *					then selects unit.
 * 01-Aug-1990 jye. Change hard disk size request from mdsence to readcap.
 * 25-Jul-1991 jye. Change the Hdx so that can be used for IDE-AT drive.
 * 11-Nov-1991 jye. change the hdx so that can got the hard disk size from
 *					page 0, or 3, or 4, or from the wincap. For the SCSI drive,
 *					getting the disk size from wincap or readcap.
 * 7-Jul-1992  jye. Change the hdx so that can be used for the sparrow scsi.
 * Feb-3-1993  jye. Fixed a bug which is when format a hard disk with no wincap
 *					file, then the HDX will bomb out. Now, you can still format
 *					the hard disk without the wincap, because the wincap file
 *					is used when HDX can't get the hard disk's informations.
 * Apr-9-1993  jye.	To fixed a problem for the Conner CP2088 drive, which HDX
 *					can't Markbad it in Format, because this kind of drive has
 *					the different values of head, cylinder, and spt between the
 *					physical and logical parameters, so I added a inqury() call
 *					right after the 'fmtunt()' in 'dodiform()' to up date the
 *					table, because 'fmtunt()' changes the physical parameters 
 *					to the logical parameters.
 */

#include "obdefs.h"
#include "gemdefs.h"
#include "osbind.h"
#include "mydefs.h"
#include "part.h"
#include "bsl.h"
#include "hdxpch.h"
#include "ipart.h"
#include "addr.h"
#include "myerror.h"

#define MFM 17

extern char sbuf[];
extern int rebootp;
extern int yesscan;
extern long disksiz;
extern long ratio;
extern int typedev;
extern int typedrv;
extern int prevnpart;
extern int atexst;		/* set for AT drive exist */
extern int floptical;	/* set if it's a floptical drive */
extern int tformat;		/* 1: called by Format */

/* Globals */
BYTE *bsl;			/* bad sector list */
long bslsiz;			/* num sectors BSL occupies */
SECTOR badbuf[WARNBADSECTS];	/* bad sectors buffer */
int rebootp = 0;	/* 1: must reboot (not return to desktop) */
int tformat;			/* TRUE: just formatted disk */
int running;		/* 1: continue evnt_multi() loop */
char sbuf[512];		/* error message buffer */
long extsiz;		/* the size of extened partition */
long ostack;		/* old stack pointer */
long bps;			/* bytes per sector */
int npart;			/* number of partition */
int ext;			/* the index of extended partition */
int extend;			/* the index of end extended partition */
int showmany;		/* the flag that show the too much device alert box */
char ttscsi;		/* SCSI hard disk drive */
char spscsixst;		/* set for sparrow scsi drive exist */
int noacsi;			/* set for no ACSI dirve in the system */
int needscan;		/* TRUE: if info in the LOGMAP update */
int noinfo=1;			/* 1: no informations in the wincap */
int athead;			/* the # of data heads on the AT drive */
int atcyl;			/* the # of cylinders on the AT drive */
int atspt;			/* the # of sectors per track on the AT drive */
int ok2draw;		/* go ahead to draw the change part of dialog box */
int ndevs;			/* the # of devices */
char *drvid[] ={	/* for the id of the drives */
	"123456789012345678901234567",
	"123456789012345678901234567",
	"123456789012345678901234567",
	"123456789012345678901234567",
	"123456789012345678901234567",
	"123456789012345678901234567",
	"123456789012345678901234567",
	"123456789012345678901234567",
	"123456789012345678901234567",
	"123456789012345678901234567",
	"123456789012345678901234567",
	"123456789012345678901234567",
	"123456789012345678901234567",
	"123456789012345678901234567",
	"123456789012345678901234567",
	"123456789012345678901234567",
	"123456789012345678901234567",
	"Identification unavaliable",
	"Not responding",
	"ACSI 0",		/* index is 19 */
	"ACSI 1",
	"ACSI 2",
	"ACSI 3",
	"ACSI 4",
	"ACSI 5",
	"ACSI 6",
	"ACSI 7",
	"SCSI 0",		/* index is 27 */
	"SCSI 1",
	"SCSI 2",
	"SCSI 3",
	"SCSI 4",
	"SCSI 5",
	"SCSI 6",
	"SCSI 7",
	"IDE 0",			/* index is 35 */
	" "
};

DEVSET devid[17];

/*  Logical-to-dev+partition mapping table. */
extern int nlogdevs;		/* #logical devs found */
extern LOGMAP logmap[];		/* logical dev map */
extern int livedevs[];		/* live physical dev flag */
extern int idevs[];			/* the devise have a id */
extern char cachexst;		/* 0: no cache. 1: with cache */

/* Partition related variables */
long mxpsiz = MAXPSIZ;

/* AES (windows and messages) related variables */
int gl_hchar;		/* height of system font (pixels) */
int gl_wchar;		/* width of system font (pixels) */
int gl_wbox;		/* width of box able to hold system font */
int gl_hbox;		/* height of box able to hold system font */

int phys_handle;	/* physical workstation handle */
int handle;		/* virtual workstation handle */
int wi_handle;		/* window handle */

int formw, formh, sx, sy, lx, ly;	/* dialogue box dimensions */
int xdesk, ydesk, hdesk, wdesk;		/* window X, Y, width, height */
int xwork, ywork, hwork, wwork;		/* desktop and work areas */

int msgbuff[8];		/* event message buffer */
int keycode;		/* keycode returned by event-keyboard */
int mx, my;		/* mouse x and y pos. */
int butdown;		/* button state tested for, UP/DOWN */
int ret;		/* dummy return variable */
int pnf;		/* 1: partition or format; 0: zero or markbad */
int hidden;		/* current state of cursor */
int contrl[12];
int intin[128];
int ptsin[128];
int intout[128];
int ptsout[128];	/* storage wasted for idiotic bindings */
int work_in[11];	/* Input to GSX parameter array */
int work_out[57];	/* Output from GSX parameter array */
int pxyarray[10];	/* input point array */
int blitxst;		/* the flag for check the BLiTTER */

/*
 * Top level;
 * we get control from the desktop.
 */
main()
{
	pnf = 0;		/* set the flag to it isn't partition yet */
    appl_init();
    phys_handle=graf_handle(&gl_wchar, &gl_hchar, &gl_wbox, &gl_hbox);
    wind_get(0, WF_WORKXYWH, &xdesk, &ydesk, &wdesk, &hdesk);
    open_vwork();
    wi_handle=wind_create(0x0040&0x0080, xdesk, ydesk, wdesk, hdesk);

    hidden = FALSE;
    butdown = TRUE;

	/* doing a checking see if the cache in the system */
	cachexst = (char) chkcache();

	/* check the existence of the BLiTTER */
	blitxst = chkblit();

    if (!rsrc_load(RESOURCEFILE)) {
	errs("[2][|", RESOURCEFILE, "][ EXIT ]");
	goto punt;
    }

    
    /* Get all addresses of dialogues from resource file */
    if (getalladdr() != OK) {
	errs("[2][|", RESOURCEFILE, "][ EXIT ]");
	goto punt;
    }


	needscan = TRUE;

redomul:
    ARROW_MOUSE;

    /* display menu bar */
    menu_bar(menuobj, 1);

    running = TRUE;
    while (running) {
    	domulti();
    }

    /*
     * If nothing has been done to the hard disks
     * then just get out, back to the desktop.
     * Otherwise reboot the system.
     */
    menu_bar(menuobj, 0);		/* erase menu bar */

punt:

    wind_delete(wi_handle);
    v_clsvwk(handle);
    appl_exit();
}


/*
 * Get a single event, process it, and return.
 *
 */
domulti(){
    int event;
    
    event = evnt_multi(MU_MESAG,
			1,1,butdown,
			0,0,0,0,0,
			0,0,0,0,0,
			msgbuff,0,0,&mx,&my,&ret,&ret,&keycode,&ret);

    if (event & MU_MESAG) {
    	wind_update(TRUE);
	switch (msgbuff[0]) {
	    case WM_REDRAW:
		do_redraw(msgbuff[4],msgbuff[5],msgbuff[6],msgbuff[7]);
		break;

	    case MN_SELECTED:
	        BEE_MOUSE;
		switch(msgbuff[3]) {
		    case MNDISK:
			switch (msgbuff[4]) {
			    case DIPART:
		        	if ((needscan)&&(rescan(0,2) == ERROR))	{
						break;	/* don't report medium changed */
					}
					needscan = FALSE;
			        dodipart(-1, NULL, NULL);
			    	break;
			    default:	    break;
			}
			break;

		    case MNFILE:
			switch (msgbuff[4]) {
			    case FIQUIT:
				running = 0;
				break;

			    default:
				break;
			}
			break;
			
		    case MNDESK:
			if(msgbuff[4] == DEABOUT) {
			    strcpy(abtdial[ABVERSN].ob_spec, "HDX Patch Version 5.03");
		 	    abtdial[ABOK].ob_state = NORMAL;
			    execform(abtdial);
			}
			break;		/* "cannot happen" */
		}

		menu_tnormal(menuobj, msgbuff[3], 1);	/* back to normal */
	        ARROW_MOUSE;
		break;
		
	    case WM_NEWTOP:
	    case WM_TOPPED:
		wind_set(wi_handle, WF_TOP, 0, 0, 0, 0);
		break;

	    case WM_CLOSED:
		running = FALSE;
		break;

	    default:
		break;
	}
	wind_update(FALSE);
    }
}


/*
 * Default partition name (no "pt" entry).
 */
#define	DEF_PARTNAME	"4-6-10"



/*
 * Handle [PARTITION] item;
 * if `xdev' is -1, throw up dialog boxes;
 * if `xdev' >= 0, just partition the dev,
 * using `pnam' as the partition type, 
 * and `pr_id' to search for the type.
 *
 */
dodipart(xdev, pnam, hsize)
int xdev;
char *pnam;
long hsize;
{
    int dev, i, ret =OK;
    char *s;
    char bs[512];
    PART *pinfo;
	long disksiz;
	int mask = 0x0001;


    if (xdev < 0) {
	tformat = FALSE;
	if ((dev = gphysdev()) < 0) {
	    return BAILOUT;
	}
	/*
	 * Let the user edit/pick partitions.
	 */
	 if (sfigpart(bs, dev, (PART *)&pinfo) != OK)	{
		if (pinfo > 0)	Mfree(pinfo);
	       return BAILOUT;
	 }

    }

    /* For REAL!! */
    dsplymsg(partmsg);
    
    
    /* Lay out partition headers */
    if (spheader(dev, &pinfo[0]) != OK) {
        ret = ERROR;
        goto partend;
    }
    
    /* Partition the device with parameters given in pinfo */
    if (stlaybs(dev, &pinfo[0]) != OK)
        ret = ERROR;
    else
        ret = OK;
    	
	pnf = 1;		/* set the flag to just doing the partition */
partend:
	inipart(pinfo, npart);
	if (pinfo > 0)	Mfree(pinfo);
    erasemsg();
    return (ret);
}



/*
 * Setup partitions on the disk;
 * write boot sectors and zero FATs and root directories.
 *
 */
stlaybs(physdev, pinfo)
int physdev;
register PART *pinfo;
{
	int i, ret;
    SECTOR nsect;
    char *devno="X";
    long ndirs;
    UWORD fatsiz;
    BOOT *bs;
	extern long cell();
	char *buf1;
	long size, remsect;
	long datsect;
	long datclst; 
	long fatclst;
	long entsect;

    /* SCAN_BS: pinfo is for scan() and laybs() use */
	if (ext != NO_EXT)	sortpart(pinfo, SCAN_BS);	

    for (i = 0; i < npart; ++i, ++pinfo) {
    	
    	/* don't care if partition does not exist */
		if (!(pinfo->p_flg & P_EXISTS)) {
		    return OK;
		}

	/* estimat the bps */
	/* MAXSECT = 16MB - 8 */
	bps = cell((pinfo->p_siz-7)*BPS, (long)MAXSECT);

	/* the real bps */
	bps = BPS * n2power((UWORD)cell(bps, (long)BPS));
	ratio = bps / BPS;
	nsect = pinfo->p_siz / ratio;

	size = (long)BPS * ratio;

	/*
	 * Compute root directory size
	 * 256 entries, plus fudge on devs > 10Mb
	 */
	if (pinfo->p_siz < 0x5000L) ndirs = NUMEN;
	else ndirs = nsect / 80;	/* 1 dir entry per 80 sectors */
	/* round to nearest sector */
	ndirs = (ndirs + ((UWORD)bps/BPDIR - 1)) & ~((UWORD)bps/BPDIR - 1);	

	/*--------------------------------------------------------------*
	 * Compute FAT size						*
	 *								*
	 * Num entries to map the entire partition			*
	 *	= partition's size in clusters				*
	 *	= partition's size in sectors / spc			*
	 *								*
	 * Num entries in FAT						*
	 *	= Num entries to map partition + reserved entries	*
	 *	= (partition's size in sectors / spc) + 2		*
	 *								*
	 * Num sectors FAT occupies					*
	 *	= Num entries in FAT / Num entries of FAT per sector	*
	 *	= Num entries in FAT / (bps / 2)    <16-bit FAT>	*
	 *	= ((partition's size in sectors / spc) + 2) / (bps/2) + 1	*
	 *					    <+1 to round up>	*
	 *--------------------------------------------------------------*/
	fatsiz = ((((nsect / SPC) + 2) * 2) / bps) + 1;/*bps ?? 512 or 1024*/

	/* Apr-23-93 jye: To fixed the same bug in the Gemdos.
	/* # of sectors in datas:  
	 *			 	datsect   = nsect - boot - 2*fatsiz - size of dir 
	 * 						  = nsect-boot-2*fatsiz-(ndirs*32)/bps
	 * # of clusters in datas: 
	 *				datclst	  = # of sectors in datas / SPC 
	 * # of clusters(entries) in Fat: 
	 *				fatclst   = fatsiz * (bps/2)
	 * # of sectors need in fat talbe for datclst:
	 *				entsect   = datclst / (bps/2)
	 * # of sectors need to remodify to 0xffff:
	 *				remsect   = fatsiz - entsect
	 */

	datsect = nsect - 1 - 2*fatsiz - (ndirs*32)/bps;
	datclst = datsect / SPC;
	fatclst = fatsiz * (bps/2);
	entsect = datclst / (bps/2);
	remsect = (fatsiz - entsect)*size;


	/* # of sectors need to remodify to 0xffff */
	if ((buf1 = (char *)Malloc(remsect)) <= 0)	{
		err(nomemory);
		if (buf1 > 0) Mfree((long)buf1);
		return ERROR;
	}

	/* 
	 * Apr-23-93 jye: To fixed the write over to next partitiona in the Gemdos  
	 *				  , here just set those entries in Fat table, which don't
	 *				  correspond to the availble date sectors in the partition.
	 *				  The pointers should be:
	 *				  	p_st+(boot+datclst/(bps/2))*ratio and 
	 *					p_st+(boot+fatsiz+datclst/(bps/2))*ratio 
	 */
	if ((ret = rdsects(physdev, (UWORD)(remsect/BPS), buf1, 
	 				(SECTOR)pinfo->p_st+(1+datclst/(bps/2))*ratio)) != OK) {
	    if (tsterr(ret) != OK)
	        err(bootwrit);
	    return ERROR;
	}
	/* fill the last sectors of FAT start at last entry with the 0xffff */
	/* +2 is for two reserved entries in the fat table */
	fillfat(buf1, ((datclst%(bps/2))+2)*2, remsect, 0xffff);
	if ((ret = wrsects(physdev,(UWORD)(remsect/BPS),buf1,
	 				(SECTOR)pinfo->p_st+(1+datclst/(bps/2))*ratio) != OK) ||
		(ret = wrsects(physdev,(UWORD)(remsect/BPS),buf1,
	 		(SECTOR)pinfo->p_st+(1+fatsiz+datclst/(bps/2))*ratio) != OK)) {
	    if (tsterr(ret) != OK)
	        err(bootwrit);
	    return ERROR;
	}
	/* Apr-23-93 jye: Add above codes to fix the Gemdos over write next
	 * 				  partition.
	 */

		     
		if (buf1 > 0) Mfree((long)buf1);
	}
	return OK;
}




/*
 * Translate unit number to tree index.
 *
 */
static int physxlat[] = {
    UNIT0, UNIT1, UNIT2, UNIT3
};

static int physid[] = {
    DRVID0, DRVID1, DRVID2, DRVID3
};

#define ROLL1 1			/* move the bar one step */
#define ROLL4 4			/* move the bar four steps */

/*
 * Get physical device#,
 * return devno or -1.
 *
 */
gphysdev()

{
    int xrun = 1, tpdev=0;
	int index=0, i, ret;

	linkdev();			/* link all live devices into a list */
	if (tformat)	{	/* when format, enable all devices in dialog box */
		if ((spscsixst)	|| (atexst)) { /* sparrow or notebook */
			ndevs = 9;
			tpdev = 8;
		} else if (ttscsi) {
			ndevs = 16;
		} else { /* if ((!ttscsi) && (!noacsi))	 Mega ST */
			ndevs = 8;
		}
	}
	/* set form for first display */
	physdial[PHYSOK].ob_state = NORMAL;
	physdial[PHYSCN].ob_state = NORMAL;
	physdial[SLBOX].ob_y = 0;
	if (ndevs <= 4)	{
		physdial[SLBOX].ob_height = physdial[SLTRK].ob_height;
	} else {
		physdial[SLBOX].ob_height = physdial[SLTRK].ob_height / (ndevs/4.0);
	}
	for (i=0; i < 4; i++)	{
		physdial[physxlat[i]].ob_state = NORMAL;
		physdial[physid[i]].ob_state = NORMAL;
	}
	ok2draw = 0;
	drawdev(index);	/* draw the devices into the dialog box */
	ARROW_MOUSE;
	dsplymsg(physdial);
	++ok2draw;
    while (xrun) 	{
		switch (ret=form_do(physdial, -1)) 	{
			case PHYSOK:xrun = 0;
						break;
			case PHYSCN:xrun = 0;			/* return */
						break;
			case SLTRK: if (ndevs > 5)	{
							scrupdn(ROLL4, &index);
						}
						break;
			case SLUP:  if (index != 0)	{
							scrupdn(ROLL1, &index);
						}
						break;
			case SLDN:  if ((index < 12) && (index+4 < ndevs))	{
							scrupdn(ROLL1, &index);
						}
						break;
			case SLBOX: if (ndevs > 5)	{
							slidebox(physdial, &index);
						}
						break;
			case DRVID0:physdial[UNIT0].ob_state = SELECTED;
				   	objc_draw(physdial,UNIT0, MAX_DEPTH, 0, 0, wdesk, hdesk);
						break;;
			case DRVID1:physdial[UNIT1].ob_state = SELECTED;
				   	objc_draw(physdial,UNIT1, MAX_DEPTH, 0, 0, wdesk, hdesk);
						break;;
			case DRVID2:physdial[UNIT2].ob_state = SELECTED;
				   	objc_draw(physdial,UNIT2, MAX_DEPTH, 0, 0, wdesk, hdesk);
						break;;
			case DRVID3:physdial[UNIT3].ob_state = SELECTED;
				   	objc_draw(physdial,UNIT3, MAX_DEPTH, 0, 0, wdesk, hdesk);
						break;;
			case UNIT0:physdial[DRVID0].ob_state = SELECTED;
				   	objc_draw(physdial,DRVID0, MAX_DEPTH, 0, 0, wdesk, hdesk);
						break;;
			case UNIT1:physdial[DRVID1].ob_state = SELECTED;
				   	objc_draw(physdial,DRVID1, MAX_DEPTH, 0, 0, wdesk, hdesk);
						break;;
			case UNIT2:physdial[DRVID2].ob_state = SELECTED;
				   	objc_draw(physdial,DRVID2, MAX_DEPTH, 0, 0, wdesk, hdesk);
						break;;
			case UNIT3:physdial[DRVID3].ob_state = SELECTED;
				   	objc_draw(physdial,DRVID3, MAX_DEPTH, 0, 0, wdesk, hdesk);
						break;;
  		}
  	}

  /*
   * Draw shrinking box and cleanup the screen;
   * return thing that caused our exit.
   */
    erasemsg();

	if (ret == PHYSCN)	{
		return ERROR;
	}
	/* search for the selected unit */
	for (i=0; i < 4; i++)	{
		if (physdial[physxlat[i]].ob_state & SELECTED)	{
			if (tformat)	{
				return(index+tpdev+i);
			} else {
				return(devid[index+i].dev);
			}
		}
	}
	return ERROR;
}

/* draw the select devices dialog box for the format operation */

fdrawdev(index)
int index;
{

	int i, st=0;

	if ((spscsixst)	|| (atexst))	{
		st = 8;
	}
	
	for (i=0; i < 4; i++)	{
		if (i+index+st < 8)	{
		  	(physdial[physxlat[i]].ob_spec)->te_ptext = &drvid[19+i+index][0];
		} else if (i+index+st < 16)	{
		(physdial[physxlat[i]].ob_spec)->te_ptext = &drvid[27+i+index+st-8][0];
		} else {
			(physdial[physxlat[i]].ob_spec)->te_ptext = &drvid[35][0];
		}
		physdial[physxlat[i]].ob_state = NORMAL;
		physdial[physid[i]].ob_state = NORMAL;
		if (i+index+st == 16)	{	/* it is sparrow */
			(physdial[physid[i]].ob_spec)->te_ptext = &drvid[i+index+st][0];
		} else if (livedevs[i+index+st])	{
			if (idevs[i+index+st])	{
				(physdial[physid[i]].ob_spec)->te_ptext = &drvid[i+index+st][0];
			} else {
				(physdial[physid[i]].ob_spec)->te_ptext = &drvid[17][0];
			}
		} else {
			if (idevs[i+index+st])	{
				(physdial[physid[i]].ob_spec)->te_ptext = &drvid[i+index+st][0];
			} else {
				(physdial[physid[i]].ob_spec)->te_ptext = &drvid[18][0];
			}
		}
		if (ok2draw)	{
			objc_draw(physdial,physxlat[i], MAX_DEPTH, 0, 0, wdesk, hdesk);
			objc_draw(physdial,physid[i], MAX_DEPTH, 0, 0, wdesk, hdesk);
		}
	}
}
    
/* draw the select devices dialog box for the partition operation */

drawdev(index)
int index;
{

	int i, j;

	if (tformat)	{
		fdrawdev(index);
		return OK;
	}

	for (i=0; i < 4; i++)	{
		(physdial[physxlat[i]].ob_spec)->te_ptext = &drvid[36][0];
		(physdial[physid[i]].ob_spec)->te_ptext = &drvid[36][0];
		if (devid[i+index].flg)	{
		   	physdial[physxlat[i]].ob_state = NORMAL;
		   	physdial[physid[i]].ob_state = NORMAL;
			j = devid[i+index].dev;
			if (j < 8)	{
				(physdial[physxlat[i]].ob_spec)->te_ptext = &drvid[19+j][0];
			} else if (j < 16)	{
				(physdial[physxlat[i]].ob_spec)->te_ptext = &drvid[27+j-8][0];
			} else {
				(physdial[physxlat[i]].ob_spec)->te_ptext = &drvid[35][0];
			}
			(physdial[physid[i]].ob_spec)->te_ptext = devid[i+index].id;
		} else {
			physdial[physxlat[i]].ob_state = DISABLED;
			physdial[physid[i]].ob_state = DISABLED;
		}
		if (ok2draw)	{
			objc_draw(physdial,physxlat[i], MAX_DEPTH, 0, 0, wdesk, hdesk);
			objc_draw(physdial,physid[i], MAX_DEPTH, 0, 0, wdesk, hdesk);
		}
	}
}

scrupdn(roll, index)
int roll;
int *index;

{
 	int gr_mkmx, gr_mkmy;
	int gr_mkmstate, gr_mkkstate;
	int barht, barx, bary;
	int eptx, epty, eptht;

	barht = physdial[SLTRK].ob_height;
	eptht = physdial[SLBOX].ob_height;
	graf_mkstate(&gr_mkmx, &gr_mkmy, &gr_mkmstate, &gr_mkkstate);
	objc_offset(physdial, SLBOX, &eptx, &epty);
	objc_offset(physdial, SLTRK, &barx, &bary);
	/* check which part of bar was clicked */
	if (gr_mkmy > (epty+eptht))	{	/* low part of bar was clicked */
		if (roll == ROLL4)	{
			if ((*index+5 >= ndevs) || (eptht > (bary+barht-epty-eptht)))	{
				physdial[SLBOX].ob_y = barht - eptht;
				*index = ndevs - 4;	/* the last 4 to display */
			} else if (*index+4 < ndevs)	{
				physdial[SLBOX].ob_y += eptht;
				*index += 4;
			}
		} else {	/* ROLL1 */
			if ((*index+5 >= ndevs)||((barht/ndevs)>(bary+barht-epty-eptht))){
				physdial[SLBOX].ob_y = barht - eptht;
				*index = ndevs - 4;	/* the last 4 to display */
			} else {
				physdial[SLBOX].ob_y += barht / ndevs;
				*index += 1;
			}
		}
	} else if (gr_mkmy < epty)	{	/* upper part of bar was clicked */
		if (roll == ROLL4)	{
			if ((eptht > (epty - bary)) || (*index <= 4))	{
				physdial[SLBOX].ob_y = 0;
				*index = 0;
			} else {
				physdial[SLBOX].ob_y -= eptht;
				*index -= 4;
			}
		} else {
			if (*index <= 1)	{
				physdial[SLBOX].ob_y = 0;
				*index = 0;
			} else {
				physdial[SLBOX].ob_y -= barht / ndevs;
				*index -= 1;
			}
		}
	} else {
	  return OK;
	}
	objc_draw(physdial,SLTRK, MAX_DEPTH, 0, 0, wdesk, hdesk);
	drawdev(*index);
}


slidebox(tree, index)

OBJECT *tree;
int *index;

{
	int gr_wreturn, eptatmax;
	int ind, tmp;

	ind = ndevs - 4;
	eptatmax = tree[SLTRK].ob_height - tree[SLBOX].ob_height;
	gr_wreturn = graf_slidebox(tree, SLTRK, SLBOX, 1);
	tmp = (ind * gr_wreturn) / 1000;
	if (tmp == *index)	{	/* slide box is in the same place */
		return OK;	
	} else {
		*index = tmp;
	}
	if (*index+4 > ndevs)	{
		*index = ndevs-4;
	} 
	tree[SLBOX].ob_y = (eptatmax * (*index)) / ind;
	objc_draw(tree, SLTRK, MAX_DEPTH, 0, 0, wdesk, hdesk);
	drawdev(*index);
}



/* put the live device into a list */

linkdev()
{

	int i, j=0;

	for (i=0; i<16; i++)	{
		devid[i].flg = 0;
		devid[i].id = &drvid[18][0];
		if (livedevs[i])	{
			devid[j].flg = P_EXISTS;
			devid[j].dev = i;
			if (idevs[i])	{
				devid[j++].id = &drvid[i][0];
			} else {
				devid[j++].id = &drvid[17][0];
			}
		} else if (idevs[i])	{
			devid[j].flg = 2;
			devid[j].dev = i;
			devid[j++].id = &drvid[i][0];
		}
	}
	if ((spscsixst) || (atexst))	{
		devid[j].flg = P_EXISTS;
		devid[j].dev = i;
		devid[j++].id = &drvid[i][0];
	}

	ndevs = j;	/* number of live devices */

}




/*
 * Open virtual workstation.
 *
 */
open_vwork()
{
    int i;

    for (i = 0; i < 10;)
	work_in[i++] = 1;
    work_in[10] = 2;
    handle = phys_handle;
    v_opnvwk(work_in, &handle, work_out);
}


/*
 * Find and redraw all clipping rectangles
 *
 */
do_redraw(xc, yc, wc, hc)
int xc, yc, wc, hc;
{
    GRECT t1, t2;
    int temp[4];

    hide_mouse();
    t2.g_x=xc;
    t2.g_y=yc;
    t2.g_w=wc;
    t2.g_h=hc;
    vsf_interior(handle, 1);
    vsf_color(handle, 0);
    wind_get(wi_handle, WF_FIRSTXYWH, &t1.g_x, &t1.g_y, &t1.g_w, &t1.g_h);
    while (t1.g_w && t1.g_h) {
	if (rc_intersect(&t2, &t1)) {
	    set_clip(t1.g_x, t1.g_y, t1.g_w, t1.g_h);
	    temp[0] = xwork;
	    temp[1] = ywork;
	    temp[2] = xwork + wwork - 1;
	    temp[3] = ywork + hwork - 1;
	    v_bar(handle, temp);
	}
	wind_get(wi_handle, WF_NEXTXYWH, &t1.g_x, &t1.g_y, &t1.g_w, &t1.g_h);
    }

    show_mouse();
}


/*
 * Hide the mouse.
 *
 */
hide_mouse()
{
    if (!hidden) {
	graf_mouse(M_OFF, 0L);
	hidden = TRUE;
    }
}


/*
 * Show the mouse.
 *
 */
show_mouse() 
{
    if (hidden) {
	graf_mouse(M_ON, 0L);
	hidden = FALSE;
    }
}


/*
 * Set clipping rectangle.
 *
 */
set_clip(x, y, w, h)
int x, y, w, h;
{
    int clip[4];

    clip[0] = x;
    clip[1] = y;
    clip[2] = x + w;
    clip[3] = y + h;
    vs_clip(handle, 1, clip);
}


/*
 * "Execute" form,
 * return thingy that caused the exit.
 *
 */
execform(tree)
OBJECT tree[];
{
    int thingy;

    ARROW_MOUSE;
    dsplymsg(tree);
    thingy = form_do(tree, 0);
    erasemsg();
    BEE_MOUSE;
    return thingy;
}


/*
 *  Display a dialogue box on the screen.
 *	Input:
 *		tree - object tree for dialogue box to be displayed.
 *	Output:
 *		formw, formh, sx, sy, lx, ly - dimensions of box.
 */
dsplymsg(tree)
OBJECT *tree;
{
    form_center(tree,&lx, &ly, &formw, &formh);

    
    form_dial(1, 0, 0, 0, 0, lx, ly, formw, formh);
    objc_draw(tree, 0, MAX_DEPTH, 0, 0, wdesk, hdesk);
}


/*
 *  Erase a dialogue box from the screen.
 *	Input:
 *		formw, formh, sx, sy, lx, ly - dimensions of box.
 */
erasemsg()
{
    form_dial(3, 0, 0, 0, 0, lx, ly, formw, formh);
}




/*
 * Fill the buffer with 0xffff start from giving pointer
 * to the end of buffer.
 */

fillfat(buf, start, size, pattern)
char *buf;
long start;
long size;
int pattern;
{
    long i;	/* index */
    
    for (i = start; i < size; i += 2)
	*(int *)&buf[i] = pattern;
}




/*
 *  Get size of the Bad Sector List (in sectors)
 *	Input:
 *		pdev - physical unit BSL belongs to.
 *	Return:
 *		number of sectors BSL occupies.
 */
long 
gbslsiz(pdev) 
int pdev;	/* physical device number */
{
    char bs[512];	/* boot sector image */
    UWORD  ret;
    
   	if ((ret = getroot(pdev, bs, (SECTOR)0)) != 0) {
   		if (tsterr(ret) == OK)
		    return MDMERR;
		else return ERROR;
   	}
   	if (((RSECT *)(bs + 0x200 - sizeof(RSECT)))->bsl_st != STBSL)
   	    return 0L;
   	return(((RSECT *)(bs + 0x200 - sizeof(RSECT)))->bsl_cnt);
}





