V10/lsys/md/consnaut.c

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

/*
 * VAX 8[578]00 console driver
 */
#include "sys/param.h"
#include "sys/stream.h"
#include "sys/ttyio.h"
#include "sys/cons.h"
#include "sys/mtpr.h"
#include "sys/conf.h"

#define	NCONS	16	/* possible console IDs */

#define	DATA	0xff
#define	IDMASK	0xff
#define	IDSHIFT	8

#define	CONPRI	(PZERO+5)	/* something interruptible */

/*
 * state bits
 */
#define	TTSTOP	01
#define	TIMEOUT	04

/*
 * cnbusy bits
 */
#define	TXBUSY	01
#define	IOBUSY	02	/* cninc/cnoutc busy */

static char cnbusy;
static char cnonext;
static char cnstate[NCONS];
static struct queue *cnrq[NCONS];
static struct queue *cnwq[NCONS];

/*
 * for internal io without device open
 */
struct cnbuf {
	int count;
	char *buf;
};
static struct cnbuf cnibuf[NCONS];
static struct cnbuf cnobuf[NCONS];
static short cnlastin;		/* debugging */

long	cnopen();
int	cnclose(), cnoput();

static struct qinit cnrinit = { nulldev, NULL, cnopen, cnclose, 0, 0 };
static struct qinit cnwinit = { cnoput, NULL, cnopen, cnclose, 200, 100 };
struct streamtab cnstream = { &cnrinit, &cnwinit };
struct cdevsw cncdev = cstrinit(&cnstream);

long
cnopen(qp, dev)
struct queue *qp;
dev_t dev;
{
	register int i;

	i = minor(dev);
	if (i >= NCONS)
		return (1);
	cnrq[i] = qp;
	cnwq[i] = WR(qp);
	qp->ptr = (caddr_t)i;
	mtpr(RXCS, mfpr(RXCS)|RXCS_IE);
	return(1);
}

cnclose(qp)
struct queue *qp;
{
	register int i;

	i = (int)qp->ptr;
	cnrq[i] = NULL;
	cnwq[i] = NULL;
}

/*
 * Console write put routine
 */
cnoput(q, bp)
register struct queue *q;
register struct block *bp;
{
	register struct ttydevb *sp;
	register int dev;

	dev = (int)OTHERQ(q)->ptr;
	switch(bp->type) {
	case M_IOCTL:		/* just acknowledge */
		sp = (struct ttydevb *)stiodata(bp);
		switch (stiocom(bp)) {
		case TIOCGDEV:
			sp->ispeed = sp->ospeed = B9600;
			bp->wptr = bp->rptr + sizeof(struct ttydevb) + STIOCHDR;
			bp->type = M_IOCACK;
			qreply(q, bp);
			return;

		case TIOCSDEV:
			bp->wptr = bp->rptr;
			bp->type = M_IOCACK;
			qreply(q, bp);
			return;

		default:
			bp->type = M_IOCNAK;
			bp->wptr = bp->rptr;
			qreply(q, bp);
			return;
		}

	case M_STOP:
		cnstate[dev] |= TTSTOP;
		break;

	case M_START:
		cnstate[dev] &= ~TTSTOP;
		cnstart();
		break;

	case M_FLUSH:
		flushq(q, 0);
		break;

	case M_DELAY:
	case M_DATA:
		if (bp->rptr >= bp->wptr)
			break;
		putq(q, bp);
		cnstart();
		return;
	
	default:		/* not handled; just toss */
		break;
	}
	freeb(bp);
}

/*
 * Console receive interrupt
 */

cnrint()
{
	register int c, dev;
	register struct queue *qp;
	register struct cnbuf *cp;

	c = mfpr(RXDB);
	dev = (c >> IDSHIFT) & IDMASK;
	cp = &cnibuf[dev];
	if (cp->count) {
		*cp->buf++ = c;
		if (--cp->count == 0)
			wakeup((caddr_t)&cp->count);
		return;
	}
	if ((qp = cnrq[dev])!=NULL) {
		if ((qp->next->flag & QFULL) == 0)
			putd(qp->next->qinfo->putp, qp->next, c);
		return;
	}
	cnlastin = c;		/* for debugging */
}

/*
 * Transmitter interrupt
 */
cnxint()
{
	cnbusy &=~ TXBUSY;
	mtpr(TXCS, mfpr(TXCS)&~TXCS_IE);
	cnstart();
}

cntime(dev)
caddr_t dev;
{
	cnstate[(int)dev] &= ~TIMEOUT;
	cnstart();
}

#define	NEXT(i)	(((i)+1)%NCONS)

cnstart()
{
	register struct block *bp;
	register int i;
	register struct queue *q;
	register struct cnbuf *cp;
	register s, j;

	s = spl6();
	if (cnbusy & TXBUSY) {
		splx(s);
		return;
	}
	i = cnonext;
	for (j = 0; j < NCONS && (cnbusy & TXBUSY) == 0; i = NEXT(i), j++) {
		cp = &cnobuf[i];
		if (cp->count) {
			mtpr(TXDB, (*cp->buf++&0377) | (i<<IDSHIFT));
			mtpr(TXCS, mfpr(TXCS)|TXCS_IE);
			cnbusy |= TXBUSY;
			if (--cp->count == 0)
				wakeup((caddr_t)&cp->count);
			continue;
		}
		if ((q = cnwq[i]) == NULL)
			continue;
		if ((cnstate[i] & (TIMEOUT|TTSTOP)) || q->count == 0)
			continue;
		bp = getq(q);
		switch (bp->type) {
		case M_DATA:
			mtpr(TXDB, (i<<IDSHIFT)|*bp->rptr++);
			mtpr(TXCS, mfpr(TXCS)|TXCS_IE);
			cnbusy |= TXBUSY;
			if (bp->rptr >= bp->wptr)
				freeb(bp);
			else
				putbq(q, bp);
			break;

		case M_DELAY:
			timeout(cntime, (caddr_t)i, (int)*bp->rptr);
			cnstate[i] |= TIMEOUT;
		default:	/* flow through */
			freeb(bp);
			break;
		}
	}
	cnonext = i;
	splx(s);
}

/*
 * Print a character on console; for printf.
 * try to preserve things; wait a bit for console to come ready.
 * all fairly hopeless.
 */
cnputc(c)
register c;
{
	register s, timo;

	timo = 3000000;
	while((mfpr(TXCS)&TXCS_RDY) == 0)
		if(--timo == 0)
			return;
	if(c == 0)
		return;
	s = mfpr(TXCS);
	mtpr(TXCS, 0);
	mtpr(TXDB, c&DATA);
	if(c == '\n')
		cnputc('\r');
	cnputc(0);
	mtpr(TXCS, s);
}

/*
 * primitives for internal console I/O
 * p = cniwrite(id, buf, count)
 * p = cniread(id, buf, count)
 * p is a pointer to an integer.
 * when the count is satisfied, *p will be zero and p will be awakened
 * *p = 0 aborts the I/O
 * cniwait(p, s) waits for at most s seconds, then aborts
 *
 * only one I/O may be outstanding per id;
 * a new one aborts the previous one, quietly
 *
 * buf had best be static; stacks move, and the process waiting for io
 * will almost certainly go out of context.
 * hence the KSTART checks.
 */

int *
cniread(id, buf, count)
int id, count;
char *buf;
{
	register struct cnbuf *cp;

	if (id < 0 || id >= NCONS || (int)buf < KSTART)
		panic("cniread");
	cp = &cnibuf[id];
	cp->buf = buf;
	cp->count = count;
	mtpr(RXCS, mfpr(RXCS)|RXCS_IE);
	return (&cp->count);
}

int *
cniwrite(id, buf, count)
int id, count;
char *buf;
{
	register struct cnbuf *cp;

	if (id < 0 || id >= NCONS || (int)buf < KSTART)
		panic("cniwrite");
	cp = &cnobuf[id];
	cp->buf = buf;
	cp->count = count;
	cnstart();
	return (&cp->count);
}

cniwait(p, t)
register int *p;
int t;
{
	register int s;
	register int sh;

	s = spl6();
	while (*p)
		if (tsleep((caddr_t)p, CONPRI, t) != TS_OK) {
			sh = *p;
			*p = 0;
			splx(s);
			return (sh);
		}
	splx(s);
	return (0);
}