/* fmt.c */

#include "obdefs.h"
#include "osbind.h"
#include "mydefs.h"
#include "part.h"
#include "hdx.h"
#include "addr.h"
#include "error.h"

#define MFM 17			/* sectors per track of MFM */
#define RLL 26			/* sectors per track of RLL */

extern long ostack;
extern int typedev;
extern int typedrv;
extern char sbuf[];

/*
 * These constants are used in a heuristic that determines
 * if the format parameter information in the boot sector
 * is intact.  (See fmtpok()).
 */
#define	MAXCYLS		4096		/* max number of cylinders */
#define	MINCYLS		100		/* minimum number of cylinders */
#define	MAXHEADS	16		/* max number of heads */
#define	MINHEADS	2		/* minimum number of heads */
#define	MAXLZ		16		/* max landing zone value */
#define	MAXRT		2		/* max step-rate code */


/*
 * These are the default format parameters;
 * they are for a 20Mb Mutsubuishi drive.
 *
 * @ If we change drives, this might have to be changed.
 *
 */
HINFO deffmt = {
	0x264,		/* 612 cylinders */
	4,			/* 4 heads */
	0x264,		/* no reduced write-current cylinder */
	0x264,		/* no write precomp cylinder */
	10,			/* landing zone position = 10 */
	2,			/* 2 use buffered seeks */
	1,			/* 2 interleave = 1 */
	17			/* 17 sectors per track */
};


/*
 * Report format error.
 *
 */
formaterr(dev)
int dev;
{
    char *pdev="X";
    
	if (dev > 7) dev -= 8;
    *pdev = dev + '0';
    (cantform[FMTDEV].ob_spec)->te_ptext = pdev;
    cantform[FMTERROK].ob_state = NORMAL;
    execform(cantform);
    return ERROR;
}


/*
 * Set format parameters in a
 * root sector image.
 * 6-13-88  only set size of hard disk.
 *
 */

sdisksiz(image, hdsiz)
char *image;
long hdsiz;
{
    ((RSECT *)(image + 0x200 - sizeof(RSECT)))->hd_siz = hdsiz;

}


/*
 * Set format parameters in a
 * root sector image.
 *
 */
sfmtparm(image, fmtparm)
char *image;
HINFO *fmtparm;
{
	register HINFO *rinfo;
	register long siz;

    rinfo = &((RSECT *)(image + 0x200 - sizeof(RSECT)))->hd_info;
	rinfo->hi_cc = fmtparm->hi_cc;
	rinfo->hi_dhc = fmtparm->hi_dhc;
	rinfo->hi_rwcc = fmtparm->hi_rwcc;
	rinfo->hi_wpc = fmtparm->hi_wpc;
	rinfo->hi_lz = fmtparm->hi_lz;
	rinfo->hi_rt = fmtparm->hi_rt;
	rinfo->hi_in = fmtparm->hi_in;
	rinfo->hi_spt = fmtparm->hi_spt;

	/* Compute total disk size
	 * = <#cyls> * <#heads> * <#sectors / track>
	 */
    ((RSECT *)(image + 0x200 - sizeof(RSECT)))->hd_siz = 
		(long)fmtparm->hi_cc *
		(long)fmtparm->hi_dhc *
		(long)fmtparm->hi_spt; 

}


/*
 * Determine if format parameters are good;
 * return OK if they appear to be,
 * ERROR if they don't appear to be.
 *
 */
fmtpok(fmtparm)
HINFO *fmtparm;
{
    if (fmtparm->hi_cc > MAXCYLS ||
	fmtparm->hi_cc < MINCYLS ||
	fmtparm->hi_dhc > MAXHEADS ||
	fmtparm->hi_dhc < MINHEADS ||
	fmtparm->hi_lz > MAXLZ ||
	fmtparm->hi_rt > MAXRT)
	    return ERROR;

    return OK;
}


/*
 * Setup default format parameters in hinfo;
 * (REAL C compilers do this with a structure assignment...)
 *
 */
fdefault(hinfop)
HINFO *hinfop;
{
    hinfop->hi_cc = deffmt.hi_cc;
    hinfop->hi_dhc = deffmt.hi_dhc;
    hinfop->hi_rwcc = deffmt.hi_rwcc;
    hinfop->hi_wpc = deffmt.hi_wpc;
    hinfop->hi_lz = deffmt.hi_lz;
    hinfop->hi_rt = deffmt.hi_rt;
    hinfop->hi_in = deffmt.hi_in;
    hinfop->hi_spt = deffmt.hi_spt;
}


/*
 * Set mode information on drive.
 *
 */
ms(dev, hinfo)
int dev;
HINFO *hinfo;
{
    int i;
    char *p;
    SETMODE mb;
    extern long mdselect();

    /* initialize parameter structure */
    p = (char *)&mb;
    for (i = sizeof(SETMODE); i--;)
	*p++ = 0;
    mb.smd_8 = 0x08;
    mb.smd_1 = 0x01;
    mb.smd_bs[1] = 0x02;	/* block size = 512 */

    cpw(&mb.smd_cc[0], hinfo->hi_cc);
    mb.smd_dhc = hinfo->hi_dhc;
    cpw(&mb.smd_rwc[0], hinfo->hi_rwcc);
    cpw(&mb.smd_wpc[0], hinfo->hi_wpc);
    mb.smd_lz = hinfo->hi_lz;
    mb.smd_rt = hinfo->hi_rt;

    return (int)mdselect(dev, 22, &mb);
}


/*
 * Move `w' to unaligned location.
 *
 */
cpw(d, w)
char *d;
WORD w;
{
    char *s;

    s = (char *)&w;
    d[0] = s[0];
    d[1] = s[1];
}


/*
 * Return format parameters in `hinfo', based on
 * the format parameter name `fpnam'.
 *
 * return 0 on OK,
 * -1 on [CANCEL].
 *
 */
gfparm(dev, noinfo, modesel, hinfop, fpnam, id)
int dev;
int noinfo;			/* 1: no information inside the wincap file */
int *modesel;
HINFO *hinfop;
char *fpnam, *id;
{
    long num;
    char name[128];
	int mask=0x0001;
	int scsidrv, set, ret = OK;
	UWORD cyl; 
	BYTE nhead, sptrk;

	set = typedev & (mask << dev);
	scsidrv = typedrv & (mask << dev);
    fdefault(hinfop);
	if ((set) || (scsidrv))		{
		*modesel = 0;
	} else if (noinfo)	{
		ret = cyhdsp(dev, &cyl, &nhead, &sptrk);
    	hinfop->hi_cc = cyl;
    	hinfop->hi_dhc = nhead;
    	hinfop->hi_rwcc = cyl;
    	hinfop->hi_wpc =  cyl;
    	hinfop->hi_spt =  sptrk;
	} else {

    	strcpy(name, fpnam);
    	if (wgetent(fpnam, id) == ERROR) {
    		nofmt[NOSCHFOK].ob_state = NORMAL;
    		(nofmt[NOSCHFMT].ob_spec)->te_ptext = name;
    		execform(nofmt);
			return ERROR;
    	}

    	if (wgetnum("cy", &num) == OK) hinfop->hi_cc = (UWORD)num;
    	if (wgetnum("hd", &num) == OK) hinfop->hi_dhc = (BYTE)num;
    	if (wgetnum("rw", &num) == OK) hinfop->hi_rwcc = (UWORD)num;
    	if (wgetnum("wp", &num) == OK) hinfop->hi_wpc = (UWORD)num;
    	if (wgetnum("lz", &num) == OK) hinfop->hi_lz = (BYTE)num;
    	if (wgetnum("rt", &num) == OK) hinfop->hi_rt = (BYTE)num;
    	if (wgetnum("in", &num) == OK) hinfop->hi_in = (BYTE)num;
    	if (wgetnum("sp", &num) == OK) hinfop->hi_spt = (BYTE)num;
    	if (wgetnum("md", &num) == OK) *modesel = (UWORD)num;
	}
    return(ret);
}


/*
 *	Set mode information on a SYQUEST drive.
 *
 */

sqms(dev, sendata)
int dev;			/* physical device number */
char sendata[];
{
	extern long mdselect();
	char buf[32];

	inquiry(dev, (WORD)16, buf);
	if (buf[8] == 'Q' & buf[9] == 'U' & buf[10] == 'A' & buf[11] == 'N') 
		/* It is a QUANTUM hard disk. So don't need to set the page one. */
		return OK;
	sendata[0] = sendata[2] = 0;	/* reserved */
	sendata[3] = 0x08;				/* block descriptor length */
	sendata[12] = 0;				/* Reserved = 0; Page Code = 0 */
	sendata[13] = 0x02;				
	sendata[14] = 0x10;				/* set inhst bit in page 00 */
	sendata[15] = 0;				/* Device type qualifier  */
	return (int)mdselect(dev, 16, sendata);
}




/* 
 * get cylinder, # of head, and sector per track for ST
 */

cyhdsp(dev, cyl, nhead, sptk)

int dev;
UWORD *cyl; 
BYTE *nhead, *sptk;

{
	char *num;
	BYTE sptrk,numhead;
	int i, ret, totcyl, numtrack;
    extern long get3bytes();
    SETMODE *mb;
    SECTOR size, msiz;	/* size of media */
    char buf[512], sendata[32];
    long dmaptr, tmpptr, spcyl;
    char *dmahigh=0xffff8609,
         *dmamid=0xffff860b,
         *dmalow=0xffff860d;

	for (i = 0; i < 22; i++)
		sendata[i] = 0;
	ostack = Super(NULL);
	/* get format parameters/ disk size from emdia */
	ret = mdsense(dev, 0, 0, 22, sendata);
	delay();
	Super(ostack);
	if (ret != 0) 	{
		return ERROR;
	}
	for (i=0; i<22; i++)	{
		if (sendata[i])
			break;
	}
	if (i == 22)	/* no info return in the buf 'sendata' */
		err(needinfo);

   	get3bytes(sendata+5);  /* it's adaptec's.  Interpret as SETMODE structure */
  	mb = (SETMODE *)sendata;
	/* get number of cylinders */
	totcyl = mb->smd_cc[0];
	totcyl <<= 8;
	totcyl |= mb->smd_cc[1];
	*cyl = (UWORD)totcyl;

	/* get number of heads */
	numhead = mb->smd_dhc;
	*nhead = numhead;
  
	sptrk = (long)MFM;
	msiz = (SECTOR)numhead * (SECTOR)totcyl * sptrk;
  
	for (i = 0; i < 20; i++) {
	    if ((ret = rdsects(dev, 1, buf, msiz+i)) == OK) {

		/* find out whether data has been transferred, by
   		   checking if dma pointer has been moved.	  */

   			ostack = Super(NULL);	/* get into Supervisor mode */
  	
			dmaptr = *dmahigh;
			dmaptr &= 0x0000003f;
			dmaptr <<= 16;
			tmpptr = *dmamid;
			tmpptr &= 0x000000ff;
			tmpptr <<= 8;
			dmaptr |= tmpptr;
			tmpptr = *dmalow;
			tmpptr &= 0x000000ff;
			dmaptr |= tmpptr;

        	delay();
        	Super(ostack);		/* back to user mode */

			if (dmaptr != buf)
			    break;
   		} else {			/* rdsects return an error */
			if (tsterr(ret) == OK) {
       		     break;
			}
   		}
    }

	if (ret == MDMCHGD)		/* check if error occurred */
		return err(cruptfmt);

	/* Determine if media is MFM or RLL */
	if (i < 20)		{
		*sptk = RLL;
	} else {
		*sptk = MFM;
	}
	return OK;
}



