SRI-NOSC/ncpk/drivers/vdh.c
#include "param.h"
#include "buf.h"
#include "net_net.h"
#include "net_netbuf.h"
#include "net_ncp.h"
#include "net_vdhstat.h"
#include "net_vdh_imp.h"
#include "net_vdh.h"
char vdhlock -1;
v_pan (msg)
char *msg;
{
register t;
struct vdhregs sv_regs;
register int *p, *q;
t = PS->integ;
spl7();
p = &sv_regs.wco; q = &VDH->wco;
do { /* save registers at time of panic */
*p-- = *q--;
} while q >= &VDH->csri;
VDH->csri =& ~ V_INTENB;
VDH->csro =& ~ (V_INTENB|V_TIMRUN);
panic (msg);
}
imp_init ()
{
register t, *ptr;
register int oldps;
oldps = PS->integ;
spl_imp ();
vdhichn = 0;
prvictl = 0;
vstatebits = VDHILAST;
impldrd ();
hellonext = 2*VDH_T*VDH_R;
vdhosnd = -1;
vdhofill = 0;
vdhoack = V_HTOI;
for(t = 0; t < NCHNS; t++)
vdhouse[t] = -1;
ptr = &VDH->csro;
if ((*ptr & V_INTENB) == 0)
{
*ptr++ = V_TIMSEL;
*ptr = 12500/(HZ/10); /* 125000 too big for one word */
*--ptr = V_TIMRUN | V_INTENB;
}
oimp.o_type = ih_nop;
for ( t = 3; --t>=0; )
sndnetbytes (&oimp,4,0,0,1);
PS->integ = oldps;
}
#ifndef UCBUFMOD
imp_output()
{
#endif UCBUFMOD
#ifdef UCBUFMOD
imp_output(msg)
struct netbuf *msg;
{
register sps;
sps = PS->integ;
spl_imp();
msg_q(&impoq, 0, 0, msg);
#endif UCBUFMOD
if (((vstatebits ^ UP) & (OUTBUSY|UP)) == 0)
{
vdhostart ();
}
#ifdef UCBUFMOD
PS->integ = sps;
#endif UCBUFMOD
}
vdhiint ()
{
register int t;
register int *p;
register int *state;
int *q;
int xorrot;
if (++vdhlock)
v_pan ("VDH-i");
#ifdef PARANOID
v_bufck ();
#endif PARANOID
state = &vstatebits;
p = &VDH->csri;
#ifndef VDHE
while ( (*p ^ V_GO) & (V_EOT|V_GO) ) {
#endif not VDHE
#ifdef VDHE
while (*p & V_EOT) {
#endif VDHE
if (!(*state & TRYING)) {
VDH->csri =& ~ V_INTENB;
goto finis;
}
if (*p<0) {
vs.harderr++;
vdherr = *p;
goto eot_done;
}
p = (*state&VDHIAB) ? &vdhibuf[1][0]:&vdhibuf[0][0];
if ((t = (VDH->cwai - p) - 1) < 0) { /* null transfer */
wcerr:
/* log some error? */
goto eot_done;
}
if (*p & V_HTOI) {
vs.looped++;
goto eot_done;
}
if (*p & V_SPBIT) {
if (t != 0) goto wcerr;
if (*p>0) {
*state =| (SAWHELLO|OUT2GO);
} else {
hellounacked = 0;
helloinarow++;
}
goto eot_done;
}
if (t != (p->hibyte&077)) goto wcerr;
if (!(*state & UP)) {
vs.wpaks++;
goto eot_done;
}
xorrot = (prvictl ^ *p) << (14-NCHNS);
t = NCHNS-1;
do {
if (xorrot<0) {
vdhouse[t] = -1;
*state =| OUT2GO;
}
xorrot =<< 1;
} while (--t>=0);
prvictl = *p;
if ((*p & V_WCBITS)==0) {
vs.inulls++;
goto eot_done;
}
*state =| (ACK2SND|OUT2GO);
if ((t = *p & V_CHBITS) != vdhichn) {
vs.chwrong++;
goto eot_done;
}
if ((*p ^ ((vdhoack>>t)*(V_EVNODD/V_C0ACK)))
& V_EVNODD) {
vs.idups++;
goto eot_done;
}
if (*state & VDHILAST) {
wakeup ( &imp );
vs.ifull++;
goto eot_done;
}
if (net_b.b_cntfree < (VDHDSIZE + NET_B_SIZE - 1)/NET_B_SIZE) {
vs.nobuf++;
*state =| VDHINEED;
wakeup (&imp);
goto eot_done;
}
t = (p++->hibyte & 077);
swabuf (p,t);
t =<< 1;
if (impi_msg==0) {
q = impleader ? &imp.type : &imp.pad1;
t =- 4;
*q++ = *p++;
*q = *p++;
}
if (t && vectomsg (p,t,&impi_msg,1))
v_pan ("vdh: vectomsg failed");
impleader = 0;
vdhoack =^ V_C0ACK<<vdhichn;
if (prvictl & V_LAST) {
#ifdef PARANOID
v_bufck();
#endif PARANOID
*state =| VDHILAST;
wakeup (&imp);
}
vdhichn++;
vdhichn =& NCHNS-1;
vs.igood++;
eot_done:
p = &VDH->csri;
VDH->cwai = (*state&VDHIAB)?&vdhibuf[1][0]:&vdhibuf[0][0];
#ifndef VDHE
VDH->wci = VDHSIZE;
do {
*p =| V_GO;
} while !(*p&V_GO);
#endif not VDHE
#ifdef VDHE
VDH->wci = -(VDHSIZE*2);
*p =| V_GO;
#endif VDHE
*state =^ VDHIAB;
*p = (*state&VDHIAB) ? (V_ABSEL | V_INTENB) : V_INTENB;
}
if (((*state ^ OUT2GO) & (OUT2GO|OUTBUSY)) == 0) {
vdhostart();
}
*state =& ~OUT2GO;
finis:
#ifdef PARANOID
v_bufck ();
#endif PARANOID
--vdhlock;
}
vdhoint ()
{
register *p;
register xorrot;
register *state;
if (++vdhlock)
v_pan ("VDH-o");
state = &vstatebits;
if (VDH->csro&V_TIMINT)
{
VDH->csro =& ~ V_TIMINT;
#ifdef NOCLOCK
*state =| CLOCKINT;
#endif NOCLOCK
if (ncpopnstate == 0)
{
*state =& ~(UP | TRYING);
goto clock_done;
}
for(xorrot = 0; xorrot < NCHNS; xorrot++)
if(vdhouse[xorrot] > 0)
vdhouse[xorrot]--;
if (--hellonext > 0)
goto clock_done;
hellonext =+ VDH_R;
switch (*state & (UP | TRYING))
{
case UP|TRYING:
if (hellounacked > VDH_T)
{
*state =& ~(TRYING | UP);
hellonext = 077777;
needinit++;
wakeup ( &imp );
goto clock_done;
}
break;
case TRYING:
if (hellounacked)
{
helloinarow = 0;
}
else
if (helloinarow >= VDH_K)
{
*state =| UP;
wakeup ( &imp );
}
break;
default:
*state =| TRYING;
*state =& ~(SAWHELLO | SENDHELLO | UP);
#ifndef VDHE
VDH->csri = 0;
VDH->cwai = &vdhibuf[0][0];
VDH->wci = VDHSIZE;
VDH->csri = V_GO | V_ABSEL;
VDH->cwai = &vdhibuf[1][0];
VDH->wci = VDHSIZE;
VDH->csri = V_INTENB | V_GO;
#endif not VDHE
#ifdef VDHE
VDH->csri = 0;
VDH->cwai = &vdhibuf[0][0];
VDH->wci = -(VDHSIZE*2);
VDH->csri = V_GO;
VDH->csri =| V_ABSEL;
VDH->cwai = &vdhibuf[1][0];
VDH->wci = -(VDHSIZE*2);
VDH->csri = V_INTENB | V_GO | V_ABSEL;
VDH->csri =& ~ V_ABSEL;
#endif VDHE
}
*state =| SENDHELLO;
}
clock_done:
if (VDH->csro&V_EOTINT)
{
*state =& ~OUTBUSY;
}
if ((*state & OUTBUSY) == 0) {
vdhostart();
#ifdef PARANOID
v_bufck ();
#endif PARANOID
}
--vdhlock;
#ifdef NOCLOCK
if (*state & CLOCKINT)
{
*state =& ~CLOCKINT;
vdh_clock(); /* no return */
}
#endif NOCLOCK
}
vdhostart ()
{
register int *p;
register int i;
register int *state;
state = &vstatebits;
if ((*state & TRYING) == 0)
return;
#ifdef PARANOID
v_bufck();
#endif PARANOID
if (*state & SAWHELLO)
{
I_HEARD_YOU;
*state =& ~ SAWHELLO;
return;
}
if (*state & SENDHELLO)
{
HELLO;
hellounacked++;
*state =& ~SENDHELLO;
return;
}
if ((*state & UP) == 0)
return;
/* Proceed below if we are UP&TRYING -- I just didn't want */
/* to indent that much.... */
fillochans();
for (i = 0; i < NCHNS; i++)
{
vdhosnd++;
vdhosnd =& NCHNS-1;
if (vdhouse[vdhosnd] == 0) {
p = vdhobuf [vdhosnd];
p [0] = (p [0] & ~V_ACKBITS) | vdhoack;
vdhsnd (p);
vdhouse[vdhosnd] = HZ*100/1000; /* hold off 100 ms */
*state =& ~ACK2SND;
return;
}
}
/* No data to be sent */
if (*state & ACK2SND) { /* And an ack to send? */
OACK;
*state =& ~ACK2SND;
}
}
#ifndef UCBUFMOD
struct buf vdbuf;
#endif UCBUFMOD
#ifdef UCBUFMOD
struct netbuf *vdhmsg;
#endif UCBUFMOD
fillochans ()
{
register int *p;
register char *bp;
register int len;
while (vdhouse[vdhofill] < 0) {
#ifndef UCBUFMOD
if (vdbuf.b_dev==0)
{
bp = impotab.d_actf;
if (bp==0)
return;
impotab.d_actf = bp->b_forw;
bytesout (&bp->b_dev, &vdbuf, BUFSIZE, 1);
vdbuf.b_wcount = msglen (vdbuf.b_dev);
len = 4;
}
else
len = min (VDHDSIZE, vdbuf.b_wcount);
bytesout (&vdbuf.b_dev, p = &vdhobuf[vdhofill][1], len, 1);
vdbuf.b_wcount =- len;
if (vdbuf.b_wcount<0)
v_pan ("Bad wcount");
#endif UCBUFMOD
#ifdef UCBUFMOD
if(vdhmsg==0) { /* must pick up new message? */
if((bp = impoq) == 0) /* if nothing to output */
return; /* just go away */
bp->b_resv =| b_eom; /* so I'm paranoid */
do { /* remove first message from q */
bp = bp->b_qlink;
} while( (bp->b_resv&b_eom) == 0 );
/* now pointing at last buffer of msg */
if(bp == impoq) { /* only message in q? */
impoq = 0; /* clear q pointer */
} else {
len = impoq->b_qlink; /* use len as temp */
impoq->b_qlink = bp->b_qlink;
bp->b_qlink = len;
}
vdhmsg = bp; len = 4; /* only header in first packet */
} else
len = VDHDSIZE;
len =- bytesout(&vdhmsg, p = &vdhobuf[vdhofill][1], len, 1);
#endif UCBUFMOD
*--p = vdhofill;
len =>> 1;
p->hibyte = len;
#ifndef UCBUFMOD
if (vdbuf.b_wcount==0)
#endif UCBUFMOD
#ifdef UCBUFMOD
if (vdhmsg==0)
#endif UCBUFMOD
*p =| V_LAST;
if ( (prvictl>>vdhofill) & V_C0ACK )
*p =| V_EVNODD;
swabuf (&p[1], len);
vdhouse[vdhofill] = 0;
vdhofill++;
vdhofill =& NCHNS-1;
vs.opaks++;
}
}
#ifndef UCBUFMOD
msglen(abp) char *abp;
{
register char *bp;
register int cnt;
bp = abp;
if(bp==0) return 0;
for( cnt = bp->b_len; (bp=bp->b_qlink)!=abp; )
cnt =+ bp->b_len&0377;
return cnt;
}
#endif UCBUFMOD
impldrd ()
{
spl_imp ();
if (!(vstatebits & VDHILAST))
log_to_ncp ("Bad impldrd");
else
{
impleader = 1;
impi_msg = 0; /* can a buffer get lost here ? */
vstatebits =& ~VDHILAST;
}
}
vdh1snd (oneliner) int oneliner;
{
static vdh1buf; /* static because we dma out of here */
vdh1buf = oneliner;
vdhsnd (&vdh1buf);
}
vdhsnd (buffer) int *buffer;
{
vstatebits =| OUTBUSY;
if ((buffer[0]&V_HTOI) == 0) v_pan ("vdhsnd");
VDH->cwao = buffer;
#ifndef VDHE
VDH->wco = (buffer->hibyte & 077)+1;
#endif not VDHE
#ifdef VDHE
VDH->wco = -(((buffer->hibyte & 077)+1)<<1);
#endif VDHE
VDH->csro =& ~ V_EOTINT;
VDH->csro =| V_GO;
}