V4/nsys/dmr/tdir/tiu.c

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

#
/*
 * TIU (DR11-B) interface to Spider
 */

#include "/sys/nsys/param.h"
#include "/sys/nsys/conf.h"
#include "/sys/nsys/user.h"
#include "/sys/nsys/buf.h"
#include "/sys/nsys/file.h"
#include "/sys/nsys/reg.h"

#define	NCHAN	8

/* bits in tiuch flags */
#define	T_WRITR	01
#define	T_RAVL	02
#define	T_ERROR	04
#define	T_DONE	010
#define	T_OPEN	020
#define	T_EOF	040

/* drst bits */
#define	T_TERROR 0100000
#define	T_REJ	04000
#define	T_IDLE	02000

/* drdb bits */
#define	T_BKSTS	0100000
#define	T_SLSTS	040000
#define	T_WTSTS	010000
#define	T_TROUB	02000
#define	T_ODD	01000
#define	T_SIGNL	0400
#define	T_SELW	0200

#define	TIUPRI	2
#define	TIUADDR	172430

/* tiu command bits */
#define	IENABLE	0100
#define	GO	01
#define	STOP	0
#define	RCH	02
#define	RDC	04
#define	RNM	06
#define	WSB	010
#define	WCH	012
#define	WDC	014
#define	WDB	016

#define	SREAD	1
#define	SWRITE	2
#define	SWSIG	3
#define	SWDONE	4

struct {
	int	drwc;
	int	drba;
	int	drst;
	int	drdb;
};
struct tiuch {
	char	t_flags;
	char	t_isig;
	char	t_osig;
	char	t_troub;
	char	*t_buffer;
};

struct tiuch tiu_dchan[NCHAN];
struct tiuch tiu_cchan[NCHAN];

struct {
	char	lbyte;
	char	hbyte;
};

struct tiu {
	char	t_state;
	char	t_chan;
	char	t_wflg;
	struct buf	*t_actf;
	struct buf	*t_actl;
} tiu;

tiuopen(dev, flag)
{
	struct tiuch *cp;

	for (cp=tiu_dchan; cp < &tiu_dchan[NCHAN]; cp++) {
		if (cp->t_flags&T_OPEN || (cp+NCHAN)->t_flags&T_OPEN)
			continue;
		cp->t_flags = T_OPEN;
		cp->t_osig = 1;
		return;
	}
	u.u_error = ENXIO;
}

tiuclose()
{
}

tiuwrite(dev)
{
	int n, i, c;
	struct tiuch *cp;
	struct buf *bp;
	char *p;

	if ((cp = tiuchan(&i)) == NULL)
		return;
	spl5();
	if (cp->t_flags&T_WRITR == 0) {
		while(tiubusy()) {
			tiu.t_wflg++;
			sleep(&tiu, TIUPRI);
		}
		stiuchan(i+0200);	/* select W */
	}
	spl0();
	do {
		bp = getblk(NODEV);
		bp->b_flags = 0;
		p = bp->b_addr;
		for (n=0; n<512 && passc(&c) >= 0; n++)
			*p++ = c;
		if (u.u_count == 0 || u.u_error)
			bp->b_flags.hbyte = cp->t_osig;
		bp->b_wcount = n;
		bp->b_blkno = i;
		spl5();
		while ((cp->t_flags&(T_WRITR|T_ERROR)) == 0)
			sleep(cp, TIUPRI);
		cp->t_flags =& ~T_DONE;
		tiustrategy(bp);
		while ((cp->t_flags&(T_DONE|T_ERROR)) == 0)
			sleep(bp, TIUPRI);
		spl0();
		if (cp->t_flags&T_ERROR)
			u.u_error = EIO;
		brelse(bp);
	} while (u.u_count>0 && u.u_error==0);
}

tiuread(dev)
{
	int i, n;
	char *p;
	struct tiuch *cp;
	struct buf *bp;

	if ((cp = tiuchan(&i)) == NULL)
		return;
	i = cp - tiu_dchan;
	do {
		if (bp = cp->t_buffer) {
			n = bp->b_wcount;
			p = bp->av_forw;
		} else {
			spl5();
			while ((cp->t_flags&(T_RAVL|T_ERROR|T_EOF))==0)
				sleep(cp, TIUPRI);
			if (cp->t_flags&T_ERROR)
				goto rerr;
			if (cp->t_flags&T_EOF)
				return;
			bp = getblk(NODEV);
			bp->b_flags = B_READ;
			bp->b_blkno = i;
			cp->t_flags =& ~T_DONE;
			tiustrategy(bp);
			while ((cp->t_flags&(T_DONE|T_ERROR|T_EOF)) == 0)
				sleep(cp, TIUPRI);
			cp->t_isig = bp->b_flags.hbyte;
			if (cp->t_flags&T_ERROR)
		    rerr:
				u.u_error = EIO;
			n = bp->b_wcount;
			p = bp->b_addr;
			spl0();
		}
		if (cp->t_flags&T_EOF) {
			n = 0;
			u.u_count = 0;
		}
		while ((n--)>0 && cpass(*p++)>=0);
		if (n<=0 || u.u_error) {
			bp->b_flags = 0;
			brelse(bp);
		} else {
			bp->b_wcount = n;
			bp->av_forw = p;
			cp->t_buffer = bp;
		}
	} while (u.u_count && u.u_error==0);
}

tiustart()
{
	struct buf *bp;

	if (tiubusy())
		return;
	if ((bp = tiu.t_actf)==0) {
		if (tiu.t_wflg) {
			tiu.t_wflg = 0;
			wakeup(&tiu);
		}
		return;
	}
	stiuchan(bp->b_blkno);
	TIUADDR->drba = bp->b_addr;
	if (bp->b_flags&B_READ) {
		TIUADDR->drwc = -256;
		tiu.t_state = SREAD;
		TIUADDR->drst = IENABLE|RDC|GO;
	} else {
		tiu.t_state = SWRITE;
		if ((TIUADDR->drwc = -(bp->b_wcount>>1))==0) {
			tiuintr();
			return;
		}
		TIUADDR->drst = IENABLE|WDC|GO;
	}
}

stiuchan(c)
{
	if (c != tiu.t_chan) {
		tiu.t_chan = c&0177;
		if ((c&0177)>=NCHAN)
			c =+ 64-NCHAN;
		TIUADDR->drdb = c;
		TIUADDR->drst = IENABLE|WCH|GO;
	}
}

tiuintr()
{
	struct buf *bp;
	struct tiuch *cp, *bcp;
	int i, s;

	if (TIUADDR->drst&(T_TERROR|T_REJ)) {
		tiuerr(-1, 2);
		return;
	}
	if (tiu.t_chan>=0)
		cp = &tiu_dchan[tiu.t_chan];
	else
		cp = NULL;
	s = tiu.t_state;
	tiu.t_state = 0;
	if (s) {
		bp = tiu.t_actf;
		if (bp==NULL || cp==NULL) {
			tiuerr(-1, 0);
			return;
		}
	}
	if (TIUADDR->drdb&T_TROUB) {
		tiuerr(tiustop(), TIUADDR->drdb);
		goto done;
	}
	switch (s) {

	case SREAD:
		if (TIUADDR->drdb&T_SIGNL == 0) {
			tiuerr(tiustop(), 10);
			goto done;
		}
		s = 512 + (TIUADDR->drwc<<1);
		if ((TIUADDR->drst&T_ODD) == 0)
			s--;
		if ((bp->b_flags.hbyte = TIUADDR->drdb) != 0)
			cp->t_flags =& ~T_RAVL;
		goto done;

	case SWRITE:
		if (bp->b_wcount&01) {
			TIUADDR->drdb = bp->b_addr[bp->b_wcount-1];
			TIUADDR->drst = IENABLE|WDB|GO;
			if ((TIUADDR->drst & T_IDLE)==0) {
				tiu.t_state = SWSIG;
				return;
			}
		}

	case SWSIG:
		cp->t_flags =& ~T_WRITR;
		TIUADDR->drdb = bp->b_flags.hbyte;
		TIUADDR->drst = IENABLE|WSB|GO;
		if ((TIUADDR->drst & T_IDLE)==0) {
			tiu.t_state = SWDONE;
			return;
		}

	done:
	case SWDONE:
		tiu.t_state = 0;
		tiu.t_actf = bp->av_forw;
		wakeup(cp);
		cp->t_flags =| T_DONE;

	default:
		if (TIUADDR->drdb&T_WTSTS && cp)
			cp->t_flags =| T_WRITR;
		while (TIUADDR->drdb&T_BKSTS) {
			TIUADDR->drst = IENABLE|RCH|GO;
			i = TIUADDR->drdb&0177;
			if (i>=64)
				i =+ NCHAN-64;
			if (i<0 || i >= 2*NCHAN) {
				i = 0;
				tiuerr(-1, 0);
			}
			bcp = &tiu_dchan[i];
			if (s==0 || bcp != cp)
				bcp =| (TIUADDR->drdb&T_SELW)?
					T_RAVL:T_WRITR;
			wakeup(bcp);
		}
		tiustart();
	}
}

tiustop()
{
	register int lastchan;

	lastchan = tiu.t_chan;
	tiu.t_chan = -1;
	tiu.t_state = 0;
	TIUADDR->drst = IENABLE|STOP|GO;
	return(lastchan);
}

tiuerr(chan, code)
{
	struct tiuch *cp;

	if (0>=chan && chan<2*NCHAN || (code&0177)>2)
		tiucherr(&tiu_dchan[chan], code);
	else {
		tiu.t_state = 0;
		tiu.t_actf = 0;
		wakeup(&tiu);
		for (cp = tiu_dchan; cp < &tiu_dchan[2*NCHAN]; cp++)
			tiucherr(cp, code);
	}
}

tiucherr(cp, code)
struct tiuch *cp;
{
	cp->t_flags =& ~(T_WRITR|T_RAVL);
	cp->t_flags =| T_ERROR|T_DONE;
	cp->t_troub = code;
	if (cp->t_buffer) {
		brelse(cp->t_buffer);
		cp->t_buffer = NULL;
	}
	wakeup(cp);
}

tiuchan(ip)
int *ip;
{
	register struct tiuch *cp;

	*ip = u.u_offset[1].hbyte;
	cp = &tiu_dchan[*ip];
	if (cp->t_flags&(T_ERROR|T_EOF)) {
		if (cp->t_flags&T_ERROR)
			u.u_error = EIO;
		return(NULL);
	}
	return(cp);
}

tiubusy()
{
	if (TIUADDR->drst&T_IDLE && TIUADDR->drdb&T_SLSTS)
		return(1);
	return(0);
}

tiustrategy(abp)
struct buf *abp;
{
	register struct buf *bp;

	bp = abp;
	bp->av_forw = NULL;
	if (tiu.t_actf==NULL) {
		tiu.t_actf = bp;
		tiustart();
	} else
		tiu.t_actl->av_forw = bp;
	tiu.t_actl = bp;
}

snstat()
{
	struct file *fp;
	struct tiu *cp;
	int op;

	op = fubyte(u.u_arg[1]);
	if ((fp=getf(u.u_ar0[R0]))==NULL)
		return;
	cp = &tiu_dchan[fp->f_offset[1].hbyte];
	switch (op) {

	/* get signal byte */
	case 0:
		cp->t_osig = fubyte(u.u_arg[0]);
		return;

	/* get signal byte */
	case 1:
		subyte(u.u_arg[0], cp->t_isig);
		cp->t_isig = 0;
		return;

	/* get channel # */
	case 2:
		op = fp->f_offset[1].hbyte;
		if (op>=NCHAN)
			op =+ 64-NCHAN;
		subyte(u.u_arg[0], op);
		return;

	/* get trouble code */
	case 3:
		subyte(u.u_arg[0], cp->t_troub);
		cp->t_troub = 0;
		cp->t_flags =& ~T_ERROR;
		return;

	/* clear EOF request */
	case 4:
		if (cp >= &tiu_dchan[NCHAN])
			cp =- NCHAN;
		cp->t_flags =& ~T_EOF;
		return;

	/* set EOF request */
	case 5:
		if (cp >= &tiu_dchan[NCHAN])
			cp =- NCHAN;
		cp->t_flags =| T_EOF;
		return;

	/* open control channel */
	case 6:
		if (cp < &tiu_dchan[NCHAN])
			cp =+ NCHAN;
		if (cp->t_flags&T_OPEN) {
			u.u_error = EINVAL;
			return;
		}
		if ((fp = falloc())==NULL)
			return;
		cp->t_flags = T_OPEN;
		return;
	}
	u.u_error = EINVAL;
}