From ad66597d8a1cfdcfedb0d3d45bbef3a4f91fe623 Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Wed, 5 Feb 1992 00:00:00 +0000 Subject: [PATCH] Plan 9 from Bell Labs 1992-02-05 --- pc/devincon.c | 1103 ++++++++++++++++++++++++++++++++++++++++++++++++ pc/devlpt.c | 2 +- pc/inconsubs.s | 51 +++ port/proc.c | 11 +- port/sturp.c | 37 +- 5 files changed, 1191 insertions(+), 13 deletions(-) create mode 100644 pc/devincon.c create mode 100644 pc/inconsubs.s diff --git a/pc/devincon.c b/pc/devincon.c new file mode 100644 index 0000000000000000000000000000000000000000..e7d8fc8c7dbf0d53e0cca561bb9519a14f71ffd5 --- /dev/null +++ b/pc/devincon.c @@ -0,0 +1,1103 @@ +#include "u.h" +#include "lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "../port/error.h" +#include "devtab.h" + +#include "io.h" + +/* Centronix parallel (printer) port */ + +/* base addresses */ +static int lptbase[] = { + 0x3bc, /* lpt1 */ + 0x378, /* lpt2 (sic) */ + 0x278 /* lpt3 (sic) */ +}; +#define NDEV (sizeof lptbase/sizeof lptbase[0]) + +/* offsets, and bits in the registers */ +enum +{ + /* data latch register */ + Qdlr= 0x0, + /* printer status register */ + Qpsr= 0x1, + Fbusy= 0x80, + Fintbar= 0x40, + /* printer control register */ + Qpcr= 0x2, + Fie= 0x10, + Fsi= 0x08, + Finitbar= 0x04, + Faf= 0x02, + Fstrobe= 0x01, + + /* other `registers' */ + Qstats= 0x03, + Qdebug= 0x04 +}; + +/* + * af si dlr<7:0> + * 0 x xxxxxxxx wr ctl/data char (si is dcto) + * 1 0 xxxxxxxx wr cmd + * 1 1 xxxxxx00 rd ctl/data char + * 1 1 xxxxxx01 rd status + * 1 1 xxxxxx11 nop (multiplexer to normal state) + * + * psr<7:3> multiplexed as follows: + * + * bc7 bc6 bc5 bc4 bc3 + * rd, st- low bsy d8 d7 d6 d5 + * rd, st- high d4 d3 d2 d1 d0 + * other bsy int- + */ + +typedef struct Incon Incon; + +#define NOW (MACHP(0)->ticks*MS2HZ) + +#define DPRINT if(incondebug)kprint + +static void inconintr(Ureg *ur); + +enum { + Minstation= 2, /* lowest station # to poll */ + Maxstation= 15, /* highest station # to poll */ + Nincon= 1, /* number of incons */ + Nin= 32, /* Blocks in the input ring */ + Bsize= 128, /* size of an input ring block */ + Mfifo= 0xff /* a mask, must be 2^n-1, must be > Nin */ +}; + +struct Incon { + QLock; + + QLock xmit; /* transmit lock */ + QLock reslock; /* reset lock */ + int dev; /* base address of port */ + int station; /* station number */ + int state; /* chip state */ + Rendez r; /* output process */ + Rendez kr; /* input kernel process */ + ushort chan; /* current input channel */ + Queue *rq; /* read queue */ + int kstarted; /* true if kernel process started */ + + /* input blocks */ + + Block *inb[Nin]; + ushort wi; + ushort ri; + + /* statistics */ + + ulong overflow; /* overflow errors */ + ulong pack0; /* channel 0 */ + ulong crc; /* crc errors */ + ulong in; /* bytes in */ + ulong out; /* bytes out */ + ulong wait; /* wait time in milliseconds */ +}; + +Incon incon[Nincon]; + +/* + * chip state + */ +enum { + Selecting, + Selected, + Notliving, +}; + +/* + * internal chip registers + */ +#define sel_polln 0 +#define sel_station 1 +#define sel_poll0 2 +#define sel_rcv_cnt 3 +#define sel_rcv_tim 4 +#define sel_tx_cnt 5 + +/* + * CSR bits + */ +#define INCON_RUN 0x80 +#define INCON_STOP 0x00 +#define ENABLE_IRQ 0x40 +#define ENABLE_TX_IRQ 0x20 +#define INCON_ALIVE 0x80 +#define TX_FULL 0x10 +#define TX_EMPTY 0x08 +#define RCV_EMPTY 0x04 +#define OVERFLOW 0x02 +#define CRC_ERROR 0x01 + +/* + * polling constants + */ +#define HT_GNOT 0x30 +#define HT_UNIX 0x31 +#define ST_UNIX 0x04 +#define NCHAN 64 + +static void inconkproc(void*); + +/* + * incon stream module definition + */ +static void inconoput(Queue*, Block*); +static void inconstopen(Queue*, Stream*); +static void inconstclose(Queue*); +Qinfo inconinfo = +{ + nullput, + inconoput, + inconstopen, + inconstclose, + "incon" +}; + +int incondebug = 0; + +Dirtab incondir[]={ + "dlr", {Qdlr}, 1, 0666, + "psr", {Qpsr}, 5, 0444, + "pcr", {Qpcr}, 0, 0666, + "stats", {Qstats}, 0, 0444, + "debug", {Qdebug}, 0, 0666, +}; +#define NINCON (sizeof incondir/sizeof incondir[0]) + +static void +reset(int dev) /* hardware reset */ +{ + outb(dev+Qpcr, Finitbar); + outb(dev+Qpcr, 0); + outb(dev+Qpcr, Finitbar|Fie); +} + +static void +wrctl(int dev, int data) /* write control character */ +{ + outb(dev+Qpcr, Finitbar); /* no interrupts, please */ + outb(dev+Qdlr, data); + outb(dev+Qpcr, Finitbar|Fstrobe); + outb(dev+Qpcr, Finitbar|Fie); +} + +static void +wrdata(int dev, int data) /* write data character */ +{ + outb(dev+Qpcr, Finitbar|Fsi); + outb(dev+Qdlr, data); + outb(dev+Qpcr, Finitbar|Fsi|Fstrobe); + outb(dev+Qpcr, Finitbar|Fsi|Fie); +} + +static void +wrcmd(int dev, int data) /* write command */ +{ + outb(dev+Qpcr, Finitbar|Faf); + outb(dev+Qdlr, data); + outb(dev+Qpcr, Finitbar|Faf|Fstrobe); + outb(dev+Qpcr, Finitbar|Faf|Fie); +} + +static int +rdstatus(Incon *ip) /* read status */ +{ + int dev, data; + + dev = ip->dev; + + outb(dev+Qpcr, Finitbar|Faf|Fsi); + outb(dev+Qdlr, 0x01); + outb(dev+Qpcr, Finitbar|Faf|Fsi|Fstrobe); + data = (inb(dev+Qpsr)&0xf8)<<2; + outb(dev+Qpcr, Finitbar|Faf|Fsi); + data |= inb(dev+Qpsr)>>3; + if(data&(OVERFLOW|CRC_ERROR)){ + if(data&OVERFLOW) + ip->overflow++; + if(data&CRC_ERROR) + ip->crc++; + } + outb(dev+Qdlr, 0x03); + outb(dev+Qpcr, Finitbar|Faf|Fsi|Fstrobe); + outb(dev+Qpcr, Finitbar|Faf|Fsi|Fie); + + return data; +} + +static void +iwrcmd(int dev, int data) /* write command at interrupt level */ +{ + outb(dev+Qdlr, data); + outb(dev+Qpcr, Finitbar|Faf|Fstrobe); + outb(dev+Qpcr, Finitbar|Faf); +} + +static int +irdstatus(Incon *ip) /* read status at interrupt level */ +{ + int dev, data; + + dev = ip->dev; + + outb(dev+Qdlr, 0x01); + outb(dev+Qpcr, Finitbar|Faf|Fsi|Fstrobe); + data = (inb(dev+Qpsr)&0xf8)<<2; + outb(dev+Qpcr, Finitbar|Faf|Fsi); + data |= inb(dev+Qpsr)>>3; + if(data&(OVERFLOW|CRC_ERROR)){ + if(data&OVERFLOW) + ip->overflow++; + if(data&CRC_ERROR) + ip->crc++; + } + + return data; +} + +static int +irddata(int dev) /* read data at interrupt level */ +{ + int data; + + outb(dev+Qdlr, 0x00); + outb(dev+Qpcr, Finitbar|Faf|Fsi|Fstrobe); + data = (inb(dev+Qpsr)&0xf8)<<2; + outb(dev+Qpcr, Finitbar|Faf|Fsi); + data |= inb(dev+Qpsr)>>3; + + return data; +} + +static int +irdnext(int dev) /* read next data at interrupt level */ +{ + int data; + + outb(dev+Qpcr, Finitbar|Faf|Fsi|Fstrobe); + data = (inb(dev+Qpsr)&0xf8)<<2; + outb(dev+Qpcr, Finitbar|Faf|Fsi); + data |= inb(dev+Qpsr)>>3; + + return data; +} + +static void +irdnop(int dev, int pcr) /* read nop (mux reset) */ +{ + outb(dev+Qdlr, 0x03); + outb(dev+Qpcr, Finitbar|Faf|Fsi|Fstrobe); + outb(dev+Qpcr, pcr); +} + +int Irdnext(int); +#define irdnext Irdnext + +/* + * set the incon parameters + */ +void +inconset(Incon *ip, int cnt, int del) +{ + int dev; + + if (cnt<1 || cnt>14 || del<1 || del>15) + error(Ebadarg); + + dev = ip->dev; + wrcmd(dev, sel_rcv_cnt | INCON_RUN); + wrdata(dev, cnt); + wrcmd(dev, sel_rcv_tim | INCON_RUN); + wrdata(dev, del); + wrcmd(dev, INCON_RUN | ENABLE_IRQ); +} + +/* + * parse a set request + */ +void +inconsetctl(Incon *ip, Block *bp) +{ + char *field[3]; + int n; + int del; + int cnt; + + del = 15; + n = getfields((char *)bp->rptr, field, 3, ' '); + switch(n){ + default: + freeb(bp); + error(Ebadarg); + case 2: + del = strtol(field[1], 0, 0); + if(del<0 || del>15){ + freeb(bp); + error(Ebadarg); + } + /* fall through */ + case 1: + cnt = strtol(field[0], 0, 0); + if(cnt<0 || cnt>15){ + freeb(bp); + error(Ebadarg); + } + } + inconset(ip, cnt, del); + freeb(bp); +} + +static void +nop(void) +{ +} + +/* + * poll for a station number + */ +void +inconpoll(Incon *ip, int station) +{ + ulong timer; + int dev; + char *p; + + dev = ip->dev; + + /* + * get us to a known state + */ + ip->state = Notliving; + wrcmd(dev, INCON_STOP); + + /* + * try a station number + */ + wrcmd(dev, sel_station); + wrdata(dev, station); + wrcmd(dev, sel_poll0); + wrdata(dev, HT_GNOT); + wrcmd(dev, sel_rcv_cnt); + wrdata(dev, 3); + wrcmd(dev, sel_rcv_tim); + wrdata(dev, 15); + wrcmd(dev, sel_tx_cnt); + wrdata(dev, 1); + wrcmd(dev, sel_polln); + wrdata(dev, 0x00); + wrdata(dev, ST_UNIX); + wrdata(dev, NCHAN); + for(p = "gnot"; *p; p++) + wrdata(dev, *p); + wrctl(dev, 0); + + /* + * poll and wait for ready (or 1/4 second) + */ + ip->state = Selecting; + wrcmd(dev, INCON_RUN | ENABLE_IRQ); + timer = NOW + 250; + while (NOW < timer) { + nop(); + if(rdstatus(ip) & INCON_ALIVE){ + ip->station = station; + ip->state = Selected; + break; + } + } +} + +/* + * reset the chip and find a new station number + */ +void +inconrestart(Incon *ip) +{ + int i; + + if(!canqlock(&ip->reslock)) + return; + + /* + * poll for incon station numbers + */ + DPRINT("inconrestart\n"); + for(i = Minstation; i <= Maxstation; i++){ + inconpoll(ip, i); + if(ip->state == Selected) + break; + } + switch(ip->state) { + case Selecting: + DPRINT("incon[%d] not polled\n", ip-incon); + print("incon[%d] not polled\n", ip-incon); + break; + case Selected: + DPRINT("incon[%d] station %d\n", ip-incon, ip->station); + print("incon[%d] station %d\n", ip-incon, ip->station); + inconset(ip, 3, 15); + break; + default: + DPRINT("incon[%d] bollixed\n", ip-incon); + print("incon[%d] bollixed\n", ip-incon); + break; + } + qunlock(&ip->reslock); +} + +/* + * reset all incon chips. + */ + +void +inconreset(void) +{ + int i; + + setvec(Parallelvec, inconintr); + /* + * state is Selected if we used incon as the boot device + * i.e. we've already got a station number. + * state is Selecting if this is a first-time open. + */ +/* inconset(&incon[0], 3, 15); /**/ + for(i=0; i= Nincon) + error(Ebadarg); + ip = &incon[i]; + if(ip->state != Selected) + inconrestart(ip); + + c = devattach('i', spec); + c->dev = i; + c->qid.path = CHDIR; + c->qid.vers = 0; + return c; +} + +Chan* +inconclone(Chan *c, Chan *nc) +{ + return devclone(c, nc); +} + +int +inconwalk(Chan *c, char *name) +{ + return devwalk(c, name, incondir, NINCON, streamgen); +} + +void +inconstat(Chan *c, char *dp) +{ + devstat(c, dp, incondir, NINCON, streamgen); +} + +Chan* +inconopen(Chan *c, int omode) +{ + if(c->qid.path != CHDIR && c->qid.path >= Slowqid) + streamopen(c, &inconinfo); + c->mode = openmode(omode); + c->flag |= COPEN; + c->offset = 0; + return c; +} + +void +inconcreate(Chan *c, char *name, int omode, ulong perm) +{ + error(Eperm); +} + +void +inconclose(Chan *c) +{ + if(c->qid.path != CHDIR && c->qid.path >= Slowqid) + streamclose(c); +} + +long +inconread(Chan *c, void *buf, long n, ulong offset) +{ + char b[256]; + Incon *ip; + + if(c->qid.path == CHDIR) + return devdirread(c, buf, n, incondir, NINCON, streamgen); + ip = &incon[c->dev]; + switch(c->qid.path){ + default: + return streamread(c, buf, n); + case Qdlr: + case Qpsr: + case Qpcr: + sprint(b, "0x%2.2ux\n", inb(ip->dev + c->qid.path)); + break; + case Qstats: + sprint(b, "state: %d\nstation: %d\nin: %d\nout: %d\noverflow: %d\ncrc: %d\nwait: %d\n", + ip->state, ip->station, ip->in, ip->out, ip->overflow, ip->crc, ip->wait); + break; + case Qdebug: + sprint(b, "%d\n", incondebug); + break; + } + return stringread(buf, n, b, offset); +} + +long +inconwrite(Chan *c, void *buf, long n, ulong offset) +{ + char b[8]; + Incon *ip; + int data; + + switch(c->qid.path){ + default: + return streamwrite(c, buf, n, 0); + case Qdlr: + case Qpcr: + case Qdebug: + break; + } + if(n > sizeof b-1) + n = sizeof b-1; + memmove(b, buf, n); + b[n] = 0; + data = strtoul(b, 0, 0); + switch(c->qid.path){ + default: + ip = &incon[c->dev]; + outb(ip->dev + c->qid.path, data); + break; + case Qdebug: + incondebug = data; + break; + } + return n; +} + +void +inconremove(Chan *c) +{ + error(Eperm); +} + +void +inconwstat(Chan *c, char *dp) +{ + error(Eperm); +} + +/* + * the stream routines + */ + +/* + * kill off the kernel process + */ +static int +kNotliving(void *arg) +{ + Incon *ip; + + ip = (Incon *)arg; + return ip->kstarted == 0; +} + +static void +inconstclose(Queue * q) +{ + Incon *ip; + + ip = (Incon *)q->ptr; + qlock(ip); + ip->rq = 0; + qunlock(ip); + wakeup(&ip->kr); + sleep(&ip->r, kNotliving, ip); +} + +/* + * create the kernel process for input + * first wait for any old ones to die + */ +static void +inconstopen(Queue *q, Stream *s) +{ + Incon *ip; + char name[32]; + + ip = &incon[s->dev]; + sprint(name, "incon%d", s->dev); + q->ptr = q->other->ptr = ip; + wakeup(&ip->kr); + sleep(&ip->r, kNotliving, ip); + ip->rq = q; + kproc(name, inconkproc, ip); +} + +/* + * free all blocks of a message in `q', `bp' is the first block + * of the message + */ +static void +freemsg(Queue *q, Block *bp) +{ + for(; bp; bp = getq(q)){ + if(bp->flags & S_DELIM){ + freeb(bp); + return; + } + freeb(bp); + } +} + +static void +showpkt(char *str, int chan, int ctl, Block *bp, int i) +{ + int n; + + n = bp->wptr - bp->rptr; + kprint("%s(%d)%uo %d", str, chan, ctl, n); + if(n > 8) + n = 8; + for(; irptr[i]); + kprint("\n"); +} + +/* + * output a block + * + * the first 2 bytes of every message are the channel number, + * low order byte first. the third is a possible trailing control + * character. + */ +void +inconoput(Queue *q, Block *bp) +{ + int dev; + Incon *ip; + ulong end; + int chan; + int ctl; + int n, size; + + ip = (Incon *)q->ptr; + + if(bp->type != M_DATA){ + if(streamparse("inconset", bp)) + inconsetctl(ip, bp); + else + freeb(bp); + return; + } + + /* + * get a whole message before handing bytes to the device + */ + if(!putq(q, bp)) + return; + + /* + * one transmitter at a time + */ + qlock(&ip->xmit); + dev = ip->dev; + + /* + * parse message + */ + bp = getq(q); + if(bp->wptr - bp->rptr < 3){ + freemsg(q, bp); + qunlock(&ip->xmit); + return; + } + chan = bp->rptr[0] | (bp->rptr[1]<<8); + ctl = bp->rptr[2]; + bp->rptr += 3; + if(chan<=0) + print("bad channel %d\n", chan); + + if(incondebug) + showpkt("->", chan, ctl, bp, 0); + + /* + * make sure there's an incon out there + */ + if(!(rdstatus(ip)&INCON_ALIVE) || ip->state==Notliving){ + DPRINT("inconoput: not ready"); + inconrestart(ip); + freemsg(q, bp); + qunlock(&ip->xmit); + return; + } + + /* + * send the 8 bit data + */ + for(;;){ + /* + * spin till there is room + */ + for(n=0, end = NOW+1000; rdstatus(ip) & TX_FULL; n++){ + nop(); /* make sure we don't optimize too much */ + if(NOW > end){ + print("incon output stuck 0\n"); + freemsg(q, bp); + qunlock(&ip->xmit); + return; + } + } + ip->wait = (n + ip->wait)>>1; + + /* + * put in next packet + */ + n = bp->wptr - bp->rptr; + if(n > 16) + n = 16; + size = n; + wrctl(dev, chan); + ip->out += n; + while(n--){ + wrdata(dev, *bp->rptr++); + } + + /* + * get next block + */ + if(bp->rptr >= bp->wptr){ + if(bp->flags & S_DELIM){ + freeb(bp); + break; + } + freeb(bp); + bp = getq(q); + if(bp==0) + break; + } + + /* + * end packet + */ + wrctl(dev, 0); + } + + /* + * send the control byte if there is one + */ + if(ctl){ + if(size >= 16){ + wrctl(dev, 0); + for(end = NOW+1000; rdstatus(ip) & TX_FULL;){ + nop(); /* make sure we don't optimize too much */ + if(NOW > end){ + print("incon output stuck 1\n"); + freemsg(q, bp); + qunlock(&ip->xmit); + return; + } + } + wrctl(dev, chan); + } + if(rdstatus(ip) & TX_FULL) + print("inconfull\n"); + ip->out += 1; + wrctl(dev, ctl); + } + wrctl(dev, 0); + + qunlock(&ip->xmit); + return; +} + +/* + * return true if the raw fifo is non-empty + */ +static int +notempty(void *arg) +{ + Incon *ip; + + ip = (Incon *)arg; + return ip->ri!=ip->wi; +} + +/* + * Read bytes from the raw input circular buffer. + */ +static void +inconkproc(void *arg) +{ + Incon *ip; + Block *bp, *nbp; + int i; + int locked; + + ip = (Incon *)arg; + ip->kstarted = 1; + + /* + * create a number of blocks for input + */ + for(i = 0; i < Nin; i++){ + bp = ip->inb[i] = allocb(Bsize); + bp->wptr += 3; + } + + locked = 0; + if(waserror()){ + if(locked) + qunlock(ip); + ip->kstarted = 0; + wakeup(&ip->r); + return; + } + + for(;;){ + /* + * sleep if input fifo empty + */ + sleep(&ip->kr, notempty, ip); + + /* + * die if the device is closed + */ + USED(locked); + qlock(ip); + locked = 1; + if(ip->rq == 0){ + qunlock(ip); + ip->kstarted = 0; + wakeup(&ip->r); + poperror(); + return; + } + + /* + * send blocks upstream and stage new blocks. if the block is small + * (< 64 bytes) copy into a smaller buffer. + */ + while(ip->ri != ip->wi){ + bp = ip->inb[ip->ri]; + ip->in += BLEN(bp); + PUTNEXT(ip->rq, bp); + bp = ip->inb[ip->ri] = allocb(Bsize); + bp->wptr += 3; + ip->ri = (ip->ri+1)%Nin; + } + USED(locked); + qunlock(ip); + locked = 0; + } +} + +/* + * drop a single packet + */ +static void +droppacket(int dev) +{ + if(irddata(dev) == 0) + return; + while(irdnext(dev)) + ; +} + +/* + * flush the input fifo + */ +static void +flushfifo(Incon *ip) +{ + while(!(irdstatus(ip) & RCV_EMPTY)) + droppacket(ip->dev); +} + +/* + * advance the queue. if we've run out of staged input blocks, + * drop the packet and return 0. otherwise return the next input + * block to fill. + */ +static Block * +nextin(Incon *ip, unsigned int c) +{ + Block *bp; + int next; + + bp = ip->inb[ip->wi]; + bp->base[0] = ip->chan; + bp->base[1] = ip->chan>>8; + bp->base[2] = c; + if(incondebug) + showpkt("<-", ip->chan, c, bp, 3); + + next = (ip->wi+1)%Nin; + if(next == ip->ri){ + bp->wptr = bp->base+3; + return bp; + } + ip->wi = next; + + return ip->inb[ip->wi]; +} + +/* + * read the packets from the device into the staged input blocks. + * we have to do this at interrupt tevel to turn off the interrupts. + */ +static void +rdpackets(Incon *ip) +{ + Block *bp; + unsigned int c; + int dev; + uchar *p; + int first = ip->wi; + + dev = ip->dev; + bp = ip->inb[ip->wi]; + if(bp==0){ + flushfifo(ip); + return; + } + p = bp->wptr; + while(!(irdstatus(ip) & RCV_EMPTY)){ + /* + * get channel number + */ + c = irddata(dev); + if(c == 0){ + droppacket(dev); + continue; + } + if(ip->chan != c){ + if(p - bp->rptr > 3){ + bp->wptr = p; + bp = nextin(ip, 0); + p = bp->wptr; + } + ip->chan = c; + } + + /* + * null byte marks end of packet + */ + while(c = irdnext(dev)){ /* assign = */ + if((c & 0x100) == 0){ + /* + * control byte ends block + */ + bp->wptr = p; + bp = nextin(ip, c); + p = bp->wptr; + }else{ + /* + * data byte, put in local buffer + */ + *p++ = c; + } + } + + /* + * pass a block on if it doesn't have room for one more + * packet. this way we don't have to check per byte. + */ + if(p + 16 > bp->lim){ + bp->wptr = p; + bp = nextin(ip, 0); + p = bp->wptr; + } + } + bp->wptr = p; + if(bp->wptr != bp->base+3) + nextin(ip, 0); + + if(first != ip->wi)/**/ + wakeup(&ip->kr); +} + +/* + * Receive an incon interrupt. One entry point + * for all types of interrupt. Until we figure out + * how to use more than one incon, this routine only + * is for incon[0]. + */ +static void +inconintr(Ureg *ur) +{ + uchar status; + int pcr; + Incon *ip; + + ip = &incon[0]; + pcr = inb(ip->dev+Qpcr); + status = irdstatus(ip); + if(incondebug){ + kprint("pcr=%2.2x status=%2.2x\n", pcr, status); + if(pcr & Fstrobe) + kprint("YIKES!!\n"); + } + if(!(status & RCV_EMPTY)) + rdpackets(ip); + + /* see if it died underneath us */ + if(!(status&INCON_ALIVE)){ + switch(ip->state){ + case Selected: + iwrcmd(ip->dev, INCON_STOP); + DPRINT("Incon died\n"); + print("Incon died\n"); + break; + case Selecting: + DPRINT("rejected\n"); + print("rejected\n"); + break; + default: + iwrcmd(ip->dev, INCON_STOP); + DPRINT("state was %d\n", ip->state); + break; + } + ip->state = Notliving; + } + irdnop(ip->dev, pcr); +} diff --git a/pc/devlpt.c b/pc/devlpt.c index 6b75e0139b8aa72b15f82914efe326658efa5261..d3e28b6f315d9fd1e92922263617c75100717114 100644 --- a/pc/devlpt.c +++ b/pc/devlpt.c @@ -9,7 +9,7 @@ /* Centronix parallel (printer) port */ /* base addresses */ -int lptbase[] = { +static int lptbase[] = { 0x3bc, /* lpt1 */ 0x378, /* lpt2 (sic) */ 0x278 /* lpt3 (sic) */ diff --git a/pc/inconsubs.s b/pc/inconsubs.s new file mode 100644 index 0000000000000000000000000000000000000000..b5337abc2e554af19325f582c5b95052f75fca09 --- /dev/null +++ b/pc/inconsubs.s @@ -0,0 +1,51 @@ +/* Centronix parallel (printer) port */ + +/* base addresses */ + +#define Lpt1 0x3bc +#define Lpt2 0x378 +#define Lpt3 0x278 + +/* offsets, and bits in the registers */ + +#define Qdlr 0x0 /* data latch register */ + +#define Qpsr 0x1 /* printer status register */ +#define Fbusy 0x80 +#define Fintbar 0x40 + +#define Qpcr 0x2 /* printer control register */ +#define Fie 0x10 +#define Fsi 0x08 +#define Finitbar 0x04 +#define Faf 0x02 +#define Fstrobe 0x01 + +/* + * read next data byte + * + * outb(dev+Qpcr, Finitbar|Faf|Fsi|Fstrobe); + * data = (inb(dev+Qpsr)&0xf8)<<2; + * outb(dev+Qpcr, Finitbar|Faf|Fsi); + * data |= inb(dev+Qpsr)>>3; + */ +TEXT Irdnext(SB),$0 + + MOVL dev+0(FP),DX /* points to base address */ + MOVL $(Finitbar|Faf|Fsi|Fstrobe),AX + ADDL $Qpcr,DX /* points to control register */ + OUTB + OUTB /* have to wait, sorry */ + SUBL $1,DX /* points to status register */ + INB + MOVL AX,CX + MOVL $(Finitbar|Faf|Fsi),AX + ADDL $1,DX /* points to control register */ + OUTB + ANDL $0xf8,CX + SHLL $2,CX + SUBL $1,DX /* points to status register */ + INB + SARL $3,AX + ORL CX,AX + RET diff --git a/port/proc.c b/port/proc.c index 10c31795827b607adddf0408479ae22fcded7283..a0c54de2f4cd665fa724b50d6376ea4e0e2299fa 100644 --- a/port/proc.c +++ b/port/proc.c @@ -506,6 +506,7 @@ void pexit(char *exitstr, int freemem) { int n; + long utime, stime; Proc *p, *c; Segment **s, **es, *os; Waitq *wq, *f, *next; @@ -527,8 +528,10 @@ pexit(char *exitstr, int freemem) if(c->kp == 0 && (p = c->parent)) { wq = newwaitq(); wq->w.pid = c->pid; - wq->w.time[TUser] = TK2MS(c->time[TUser]); - wq->w.time[TSys] = TK2MS(c->time[TSys]); + utime = c->time[TUser] + c->time[TCUser]; + stime = c->time[TSys] + c->time[TCSys]; + wq->w.time[TUser] = TK2MS(utime); + wq->w.time[TSys] = TK2MS(stime); wq->w.time[TReal] = TK2MS(MACHP(0)->ticks - c->time[TReal]); if(exitstr && exitstr[0]){ n = sprint(wq->w.msg, "%s %d:", c->text, c->pid); @@ -540,8 +543,8 @@ pexit(char *exitstr, int freemem) /* My parent still alive */ if(p->pid == c->parentpid && p->state != Broken && p->nwait < 128) { p->nchild--; - p->time[TCUser] += c->time[TUser] + c->time[TCUser]; - p->time[TCSys] += c->time[TSys] + c->time[TCSys]; + p->time[TCUser] += utime; + p->time[TCSys] += stime; wq->next = p->waitq; p->waitq = wq; diff --git a/port/sturp.c b/port/sturp.c index 97a95f28d4cb5082b77104726df9e87f43e62143..923bf91f0265c76cb78fdcc9158e1135d1cc722c 100644 --- a/port/sturp.c +++ b/port/sturp.c @@ -169,7 +169,10 @@ urpopen(Queue *q, Stream *s) WR(q)->ptr = 0; exhausted("urp structures"); } - +/* + q->flag |= QDEBUG; + q->other->flag |= QDEBUG; +*/ q->ptr = q->other->ptr = up; q->rp = &urpkr; up->rq = q; @@ -298,16 +301,19 @@ urpciput(Queue *q, Block *bp) case 0: break; case ENQ: + DPRINT("rENQ(c)\n"); urpstat.enqsr++; sendctl(up, up->lastecho); sendctl(up, ACK+up->iseq); break; case CHECK: + DPRINT("rCHECK(c)\n"); sendctl(up, ACK+up->iseq); break; case AINIT: + DPRINT("rAINIT(c)\n"); up->state &= ~INITING; flushinput(up); wakeup(&urpkr); @@ -315,6 +321,7 @@ urpciput(Queue *q, Block *bp) case INIT0: case INIT1: + DPRINT("rINIT%d(c)\n", ctl-INIT0); sendctl(up, AINIT); if(ctl == INIT1) q->put = urpiput; @@ -322,6 +329,7 @@ urpciput(Queue *q, Block *bp) break; case INITREQ: + DPRINT("rINITREQ(c)\n"); initoutput(up, 0); break; @@ -330,6 +338,7 @@ urpciput(Queue *q, Block *bp) case REJ+0: case REJ+1: case REJ+2: case REJ+3: case REJ+4: case REJ+5: case REJ+6: case REJ+7: + DPRINT("rREJ%d(c)\n", ctl-REJ); rcvack(up, ctl); break; @@ -337,11 +346,13 @@ urpciput(Queue *q, Block *bp) case ACK+4: case ACK+5: case ACK+6: case ACK+7: case ECHO+0: case ECHO+1: case ECHO+2: case ECHO+3: case ECHO+4: case ECHO+5: case ECHO+6: case ECHO+7: + DPRINT("%s%d(c)\n", (ctl&ECHO)?"rECHO":"rACK", ctl&7); rcvack(up, ctl); break; case SEQ+0: case SEQ+1: case SEQ+2: case SEQ+3: case SEQ+4: case SEQ+5: case SEQ+6: case SEQ+7: + DPRINT("rSEQ%d(c)\n", ctl-SEQ); qlock(&up->ack); i = ctl & Nmask; if(!QFULL(q->next)) @@ -427,10 +438,12 @@ urpiput(Queue *q, Block *bp) break; case CHECK: + DPRINT("rCHECK\n"); sendctl(up, ACK+up->iseq); break; case AINIT: + DPRINT("rAINIT\n"); up->state &= ~INITING; flushinput(up); wakeup(&urpkr); @@ -438,6 +451,7 @@ urpiput(Queue *q, Block *bp) case INIT0: case INIT1: + DPRINT("rINIT%d\n", ctl-INIT0); sendctl(up, AINIT); if(ctl == INIT0) q->put = urpciput; @@ -445,6 +459,7 @@ urpiput(Queue *q, Block *bp) break; case INITREQ: + DPRINT("rINITREQ\n"); initoutput(up, 0); break; @@ -454,14 +469,14 @@ urpiput(Queue *q, Block *bp) case BOT: case BOTM: case BOTS: - DPRINT("rBOT%d...", ctl-BOT); + DPRINT("rBOT%c...", " MS"[ctl-BOT]); up->trx = 1; up->trbuf[0] = ctl; break; case REJ+0: case REJ+1: case REJ+2: case REJ+3: case REJ+4: case REJ+5: case REJ+6: case REJ+7: - DPRINT("rREJ\n"); + DPRINT("rREJ%d\n", ctl-REJ); rcvack(up, ctl); break; @@ -469,7 +484,7 @@ urpiput(Queue *q, Block *bp) case ACK+4: case ACK+5: case ACK+6: case ACK+7: case ECHO+0: case ECHO+1: case ECHO+2: case ECHO+3: case ECHO+4: case ECHO+5: case ECHO+6: case ECHO+7: - DPRINT("rACK %ux\n", ctl); + DPRINT("%s%d\n", (ctl&ECHO)?"rECHO":"rACK", ctl&7); rcvack(up, ctl); break; @@ -481,6 +496,7 @@ urpiput(Queue *q, Block *bp) */ case SEQ+0: case SEQ+1: case SEQ+2: case SEQ+3: case SEQ+4: case SEQ+5: case SEQ+6: case SEQ+7: + DPRINT("rSEQ%d...", ctl-SEQ); i = ctl & Nmask; if(up->trx != 3){ urpstat.rjtrs++; @@ -499,7 +515,7 @@ urpiput(Queue *q, Block *bp) flushinput(up); break; } - DPRINT("rSEQ%d accept %d\n", i, q->len); + DPRINT("accept %d\n", q->len); /* * send data upstream @@ -622,6 +638,8 @@ output(Urp *up) now = NOW; if(up->state & INITING){ if(now > up->timer){ + q = up->wq; + DPRINT("INITING timer (%d, %d): ", now, up->timer); sendctl(up, INIT1); up->timer = now + MSrexmit; } @@ -667,6 +685,7 @@ output(Urp *up) * if a retransmit time has elapsed since a transmit, * send an ENQ */ + DPRINT("OUTPUT timer (%d, %d): ", NOW, up->timer); up->timer = NOW + MSrexmit; up->state &= ~REJECTING; urpstat.enqsx++; @@ -715,8 +734,8 @@ sendctl(Urp *up, int ctl) bp->rptr = bp->lim-1; *bp->rptr = ctl; bp->flags |= S_DELIM; - PUTNEXT(q, bp); DPRINT("sCTL %ulx\n", ctl); + PUTNEXT(q, bp); } /* @@ -763,6 +782,7 @@ sendack(Urp *up) /* * send the ack */ + { Queue *q = up->wq; DPRINT("sendack: "); } sendctl(up, up->lastecho = ECHO|up->iseq); qunlock(&up->ack); } @@ -810,7 +830,7 @@ sendblock(Urp *up, int bn) m->rptr[2] = n<<8; m->flags |= S_DELIM; PUTNEXT(q, m); - DPRINT("sb %d\n", bn); + DPRINT("sb %d (%d)\n", bn, up->timer); } /* @@ -930,6 +950,7 @@ initoutput(Urp *up, int window) */ up->state |= INITING; up->timer = NOW + MSrexmit; + { Queue *q = up->wq; DPRINT("initoutput (%d): ", up->timer); } sendctl(up, INIT1); } @@ -1021,6 +1042,6 @@ urpfillstats(Chan *c, char *buf, int len) USED(c); sprint(b, "in: %d\nout: %d\nrexmit: %d\nrjtrs: %d\nrjpks: %d\nrjseq: %d\nenqsx: %d\nenqsr: %d\n", urpstat.input, urpstat.output, urpstat.rexmit, urpstat.rjtrs, - urpstat.rjpks, urpstat.rjseq, urpstat.enqsr, urpstat.enqsr); + urpstat.rjpks, urpstat.rjseq, urpstat.enqsx, urpstat.enqsr); strncpy(buf, b, len); }