V10/lsys/md/consuvax.c
/*
* MicroVAX II console driver
* -- perhaps add a hack for ^P?
*/
#include "sys/param.h"
#include "sys/stream.h"
#include "sys/ttyio.h"
#include "sys/cons.h"
#include "sys/mtpr.h"
#include "sys/conf.h"
/*
* state bits
*/
#define TTSTOP 01
#define BUSY 02
#define TIMEOUT 04
char cnstate;
struct queue *cnrq;
struct queue *cnwq;
long cnopen();
int cnclose(), cnoput(), nodev();
static struct qinit cnrinit = { nodev, 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)
register struct queue *qp;
{
cnrq = qp;
cnwq = WR(qp);
mtpr(RXCS, mfpr(RXCS)|RXCS_IE);
return(1);
}
cnclose(qp)
struct queue *qp;
{
cnrq = NULL;
cnwq = NULL;
}
/*
* Console write put routine
*/
cnoput(q, bp)
register struct queue *q;
register struct block *bp;
{
register struct ttydevb *sp;
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 |= TTSTOP;
break;
case M_START:
cnstate &= ~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
*/
/*ARGSUSED*/
cnrint(dev)
{
register int c;
c = mfpr(RXDB);
if (c&RXDB_ID || cnrq==NULL)
return;
if ((cnrq->next->flag & QFULL) == 0)
putd(cnrq->next->qinfo->putp, cnrq->next, c);
}
/*
* Transmitter interrupt
*/
/*ARGSUSED*/
cnxint(dev)
{
cnstate &= ~BUSY;
mtpr(TXCS, mfpr(TXCS)&~TXCS_IE);
cnstart();
}
cntime()
{
cnstate &= ~TIMEOUT;
cnstart();
}
cnstart()
{
register s;
register struct block *bp;
if (cnwq==NULL)
return;
s = spl6();
if ((cnstate & (TIMEOUT|BUSY|TTSTOP))==0 && cnwq->count) {
bp = getq(cnwq);
switch (bp->type) {
case M_DATA:
mtpr(TXDB, *bp->rptr++);
mtpr(TXCS, mfpr(TXCS)|TXCS_IE);
cnstate |= BUSY;
if (bp->rptr >= bp->wptr)
freeb(bp);
else
putbq(cnwq, bp);
break;
case M_DELAY:
timeout(cntime, (caddr_t)NULL, (int)*bp->rptr);
cnstate |= TIMEOUT;
default: /* flow through */
freeb(bp);
break;
}
}
splx(s);
}
/*
* Print a character on console.
* Attempts to save and restore device
* status.
*/
cnputc(c)
register c;
{
register s, timo;
timo = 30000;
/*
* Try waiting for the console tty to come ready,
* otherwise give up after a reasonable time.
*/
while((mfpr(TXCS)&TXCS_RDY) == 0)
if(--timo == 0)
return;
if(c == 0)
return;
s = mfpr(TXCS);
mtpr(TXCS, 0);
mtpr(TXDB, c&0xff);
if(c == '\n')
cnputc('\r');
cnputc(0);
mtpr(TXCS, s);
}