From b937ce47ef8b34262825b478d2448ab5fc021f33 Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Tue, 9 Jun 1992 00:00:00 +0000 Subject: [PATCH] Plan 9 from Bell Labs 1992-06-09 --- boot/aux.c | 4 +- boot/boot.c | 3 +- gnot/dat.h | 2 + gnot/devhifi.c | 753 +++++++++++++++++++++++++++++++++++++++++++++ gnot/devisdn.c | 711 ++++++++++++++++++++++++++++++++++++++++++ gnot/hifi.h | 106 +++++++ gnot/isdn.h | 137 +++++++++ gnot/unite.h | 120 ++++++++ pc/fns.h | 1 - pc/main.c | 2 +- pc/trap.c | 18 +- port/devconc.c | 489 +++++++++++++++++++++++++++++ port/portfns.h | 2 + port/proc.c | 8 +- port/stlapd.c | 768 ++++++++++++++++++++++++++++++++++++++++++++++ port/stream.c | 24 ++ power/devhotrod.c | 7 +- power/faultmips.c | 2 + power/io.h | 6 +- 19 files changed, 3144 insertions(+), 19 deletions(-) create mode 100644 gnot/devhifi.c create mode 100644 gnot/devisdn.c create mode 100644 gnot/hifi.h create mode 100644 gnot/isdn.h create mode 100644 gnot/unite.h create mode 100644 port/devconc.c create mode 100644 port/stlapd.c diff --git a/boot/aux.c b/boot/aux.c index 80a6344147a7ee1aa15157f251d75d60314e5744..927975d19bf4ce8bf9f14173e41b7fe0d3e1f8fc 100644 --- a/boot/aux.c +++ b/boot/aux.c @@ -131,12 +131,14 @@ outin(char *prompt, char *def, int len) int n; char buf[256]; + alarm(60*1000); do{ print("%s[%s]: ", prompt, *def ? def : "no default"); n = read(0, buf, len); }while(n==0); + alarm(0); if(n < 0) - fatal("can't read #c/cons; please reboot"); + fatal("can't read #c/cons or timeout; please reboot"); if(n != 1){ buf[n-1] = 0; strcpy(def, buf); diff --git a/boot/boot.c b/boot/boot.c index e1cd7c04a261e9454789608b42fb6cb5e6719fec..7237b7fd49441ea898a33efc7a74d86cdd0e1419 100644 --- a/boot/boot.c +++ b/boot/boot.c @@ -104,7 +104,8 @@ boot(int argc, char *argv[]) fatal("mount"); } close(fd); - newkernel(); + if(cpuflag == 0) + newkernel(); /* * if a local file server exists and it's not the diff --git a/gnot/dat.h b/gnot/dat.h index a4544bedb65598ed994c5c6e38ae598c7605dab5..37ae82f4db0cb99bb2bcf619ef2c748546293363 100644 --- a/gnot/dat.h +++ b/gnot/dat.h @@ -102,12 +102,14 @@ struct Conf int npipe; /* number of pipes */ int nservice; /* number of services */ int nfsyschan; /* number of filsys open channels */ + int nisdn; /* number of isdn interfaces */ int nlapd; /* number of dragnet protocol modules */ ulong maxialloc; /* maximum bytes used by ialloc */ int copymode; /* 0 is copy on write, 1 is copy on reference */ int portispaged; /* ??? */ int cntrlp; /* panic on ^P */ int dkif; /* number of datakit interfaces */ + int nconc; /* number of datakit concentrators */ }; #include "../port/portdat.h" diff --git a/gnot/devhifi.c b/gnot/devhifi.c new file mode 100644 index 0000000000000000000000000000000000000000..04aba9aa33f1f38579bdd3990b2024db37ba277d --- /dev/null +++ b/gnot/devhifi.c @@ -0,0 +1,753 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "../port/error.h" +#include "devtab.h" + +#include "io.h" +#ifdef SET +#undef SET +#endif +#include "isdn.h" +#include "hifi.h" + +#define DPRINT if(hifidebug)kprint + +#define BSIZE 4096 + +typedef struct Hifichan +{ + Isdn * udev; /* unite interface */ + Hifi * hdev; /* pointer to device */ + uchar imask; /* interrupt bit */ + uchar opreg; /* sticky bits */ + uchar tctl; /* more sticky bits */ + uchar devaddr; /* debug access */ + + Lock kctl; /* kproc start */ + Rendez kr; /* kernel process sleep/wakeup */ + QLock; /* access to struct */ + int hdlc; /* hdlc mode enabled */ + int hangup; /* hangup pending */ + + int renable; /* reading enabled */ + Block * inb[NB]; /* input buffer */ + int ri; /* input read pointer */ + int wi; /* input write pointer */ + Queue * rq; /* read queue */ + + int wenable; /* writing enabled */ + int wactive; /* writing in progress */ + QLock wlock; /* write's are atomic */ + Block * outb[NB]; /* output buffer */ + int so; /* output scavenge pointer */ + int ro; /* output read pointer */ + int wo; /* output write pointer */ + Block * out; /* current output block */ + Rendez tr; /* if transmitter must wait */ + Rendez cr; /* waiting to close */ + + /* statistics */ + + ulong inchars; + ulong badcrc; + ulong abort; + ulong overrun; + ulong badcount; + ulong overflow; + ulong toolong; + ulong underrun; + ulong outchars; +} Hifichan; + +Hifichan * hifichan; +Hifichan * hifichanN; + +static void devinit(int); +static int hifiintr(void); +static void hifikproc(void*); +static void hifiloopctl(Hifichan*, int); +static int hifirecv(Hifichan*); +static void hifirecven(Hifichan*, int); +static int hifixmit(Hifichan*); +static void hifixmitdis(Hifichan*, int); +static void hifixmiten(Hifichan*, int); + +enum { + Qdir, Qdev, Qstats +}; + +Dirtab hifidir[]={ + "dev", {Qdev}, 0, 0666, + "stats", {Qstats}, 0, 0444, +}; +#define NHIFI (sizeof hifidir/sizeof(Dirtab)) + +/* + * stream module definition + */ +static void hifiiput(Queue*, Block*); +static void hifioput(Queue*, Block*); +static void hifistopen(Queue*, Stream*); +static void hifistclose(Queue*); +Qinfo hifiinfo = { hifiiput, hifioput, hifistopen, hifistclose, "hifi" }; + +int hifidebug = 1; + +void +hifireset(void) +{ + hifichan = ialloc(2*conf.nisdn*sizeof(Hifichan), 0); + hifichanN = &hifichan[2*conf.nisdn]; +} + +void +hifiinit(void) +{} + +Chan* +hifiattach(char *spec) +{ + int dev; + Chan *c; + Hifichan *hp; + static int intrinited; + + dev = strtoul(spec, 0, 0); + if(dev >= 2*conf.nisdn) + error(Enonexist); + + c = devattach('H', spec); + c->dev = dev; + hp = &hifichan[dev]; + if(!hp->udev){ + DPRINT("hifiattach: init dev=%d\n", c->dev); + if(!intrinited){ + intrinited = 1; + DPRINT("addportintr(hifiintr)\n"); + addportintr(hifiintr); + } + devinit(c->dev); + } + return c; +} + +Chan* +hificlone(Chan *c, Chan *nc) +{ + return devclone(c, nc); +} + +int +hifiwalk(Chan *c, char *name) +{ + return devwalk(c, name, hifidir, NHIFI, streamgen); +} + +void +hifistat(Chan *c, char *dp) +{ + devstat(c, dp, hifidir, NHIFI, streamgen); +} + +Chan* +hifiopen(Chan *c, int omode) +{ + Hifichan *hp = &hifichan[c->dev]; + + if(c->qid.path == CHDIR){ + if(omode != OREAD) + error(Eperm); + }else switch(STREAMTYPE(c->qid.path)){ + case Qdev: + case Qstats: + break; + default: + DPRINT("hifiopen dev=%d\n", c->dev); + streamopen(c, &hifiinfo); + } + c->mode = openmode(omode); + c->flag |= COPEN; + c->offset = 0; + return c; +} + +void +hificreate(Chan *c, char *name, int omode, ulong perm) +{ + error(Eperm); +} + +void +hificlose(Chan *c) +{ + Hifichan *hp = &hifichan[c->dev]; + + if(c->qid.path != CHDIR) + streamclose(c); +} + +long +hifiread(Chan *c, void *buf, long n, ulong offset) +{ + Hifichan *hp = &hifichan[c->dev]; + char nbuf[512], *p; int k; + + if(n <= 0) + return 0; + if(c->qid.path == CHDIR){ + return devdirread(c, buf, n, hifidir, NHIFI, streamgen); + }else switch(STREAMTYPE(c->qid.path)){ + case Qdev: + p = nbuf; + p += sprint(p, "0x%2.2ux = 0x%2.2ux\n", + hp->devaddr, isdnpeek(hp->udev, (void *)hp->devaddr)); + goto Readnbuf; + + case Qstats: + p = nbuf; + p += sprint(p, "inchars %10lud\n", hp->inchars); + p += sprint(p, "badcrc %10lud\n", hp->badcrc); + p += sprint(p, "abort %10lud\n", hp->abort); + p += sprint(p, "overrun %10lud\n", hp->overrun); + p += sprint(p, "badcount %10lud\n", hp->badcount); + p += sprint(p, "overflow %10lud\n", hp->overflow); + p += sprint(p, "toolong %10lud\n", hp->toolong); + p += sprint(p, "underrun %10lud\n", hp->underrun); + p += sprint(p, "outchars %10lud\n", hp->outchars); + Readnbuf: + k = p - nbuf; + if (offset >= k) + return 0; + if (offset+n > k) + n = k - offset; + memmove(buf, &nbuf[offset], n); + return n; + } + if(!hp->renable) + hifirecven(hp, 1); + return streamread(c, buf, n); +} + +long +hifiwrite(Chan *c, void *buf, long n, ulong offset) +{ + Hifichan *hp = &hifichan[c->dev]; + Hifi *hifi = hp->hdev; + char nbuf[32], *p; + + if(n < 0) + return 0; + switch(STREAMTYPE(c->qid.path)){ + case Qdev: + if(n>sizeof nbuf-1) + n = sizeof nbuf-1; + memmove(nbuf, buf, n); + nbuf[n-1] = 0; + hp->devaddr = (int)hp->hdev + strtoul(nbuf,0,0); + if(p = strchr(nbuf, '=')) /* assign = */ + isdnpoke(hp->udev, (void *)hp->devaddr, strtoul(++p,0,0)); + return n; + } + return streamwrite(c, buf, n, 0); +} + +void +hifiremove(Chan *c) +{ + error(Eperm); +} + +void +hifiwstat(Chan *c, char *dp) +{ + error(Eperm); +} + +/* + * the stream routines + */ + +#define Predicate(name, expr) static int name(void *arg) { return expr; } +#define hp ((Hifichan *)arg) + +Predicate(kRun, hp->ri != hp->wi || hp->so != hp->ro) + +Predicate(tActive, hp->wenable) +Predicate(tDead, hp->wenable == 0) +Predicate(tEmpty, hp->ro == hp->wo) +Predicate(tFull, NEXT(hp->wo) == hp->so) +Predicate(tNotFull, NEXT(hp->wo) != hp->so) + +#undef hp + +static void +hifistopen(Queue *q, Stream *s) +{ + Hifichan *hp = &hifichan[s->dev]; + char name[32]; + + DPRINT("hifistopen %d\n", s->dev); + qlock(hp); + q->ptr = q->other->ptr = hp; + hp->rq = q; + if(canlock(&hp->kctl)){ + sprint(name, "hifi%d", s->dev); + kproc(name, hifikproc, hp); + } + qunlock(hp); +} + +static void +hifistclose(Queue * q) +{ + Hifichan *hp = (Hifichan *)q->ptr; + + DPRINT("hifistclose %d...\n", hp-hifichan); + hifirecven(hp, -1); + qlock(hp); + hp->rq = 0; + hp->hangup = 0; + if(tActive(hp)){ + if(!hp->wactive || waserror()){ + hifixmitdis(hp, 1); + wakeup(&hp->kr); + }else{ + sleep(&hp->cr, tDead, hp); + poperror(); + } + } + qunlock(hp); + DPRINT("hifistclose %d OK\n", hp-hifichan); +} + +/* + * this is only called by hangup + */ +static void +hifiiput(Queue *q, Block *bp) +{ + Hifichan *hp = (Hifichan *)q->ptr; + + if(bp->type == M_HANGUP){ + DPRINT("hifiiput %d M_HANGUP\n", hp-hifichan); + hifirecven(hp, 0); + } + freeb(bp); +} + +void +hifioput(Queue *q, Block *bp) +{ + Hifichan *hp = (Hifichan *)q->ptr; + + if(bp->type != M_DATA){ + if(hifidebug){ + char fmt[32]; + sprint(fmt, "hifioput %%d: %%.%ds\n", bp->wptr-bp->rptr); + kprint(fmt, hp-hifichan, bp->rptr); + } + if(streamparse("hdlc", bp)){ + if(streamparse("on", bp)){ + hp->hdlc = 1; + hifixmiten(hp, 1); + }else{ + hp->hdlc = 0; + if(hp->wenable) + hifixmiten(hp, 1); + } + }else if(streamparse("loop", bp)){ + if(streamparse("on", bp)) + hifiloopctl(hp, 1); + else + hifiloopctl(hp, 0); + }else if(streamparse("click!", bp)){ + hifirecven(hp, 0); + }else if(streamparse("recven", bp)){ + hifirecven(hp, 1); + } + freeb(bp); + return; + } + qlock(&hp->wlock); + if(!putq(q, bp)){ /* send only whole messages */ + qunlock(&hp->wlock); + return; + } + DPRINT("hifioput %d: [%d] len=%d\n", + hp-hifichan, TK2MS(MACHP(0)->ticks), q->len); + if(tFull(hp)) + sleep(&hp->tr, tNotFull, hp); + hp->outb[hp->wo] = grabq(q); + hp->wo = NEXT(hp->wo); + qunlock(&hp->wlock); + + isdnlock(hp->udev); + if(hifixmit(hp)) + wakeup(&hp->kr); + isdnunlock(hp->udev); +} + +static void +hifirecven(Hifichan *hp, int r) +{ + Hifi *hifi = hp->hdev; + int i; + + qlock(hp); + if(!hp->renable && r > 0){ + hp->ri = hp->wi; + for (i=0; iinb[i]) + hp->inb[i] = allocb(BSIZE); + hp->renable = 1; + isdnpoke(hp->udev, &hifi->opreg, hp->opreg |= Enr); + DPRINT("hifirecven %d: enabled\n", hp-hifichan); + }else if(hp->renable && r <= 0){ + isdnpoke(hp->udev, &hifi->opreg, hp->opreg &= ~Enr); + hp->renable = 0; + hp->hangup = 1; + wakeup(&hp->kr); + DPRINT("hifirecven %d: disabled\n", hp-hifichan); + } + if(r < 0){ + hp->ri = hp->wi; + for (i=0; iinb[i]){ + freeb(hp->inb[i]); + hp->inb[i] = 0; + } + DPRINT("hifirecven %d: flushed\n", hp-hifichan); + } + qunlock(hp); +} + +static void +hifikproc(void *arg) +{ + Hifichan *hp = arg; + Block *bp; + int i; +Top: + if(waserror()){ + print("hifikproc: error\n"); + goto Top; + } + for(;;){ + qlock(hp); + while(hp->ri != hp->wi){ + if(hp->rq) + PUTNEXT(hp->rq, hp->inb[hp->ri]); + else + freeb(hp->inb[hp->ri]); + if(hp->renable) + hp->inb[hp->ri] = allocb(BSIZE); + else + hp->inb[hp->ri] = 0; + hp->ri = NEXT(hp->ri); + } + if(hp->hangup){ + hp->hangup = 0; + if(hp->rq){ + bp = allocb(0); + bp->type = M_HANGUP; + PUTNEXT(hp->rq, bp); + } + } + i = 0; + while(hp->so != hp->ro){ + freeb(hp->outb[hp->so]); + hp->so = NEXT(hp->so); + i++; + } + qunlock(hp); + if(i) + wakeup(&hp->tr); + sleep(&hp->kr, kRun, hp); + } +} + +static void +devinit(int h) +{ + Hifichan *hp = &hifichan[h]; + Hifi *hifi = (h&1) ? hifi1 : hifi0; + Isdn *ip = &isdndev[h>>1]; + + isdnlock(ip); + + hp->udev = ip; + hp->hdev = hifi; + hp->imask = (h&1) ? Hint1 : Hint0; + + hp->opreg = 0; + SET(hifi->opreg, Rres|Tres); /* master reset */ + SET(hifi->config, Fsen); /* frame sync enable */ + hp->tctl = 30; + SET(hifi->tctl, hp->tctl); /* transmitter interrupt level */ + SET(hifi->rctl, 20); /* receiver interrupt level */ + SET(hifi->bofctl, Clkxi); /* transmit in rising edge of CLKX */ + /* SET(hifi->tofctl, Dxi); /* transmit inverted data */ + SET(hifi->tofctl, 0); /* transmit normal data */ + SET(hifi->rof_tm, Dri); /* receive inverted data */ + SET(hifi->config, Fsen|Alt); /* alternate reg's... */ + SET(hifi->rof_tm, Trans); /* transparent mode */ + SET(hifi->config, Fsen); /* normal reg's... */ + SET(hifi->tmask, 0xff); /* transmit all bits */ + SET(hifi->imask, Undie|Tdie|Teie|Rfie|Reofie); /* interrupt enables */ + + isdnunlock(ip); +} + +static void +hifiloopctl(Hifichan *hp, int loop) +{ + Isdn *ip = hp->udev; + Hifi *hifi = hp->hdev; + + DPRINT("hifiloopctl %d: %d\n", hp-hifichan, loop); + isdnlock(ip); + if(loop) + SET(hifi->opreg, hp->opreg |= Lloop); + else + SET(hifi->opreg, hp->opreg &= ~Lloop); + isdnunlock(ip); +} + +static int +hifiintr(void) +{ + Isdn *ip; + Hifichan *hp; + Hifi *hifi; + int intr = 0, status, n, c, wake = 0, w = 0; + uchar *p; + + for(hp=hifichan; hpudev)) /* assign = */ + continue; + if (!(*(ip->asr)&hp->imask)) + continue; + ++intr; + hifi = hp->hdev; + status = GET(hifi->istat); + if(status&(Rf|Reof)){ + status &= ~(Rf|Reof); + wake += hifirecv(hp); + } + if(status&Te){ + status &= ~Te; + wake += w = hifixmit(hp); + } + if(status&Undabt){ + status &= ~Undabt; + DPRINT("hifiintr: hdlc %d under run\n", hp-hifichan); + ++hp->underrun; + } + if(status&Tdone){ + status &= ~Tdone; + hp->wactive = 0; + if(!hp->hdlc && (w || hp->out || hp->ro != hp->wo)){ + DPRINT("hifiintr: trans %d under run\n", + hp-hifichan); + ++hp->underrun; + }else if(!hp->hdlc || !hp->rq){ + DPRINT("hifiintr: xmtr %d done\n", hp-hifichan); + hifixmitdis(hp, 0); + ++wake; + wakeup(&hp->cr); + } + } + if(wake) + wakeup(&hp->kr); + if(status) + DPRINT("hifiintr: status %d 0x%2.2x\n", + status, hp-hifichan); + } + return intr; +} + +static int +hifirecv(Hifichan *hp) +{ + Isdn *ip = hp->udev; + Hifi *hifi = hp->hdev; + Block *bp = hp->inb[hp->wi]; + uchar *p; + int status, i, n, m, wake = 0; +Loop: + status = GET(hifi->rstat); + if(status == 0) + return wake; + n = status&0x7f; + p = bp->wptr; + m = bp->lim - p; + if(hp->hdlc){ + if(n > m){ + hp->toolong++; + bp->wptr = bp->base; + SET(hifi->opreg, hp->opreg | Rres); + return wake; + } + hp->inchars += n; + SETADDR(&hifi->data); + while(--n >= 0) + *p++ = *(ip->data); + if(status&Eof){ + if(*--p == 0){ + i = NEXT(hp->wi); + if(i == hp->ri) + hp->overflow++; + else{ + bp->wptr = p; + bp->flags |= S_DELIM; + hp->wi = i; + bp = hp->inb[i]; + ++wake; + } + }else{ + if(*p & 0x80) + hp->badcrc++; + if(*p & 0x40) + hp->abort++; + if(*p & 0x20) + hp->overrun++; + if(*p & 0x10) + hp->badcount++; + } + bp->wptr = bp->base; + }else + bp->wptr = p; + }else{ + if(n > m) + n = m; + hp->inchars += n; + SETADDR(&hifi->data); + while(--n >= 0) + *p++ = *(ip->data); + bp->wptr = p; + if(p >= bp->lim){ + i = NEXT(hp->wi); + if(i == hp->ri){ + bp->wptr = bp->base; + return wake; + }else{ + bp->flags |= S_DELIM; + hp->wi = i; + bp = hp->inb[i]; + ++wake; + } + } + } + goto Loop; +} + +static int +hifixmit(Hifichan *hp) +{ + Isdn *ip = hp->udev; + Hifi *hifi = hp->hdev; + Block *bp; + uchar *p; + int n, k, wake = 0; + +Loop: + n = GET(hifi->tstat)&0x7f; + if(n == 0) + return wake; + if(!(bp = hp->out)){ /* assign = */ + if(hp->ro == hp->wo){ + DPRINT("hifixmit %d: [%d] empty\n", + TK2MS(MACHP(0)->ticks), hp-hifichan); + return wake; + } + hp->out = bp = hp->outb[hp->ro]; + } + p = bp->rptr; + k = bp->wptr - p; + if (n > k) + n = k; + hp->outchars += n; + SETADDR(&hifi->data); + if(hp->hdlc){ + while(--n >= 0) + *(ip->data) = *p++; + }else{ + while(--n >= 0) + *(ip->data) = ~*p++; + } + bp->rptr = p; + hp->wactive = 1; + if(!hp->wenable) + hifixmiten(hp, 0); + if(bp->rptr == bp->wptr){ + if(hp->hdlc && (bp->flags & S_DELIM)) + SET(hifi->tctl, hp->tctl|Tfc); + if(!(hp->out = bp = bp->next)){ /* assign = */ + hp->ro = NEXT(hp->ro); + ++wake; + } + } + goto Loop; +} + +static void +hifixmiten(Hifichan *hp, int dolock) +{ + Isdn *ip = hp->udev; + Hifi *hifi = hp->hdev; + + DPRINT("hifixmiten %d: %s\n", hp-hifichan, hp->hdlc?"hdlc":"trans"); + if(dolock) + isdnlock(ip); + if(hp->hdlc){ + SET(hifi->tofctl, Dxi|Tlbit); /* xmit ~data, lsb first */ + SET(hifi->rof_tm, Dri|Rlbit); /* rcv ~data, lsb first */ + SET(hifi->config, Fsen|Alt); /* alternate reg's... */ + SET(hifi->rof_tm, 0); /* hdlc mode */ + SET(hifi->config, Fsen|Flags); /* normal reg's, send flags */ + }else{ + SET(hifi->tofctl, 0); /* xmit data, msb first */ + SET(hifi->rof_tm, Dri); /* rcv ~data, msb first */ + SET(hifi->config, Fsen|Alt); /* alternate reg's... */ + SET(hifi->rof_tm, Trans); /* transparent mode */ + SET(hifi->config, Fsen); /* normal reg's, send ones */ + } + hp->wenable = 1; + if(hp->hdev == hifi0){ + ip->venval &= ~DXCODEC; + if(hp->hdlc) + ip->venval &= ~DRCODEC; + }else if(hp->hdlc) + SET(hifi->config, Flags); /* no fs on chan. 2 */ + SET(hifi->ttsctl, Dxac); + SET(hifi->opreg, hp->opreg |= Ent); + if(dolock) + isdnunlock(ip); +} + +static void +hifixmitdis(Hifichan *hp, int dolock) +{ + Isdn *ip = hp->udev; + Hifi *hifi = hp->hdev; + + DPRINT("hifixmitdis %d\n", hp-hifichan); + if(dolock) + isdnlock(ip); + SET(hifi->ttsctl, 0); + if(hp->hdev == hifi0){ + ip->venval |= DXCODEC; + if(hp->hdlc) + ip->venval |= DRCODEC; + } + SET(hifi->opreg, hp->opreg &= ~Ent); + hp->out = 0; + hp->ro = hp->wo; + hp->wenable = 0; + /*SET(hifi->opreg, hp->opreg | Tres);*/ + if(dolock) + isdnunlock(ip); +} diff --git a/gnot/devisdn.c b/gnot/devisdn.c new file mode 100644 index 0000000000000000000000000000000000000000..1b623feb683b72e3425cef7e74547ad0ae9449ce --- /dev/null +++ b/gnot/devisdn.c @@ -0,0 +1,711 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "../port/error.h" +#include "devtab.h" + +#include "io.h" +#ifdef SET +#undef SET +#endif +#include "isdn.h" +#include "unite.h" + +#define DPRINT if(isdndebug)kprint + +#define BSIZE 260 + +Isdn * isdndev; +Isdn * isdndevN; + +static void devinit(int); +static void devctl(Isdn*, int, int); +static void devlctl(Isdn*, int); +static void isdnkproc(void*); +static int isdnintr(void); +static int isdnInfo(Isdn*); +static int isdnrecv(Isdn*); +static int isdnxmit(Isdn*); + +enum { + Qdir, Qloop, QInfo, Qstats, Qdev, Qdebug +}; + +Dirtab isdndir[]={ + "loop", {Qloop}, 5, 0666, + "info", {QInfo}, 1, 0666, + "stats", {Qstats}, 0, 0444, + "dev", {Qdev}, 0, 0666, + "debug", {Qdebug}, 0, 0666, +}; +#define NISDN (sizeof isdndir/sizeof(Dirtab)) + +/* + * I.430 stream module definition + */ +static void isdniput(Queue*, Block*); +static void isdnoput(Queue*, Block*); +static void isdnstopen(Queue*, Stream*); +static void isdnstclose(Queue*); +Qinfo isdninfo = { isdniput, isdnoput, isdnstopen, isdnstclose, "isdn" }; + +int venval; +int isdndebug; + +void +isdnreset(void) +{ + isdndev = ialloc(conf.nisdn*sizeof(Isdn), 0); + isdndevN = &isdndev[conf.nisdn]; +} + +void +isdninit(void) +{} + +Chan* +isdnattach(char *spec) +{ + Chan *c; + int dev; + + if(spec && *spec){ + if(*spec < '0' || *spec > '9') + error(Enonexist); + dev = strtoul(spec, 0, 0); + }else + dev = 0; + if(dev >= conf.nisdn) + error(Enonexist); + if(!isdndev[dev].asr){ + addportintr(isdnintr); + devinit(dev); + } + c = devattach('I', spec); + c->dev = dev; + return c; +} + +Chan* +isdnclone(Chan *c, Chan *nc) +{ + return devclone(c, nc); +} + +int +isdnwalk(Chan *c, char *name) +{ + return devwalk(c, name, isdndir, NISDN, streamgen); +} + +void +isdnstat(Chan *c, char *dp) +{ + devstat(c, dp, isdndir, NISDN, streamgen); +} + +Chan* +isdnopen(Chan *c, int omode) +{ + if(c->qid.path == CHDIR){ + if(omode != OREAD) + error(Eperm); + }else switch(STREAMTYPE(c->qid.path)){ + case Qloop: + case QInfo: + case Qstats: + case Qdev: + case Qdebug: + break; + default: + DPRINT("isdnopen dev=%d\n", c->dev); + streamopen(c, &isdninfo); + } + c->mode = openmode(omode); + c->flag |= COPEN; + c->offset = 0; + return c; +} + +void +isdncreate(Chan *c, char *name, int omode, ulong perm) +{ + error(Eperm); +} + +void +isdnclose(Chan *c) +{ + if(c->qid.path != CHDIR) + streamclose(c); +} + +long +isdnread(Chan *c, void *buf, long n, ulong offset) +{ + Isdn *ip = &isdndev[c->dev]; + char nbuf[512]; int k; + + if(n <= 0) + return 0; + if(c->qid.path == CHDIR){ + return devdirread(c, buf, n, isdndir, NISDN, streamgen); + }else switch(STREAMTYPE(c->qid.path)){ + case Qloop: + k = sprint(nbuf, "0x%2.2ux ", ip->lctl); + goto Readnbuf; + case QInfo: + if(offset>0) + return 0; + k = isdnpeek(ip, &unite->listat)&Rss; + *(char *)buf = "024L"[k>>2]; + return 1; + case Qstats: + k = 0; + k += sprint(&nbuf[k], "inchars %10lud\n", ip->inchars); + k += sprint(&nbuf[k], "badcrc %10lud\n", ip->badcrc); + k += sprint(&nbuf[k], "abort %10lud\n", ip->abort); + k += sprint(&nbuf[k], "overrun %10lud\n", ip->overrun); + k += sprint(&nbuf[k], "badcount %10lud\n", ip->badcount); + k += sprint(&nbuf[k], "overflow %10lud\n", ip->overflow); + k += sprint(&nbuf[k], "toolong %10lud\n", ip->toolong); + k += sprint(&nbuf[k], "underrun %10lud\n", ip->underrun); + k += sprint(&nbuf[k], "outchars %10lud\n", ip->outchars); + goto Readnbuf; + case Qdev: + k = isdnpeek(ip, (void *)ip->devaddr); + k = sprint(nbuf, "0x%2.2ux = 0x%2.2ux\n", ip->devaddr, k); + goto Readnbuf; + case Qdebug: + k = sprint(nbuf, "%d\n", isdndebug); + Readnbuf: + if (offset >= k) + return 0; + if (offset+n > k) + n = k - offset; + memmove(buf, nbuf+offset, n); + return n; + } + return streamread(c, buf, n); +} + +long +isdnwrite(Chan *c, void *buf, long n, ulong offset) +{ + Isdn *ip = &isdndev[c->dev]; + char nbuf[32], *p; + + if(n <= 0) + return 0; + switch(STREAMTYPE(c->qid.path)){ + case Qloop: + if(offset>0) + return 0; + if (n>sizeof nbuf) + n = sizeof nbuf; + memmove(nbuf, buf, n); + nbuf[n-1] = 0; + devlctl(ip, strtoul(nbuf,0,0)); + return n; + case QInfo: + if(offset>0) + return 0; + switch(*(char *)buf){ + case '0': + case '1': + case '3': + devctl(ip, Tss, *(char *)buf - '0'); + break; + default: + error(Ebadarg); + } + return 1; + case Qdev: + if (n>sizeof nbuf) + n = sizeof nbuf; + memmove(nbuf, buf, n); + nbuf[n-1] = 0; + ip->devaddr = strtoul(nbuf,0,0); + if (p = strchr(nbuf, '=')) /* assign = */ + isdnpoke(ip, (void *)ip->devaddr, strtoul(++p,0,0)); + return n; + case Qdebug: + if (n>sizeof nbuf) + n = sizeof nbuf; + memmove(nbuf, buf, n); + nbuf[n-1] = 0; + isdndebug = strtoul(nbuf,0,0); + return n; + } + return streamwrite(c, buf, n, 0); +} + +void +isdnremove(Chan *c) +{ + error(Eperm); +} + +void +isdnwstat(Chan *c, char *dp) +{ + error(Eperm); +} + +/* + * to sleep, perchance to dream... + */ + +#define Predicate(name, expr) static int name(void *arg) { return expr; } +#define ip ((Isdn *)arg) + +Predicate(kLive, ip->kstart != 0) +Predicate(kDead, ip->kstart == 0) + +Predicate(kRun, !ip->rq || ip->ri != ip->wi || ip->so != ip->ro) + +Predicate(lActive, (ip->listat&Rss)>>1 == 4) + +Predicate(tEmpty, ip->ro == ip->wo) +Predicate(tFull, NEXT(ip->wo) == ip->so) +Predicate(tNotFull, NEXT(ip->wo) != ip->so) + +#undef ip + +/* + * the stream routines + */ + +static void +isdnstopen(Queue *q, Stream *s) +{ + Isdn *ip = &isdndev[s->dev]; + char name[32]; + int rss; + + DPRINT("isdnstopen %d...", s->dev); + qlock(&ip->kctl); + if (ip->kstart) { + qunlock(&ip->kctl); + DPRINT("active\n", s->dev); + return; + } + q->ptr = q->other->ptr = ip; + ip->rq = q; + rss = (isdnpeek(ip, &unite->listat)&Rss)>>1; + if (ip->lctl & Lld) /* if loopback D, */ + devctl(ip, Tss, 0); /* transmit INFO 0 */ + else if (rss == 2 || rss ==4) /* else if line active */ + devctl(ip, Tss, 3); /* transmit INFO 3 */ + else + devctl(ip, Tss, 1); /* transmit INFO 1 */ + sprint(name, "isdn%d", s->dev); + kproc(name, isdnkproc, ip); + if (waserror()) { + qunlock(&ip->kctl); + DPRINT("aborted\n"); + nexterror(); + } + sleep(&ip->kctlr, kLive, ip); + qunlock(&ip->kctl); + poperror(); + DPRINT("started\n"); + if (!(ip->lctl & Lld)) { + DPRINT("waiting for INFO 4\n"); + sleep(&ip->ar, lActive, ip); + DPRINT("got INFO 4\n"); + } +} + +static void +isdnstclose(Queue * q) +{ + Isdn *ip = (Isdn *)q->ptr; + DPRINT("isdnstclose %d...", ip-isdndev); + qlock(&ip->kctl); + qlock(ip); + ip->rq = 0; + qunlock(ip); + wakeup(&ip->kr); + if (waserror()) { + qunlock(&ip->kctl); + DPRINT("aborted\n"); + nexterror(); + } + sleep(&ip->kctlr, kDead, ip); + qunlock(&ip->kctl); + poperror(); + DPRINT("stopped\n"); +} + +static void +showframe(char *t, uchar *buf, int n) +{ + kprint("I %s [", t); + while (--n >= 0) + kprint(" %2.2ux", *buf++); + kprint(" ]\n"); +} + +/* + * this is only called by hangup + */ +static void +isdniput(Queue *q, Block *bp) +{ + PUTNEXT(q, bp); +} + +/* + * output a block + */ +static void +isdnoput(Queue *q, Block *bp) +{ + Isdn *ip = (Isdn *)q->ptr; + uchar set, clr; + + if(bp->type != M_DATA){ + set = clr = 0; + if(streamparse("ear", bp)){ + if(streamparse("on", bp)) + set = DRCODEC; + else if(streamparse("off", bp)) + clr = DRCODEC; + }else if(streamparse("mic", bp)){ + if(streamparse("on", bp)) + set = DXCODEC; + else if(streamparse("off", bp)) + clr = DXCODEC; + } + freeb(bp); + isdnlock(ip); + ip->venval &= ~clr; + ip->venval |= set; + *(ip->asr) = ip->venval; + isdnunlock(ip); + return; + } + qlock(&ip->wlock); + if(!putq(q, bp)){ /* send only whole messages */ + qunlock(&ip->wlock); + return; + } + DPRINT("isdnoput: len=%d\n", q->len); + if (tFull(ip)) + sleep(&ip->tr, tNotFull, ip); + ip->outb[ip->wo] = grabq(q); + ip->wo = NEXT(ip->wo); + qunlock(&ip->wlock); + + isdnlock(ip); + if (isdnxmit(ip)) + wakeup(&ip->kr); + isdnunlock(ip); +} + +static void +isdnkproc(void *arg) +{ + Isdn *ip = (Isdn *)arg; + int i; + + if (waserror()) { + devctl(ip, Enr, 0); + ip->kstart = 0; + wakeup(&ip->kctlr); + return; + } + /* + * create a number of blocks for input + */ + for (i=0; iinb[i]) + ip->inb[i] = allocb(BSIZE); + ip->ri = 0; + ip->wi = 0; + devctl(ip, 0, Enr); + ip->kstart = 1; + wakeup(&ip->kctlr); + for (;;) { + qlock(ip); + if (!ip->rq) { + qunlock(ip); + break; + } + while (ip->ri != ip->wi) { + PUTNEXT(ip->rq, ip->inb[ip->ri]); + ip->inb[ip->ri] = allocb(BSIZE); + ip->ri = NEXT(ip->ri); + } + i = 0; + while (ip->so != ip->ro) { + freeb(ip->outb[ip->so]); + ip->so = NEXT(ip->so); + i++; + } + qunlock(ip); + if (i) + wakeup(&ip->tr); + sleep(&ip->kr, kRun, ip); + } + devctl(ip, Enr, 0); + sleep(&ip->kr, tEmpty, ip); + while (ip->so != ip->ro) { + freeb(ip->outb[ip->so]); + ip->so = NEXT(ip->so); + } + poperror(); + ip->kstart = 0; + wakeup(&ip->kctlr); +} + +void +isdnlock(Isdn *ip) +{ + int s; + + s = spl2(); + lock(&ip->dev); + ip->pri = s; +} + +void +isdnunlock(Isdn *ip) +{ + int s; + + s = ip->pri; + unlock(&ip->dev); + splx(s); +} + +static void +devinit(int h) +{ + Isdn *ip = &isdndev[h]; + + isdnlock(ip); + ip->asr = ISDNDEV0+2*h; + ip->data = ip->asr+1; + ip->venval = DRCODEC | DXCODEC; + SET(unite->reset, Mres); + ip->lctl = 0; /* no loopback or 1's transmission */ + SET(unite->lctl, ip->lctl); + SET(unite->stictl, Prye); /* S/T interface normal */ + SET(unite->itl, 0x88); /* interrupt on 8 rcv/xmit char's */ + SET(unite->hcr, Tpol|Ipol|Clkmux|B2f|B1f); + ip->tctl = Ent; /* enable transmitter, send INFO 0 */ + ip->imask = Richgie|Teie; + SET(unite->tctl, ip->tctl); + SET(unite->imask, ip->imask); + ip->listat = GET(unite->listat); + isdnunlock(ip); +} + +static void +devctl(Isdn *ip, int clear, int set) +{ + isdnlock(ip); + ip->tctl &= ~clear; + ip->tctl |= set; + if (clear & Ent) + ip->imask &= ~Teie; + if (set & Ent) + ip->imask |= Teie; + if (clear & Enr) + ip->imask &= ~(Rfie|Reofie); + if (set & Enr) + ip->imask |= (Rfie|Reofie); + ip->imask |= Richgie; + SET(unite->tctl, ip->tctl); + SET(unite->imask, ip->imask); + isdnunlock(ip); +} + +int +isdnpeek(Isdn *ip, void *arg) +{ + int r; + + isdnlock(ip); + SETADDR(arg); + r = *(ip->data); + isdnunlock(ip); + return r; +} + +void +isdnpoke(Isdn *ip, void *arg, int data) +{ + isdnlock(ip); + SETADDR(arg); + *(ip->data) = data; + isdnunlock(ip); +} + +static void +devlctl(Isdn *ip, int val) +{ + isdnlock(ip); + ip->lctl = val; + SET(unite->lctl, val); + if (val & Lld) + SET(unite->stictl, Clrmm); + else + SET(unite->stictl, Prye); + isdnunlock(ip); +} + +static int +isdnintr(void) +{ + int status, wake = 0, intr = 0; + Isdn *ip; + + for(ip=isdndev; ipasr) + continue; + if (!(*(ip->asr)&Uint)) + continue; + ++intr; + status = GET(unite->istat); + if (status & Richg) + wake += isdnInfo(ip); + if (status & (Rfull|Reof)) + wake += isdnrecv(ip); + if (status & Tempty) + wake += isdnxmit(ip); + if (wake) + wakeup(&ip->kr); + } + return intr; +} + +static int +isdnInfo(Isdn *ip) +{ + int newstat; + + newstat = GET(unite->listat); + DPRINT("isdnInfo: old=0x%2.2ux, new=0x%2.2ux\n", + ip->listat, newstat); + ip->listat = newstat; + if (!ip->rq) { + ip->imask &= ~Richgie; + SET(unite->imask, ip->imask); + return 0; + } + newstat = (newstat&Rss)>>1; + ip->tctl &= ~Tss; + if (newstat == 2 || newstat == 4) + ip->tctl |= 3; /* transmit INFO 3 */ + else + ip->tctl |= 1; /* transmit INFO 1 */ + SET(unite->tctl, ip->tctl); + DPRINT("isdnInfo: tctl=0x%2.2ux\n", ip->tctl); + if (newstat == 4) + wakeup(&ip->ar); + return 0; +} + +static int +isdnrecv(Isdn *ip) +{ + Block *bp = ip->inb[ip->wi]; + uchar status, *p; + int i, n, wake = 0; +Loop: + status = GET(unite->rstat); + if (status&Overrun) { + ip->overrun++; + goto Reset; + } + if (!(n = status&Rqs)) + return wake; + p = bp->wptr; + if (p+n > bp->lim) { + ip->toolong++; + goto Reset; + } + ip->inchars += n; + SETADDR(&unite->data); + while (--n >= 0) + *p++ = *(ip->data); + if (status&Eof) { + if (*--p == 0) { + i = NEXT(ip->wi); + if (i == ip->ri) + ip->overflow++; + else { + bp->wptr = p; + bp->flags |= S_DELIM; + ip->wi = i; + bp = ip->inb[i]; + ++wake; + } + } else { + if (*p & 0x80) + ip->badcrc++; + if (*p & 0x40) + ip->abort++; + if (*p & 0x20) + ip->overrun++; + if (*p & 0x10) + ip->badcount++; + } + bp->wptr = bp->base; + } else + bp->wptr = p; + goto Loop; +Reset: + bp->wptr = bp->base; + SET(unite->reset, Rres); + return wake; +} + +static int +isdnxmit(Isdn *ip) +{ + Block *bp; + uchar status, *p; + int n, k, wake = 0; +Loop: + status = GET(unite->tstat); + if (status&Undabt) { + ip->underrun++; + SET(unite->reset, Tres); + if (ip->out) { + ip->ro = NEXT(ip->ro); + ip->out = 0; + ++wake; + } + } + if (!(n = status&Tqs)) + return wake; + if (!(bp = ip->out)) { + if (ip->ro == ip->wo) + return wake; + ip->out = bp = ip->outb[ip->ro]; + } + p = bp->rptr; + k = bp->wptr - p; + if (n > k) + n = k; + ip->outchars += n; + SETADDR(&unite->data); + while (--n >= 0) + *(ip->data) = *p++; + bp->rptr = p; + if (bp->rptr == bp->wptr) { + if (bp->flags & S_DELIM) + SET(unite->tctl, ip->tctl|Tfc); + if (!(ip->out = bp = bp->next)) { + ip->ro = NEXT(ip->ro); + ++wake; + } + } + goto Loop; +} diff --git a/gnot/hifi.h b/gnot/hifi.h new file mode 100644 index 0000000000000000000000000000000000000000..5114fc545e6cc23de77fdc7f7ec87f6bffdf8822 --- /dev/null +++ b/gnot/hifi.h @@ -0,0 +1,106 @@ +/* AT&T T7121 HDLC Interface for ISDN (HIFI-64) */ + +enum Hifi_r0 { /* Chip Configuration Register */ + Dint = Bit(0), + Ipol = Bit(1), + Flags = Bit(2), + Bm = Bit(3), + Alt = Bit(4), + Fe = Bit(5), + Fspol = Bit(6), + Fsen = Bit(7) +}; + +enum Hifi_r1 { /* Transmitter Control Register */ + Til = Bits(0,5), + Tabt = Bit(6), + Tfc = Bit(7) +}; + +enum Hifi_r2 { /* Transmitter Status Register */ + Tqs = Bits(0,6), + Ted = Bit(7) +}; + +enum Hifi_r4 { /* Receiver Status Register */ + Rqs = Bits(0,6), + Eof = Bit(7) +}; + +enum Hifi_r5 { /* Receiver Control Register */ + Ril = Bits(0,5), + P21ctl = Bit(6), + P17ctl = Bit(7) +}; + +enum Hifi_r6 { /* Operation Control Register */ + Rloop = Bit(0), + Lloop = Bit(1), + Enr = Bit(2), + Ent = Bit(3), + Rres = Bit(4), + Tres = Bit(5), + Tristate= Bit(6), + Pdwn = Bit(7) +}; + +enum Hifi_r7 { /* Transmit Time Slot Control Register */ + Tslt = Bits(0,5), + Dxbc = Bit(6), + Dxac = Bit(7) +}; + +enum Hifi_r8 { /* Receiver Time Slot Control Register */ + Rslt = Bits(0,5), + Iom2 = Bit(6), + Drab = Bit(7) +}; + +enum Hifi_r9 { /* Bit Offset Control Register */ + Clkri = Bit(0), + Rbof = Bits(1,3), + Clkxi = Bit(4), + Tbof = Bits(5,7), +}; + +enum Hifi_r10 { /* Transmitter Time Slot Offset Control Register */ + Ttsof = Bits(0,5), + Tlbit = Bit(6), + Dxi = Bit(7) +}; + +enum Hifi_r11 { /* Receiver Time Slot Offset Control Register */ + Rtsof = Bits(0,5), + Rlbit = Bit(6), + Dri = Bit(7) +}; + +enum Hifi_ar11 { /* Transparent Mode Control Register */ + Octof = Bits(0,2), + Mstat = Bit(3), + Aloct = Bit(4), + Match = Bit(5), + Trans = Bit(6), + Test = Bit(7) +}; + +enum Hifi_r14 { /* Interrupt Mask Register */ + Tdie = Bit(0), + Teie = Bit(1), + Undie = Bit(2), + Rfie = Bit(3), + Reofie = Bit(4), + Rovie = Bit(5), + Riie = Bit(6), + Tbcrc = Bit(7) +}; + +enum Hifi_r15 { /* Interrupt Status Register */ + Tdone = Bit(0), + Te = Bit(1), + Undabt = Bit(2), + Rf = Bit(3), + Reof = Bit(4), + Overun = Bit(5), + Ridl = Bit(6) +}; diff --git a/gnot/isdn.h b/gnot/isdn.h new file mode 100644 index 0000000000000000000000000000000000000000..6dab32ab584b2fc0a0a94f16a86fcccc3f03f6c1 --- /dev/null +++ b/gnot/isdn.h @@ -0,0 +1,137 @@ +typedef struct Isdn Isdn; +typedef struct Unite Unite; +typedef struct Hifi Hifi; + +/* +struct Isdndev { + uchar asr; + uchar data; +}; +*/ + +#define ISDNDEV0 ((uchar *)&PORT[52]) /* the first one */ + +#define Bit(n) (1<<(n)) + +#define Bits(m,n) (((1<<((n)-(m)+1))-1)<<(m)) + +enum Isdn_asr { /* Board status */ + Uint = Bit(0), + Hint0 = Bit(1), + Hint1 = Bit(2), + DRCODEC = Bit(6), /* enable codec receiver */ + DXCODEC = Bit(7) /* enable codec transmitter */ +}; + +/* + * Board addresses + */ + +#define unite ((Unite *)(0*Bit(4))) +#define hifi0 ((Hifi *) (2*Bit(4))) +#define hifi1 ((Hifi *) (3*Bit(4))) + +struct Unite { + uchar config; /* Chip/Hardware Configuration Register */ + uchar listat; /* Line Interface Status */ + uchar tctl; /* Transmitter Control Register */ + uchar data; /* D-channel data register */ + uchar hcr; /* Hardware Configuration Register */ + uchar rstat; /* HDLC Receiver Status */ + uchar itl; /* Interrupt Trigger Levels for D-Channel Queues */ + uchar mfstat; /* Multiframe Status and S-Channel Queues */ + uchar stictl; /* S/T Interface control */ + uchar imask; /* Interrupt masks */ + uchar istat; /* Interrupt Status */ + uchar qstat; /* Q-Channel Data and Status */ + uchar lctl; /* Loopback and Transmit 1's Control */ + uchar timctl; /* Timer Configuration Control */ + uchar tstat; /* Transmitter Queue Status */ + uchar reset; /* Software Resets */ +}; + +struct Hifi { + uchar config; /* Chip Configuration Register */ + uchar tctl; /* Transmitter Control Register */ + uchar tstat; /* Transmitter Status Register */ + uchar data; /* r3 is the Data Byte Register. */ + uchar rstat; /* Receiver Status Register */ + uchar rctl; /* Receiver Control Register */ + uchar opreg; /* Operation Register */ + uchar ttsctl; /* Transmitter Time Slot Control Register */ + uchar rtsctl; /* Receiver Time Slot Control Register */ + uchar bofctl; /* Bit Offset Control Register */ + uchar tofctl; /* Transmitter Time Slot Offset Control Register */ + uchar rof_tm; /* Rcvr Time Slot Offset/Trans. Mode Control Register */ + uchar rmask; /* Receiver Mask/Character Register. */ + uchar tmask; /* Transmitter Mask/Idle Char. Register. */ + uchar imask; /* Interrupt Mask Register */ + uchar istat; /* Interrupt Status Register */ +}; + +/* + * usage: SET(unite->chcr, C2pol); + */ + +#define SETADDR(addr) (*(ip->asr) = ip->venval | ((int)(addr))) + +#define GET(lval) (SETADDR(&(lval)), *(ip->data)) + +#define SET(lval, rval) (SETADDR(&(lval)), *(ip->data)=(rval)) + +#define NBMASK 0x0f +#define NB (NBMASK+1) +#define NEXT(a) (((a)+1)&NBMASK) + +struct Isdn +{ + QLock; /* access to struct */ + QLock kctl; /* kproc start/stop */ + Rendez kctlr; + int kstart; /* set if kernel process started */ + Rendez kr; /* kernel process sleep/wakeup */ + Rendez ar; /* wait for active link (INFO 4) */ + + int pri; /* priority at time of lock(&dev) */ + Lock dev; /* access to device */ + uchar venval; + uchar * asr; + uchar * data; + uchar listat; /* previous line interface status */ + uchar tctl; /* transmitter control */ + uchar imask; /* interrupt mask */ + uchar lctl; /* loopback control */ + uchar devaddr; /* debug access */ + + Block * inb[NB]; /* input buffer */ + int ri; /* input read pointer */ + int wi; /* input write pointer */ + Queue * rq; /* read queue */ + + QLock wlock; /* write's are atomic */ + Block * outb[NB]; /* output buffer */ + int so; /* output scavenge pointer */ + int ro; /* output read pointer */ + int wo; /* output write pointer */ + Block * out; /* current output block */ + Rendez tr; /* if transmitter must wait */ + + /* statistics */ + + ulong inchars; + ulong badcrc; + ulong abort; + ulong overrun; + ulong badcount; + ulong overflow; + ulong toolong; + ulong underrun; + ulong outchars; +}; + +extern Isdn * isdndev; +extern void isdnlock(Isdn*); +extern int isdnpeek(Isdn*, void*); +extern void isdnpoke(Isdn*, void*, int); +extern void isdnunlock(Isdn*); +extern int spl2(void); diff --git a/gnot/unite.h b/gnot/unite.h new file mode 100644 index 0000000000000000000000000000000000000000..a68cdadd0a6c0f3d2593e3e630f9376057ee3aa7 --- /dev/null +++ b/gnot/unite.h @@ -0,0 +1,120 @@ +/* AT&T T7250A User Network Interface for Terminal Equipment (UNITE) */ + +enum Unite_r0 { /* Chip/Hardware Configuration Register */ + Ckdm = Bit(1), + C2pol = Bit(2), + C1pol = Bit(3), + Dynrd = Bit(4), +}; + +enum Unite_r1 { /* Line Interface Status */ + Prss = Bits(0,1), + Rss = Bits(2,3), +}; + +enum Unite_r2 { /* Transmitter Control Register */ + Tss = Bits(0,1), + Tabt = Bit(2), + Tfc = Bit(3), + Tinv = Bit(4), + Rinv = Bit(5), + Ent = Bit(6), + Enr = Bit(7) +}; + +enum Unite_r4 { /* Hardware Configuration Register */ + Tpol = Bit(0), + Ipol = Bit(1), + Clkmux = Bit(2), + B2f = Bit(3), + B1f = Bit(4), + Syscko = Bit(5), + Codec2 = Bit(6), + Codec1 = Bit(7) +}; + +enum Unite_r5 { /* HDLC Receiver Status */ + Rqs = Bits(0,4), + Overrun = Bit(5), + Ridl = Bit(6), + Eof = Bit(7) +}; + +enum Unite_r6 { /* Interrupt Trigger Levels for D-Channel Queues */ + Tel = Bits(0,3), + Rfl = Bits(4,7) +}; + +enum Unite_r7 { /* Multiframe Status and S-Channel Queues */ + Sdata = Bits(0,4), + Mstate = Bits(5,6), + Mse = Bit(7) +}; + +enum Unite_r8 { /* S/T Interface control */ + Clrmm = Bit(0), + B1xb2 = Bit(1), + Pry = Bit(2), + Prye = Bit(3), + Lpry = Bit(4), + Ssm = Bit(5), + B2i = Bit(6), + B1i = Bit(7) +}; + +enum Unite_r9 { /* Interrupt masks */ + Mmie = Bit(0), + Richgie = Bit(1), + Qdie = Bit(2), + Ssie = Bit(3), + Tdie = Bit(4), + Teie = Bit(5), + Rfie = Bit(6), + Reofie = Bit(7) +}; + +enum Unite_r10 { /* Interrupt Status */ + Mm = Bit(0), + Richg = Bit(1), + Qdone = Bit(2), + Ss = Bit(3), + Tdone = Bit(4), + Tempty = Bit(5), + Rfull = Bit(6), + Reof = Bit(7) +}; + +enum Unite_r11 { /* Q-Channel Data and Status */ + Qdata = Bits(0,3), + Enflg = Bit(4), + Doneq = Bit(5), + Qse = Bit(7) +}; + +enum Unite_r12 { /* Loopback and Transmit 1's Control */ + Rlb2 = Bit(0), + Rlb1 = Bit(1), + Rld = Bit(2), + Llb2 = Bit(3), + Llb1 = Bit(4), + Lld = Bit(5), + T1b2 = Bit(6), + T1b1 = Bit(7) +}; + +enum Unite_r13 { /* Timer Configuration Control */ + Tim = Bits(0,3), + Tm = Bits(4,7) +}; + +enum Unite_r14 { /* Transmitter Queue Status */ + Tqs = Bits(0,4), + Undabt = Bit(5), +}; + +enum Unite_r15 { /* Software Resets */ + Mres = Bit(0), + Rres = Bit(1), + Tres = Bit(2), + Tcrcb = Bit(4), +}; diff --git a/pc/fns.h b/pc/fns.h index 89ecb906109fbe0201f781a83cf9f1454e287b02..0b54a7c2433acb57f63572d7b356c00d0ac897b3 100644 --- a/pc/fns.h +++ b/pc/fns.h @@ -7,7 +7,6 @@ void bootargs(ulong); void clock(Ureg*); void clockinit(void); void config(int); -void confinit1(void); int cpuspeed(int); void delay(int); void dmaend(int); diff --git a/pc/main.c b/pc/main.c index 3e793e7fafd5b7e01032e214b37ff0282e9f281a..ae3296dad98c86db7be9942b6804c13d01adbce9 100644 --- a/pc/main.c +++ b/pc/main.c @@ -278,7 +278,7 @@ confinit(void) conf.nfloppy = 2; conf.nhard = 1; conf.dkif = 1; - confinit1(); + confinit1(mul); } char *mathmsg[] = diff --git a/pc/trap.c b/pc/trap.c index a5cfa23e80334d0477a67b8d84717d8fc35eec7e..c18a8b750ee490b86d0654c53e46294b6a5939e1 100644 --- a/pc/trap.c +++ b/pc/trap.c @@ -343,7 +343,15 @@ syscall(Ureg *ur) u->p->insyscall = 0; u->p->psstate = 0; + + /* + * Put return value in frame. On the safari the syscall is + * just another trap and the return value from syscall is + * ignored. On other machines the return value is put into + * the results register by caller of syscall. + */ ur->ax = ret; + if(ax == NOTED) noted(ur, *(ulong*)(sp+BY2WD)); @@ -432,9 +440,7 @@ noted(Ureg *ur, ulong arg0) { Ureg *nur; - nur = u->ureg; - validaddr(nur->pc, 1, 0); - validaddr(nur->usp, BY2WD, 0); + nur = u->ureg; /* pointer to user returned Ureg struct */ if(nur->cs!=u->svcs || nur->ss!=u->svss || (nur->flags&0xff00)!=(u->svflags&0xff00)){ pprint("bad noted ureg cs %ux ss %ux flags %ux\n", nur->cs, nur->ss, @@ -449,8 +455,8 @@ noted(Ureg *ur, ulong arg0) return; } u->notified = 0; - nur->flags = (u->svflags&0xffffff00) | (ur->flags&0xff); - memmove(ur, u->ureg, sizeof(Ureg)); + nur->flags = (u->svflags&0xffffff00) | (nur->flags&0xff); + memmove(ur, nur, sizeof(Ureg)); switch(arg0){ case NCONT: if(waserror()){ @@ -458,7 +464,7 @@ noted(Ureg *ur, ulong arg0) qunlock(&u->p->debug); goto Die; } - validaddr(nur->pc, 1, 0); + validaddr(nur->pc, 1, 0); /* check for valid pc & usp */ validaddr(nur->usp, BY2WD, 0); poperror(); qunlock(&u->p->debug); diff --git a/port/devconc.c b/port/devconc.c new file mode 100644 index 0000000000000000000000000000000000000000..a328f485241d41a1abb1ac28b213b0b9b69e0ccd --- /dev/null +++ b/port/devconc.c @@ -0,0 +1,489 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" +#include "../port/error.h" + +#include "fcall.h" + +#define concdebug 1 + +#define DPRINT if(concdebug)kprint + +typedef struct Conc Conc; +typedef struct Subdev Subdev; + +/* + * A concentrator. One exists for every stream that a + * conc line discipline is pushed onto. + */ +struct Conc +{ + QLock; + Stream *s; + Queue * wq; + char name[64]; + int ndev; + Subdev *dev; + Block * bp; +}; + +struct Subdev +{ + Conc * cp; + int chan0; + Queue * rq; +}; + +static Lock conclock; +static Conc *concs; + +/* + * Concentrator line discipline (push here). + */ + +static void concstopen(Queue*, Stream*); +static void concstclose(Queue*); +static void concstoput(Queue*, Block*); +static void concstiput(Queue*, Block*); +Qinfo concinfo = +{ + concstiput, + concstoput, + concstopen, + concstclose, + "conc" +}; + +/* + * Stream interface to concentrator device (open here). + */ + +static void concdevstopen(Queue*, Stream*); +static void concdevstclose(Queue*); +static void concdevstoput(Queue*, Block*); +static void concdevstiput(Queue*, Block*); +Qinfo concdevinfo = +{ + concdevstiput, + concdevstoput, + concdevstopen, + concdevstclose, + "concdev" +}; + +static void +concstopen(Queue *q, Stream *s) +{ + DPRINT("concstopen q=0x%ux s=0x%ux\n", q, s); + + RD(q)->ptr = 0; /* (Conc *) for concstiput */ + WR(q)->ptr = s; + + s->opens++; /* Hold this queue in place */ + s->inuse++; +} + +static void +concstclose(Queue *q) +{ + Conc *cp = q->ptr; + Subdev *dp; + Block *bp; + int ndev; + + if(RD(q)->ptr == 0) + return; + DPRINT("concstclose \"%s\"\n", cp->name); + + qlock(cp); + ndev = cp->ndev; + cp->ndev = 0; + for(dp=cp->dev; dp<&cp->dev[ndev]; dp++){ + continue; + bp = allocb(0); + bp->type = M_HANGUP; + PUTNEXT(dp->rq, bp); + } + qunlock(cp); + cp->name[0] = 0; +} + +static Conc * +concalloc(char *name, int aflag) +{ + Conc *free, *cp; + + DPRINT("concalloc \"%s\" %d...", name, aflag); + lock(&conclock); + free = 0; + for(cp = concs; cp < &concs[conf.nconc]; cp++){ + if(strcmp(name, cp->name) == 0){ + unlock(&conclock); + DPRINT("found\n"); + return cp; + } + if(cp->name[0] == 0) + free = cp; + } + if(!aflag || free == 0){ + unlock(&conclock); + DPRINT("not found/none free\n"); + return 0; + } + strncpy(free->name, name, sizeof free->name-1); + unlock(&conclock); + DPRINT("alloc'd\n"); + return free; +} + +static void +concstoput(Queue *q, Block *bp) +{ + Conc *cp = 0; + Subdev *dp; + char *p, *err = 0; + int n, ndev, k; + + if(bp->type != M_CTL || streamparse("config", bp) == 0){ + PUTNEXT(q, bp); + return; + } + if(concdebug){ + char fmt[32]; + sprint(fmt, "concstoput config: %%.%ds\n", bp->wptr-bp->rptr); + kprint(fmt, bp->rptr); + } + if(RD(q)->ptr){ + err = "stream already configured"; + goto out; + } + n = BLEN(bp); + if(bp->wptr >= bp->lim){ + memmove(bp->base, bp->rptr, n); + bp->rptr = bp->base; + bp->wptr = bp->rptr+n; + } + *bp->wptr++ = 0; + p = strchr((char *)bp->rptr, ' '); + if(p == 0){ + err = "bad config command"; + goto out; + } + *p++ = 0; + cp = concalloc((char *)bp->rptr, 1); + bp->rptr = (uchar *)p; + if(cp == 0){ + err = "no free conc's"; + goto out; + } + qlock(cp); + if(cp->ndev){ + err = "conc name in use"; + goto out; + } + p = (char *)bp->rptr; + for(ndev=0; strtoul(p, &p, 0); ndev++) ; + DPRINT("concstoput: ndev=%d\n", ndev); + cp->bp = allocb(ndev*sizeof(Subdev)); + if(cp->bp == 0){ + err = "can't allocb for subdevices"; + cp->name[0] = 0; + goto out; + } + cp->dev = (Subdev *)cp->bp->base; + p = (char *)bp->rptr; + k = 0; + DPRINT("concstoput: chan0="); + for(dp=cp->dev; dp<&cp->dev[ndev]; dp++){ + dp->cp = cp; + dp->chan0 = k; + DPRINT(" %d", dp->chan0); + k += strtoul(p, &p, 0); + dp->rq = 0; + } + DPRINT("\n"); + cp->s = q->ptr; + cp->wq = q; + cp->ndev = ndev; + q->ptr = cp; + q->other->ptr = cp; +out: + freeb(bp); + if(cp) + qunlock(cp); + if(err){ + DPRINT("concstoput: err=\"%s\"\n", err); + error(err); + } +} + +/* + * Simplifying assumption: one put == one message && the channel number + * is in the first block (cf. dkmuxiput). + */ +static void +concstiput(Queue *q, Block *bp) +{ + Conc *cp = q->ptr; + Subdev *dp; + int chan; + + if(bp->type != M_DATA){ + PUTNEXT(q, bp); + return; + } + if(BLEN(bp) < 2 || cp == 0) + goto Drop; + chan = bp->rptr[0] | (bp->rptr[1]<<8); + for(dp=&cp->dev[cp->ndev-1]; dp>=cp->dev; dp--) + if(chan >= dp->chan0) + break; + if(dp < cp->dev || dp->rq == 0) + goto Drop; + chan -= dp->chan0; + bp->rptr[0] = chan; + bp->rptr[1] = chan>>8; + bp->flags |= S_DELIM; /* a process is probably waiting for this */ + PUTNEXT(dp->rq, bp); + return; + +Drop: + freeb(bp); + return; +} + +static void +concdevstopen(Queue *q, Stream *s) +{ + Conc *cp; + Subdev *dp; + + cp = &concs[s->dev]; + qlock(cp); + if(s->id > cp->ndev){ + qunlock(cp); + error("no such subdevice"); + } + dp = &cp->dev[s->id]; + q->ptr = dp; + q->other->ptr = dp; + dp->rq = RD(q); + streamenter(cp->s); + qunlock(cp); +} + +static void +concdevstclose(Queue *q) +{ + Subdev *dp = q->ptr; + Conc *cp = dp->cp; + + qlock(cp); + q->ptr = 0; + q->other->ptr = 0; + dp->rq = 0; + streamexit(cp->s, 0); + qunlock(cp); +} + +/* + * this is only called by concstclose (hangup) + */ +static void +concdevstiput(Queue *q, Block *bp) +{ + PUTNEXT(q, bp); +} + +static void +concdevstoput(Queue *q, Block *bp) +{ + Subdev *dp = q->ptr; + Conc *cp; + int chan; + + if(dp == 0){ + DPRINT("concdevstoput: not config'd, dropped %d\n", BLEN(bp)); + freeb(bp); + return; + } + cp = dp->cp; + qlock(cp); + if(!putq(q, bp)){ /* send only whole messages */ + qunlock(cp); + return; + } + bp = grabq(q); + qunlock(cp); + if(BLEN(bp) < 2 || bp->type != M_DATA){ + DPRINT("concdevstoput: dropped %d\n", BLEN(bp)); + freeb(bp); + return; + } + chan = bp->rptr[0] | (bp->rptr[1]<<8); + chan += dp->chan0; + bp->rptr[0] = chan; + bp->rptr[1] = chan>>8; + PUTNEXT(cp->wq, bp); +} + +void +concreset(void) +{ + concs = ialloc(conf.nconc*sizeof(Conc), 0); + newqinfo(&concinfo); +} + +void +concinit(void) +{ +} + +Chan * +concattach(char *spec) +{ + Chan *c; + Conc *cp; + + /* + * find a concentrator with the same name (default conc) + */ + if(*spec == 0) + spec = "conc"; + cp = concalloc(spec, 0); + if(cp == 0 || cp->ndev == 0) + error("device not configured"); + + c = devattach('K', spec); + c->dev = cp-concs; + c->qid = (Qid){CHDIR, 0}; + return c; +} + +Chan * +concclone(Chan *c, Chan *nc) +{ + return devclone(c, nc); +} + +#define TOPDIR (CHDIR+1) +#define CHANDIR (CHDIR+2) + +static int +concgen(Chan *c, Dirtab *tab, int ntab, int i, Dir *dp) +{ + Conc *cp; + char buf[16]; + + cp = &concs[c->dev]; + switch(c->qid.path){ + case CHDIR: + devdir(c, (Qid){TOPDIR,0}, concs[c->dev].name, 0, eve, 0555, dp); + return i==0 ? 1 : -1; + case TOPDIR: + if(i<0 || i >= cp->ndev) + return -1; + sprint(buf, "%d", i); + devdir(c, (Qid){STREAMQID(i,CHANDIR),0}, buf, 0, eve, 0555, dp); + return 1; + } + return streamgen(c, 0, 0, i, dp); +} + +int +concwalk(Chan *c, char *name) +{ + return devwalk(c, name, 0, 0, concgen); +} + +void +concstat(Chan *c, char *dp) +{ + char buf[16], *name; + Dir dir; + + if(c->qid.path&CHDIR)switch(c->qid.path){ + case CHDIR: + name = "."; + break; + case TOPDIR: + name = concs[c->dev].name; + break; + default: + sprint(name = buf, "%d", STREAMID(c->qid.path)); + break; + }else switch(STREAMTYPE(c->qid.path)){ + case Sdataqid: + name = "data"; + break; + case Sctlqid: + name = "ctl"; + break; + default: + name = "panic"; + break; + } + devdir(c, c->qid, name, 0, eve, (c->qid.path&CHDIR)?0555:0600, &dir); + convD2M(&dir, dp); +} + +Chan * +concopen(Chan *c, int omode) +{ + if(c->qid.path & CHDIR){ + if(omode != OREAD) + error(Eperm); + }else + streamopen(c, &concdevinfo); + c->mode = openmode(omode); + c->flag |= COPEN; + c->offset = 0; + return c; +} + +void +conccreate(Chan *c, char *name, int omode, ulong perm) +{ + USED(c); + error(Eperm); +} + +void +concclose(Chan *c) +{ + if(c->stream) + streamclose(c); +} + +long +concread(Chan *c, void *a, long n, ulong offset) +{ + if(c->stream) + return streamread(c, a, n); + if(c->qid.path & CHDIR) + return devdirread(c, a, n, 0, 0, concgen); + error(Eio); +} + +long +concwrite(Chan *c, void *a, long n, ulong offset) +{ + return streamwrite(c, a, n, 0); +} + +void +concremove(Chan *c) +{ + USED(c); + error(Eperm); +} + +void +concwstat(Chan *c, char *dp) +{ + USED(c); + error(Eperm); +} diff --git a/port/portfns.h b/port/portfns.h index a7cc2c5704b4a8d979b59a23de7bb1db1ca795e4..158a28a231138cda8d48b816830f6b5e10d9b8f8 100644 --- a/port/portfns.h +++ b/port/portfns.h @@ -26,6 +26,7 @@ void closemount(Mount*); void closepgrp(Pgrp*); long clrfpintr(void); void confinit(void); +void confinit1(int mul); int consactive(void); void consdebug(void); Block *copyb(Block*, int); @@ -83,6 +84,7 @@ int getfields(char*, char**, int, char); Block* getq(Queue*); int gets(IOQ*, void*, int); void gotolabel(Label*); +Block* grabq(Queue*); void grpinit(void); int hwcursmove(int, int); int hwcursset(uchar*, uchar*, int, int); diff --git a/port/proc.c b/port/proc.c index 4847a0a1cc7d372158e34747b71354e519e0e1ec..35ec7bb1fa3d4d3e412c32f6cb2f3000f868fe02 100644 --- a/port/proc.c +++ b/port/proc.c @@ -730,6 +730,10 @@ kproc(char *name, void (*func)(void *), void *arg) flushmmu(); } +/* + * called splhi() by notify(). See comment in notify for the + * reasoning. + */ void procctl(Proc *p) { @@ -737,6 +741,7 @@ procctl(Proc *p) switch(p->procctl) { case Proc_exitme: + spllo(); /* pexit has locks in it */ pexit("Killed", 1); case Proc_traceme: if(u->nnote == 0) @@ -754,7 +759,8 @@ procctl(Proc *p) } qunlock(&p->debug); p->state = Stopped; - sched(); + sched(); /* sched returns spllo() */ + splhi(); p->psstate = state; return; } diff --git a/port/stlapd.c b/port/stlapd.c new file mode 100644 index 0000000000000000000000000000000000000000..6a6c4a0e52a61122812129ece7e89720676aa14f --- /dev/null +++ b/port/stlapd.c @@ -0,0 +1,768 @@ +#include "u.h" +#include "lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" +#include "../port/error.h" + +#define DPRINT if(q->flag&QDEBUG)kprint + +typedef struct Lapd Lapd; + +#define NOW TK2MS(MACHP(0)->ticks) +#define T200 (NOW+2500) + + /* C/R bits */ + +#define UCmd 0 /* command, user to network */ +#define UResp 2 /* response, user to network */ +#define NCmd 2 /* command, network to user */ +#define NResp 0 /* response, network to user */ + +#define SAPI(s, cr) (((s)<<2)|cr) +#define TEI(t) (((t)<<1)|1) + +/* + * Commands and responses + */ + +#define RR 0x01 /* Receiver Ready */ +#define RNR 0x05 /* Receiver Not Ready */ +#define REJ 0x09 /* Reject */ +#define SABME 0x6f /* Set Asynchronous Balanced Mode Extended */ +#define DM 0x0f /* Disconnect Mode */ +#define UI 0x03 /* Unnumbered Information */ +#define DISC 0x43 /* Disconnect */ +#define UA 0x63 /* Unnumbered Acknowledgement */ +#define FRMR 0x87 /* Frame Reject */ +#define XID 0xaf /* Exchange Identification */ + +enum States { + Unused = 0, + NoTEI, + WaitTEI, + TEIassigned, + WaitEst, + Multiframe, + WaitRel, +}; + +enum Flags { + Ownbusy = 0x01, + Peerbusy = 0x02, + Rejecting = 0x04, + Timeout = 0x08, + Hungup = 0x80 +}; + +#define SMASK 127 +#define NSEQ (SMASK+1) +#define THISS(i) ((i)&SMASK) +#define NEXTS(i) (((i)+1)&SMASK) + +#define OMASK 7 +#define NOBUF (OMASK+1) +#define THISO(i) ((i)&OMASK) +#define NEXTO(i) (((i)+1)&OMASK) + +#define RSTATE(lp) ((lp->flags&Ownbusy) ? RNR : \ + (lp->flags&Rejecting) ? REJ : RR) + +struct Lapd { + QLock; /* access, state change */ + Rendez; /* waiting for state change */ + int state; + int flags; + Queue * rq; + Queue * wq; + ushort refnum; + int tei; + int kout; /* maximum allowed number of outstanding I frames */ + int vs; /* send state variable (next seq. no. to send) */ + int va; /* acknowledge state variable (next expected ack) */ + int vr; /* receive state variable (next expected input) */ + Rendez tr; /* so transmit writer can wait */ + Block * outb[NOBUF]; /* transmitter circular buffer */ + int vt; /* input pointer for outb */ + int t200; + Rendez timer; + int kstarted; + int error; +}; + +enum { + LAPD_OK, + Address, + BadUA, + Badassign, + Badmanage, + Tooshort, + Unimpmanage, + Unkdlci, + Egates, +}; + +char *lapderrors[] = { + "LAPD OK", + "Address", + "BadUA", + "Badassign", + "Badmanage", + "Tooshort", + "Unimpmanage", + "Egates", +}; + +Lapd *lapd; + +/* + * predeclared + */ +static void assigntei(Lapd *); +static void dl_establish(Lapd *); +static void dl_release(Lapd *); +static void lapdreset(void); +static void lapdclose(Queue *); +static void lapdiput(Queue*, Block*); +static void lapdkproc(void *); +static void lapdopen(Queue*, Stream*); +static void lapdoput(Queue*, Block*); +static int lapdxmit(Lapd *); +static void mdl_assign(Lapd *); +static void mdl_iput(Queue *, Block *); +static int recvack(Lapd *, int); +static void sendctl(Lapd *, int, int, int); + +Qinfo lapdinfo = { lapdiput, lapdoput, lapdopen, lapdclose, "lapd", lapdreset }; + +#define Predicate(name, expr) static int name(void *arg) { return expr; } +#define lp ((Lapd *)arg) + +Predicate(pTEIassigned, lp->state == TEIassigned); +Predicate(pMultiframe, lp->state == Multiframe); + +Predicate(tEmpty, lp->vs == lp->va) +Predicate(tFull, NEXTO(lp->vt) == THISO(lp->va)) +Predicate(tNotFull, NEXTO(lp->vt) != THISO(lp->va)) + +#undef lp + +static void +lapderror(Lapd *lp, int code) +{ + lp->error = code; + nexterror(); +} + +static void +lapdreset(void) +{ + lapd = ialloc(conf.nlapd*sizeof(Lapd), 0); +} + +static void +lapdopen(Queue *q, Stream *s) +{ + Lapd *lp; + char name[32]; + + for(lp=lapd; lp<&lapd[conf.nlapd]; lp++){ + qlock(lp); + if(lp->state == 0) + break; + qunlock(lp); + } + if(lp>=&lapd[conf.nlapd]) + error(Enoifc); + + /*q->flag |= QDEBUG; + q->other->flag |= QDEBUG;*/ + DPRINT("lapdopen: lapd %d\n", lp - lapd); + q->ptr = q->other->ptr = lp; + lp->rq = q; + lp->wq = q->other; + lp->state = NoTEI; + lp->flags = 0; + lp->kout = 1; + qunlock(lp); + sprint(name, "lapd%d", lp - lapd); + kproc(name, lapdkproc, lp); + DPRINT("lapdopen: mdl_assign\n"); + mdl_assign(lp); + DPRINT("lapdopen: dl_establish\n"); + dl_establish(lp); +} + +static void +mdl_assign(Lapd *lp) +{ + Block *b; uchar *p; + + qlock(lp); + if (lp->state != NoTEI) { + qunlock(lp); + error(Egreg); + } + lp->state = WaitTEI; + assigntei(lp); + lp->t200 = T200; + qunlock(lp); + sleep(lp, pTEIassigned, lp); + if (lp->state != TEIassigned){ + lapdclose(lp->rq); + error(Egreg); + } +} + +static void +assigntei(Lapd *lp) +{ + Queue *q = lp->rq; + Block *b = allocb(16); + uchar *p = b->wptr; + + lp->refnum = NOW; + *p++ = SAPI(63, UCmd); + *p++ = TEI(127); + *p++ = UI; + *p++ = 0x0f; + *p++ = lp->refnum>>8; + *p++ = lp->refnum; + *p++ = 0x01; + *p++ = 0xff; + b->wptr = p; + b->flags |= S_DELIM; + DPRINT("assigntei: refnum=0x%4.4ux\n", lp->refnum); + PUTNEXT(lp->wq, b); +} + +static void +dl_establish(Lapd *lp) +{ + Block *b; uchar *p; + + qlock(lp); + if (lp->state != TEIassigned) { + qunlock(lp); + error(Egreg); + } + lp->state = WaitEst; + sendctl(lp, UCmd, SABME, 0); + lp->t200 = T200; + qunlock(lp); + sleep(lp, pMultiframe, lp); + if (lp->state != Multiframe){ + lapdclose(lp->rq); + error(Egreg); + } +} + +static void +dl_release(Lapd *lp) +{ + Block *b; uchar *p; + + qlock(lp); + if (lp->state != Multiframe) { + qunlock(lp); + error(Egreg); + } + lp->state = WaitRel; + sendctl(lp, UCmd, DISC, 0); + lp->t200 = T200; + qunlock(lp); + tsleep(lp, pTEIassigned, lp, 30*1000); + qlock(lp); + if(lp->state > TEIassigned) + lp->state = TEIassigned; + qunlock(lp); +} + +static void +lapdclose(Queue *q) +{ + Lapd *lp = (Lapd *)q->ptr; + int i; + + if(lp == 0) + return; + + if (lp->state == Multiframe) { + for(i=0; itr, tEmpty, lp, 2500); /* drain */ + dl_release(lp); /* DISC to NT */ + for(i=0; ioutb[i]){ + freeb(lp->outb[i]); + lp->outb[i] = 0; + } + } + + lp->flags |= Hungup; /* tell kernel proc */ + lp->t200 = NOW; + wakeup(&lp->timer); + for(i=0; i<10 && lp->kstarted; i++) + tsleep(lp, return0, 0, 500); + + lp->state = 0; +} + +/* + * upstream control messages + */ +static void +lapdctliput(Lapd *lp, Queue *q, Block *bp) +{ + switch(bp->type){ + case M_HANGUP: + lp->flags |= Hungup; + wakeup(lp); + break; + } + PUTNEXT(q, bp); +} + +void +lapdiput(Queue *q, Block *bp) +{ + Lapd *lp = (Lapd *)q->ptr; + int sapi, cr, tei, ctl, ns, nr = 0, pf; + uchar *start, *p; + + DPRINT("lapdiput: %d byte(s)\n", bp->wptr-bp->rptr); + qlock(lp); + lp->error = 0; + p = start = bp->rptr; + if (waserror()) { + qunlock(lp); + kprint("lapdiput: %s:", lapderrors[lp->error]); + for(p=start; pwptr; p++) + kprint(" %2.2ux", *p); + kprint("\n"); + freeb(bp); + return; + } + + if(bp->type != M_DATA){ + lapdctliput(lp, q, bp); + bp = 0; + goto out; + } + if (bp->wptr-p < 3) + lapderror(lp, Tooshort); + if ((p[0] & 0x01) || !(p[1] & 0x01)) + lapderror(lp, Address); + sapi = p[0] >> 2; + cr = p[0] & 0x02; + tei = p[1] >> 1; + ctl = p[2]; + if ((ctl&0x03) != 0x03) { + if (bp->wptr-p < 4) + lapderror(lp, Tooshort); + pf = p[3]&0x01; + nr = p[3]>>1; + p += 4; + } else { + pf = ctl&0x10; + ctl &= ~0x10; + p += 3; + } + bp->rptr = p; + DPRINT("lapdiput: cr=%d sapi=%d tei=%d ctl=0x%2.2x pf=%d\n", + cr, sapi, tei, ctl, pf); + if (cr==NCmd && tei==127 && ctl==UI) { + switch (sapi) { + case 0: + PUTNEXT(q, bp); + bp = 0; + break; + case 63: + mdl_iput(q, bp); + bp = 0; + break; + default: + lapderror(lp, Unkdlci); + break; + } + goto out; + } + if (sapi != 0 || lp->state < TEIassigned || tei != lp->tei) + lapderror(lp, Unkdlci); + if (!(ctl&0x01)) { /* Information */ + if (recvack(lp, nr)>0 && !(lp->flags&(Peerbusy|Timeout))) + lp->t200 = 0; + if (lp->flags&Ownbusy) { + if (pf) + sendctl(lp, cr, RNR, pf); + lapdxmit(lp); + goto out; + } + ns = ctl>>1; + if (ns != lp->vr) { + lp->flags |= Rejecting; + sendctl(lp, cr, REJ, pf); + lapdxmit(lp); + goto out; + } + PUTNEXT(q, bp); + bp = 0; + lp->flags &= ~Rejecting; + lp->vr = NEXTS(lp->vr); + if (QFULL(q->next)) + lp->flags |= Ownbusy; + if (pf || (lp->flags&Ownbusy)) { + sendctl(lp, cr, RSTATE(lp), pf); + lapdxmit(lp); + } else if (!lapdxmit(lp)) + sendctl(lp, cr, RR, pf); + goto out; + } + switch (ctl) { + case RR: + if (recvack(lp, nr)<0) + goto out; + lp->flags &= ~Peerbusy; + if (cr==NCmd && pf) + sendctl(lp, cr, RSTATE(lp), pf); + if (!(lp->flags&Timeout)) { + lp->t200 = 0; + if (cr==NResp && pf) + DPRINT("lapdiput: RR response with F==1\n"); + lapdxmit(lp); + } else if (cr==NResp && pf) { + lp->flags &= ~Timeout; + lp->vs = nr; + lp->t200 = 0; + lapdxmit(lp); + } + break; + case RNR: + if (recvack(lp, nr)<0) + goto out; + lp->flags |= Peerbusy; + if (cr==NCmd && pf) + sendctl(lp, cr, RSTATE(lp), pf); + if (!(lp->flags&Timeout)) { + lp->t200 = T200; + if (cr==NResp && pf) + DPRINT("lapdiput: RNR response with F==1\n"); + } else if (cr==NResp && pf) { + lp->flags &= ~Timeout; + lp->vs = nr; + lp->t200 = T200; + } + break; + case REJ: + if (recvack(lp, nr)<0) + goto out; + lp->flags &= ~Peerbusy; + if (cr==NCmd && pf) + sendctl(lp, cr, RSTATE(lp), pf); + if (!(lp->flags&Timeout)) { + lp->vs = nr; + lp->t200 = 0; + if (cr==NResp && pf) + DPRINT("lapdiput: REJ response with F==1\n"); + lapdxmit(lp); + } else if (cr==NResp && pf) { + lp->flags &= ~Timeout; + lp->vs = nr; + lp->t200 = 0; + lapdxmit(lp); + } + break; + case DM: + lp->state = TEIassigned; + lp->flags = 0; + lp->t200 = 0; + wakeup(lp); + break; + case UA: + if (lp->state == WaitEst) { + lp->state = Multiframe; + lp->flags = 0; + lp->vs = 0; + lp->va = 0; + lp->vr = 0; + lp->vt = 0; + lp->t200 = 0; + wakeup(lp); + } else if (lp->state == WaitRel) { + lp->state = TEIassigned; + lp->flags = 0; + lp->t200 = 0; + wakeup(lp); + } else + lapderror(lp, BadUA); + break; + case SABME: + case UI: + case DISC: + case FRMR: + case XID: + lapderror(lp, Egates); + break; + } +out: + if (bp) + freeb(bp); + poperror(); + qunlock(lp); +} + +static void +mdl_iput(Queue *q, Block *bp) +{ + Lapd *lp = (Lapd *)q->ptr; + uchar *p = bp->rptr; + ushort refnum; + int ai; + + if (bp->wptr-p != 5 || p[0] != 0x0f || !(p[4]&0x01)) + lapderror(lp, Badmanage); + refnum = (p[1]<<8)|p[2]; + ai = p[4]>>1; + switch (p[3]) { + case 2: /* identity assigned */ + if (lp->state == WaitTEI && lp->refnum == refnum) { + lp->state = TEIassigned; + lp->tei = ai; + lp->t200 = 0; + DPRINT("assigned tei = %d\n", lp->tei); + wakeup(lp); + } else + lapderror(lp, Badassign); + break; + case 3: /* identity denied */ + if (lp->state == WaitTEI && lp->refnum == refnum) { + lp->t200 = 0; + DPRINT("denied tei = %d\n", ai); + wakeup(lp); + } else + lapderror(lp, Badassign); + break; + case 4: /* identity check request */ + if (lp->state >= TEIassigned && (ai==127||ai==lp->tei)) { + Block *b = allocb(16); + uchar *p = b->wptr; + + *p++ = SAPI(63, UCmd); + *p++ = TEI(127); + *p++ = UI; + *p++ = 0x0f; + *p++ = NOW>>8; + *p++ = NOW; + *p++ = 0x05; + *p++ = (lp->tei<<1)|1; + b->wptr = p; + b->flags |= S_DELIM; + DPRINT("id check response: tei=%d\n", lp->tei); + PUTNEXT(lp->wq, b); + } else + lapderror(lp, Badassign); + break; + default: + { + Block *b = allocb(0); + b->type = M_HANGUP; + PUTNEXT(lp->rq, b); + } + lapderror(lp, Unimpmanage); + break; + } + freeb(bp); +} + +static int +recvack(Lapd *lp, int nr) +{ + Queue *q = lp->wq; + int i; + + for(i=lp->va; i!=lp->vs; i=NEXTS(i)){ + if(i==nr) + break; + } + if(i!=nr) { + DPRINT("lapd recvack: va,nr,vs = %d,%d,%d\n", + lp->va, nr, lp->vs); + return -1; + } + i = 0; + while (lp->va != nr) { + freeb(lp->outb[THISO(lp->va)]); + lp->outb[THISO(lp->va)] = 0; + lp->va = NEXTS(lp->va); + i++; + } + if (i > 0) + wakeup(&lp->tr); + return i; +} + +/* + * downstream control + */ +static void +lapdctloput(Lapd *lp, Queue *q, Block *bp) +{ + char *fields[2]; + + switch(bp->type){ + case M_CTL: + if(streamparse("debug", bp)){ + switch(getfields((char *)bp->rptr, fields, 2, ' ')){ + case 1: + if (strcmp(fields[0], "on") == 0) { + q->flag |= QDEBUG; + q->other->flag |= QDEBUG; + } + if (strcmp(fields[0], "off") == 0) { + q->flag &= ~QDEBUG; + q->other->flag &= ~QDEBUG; + } + } + freeb(bp); + return; + } + } + PUTNEXT(q, bp); +} + +/* + * accept data from a writer + */ +static void +lapdoput(Queue *q, Block *bp) +{ + Lapd *lp = (Lapd *)q->ptr; + + if(bp->type != M_DATA){ + lapdctloput(lp, q, bp); + return; + } + if(!putq(q, bp)) /* send only whole messages */ + return; + DPRINT("lapdoput: len=%d\n", q->len); + if (tFull(lp)) + sleep(&lp->tr, tNotFull, lp); + qlock(lp); + if (waserror()) { + qunlock(lp); + nexterror(); + } + lp->outb[lp->vt] = grabq(q); + lp->vt = NEXTO(lp->vt); + + lapdxmit(lp); + poperror(); + qunlock(lp); +} + +static int +lapdxmit(Lapd *lp) +{ + Block *bp, *db; + int i; uchar *p; + + for (i=0;;i++) { + if (THISO(lp->vs) == lp->vt) /* buffer empty */ + break; + if (THISS(lp->va+lp->kout) == lp->vs) /* window full */ + break; + if (lp->flags & Peerbusy) /* flow-controlled */ + break; + bp = allocb(16); + p = bp->wptr; + *p++ = SAPI(0, UCmd); + *p++ = TEI(lp->tei); + *p++ = lp->vs<<1; + *p++ = lp->vr<<1; + bp->wptr = p; + PUTNEXT(lp->wq, bp); + for(bp=lp->outb[THISO(lp->vs)]; bp; bp=bp->next){ + db = allocb(0); + db->rptr = bp->rptr; + db->wptr = bp->wptr; + db->flags |= (bp->flags&S_DELIM); + PUTNEXT(lp->wq, db); + } + lp->vs = NEXTS(lp->vs); + lp->t200 = T200; + } + return i; +} + +/* + * send a control frame. + */ +static void +sendctl(Lapd *lp, int cmd, int ctl, int pf) +{ + Block *bp = allocb(16); + uchar *p = bp->wptr; + + *p++ = SAPI(0, cmd); + *p++ = TEI(lp->tei); + if (ctl & 0x02) { + *p++ = ctl|(pf?0x10:0); + } else { + *p++ = ctl; + *p++ = (lp->vr<<1)|(pf?0x01:0); + } + bp->wptr = p; + bp->flags |= S_DELIM; + PUTNEXT(lp->wq, bp); +} + +static void +lapdkproc(void *arg) +{ + Lapd *lp = (Lapd *)arg; + int locked = 0; + lp->kstarted = 1; + + if(waserror()){ + if (locked) + qunlock(lp); + print("lapdkproc %d error\n", lp-lapd); + lp->kstarted = 0; + wakeup(lp); + return; + } + for(;;){ + tsleep(&lp->timer, return0, 0, 500); + if(!lp->t200 || NOW < lp->t200) + continue; + qlock(lp); + locked = 1; + USED(locked); + if(lp->flags & Hungup){ + qunlock(lp); + locked = 0; + USED(locked); + break; + } + switch(lp->state){ + case WaitTEI: + assigntei(lp); + lp->t200 = T200; + break; + case WaitEst: + sendctl(lp, UCmd, SABME, 0); + break; + case Multiframe: + sendctl(lp, UCmd, RSTATE(lp), 1); + lp->flags |= Timeout; + lp->t200 = T200; + break; + } + qunlock(lp); + locked = 0; + USED(locked); + } + lp->kstarted = 0; + wakeup(lp); + poperror(); +} diff --git a/port/stream.c b/port/stream.c index ac7825066aad1202a8a13087c3b90cd4fd52a75a..a404ef6d85e2607c573953d448c3dcb3ddfc66f4 100644 --- a/port/stream.c +++ b/port/stream.c @@ -542,6 +542,30 @@ getq(Queue *q) return bp; } +/* + * grab all the blocks in a queue + */ +Block * +grabq(Queue *q) +{ + Block *bp; + + lock(q); + bp = q->first; + if(bp){ + q->first = 0; + q->last = 0; + q->len = 0; + q->nb = 0; + if(q->flag&QHIWAT){ + wakeup(q->other->next->other->rp); + q->flag &= ~QHIWAT; + } + } + unlock(q); + return bp; +} + /* * remove the first block from a list of blocks */ diff --git a/power/devhotrod.c b/power/devhotrod.c index 5ad01f52638f9704c023adafa41ef3c46332aa6a..3fbe2f8647d9ab6a64aef85f8bcbf66bc7083e6f 100644 --- a/power/devhotrod.c +++ b/power/devhotrod.c @@ -75,9 +75,9 @@ hotwait(Hotmsg **mp) l = 0; while(*mp){ delay(0); /* just a subroutine call; stay off VME */ - if(++l > 1000*1000){ + if(++l > 10*1000*1000){ l = 0; - print("hotsend blocked\n"); + panic("hotsend blocked"); } } return; @@ -412,11 +412,9 @@ hotrodintr(int vec) Hotmsg *hm; ulong l; - LEDON(LEDhotintr); h = &hotrod[vec - Vmevec]; if(h&hotrod[Nhotrod]){ print("bad hotrod vec\n"); - LEDOFF(LEDhotintr); return; } while(l = h->addr->replyq[h->ri]){ /* assign = */ @@ -429,5 +427,4 @@ hotrodintr(int vec) if(!hm->abort) wakeup(&hm->r); } - LEDOFF(LEDhotintr); } diff --git a/power/faultmips.c b/power/faultmips.c index 66520d1214e6b538835ae1a182a623a2adaf1e90..49327ba4d89b6fdc3673623db714446bed53b5ea 100644 --- a/power/faultmips.c +++ b/power/faultmips.c @@ -21,6 +21,8 @@ faultmips(Ureg *ur, int user, int code) LEDON(LEDfault); addr = ur->badvaddr; + if(addr & KZERO) + LEDON(LEDkfault); addr &= ~(BY2PG-1); read = !(code==CTLBM || code==CTLBS); diff --git a/power/io.h b/power/io.h index 7ca96decdd993639e1649df718b5230f7a4c0a33..b5c7c6fafd888a39724ddb79327a78d8b0f57032 100644 --- a/power/io.h +++ b/power/io.h @@ -10,13 +10,13 @@ enum { LEDtrapmask= 0xf<<0, - LEDhotintr= 1<<4, + LEDkfault= 1<<4, LEDclock= 1<<5, LEDfault= 1<<6, LEDpulse= 1<<7, }; -#define LEDON(x) (m->ledval &= ~x, *LED = m->ledval) -#define LEDOFF(x) (m->ledval |= x, *LED = m->ledval) +#define LEDON(x) (m->ledval &= ~(x), *LED = m->ledval) +#define LEDOFF(x) (m->ledval |= (x), *LED = m->ledval) typedef struct SBCC SBCC; typedef struct Timer Timer;