SRI-NOSC/dmr/misc/da.c

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

#
/*
 * add check to see if system is built right : if swap or root is on
 * aed, then....
 */
/*
 * DA Converter Driver
 *
 * Modified 26Nov77 J.S.Kravitz to allow
 *
 * 1) Display list operation after particular stty call (eventuall, all will
 *    be display list operation, but for the moment, this is compatible
 *    with existing software.)
 * 2) Writes from multiple processes
 * 3) gtty returns various values, depending on last stty call
 *
 */

#include	"/usr/sys/h/param.h"
#include	"/usr/sys/h/buf.h"
#include	"/usr/sys/h/conf.h"
#include	"/usr/sys/h/user.h"
#include	"/usr/sys/h/da.h"

struct
{
	char	lo_byte;
	char	hi_byte;
};

struct devtab daadtab;		/* aed device driver table */

struct buf	dapbuf;		/* for passing parameters between
				 * write and strategy routines with help
				 * from physio
				 */

struct buf	dabuf[2];	/* the buffer headers for ad and da;
				 * two for double-buffering
				 */

int	dabufn;			/* selects current dabuf */

#define	DABSIZE	2560		/* buffer size */

#define	DABLREC	(2560/256)	/* NOTE: NUMERATOR MUST = DABSIZE !!!
				 * this is the number of disk blocks per record
				 */

struct buf	*daorgbp;	/* will point to original buffer header */

char	*daebn;			/* block number of last block to be
				 *  transferred
				 */

int	daewc;			/* word count for last transfer */

struct
{
	int	word;
};

struct {
	int	adds;
	int	ader;
	int	adcs;
	int	adwc;
	int	adba;
	int	adca;
	int	adda;
};

#define	ADADDR	0176710

struct			/* global dec for the ad format structs */
{
	char	*nblocks;
	int	cyloff;
}
ad_sizes[8];


dastrategy(bufp)
struct buf	*bufp;
{
	register struct buf	*bp;
	register int	ub;		/* copy of u.u_base for getting
					 * params out of user space
					 */
	register int	ssplno;		/* holds index of 1st desired sample
					 * in 1st buffer, becomes virtual
					 * address of same later
					 */
	char	*t[4];			/* will hold params when we get them
					 * from user space
					 */

	bp = bufp;			/* get pointer to param buffer */
	daorgbp = bp;			/* remember for dastart's use later */
	if ( (-bp->b_wcount) < ((DABSIZE * 2) + 4) )	/* user's buffer too
							   small? */
	{
badpar:		/* come here on bad param errors */
		bp->b_flags =| B_ERROR;		/* set buf's error bit */
		bp->b_error = EINVAL;		/* set error code */
		iodone(bp);			/* takes care of the rest */
		return;				/* we're all done */
	}
	ub = u.u_base;		/* get virtual address of user's write */
	t[0] = fuword(ub);	/* get 1st sample number (2 words) */
	t[1] = fuword(ub =+ 2);
	t[2] = fuword(ub =+ 2);	/* get last sample number (2 words) */
	t[3] = fuword(ub =+ 2);
	ssplno = t[1].lo_byte & 0377;	/* 1st sample # mod 256
					 * gives 1st sample # in 1st block
					 */
	dabuf[0].b_blkno = lshift(&t[0],-8);	/* 1st sample # div 256
						 * gives 1st block #
						 */
	t[1] = lrem(dabuf[0].b_blkno,DABLREC);	/* 1st block # mod blocks/rec
						 * gives residue of 1st block
						 * in 1st record
						 */
	dabuf[0].b_blkno =- t[1];	/* 1st block # - residue
					 * gives block # of 1st record
					 */
	ssplno =+ (t[1] <<8);		/* (1st sample # in 1st block)
					 * +(block residue * 256)
					 * gives 1st sample # in 1st record
					 */
		/* the following work similarly to the previous, but it
		 * is the quantities for the last sample we are computing;
		 * note that we compute a word count (negative).
		 */
	daewc = t[3].lo_byte & 0377;
	daebn = lshift(&t[2],-8);
	t[3] = lrem(daebn,DABLREC);
	daebn =- t[3];
	daewc = -(daewc + (t[3] << 8) );

	if ( daewc == 0 )		/* final word count = 0? */
	{
		daewc = -DABSIZE;	/* set to full buffer size */
		daebn =- (DABLREC);	/* decrease last block number
						   by blocks per buffer */
	}
	if (daebn <= dabuf[0].b_blkno)	/* last block # <= first? */
		goto	badpar;		/* process bad parameter */
	dabuf[0].b_wcount = dabuf[1].b_wcount = -DABSIZE;	/* word counts */
	dabuf[0].b_dev = dabuf[1].b_dev = DAADDEV;	/* devices */
	dabuf[0].b_error = dabuf[1].b_error = 0;	/* error codes */
	dabuf[0].b_addr = bp->b_addr + 010;		/* buffer addr (skip over
							   params ) */
	dabuf[0].b_xmem = bp->b_xmem;		/* copy xmem bits */
	if ( dabuf[0].b_addr < bp->b_addr )	/* did adding to addr overflow?
						*/
	{
		dabuf[0].b_xmem++;	/* increment xmem bits */
	}
	dabuf[0].b_flags = B_READ;		/* set read bit */
	dabuf[1].b_flags = B_READ;		/* in both buffers */
	dabuf[1].b_addr = dabuf[0].b_addr + (DABSIZE<<1);
						/* addr of 2nd buf is 1st +
						   buffer size */
	dabuf[1].b_xmem = dabuf[0].b_xmem;	/* copy xmem bits */
	if ( dabuf[1].b_addr < dabuf[0].b_addr ) /* did addr overflow? */
	{
		dabuf[1].b_xmem++;	/* increment xmem bits */
	}
	DAADDR->dadrba = 0;			/* clear ba overflow if any */
	DAADDR->dadrst = ( DARSET1 | DARESET);		/* reset attention */
	daadstrategy(&dabuf[0]);		/* start 1st disk transfer */
	dabufn = 0;			/* set buffer switch */
	/*
	 * reset done, diskwaiting and converter waiting flags
	 */
	dastate =& ~ ( DADONE | DAADWT | DACVWT );
	iowait(&dabuf[0]);		/* wait for 1st disk read */
	dastate =| DAADLOCK;			/* set ad lockout of other requests */
	spl1();				/* let interrupts happen */
	/*
	 * wait until all aed requests are done, and then swipe
	 * controller
	 */
	while ( (daadtab.d_active | daadtab.d_actf) != 0 );
	dastate =| DAADISW | DASEEK;
	DAADDR->dadrst = DARESET;		/* reset reset attention */
	ub = u.u_base;			/* set back to beg of buffer */
	for ( ssplno =+ ub ; --ssplno >= ub ; )		/* loop thru virtual
							   addresses of undesired
							   samples in 1st buffer,
							   if any */
		suword(ssplno,0);	/* set undesired samples to zero */
	dabuf[1].b_blkno = dabuf[0].b_blkno + (DABLREC);	/* block number for 2nd block */
	dadskstart(&dabuf[1]);		/* start read of 2nd block */
	sleep (&dastate, PRIBIO);	/* wait til done */
	spl6();				/* no interrupts during dastart */
	bp->b_flags =& ~B_DONE;		/* reset done to avoid trouble */
	dastart();	/* start conversion */
	sleep (&dastate.hibyte, PRIBIO);	/* wait til done */
	iodone(bp);	/* io is finished */
}


dastart()
{
	register struct buf	*dabp,		/* will point to buffer now
						   going to converter */
				*adbp;		/* will point to buffer now
						   going to disk */

	if ( daorgbp->b_flags & B_DONE )	/* already done? */
		return;
	if ( dastate & DADONE )		/* all done? */
	{
		DAADDR->dadrst =& ~DAINTENB;	/* shut off converter interrupts */
		/*
		 * restore disk interrupt handling to normal and re-enable
		 * other's use of the disk
		 */
		dastate =& ~ (DAADISW | DAADLOCK);
		wakeup (&dastate.hibyte);	/* wake waiters on it */
		return;				/* that's all */
	}
	dabp = &dabuf[dabufn];		/* point to current buffer from disk */
	DAADDR->dadrwc = dabp->b_wcount;	/* set word count in interface */
	DAADDR->dadrba = dabp->b_addr;	/* set buffer address in interface */
	/*
	 * set interface status: extended mem bits, interrupt enable
	 * reset attention, set go
	 */
	DAADDR->dadrst = ( (dabp->b_xmem << DAMEMSHIFT) & DAXMEM)
			| (DARESET | DAINTENB | DAGO)
			| ( (dastate & DASETSTEREO) ? DASTEREO:0);
	adbp = &dabuf[dabufn =^ 1];	/* point to other buffer */
	/* next block number is previous + blocks per record;
	 * is this <= last block number?
	 */
	if ( (adbp->b_blkno = dabp->b_blkno + (DABLREC)) <= daebn )
	{
		if ( adbp->b_blkno == daebn )	/* last read? */
			adbp->b_wcount = daewc;	/* set word count */
		adbp->b_flags = B_READ;		/* set read */
		dadskstart(adbp);		/* start read */
	}
	else		/* block number > last block number */
	{
		dastate =| DADONE;	/* set done flag */
	}
}

dadskstart(bp)
struct buf	*bp;
{
	register char	*p1,	/* scratch for computations */
			*p2;

	p1 = bp->b_blkno;	/* get block # */
	p2 = lrem(p1,10);	/* sector */
	p1 = ldiv(p1,10);	/* cylinder and track */
	ADADDR->adda = (p1 % 20) << 8 | p2;
	devstart(bp,&ADADDR->adca, ad_sizes[DAADDEV].cyloff +(p1/20),0);
}

daintr()
{
	if ( dastate & DADONE )	/* all done? */
	{
		dastart();	/* final processing */
		return;
	}
	if ( DAADDR->dadrst < 0 )	/* error? */
	{
		/*
		 * no error bits set and buf addr = 0?
		 */
		if ( ( (DAADDR->dadrst & DAEBITS) | DAADDR->dadrba) == 0 )
		{
			/*
			 * reset error condition and re-init
			 */
			DAADDR->dadrba = 0;	/* yes, 0 = 0, resets error */
			DAADDR->dadrst = ((DAADDR->dadrst + DAINCMEM) & DAXMEM)
					 | (DARESET | DAINTENB | DAGO);
			return;		/* that's all */
		}
		/*
		 * set error bit in original request
		 */
		daorgbp->b_flags =| B_ERROR;
		dastate =| DADONE;		/* set done flag */
		dastart();			/* process done */
		return;
	}
	if ( dastate & DAADWT )		/* disk waiting? */
	{
		dastate =& ~ DAADWT;	/* reset flag */
		dastart();		/* start conversion */
	}
	else				/* last read not complete */
	{
		dastate =| DACVWT;	/* set converter waiting flag */
	}
}

dadskint()
{
	spl6();					/* lock out converter ints */
	if ( dastate & DASEEK )			/* seeking 2nd block? */
	{
		dastate =& ~ DASEEK;		/* reset flag */
		wakeup (&dastate);		/* wake waiter */
		return;
	}
	if ( dastate & DADONE )			/* all done? */
		return;
	if ( ADADDR->adcs < 0 )			/* disk error? */
	{
		daorgbp->b_flags =| B_ERROR;	/* set error flag in buf */
		dastate =| DADONE;		/* set done flag */
		dastart();			/* process done */
		return;
	}
	if ( dastate & DACVWT )			/* converter waiting? */
	{
		dastate =& ~ DACVWT;		/* reset flag */
		dastart();			/* and start converter */
	}
	else
	{
		dastate =| DAADWT;		/* else set disk wait flag */
	}
}

dawrite(dev)
{
	physio (dastrategy, &dapbuf, dev, B_WRITE);
}

dasgtty(dev,vec)
int	*vec;
{
	register int	*v;

	v = vec;
	if ( v != 0 )				/* gtty */
	{
		switch (dastate & DARETMODES)
		{
		case DANORM:
			*v++ = DAADDR->dadrwc;
			*v++ = DAADDR->dadrba;
			*v++ = DAADDR->dadrst;
			return;

		case DARETSTATE:
			*v++ = 0;
			*v++ = 0;
			*v++ = 0;
			return;
		}
	}
	switch (u.u_arg[0])
	{
	case 0:
		DAADDR->dadrst = u.u_arg[1];
		return;

	case 1:
		/*
		 * damn well better not be a transfer running now
		 */
		dastate = (dastate & ~DASETMODES)
			| (u.u_arg[1] & DASETMODES);
		return;
	}
}

daopen()
{
}

daclose()
{
}