V7M/sys/dev/du.c

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

/*
 * DU-11 Synchronous interface driver
 */

#include "../h/param.h"
#include "../h/systm.h"
#include "../h/dir.h"
#include "../h/user.h"
#include "../h/buf.h"

/* device registers */
struct dureg {
	int	rxcsr, rxdbuf;
#define	parcsr	rxdbuf
	int	txcsr, txdbuf;
};

struct du {
	struct dureg	*du_addr;
	int		du_state;
	struct proc	*du_proc;
	struct buf	*du_buf;
	caddr_t		du_bufb;
	caddr_t		du_bufp;
	int		du_nxmit;
	int		du_timer;
} du[] = {
	{ (struct dureg *) 0160110 },
};

#define	NDU	(sizeof(du)/sizeof(du[0]))

#define	DONE	0200
#define	IE	0100
#define	SIE	040
#define CTS	020000
#define	CARRIER	010000
#define	RCVACT	04000
#define	DSR	01000
#define STRIP	0400
#define SCH	020
#define RTS	04
#define	DTR	02
#define MR	0400
#define SEND	020
#define	HALF	010

#define	READ	0
#define	WRITE	1
#define PWRIT	2

#define	DUPRI	(PZERO+1)

duopen(dev)
register dev;
{
	int dutimeout();
	register struct du *dp;
	register struct dureg *lp;

	dev = minor(dev);
	if (dev >= NDU ||
	   ((dp = &du[dev])->du_proc!=NULL && dp->du_proc!=u.u_procp)) {
		u.u_error = ENXIO;
		return;
	}
	dp->du_proc = u.u_procp;
	lp = dp->du_addr;
	if (dp->du_buf==NULL) {
		dp->du_buf = geteblk();
		dp->du_bufb = dp->du_buf->b_un.b_addr;
		dp->du_state = WRITE;
		lp->txcsr = MR;
		lp->parcsr = 035026;		/* Sync Int, 7 bits, even parity, sync=026 */
		timeout(dutimeout, (caddr_t)dp, HZ);
		duturn(dp);
	}
}

duclose(dev)
{
	register struct du *dp;
	register struct dureg *lp;

	dp = &du[minor(dev)];
	lp = dp->du_addr;
	lp->rxcsr = 0;
	lp->txcsr = 0;
	dp->du_timer = 0;
	dp->du_proc = 0;
	if (dp->du_buf != NULL) {
		brelse(dp->du_buf);
		dp->du_buf = NULL;
	}
}

duread(dev)
{
	register char *bp;
	register struct du *dp;

	dp = &du[minor(dev)];
	bp = dp->du_bufb;
	for(;;) {
		if(duwait(dev))
			return;
		if (dp->du_bufp > bp)
			break;
		spl6();
		if (dp->du_timer <= 1) {
			spl0();
			return;
		}
		sleep((caddr_t)dp, DUPRI);
		spl0();
	}
	u.u_offset = 0;
	iomove(dp->du_bufb, (int)min(u.u_count, (unsigned)(dp->du_bufp-bp)), B_READ);
}

duwrite(dev)
{
	register struct du *dp;
	register struct dureg *lp;

	dev = minor(dev);
	dp = &du[dev];
	if (u.u_count==0 || duwait(dev))
		return;
	dp->du_bufp = dp->du_bufb;
	dp->du_state = PWRIT;
	dp->du_addr->rxcsr &= ~SCH;
	dp->du_addr->rxcsr = SIE|RTS|DTR;
	if (u.u_count > BSIZE)
		u.u_count = BSIZE;
	dp->du_nxmit = u.u_count;
	u.u_offset = 0;
	iomove(dp->du_bufb, (int)u.u_count, B_WRITE);
	lp = dp->du_addr;
	dp->du_timer = 10;
	spl6();
	while((lp->rxcsr&CTS)==0)
		sleep((caddr_t)dp, DUPRI);
	if (dp->du_state != WRITE) {
		dp->du_state = WRITE;
		lp->txcsr = IE|SIE|SEND|HALF;
		dustart(dev);
	}
	spl0();
}

duwait(dev)
{
	register struct du *dp;
	register struct dureg *lp;

	dp = &du[minor(dev)];
	lp = dp->du_addr;
	for(;;) {
		if ((lp->rxcsr&DSR)==0 || dp->du_buf==0) {
			u.u_error = EIO;
			return(1);
		}
		spl6();
		if (dp->du_state==READ &&
			((lp->rxcsr&RCVACT)==0)) {
			spl0();
			return(0);
		}
		sleep((caddr_t)dp, DUPRI);
		spl0();
	}
}

dustart(dev)
{
	register struct du *dp;
	register struct dureg *lp;

	dp = &du[minor(dev)];
	lp = dp->du_addr;
	dp->du_timer = 10;
	if (dp->du_nxmit > 0) {
		dp->du_nxmit--;
		lp->txdbuf = *dp->du_bufp++;
	} else {
		duturn(dp);
	}
}

durint(dev)
{
	register struct du *dp;
	register c, s;
	int dustat;

	dp = &du[minor(dev)];
	dustat = dp->du_addr->rxcsr;
	if(dustat<0) {
		if((dustat&CARRIER)==0 && dp->du_state==READ)
			duturn(dp);
		else
			wakeup((caddr_t)dp);
	} else
	if(dustat&DONE) {
		dp->du_addr->rxcsr = IE|SIE|SCH|DTR;
		c = s = dp->du_addr->rxdbuf;
		c &= 0177;
		if(s<0)
			c |= 0200;
		if (dp->du_bufp < dp->du_bufb+BSIZE)
			*dp->du_bufp++ = c;
	}
}

duxint(dev)
{
	register struct du *dp;
	register struct dureg *lp;
	register int dustat;

	dp = &du[minor(dev)];
	lp = dp->du_addr;
	dustat = lp->txcsr;
	if(dustat<0)
		duturn(dp);
	else if(dustat&DONE)
		dustart(dev);
}

duturn(dp)
register struct du *dp;
{
	register struct dureg *lp;

	lp = dp->du_addr;
	if (dp->du_state!=READ) {
		dp->du_state = READ;
		dp->du_timer = 10;
		dp->du_bufp = dp->du_bufb;
	}
	lp->txcsr = HALF;
	lp->rxcsr &= ~SCH;
	lp->rxcsr = STRIP|IE|SIE|SCH|DTR;
	wakeup((caddr_t)dp);
}

dutimeout(dp)
register struct du *dp;
{
	if (dp->du_timer == 0)
		return;
	if (--dp->du_timer == 0) {
		duturn(dp);
		dp->du_timer = 1;
	}
	timeout(dutimeout, (caddr_t)dp, HZ);
}