SRI-NOSC/dmr/oldstuff/mpx.c
#define CSR 0177570
#include "../../h/param.h"
#include "../../h/conf.h"
#include "../../h/user.h"
#include "../../h/proc.h"
#define NMINOR 50
#define OCHAN 20
#define NCHAN 20
#define XHIWAT 30
#define RHIWAT 30
#define XLOWAT 10
#define RLOWAT 10
#define XPRI 5
#define RPRI 5
#define CPRI 1
#define FOPEN 01
#define FWAIT 02
#define OOPEN 01
#define NOPEN 02
#define XWAIT 04
#define RWAIT 010
#define BLOCK 020
#define RUN 040
struct clist
{
int c_cc;
int c_cf;
int c_cl;
};
/*
* list of channels that need
* acks transmitted.
* list of channels that have
* data to be transmitted.
*/
struct clist ackq, datq;
int mpconf;
int mprnext;
int mpxnext;
/*
* map of minor device to channel
*/
struct
{
char flag;
char chano;
} minor[NMINOR];
/*
* channel structure.
* and input and output data q's.
*/
struct
{
char flag;
char chano;
struct clist iq;
struct clist oq;
} ochan[OCHAN], nchan[NCHAN];
mpopen(dev)
{
register f, *p;
static first;
if(first == 0) {
for(f=0; f<128; f++) {
p = cptr(f);
if(p)
p->chano = f;
}
mpinit();
first++;
}
ochan[0].flag =| OOPEN|NOPEN;
nchan[0].flag =| OOPEN|NOPEN;
f = dev.d_minor & 0377;
if(f >= NMINOR)
goto bad;
p = &minor[f];
if(p->flag & FOPEN)
goto bad;
p->flag =| FOPEN;
p->chano = 0;
return;
bad:
u.u_error = ENXIO;
}
mpclose(dev)
{
register f;
f = dev.d_minor & 0377;
minor[f].flag = 0;
mpdis(f);
}
mpsgtty(dev, v)
{
register f, *p;
if(v)
goto bad;
f = dev.d_minor & 0377;
if(f >= NMINOR)
goto bad;
switch(u.u_arg[0]) {
default:
bad:
u.u_error = ENXIO;
return;
case 1: /* connect */
mpcon(f);
return;
case 2: /* disconnect */
mpdis(f);
return;
case 3: /* wait connect */
p = &minor[f];
spl5();
while(p->chano == 0) {
p->flag =| FWAIT;
sleep(p, RPRI);
}
spl0();
return;
case 4: /* establish process group */
p = u.u_procp;
p->p_pgrp = p->p_pid;
return;
case 100: /* reset driver */
while(getc(&ackq) >= 0)
;
while(getc(&datq) >= 0)
;
mpconf = 0;
mprnext = 0;
mpxnext = 0;
for(f=0; f<128; f++) {
if(f < NMINOR) {
p = &minor[f];
p->flag = 0;
p->chano = 0;
}
p = cptr(f);
if(p) {
p->flag = 0;
p->chano = f;
while(getc(&p->iq) >= 0)
;
while(getc(&p->oq) >= 0)
;
}
}
return;
}
}
mpwrite(dev)
{
register d, *p;
p = mpf(dev);
if(p == NULL)
return;
while(mpisc(p) && (d = cpass()) >= 0) {
spl5();
while(p->oq.c_cc > XHIWAT) {
p->flag =| XWAIT;
sleep(&p->oq, XPRI);
}
putc(d, &p->oq);
mprun(p);
spl0();
}
}
mpread(dev)
{
register d, *p;
p = mpf(dev);
if(p == NULL)
return;
do {
spl5();
while((d = getc(&p->iq)) < 0) {
if(!mpisc(p))
goto out;
p->flag =| RWAIT;
sleep(&p->iq, RPRI);
}
spl0();
} while(passc(d) >= 0 && p->iq.c_cc > 0);
out:
spl5();
if((p->flag&BLOCK) != 0 && p->iq.c_cc < RLOWAT) {
p->flag =& ~BLOCK;
putc(p->chano, &ackq);
mpxintr();
}
spl0();
}
mpisc(pp)
int *pp;
{
register *p;
p = pp;
if(p->flag & NOPEN)
if(p->flag & OOPEN)
return(1);
u.u_error = ENXIO;
return(0);
}
mpcon(f)
{
register *p, *q;
p = &minor[f];
if(p->chano)
goto bad;
spl5();
while(mpconf)
sleep(&mpconf, CPRI);
mpconf = p;
q = cptr(0);
putc(u.u_arg[1], &q->oq);
mprun(q);
while(mpconf)
sleep(&mpconf, CPRI);
spl0();
if(p->chano != 0)
return;
bad:
u.u_error = ENXIO;
}
mpdis(f)
{
register c, *p;
p = &minor[f];
c = p->chano;
if(c) {
spl5();
p->chano = 0;
p = cptr(c);
if(p) {
p->flag =& ~(OOPEN|XWAIT|RWAIT);
while(getc(&p->iq) >= 0)
;
wakeup(&p->iq);
wakeup(&p->oq);
mprun(p);
}
spl0();
}
}
mprun(pp)
{
register *p;
p = pp;
if((p->flag&RUN) == 0) {
p->flag =| RUN;
putc(p->chano, &datq);
mpxintr();
}
}
mpf(dev)
{
register c, *p;
c = dev.d_minor & 0377;
if(c >= NMINOR)
goto bad;
c = minor[c].chano;
if(c == 0)
goto bad;
p = cptr(c);
if(p)
return(p);
bad:
u.u_error = ENXIO;
return(NULL);
}
/*
* return pointer to channel
* structure, given chan number.
* ochans are 1 thru OCHAN-1
* nchans are 64 thru NCHAN+63
*/
cptr(c)
{
if(c < 64) {
if(c < 0 || c >= OCHAN)
return(NULL);
return(&ochan[c]);
}
c =- 64;
if(c < 0 || c >= NCHAN)
return(NULL);
return(&nchan[c]);
}
/*
* convert to/from
* orig and non-orig chan
*/
invert(c)
{
if(c >= 64)
return(c-64);
return(c+64);
}
mpexec(cc, d)
{
register i, c, *p;
c = d;
/*
* reply to connect
*/
if(cc == 0) {
if(mpconf)
if(c && c != 64) {
p = cptr(c);
if(p) {
p->flag =| OOPEN|NOPEN;
p = mpconf;
p->chano = c;
}
}
mpconf = 0;
wakeup(&mpconf);
return;
}
/*
* discon
*/
if(c >= 128) {
c =- 128;
p = cptr(c);
if(p) {
p->flag =& ~(RUN|NOPEN|RWAIT|XWAIT);
while(getc(&p->oq) >= 0)
;
wakeup(&p->iq);
wakeup(&p->oq);
}
return;
}
/*
* request connect
*/
if(c >= NMINOR)
goto bad;
p = &minor[c];
if(p->chano)
goto bad;
for(i=1; i<NCHAN; i++)
if(nchan[i].flag == 0) {
nchan[i].flag =| OOPEN|NOPEN;
goto found;
}
bad:
i = 0;
goto out;
found:
p->chano = invert(i);
if(p->flag & FWAIT) {
p->flag =& ~FWAIT;
wakeup(p);
}
out:
p = cptr(64);
putc(i, &p->oq);
mprun(p);
}
mpx()
{
register c, d, *p;
/*
* transmit 2nd half of 2 char mesg
*/
if(mpxnext) {
d = ~mpxnext;
mpxnext = 0;
return(d);
}
/*
* transmit ack
*/
c = getc(&ackq);
if(c >= 0)
return(invert(c)+128);
/*
* transmit 2 char (chan,data) message
*/
loop:
c = getc(&datq);
if(c >= 0) {
p = cptr(c);
if(p == NULL)
goto loop;
d = getc(&p->oq);
if(d < 0) {
p->flag =& ~RUN;
if((p->flag & OOPEN) != 0)
goto loop;
d = invert(c) + 128;
c = 0;
} else
if(c == 0 || c == 64)
putc(c, &datq);
mpxnext = ~d;
if((p->flag & XWAIT) && p->oq.c_cc < XLOWAT) {
p->flag =& ~XWAIT;
wakeup(&p->oq);
}
return(invert(c));
}
out:
return(-1);
}
mpr(d)
{
register c, *p;
if(CSR->integ == 0314)
printf("%o\n", d);
/*
* if 2nd half of incomming message,
* put data on in q and put chan on ack q.
*/
if(mprnext) {
c = ~mprnext;
mprnext = 0;
p = cptr(c);
if(p == NULL)
return;
if(c == 64 || c == 0) {
mpexec(c, d);
return;
}
if(p->flag&OOPEN)
putc(d, &p->iq);
if(p->flag & RWAIT) {
p->flag =& ~RWAIT;
wakeup(&p->iq);
}
if(p->iq.c_cc > RHIWAT) {
p->flag =| BLOCK;
return;
}
putc(c, &ackq);
mpxintr();
return;
}
/*
* recieve ack message.
* put channel back on data q.
*/
if(d >= 128) {
putc(d-128, &datq);
mpxintr();
return;
}
mprnext = ~d;
}