M boot/aux.c => boot/aux.c +3 -1
@@ 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);
M boot/boot.c => boot/boot.c +2 -1
@@ 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
M gnot/dat.h => gnot/dat.h +2 -0
@@ 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"
A gnot/devhifi.c => gnot/devhifi.c +753 -0
@@ 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; i<NB; i++)
+ if(!hp->inb[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; i<NB; i++)
+ if(hp->inb[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; hp<hifichanN; hp++){
+ if(!(ip = hp->udev)) /* 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);
+}
A gnot/devisdn.c => gnot/devisdn.c +711 -0
@@ 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; i<NB; i++)
+ if (!ip->inb[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; ip<isdndevN; ip++){
+ if (!ip->asr)
+ 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;
+}
A gnot/hifi.h => gnot/hifi.h +106 -0
@@ 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)
+};
A gnot/isdn.h => gnot/isdn.h +137 -0
@@ 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);
A gnot/unite.h => gnot/unite.h +120 -0
@@ 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),
+};
M pc/fns.h => pc/fns.h +0 -1
@@ 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);
M pc/main.c => pc/main.c +1 -1
@@ 278,7 278,7 @@ confinit(void)
conf.nfloppy = 2;
conf.nhard = 1;
conf.dkif = 1;
- confinit1();
+ confinit1(mul);
}
char *mathmsg[] =
M pc/trap.c => pc/trap.c +12 -6
@@ 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);
A port/devconc.c => port/devconc.c +489 -0
@@ 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);
+}
M port/portfns.h => port/portfns.h +2 -0
@@ 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);
M port/proc.c => port/proc.c +7 -1
@@ 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;
}
A port/stlapd.c => port/stlapd.c +768 -0
@@ 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; i<NOBUF && !tEmpty(lp); i++)
+ tsleep(&lp->tr, tEmpty, lp, 2500); /* drain */
+ dl_release(lp); /* DISC to NT */
+ for(i=0; i<NOBUF; i++)
+ if(lp->outb[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; p<bp->wptr; 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();
+}
M port/stream.c => port/stream.c +24 -0
@@ 543,6 543,30 @@ getq(Queue *q)
}
/*
+ * 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
*/
Block *
M power/devhotrod.c => power/devhotrod.c +2 -5
@@ 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 || 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);
}
M power/faultmips.c => power/faultmips.c +2 -0
@@ 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);
M power/io.h => power/io.h +3 -3
@@ 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;