V10/lsys/io/mg.c
/*
* DR11C for Mergenthaler 202
*/
#include "sys/param.h"
#include "sys/conf.h"
#include "sys/stream.h"
#include "sys/ubaddr.h"
#include "sys/mg.h"
/*
* hardware
*/
struct device {
u_short csr;
u_short wbuf;
u_short rbuf;
};
#define CSR0 1
#define CSR1 2
#define REQA 0200
#define REQB 0100000
#define INTA 0100
#define INTB 040
/*
* stream glue
*/
long mgopen();
int nodev(), mgclose(), mgoput();
static struct qinit mgrinit = {
nodev, NULL, mgopen, mgclose, 0, 0
};
static struct qinit mgwinit = {
mgoput, NULL, mgopen, mgclose, 200, 100
};
struct streamtab mginfo = {
&mgrinit, &mgwinit
};
/*
* config glue
*/
extern struct mg mg[]; /* one per device */
extern struct ubaddr mgaddr[]; /* one per device */
extern int mgcnt; /* one per device or what? */
struct cdevsw mgcdev = cstrinit(&mginfo);
long
mgopen(q, d)
register struct queue *q;
{
register struct mg *mp;
register dev, s;
if((dev = (minor(d) >> 1)) >= mgcnt)
return 0;
mp = &mg[dev];
if((mp->addr = (struct device *)ubaddr(&mgaddr[dev])) == 0
|| ubbadaddr(mgaddr[dev].ubno, mp->addr, sizeof(u_short))) {
printf("mg%d absent\n", d);
return 0;
}
mp->addr->csr |= CSR0 | CSR1;
if(d & 01) {
if(mp->wq != NULL)
return 0;
mp->addr->csr |= INTA;
mp->wq = WR(q);
}
else {
if(mp->rq != NULL)
return 0;
s = mp->addr->rbuf;
mp->addr->csr |= INTB;
mp->rq = q;
}
WR(q)->ptr = q->ptr = (caddr_t) minor(d);
return 1;
}
mgclose(q)
register struct queue *q;
{
register struct mg *mp = &mg[((int)q->ptr) >> 1];
if(((int)q->ptr) & 01) {
mp->wq = NULL;
}
else {
mp->addr->csr &= (~INTB);
flushq(WR(q), 1);
mp->rq = NULL;
}
}
mg1int(dev)
{
register struct mg *mp = &mg[dev];
register c;
c = mp->addr->rbuf;
if(mp->rq && (mp->rq->flag & QFULL) == 0)
putd(mp->rq->next->qinfo->putp, mp->rq->next, c);
}
mg0int(dev)
{
register struct mg *mp = &mg[dev];
mp->busy = 0;
mgstart(mp);
}
mgoput(q, bp)
register struct queue *q;
register struct block *bp;
{
switch(bp->type) {
case M_IOCTL:
bp->type = M_IOCNAK;
bp->wptr = bp->rptr;
qreply(q, bp);
return;
case M_FLUSH:
flushq(q, 0);
break;
case M_DATA:
putq(q, bp);
mgstart(&mg[((int)q->ptr) >> 1]);
return;
default:
break;
}
freeb(bp);
}
mgstart(mp)
register struct mg *mp;
{
register struct block *bp;
register s;
if(mp->wq == NULL)
return;
s = spl6();
if((mp->busy == 0) && mp->wq->count) {
bp = getq(mp->wq);
switch(bp->type) {
case M_DATA:
mp->addr->wbuf = *bp->rptr++;
mp->busy = 1;
if(bp->rptr >= bp->wptr)
freeb(bp);
else
putbq(mp->wq, bp);
break;
default:
freeb(bp);
break;
}
}
splx(s);
}