M mpc/clock.c => mpc/clock.c +2 -2
@@ 106,8 106,8 @@ clockintr(Ureg *ur)
putdec(clkreload-v);
m->ticks++;
- if(m->ticks%MS2TK(1000) == 0)
- m->bcsr[4] ^= DisableLamp;
+// if(m->ticks%MS2TK(1000) == 0)
+// m->bcsr[4] ^= DisableLamp;
if(up)
up->pc = ur->pc;
M mpc/cpm.c => mpc/cpm.c +6 -6
@@ 45,7 45,7 @@ cpminit(void)
io = m->iomem;
io->rccr = 0;
io->rmds = 0;
- io->lccr &= ~1; /* disable LCD */
+// io->lccr &= ~1; /* disable LCD */
io->sdcr = 1;
io->pcint = 0; /* disable all port C interrupts */
io->pcso = 0;
@@ 145,7 145,7 @@ scc2claim(int force, ulong enable, void (*stop)(void*), void *arg)
clash = scc2owner.clash & ~enable;
ilock(&scc2owner);
- if(~m->bcsr[1] & clash){
+ if(/* ~m->bcsr[1] & clash */ 0){
if(!force){
iunlock(&scc2owner);
return 0;
@@ 153,12 153,12 @@ scc2claim(int force, ulong enable, void (*stop)(void*), void *arg)
/* notify current owner */
if(scc2owner.stop)
scc2owner.stop(scc2owner.arg);
- m->bcsr[1] |= clash;
+// m->bcsr[1] |= clash;
}
scc2owner.stop = stop;
scc2owner.arg = arg;
scc2owner.active = enable;
- m->bcsr[1] &= ~enable; /* the bits are active low */
+// m->bcsr[1] &= ~enable; /* the bits are active low */
iunlock(&scc2owner);
/* beware: someone else can claim it during the `successful' return */
return 1;
@@ 178,7 178,7 @@ scc2stop(void *a)
cpmop(CloseRxBD, SCC2ID, 0);
delay(1);
scc->gsmrl &= ~(3<<4); /* disable current use */
- m->bcsr[1] |= scc2owner.clash;
+// m->bcsr[1] |= scc2owner.clash;
}
}
@@ 189,7 189,7 @@ void
scc2free(void)
{
ilock(&scc2owner);
- m->bcsr[1] |= scc2owner.active;
+// m->bcsr[1] |= scc2owner.active;
scc2owner.active = 0;
iunlock(&scc2owner);
}
M mpc/dat.h => mpc/dat.h +1 -1
@@ 126,7 126,7 @@ struct Mach
long clockgen; /* clock generator frequency (cycles) */
int cputype;
ulong delayloop;
- ulong* bcsr;
+// ulong* bcsr;
IMM* iomem; /* MPC8xx internal i/o control memory */
ulong fairness; /* for runproc */
M mpc/devrtc.c => mpc/devrtc.c +2 -2
@@ 97,7 97,7 @@ static long
rtcread(Chan *c, void *buf, long n, vlong offset)
{
ulong t;
- char *b;
+// char *b;
if(c->qid.path & CHDIR)
return devdirread(c, buf, n, rtcdir, NRTC, devgen);
@@ 108,7 108,7 @@ rtcread(Chan *c, void *buf, long n, vlong offset)
n = readnum(offset, buf, n, t, 12);
return n;
case Qswitch:
- return readnum(offset, buf, n, (m->bcsr[2]>>19)&0xF, 12);
+ return readnum(offset, buf, n, 0xf/*(m->bcsr[2]>>19)&0xF*/, 12);
}
error(Egreg);
return 0; /* not reached */
A mpc/devuart.c => mpc/devuart.c +1438 -0
@@ 0,0 1,1438 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+#include "../port/error.h"
+
+#include "../port/netif.h"
+
+enum {
+ FADS823 = 1,
+
+ Rbufsize= 512,
+ Nuart= 3, /* max per machine (SMC1, SMC2, SCC2) */
+ CTLS= 's'&037,
+ CTLQ= 'q'&037,
+};
+
+enum {
+ /* status bits in SCC receive buffer descriptors */
+ RxBRK= 1<<7, /* break ended frame (async hdlc) */
+ RxDE= 1<<7, /* DPLL error (hdlc) */
+ RxBOF= 1<<6, /* BOF ended frame (async hdlc) */
+ RxLG= 1<<5, /* frame too large (hdlc) */
+ RxNO= 1<<4, /* bad bit alignment (hdlc) */
+ RxBR= 1<<5, /* break received during frame (uart) */
+ RxFR= 1<<4, /* framing error (uart) */
+ RxPR= 1<<3, /* parity error (uart) */
+ RxAB= 1<<3, /* frame aborted (hdlc, async hdlc) */
+ RxCR= 1<<2, /* bad CRC (hdlc, async hdlc) */
+ RxOV= 1<<1, /* receiver overrun (all) */
+ RxCD= 1<<0, /* CD lost (all) */
+
+ /* hdlc-specific Rx/Tx BDs */
+ TxTC= 1<<10,
+};
+
+/*
+ * SMC in UART mode
+ */
+enum {
+ USESMC2 = 0
+};
+
+typedef struct Uartsmc Uartsmc;
+struct Uartsmc {
+ IOCparam;
+ ushort maxidl;
+ ushort idlc;
+ ushort brkln;
+ ushort brkec;
+ ushort brkcr;
+ ushort rmask;
+};
+
+/*
+ * SCC2 UART parameters
+ */
+enum {
+ USESCC2 = 0,
+
+ /* special mode bits */
+ SccAHDLC = 1<<0,
+ SccHDLC = 1<<1,
+ SccIR = 1<<2,
+ SccPPP = 1<<3,
+};
+
+typedef struct Uartscc Uartscc;
+struct Uartscc {
+ SCCparam;
+ uchar rsvd[8];
+ ushort max_idl;
+ ushort idlc;
+ ushort brkcr;
+ ushort parec;
+ ushort frmec;
+ ushort nosec;
+ ushort brkec;
+ ushort brkln;
+ ushort uaddr1;
+ ushort uaddr2;
+ ushort rtemp;
+ ushort toseq;
+ ushort character[8];
+ ushort rccm;
+ ushort rccrp;
+ ushort rlbc;
+};
+
+typedef struct UartAHDLC UartAHDLC;
+struct UartAHDLC {
+ SCCparam;
+ ulong rsvd1;
+ ulong c_mask;
+ ulong c_pres;
+ ushort bof;
+ ushort eof;
+ ushort esc;
+ ushort rsvd2[2];
+ ushort zero;
+ ushort rsvd3;
+ ushort rfthr;
+ ushort resvd4[2];
+ ulong txctl_tbl;
+ ulong rxctl_tbl;
+ ushort nof;
+ ushort rsvd5;
+};
+
+typedef struct UartHDLC UartHDLC;
+struct UartHDLC {
+ SCCparam;
+ ulong rsvd1;
+ ulong c_mask;
+ ulong c_pres;
+ ushort disfc;
+ ushort crcec;
+ ushort abtsc;
+ ushort nmarc;
+ ushort retrc;
+ ushort mflr;
+ ushort max_cnt;
+ ushort rfthr;
+ ushort rfcnt;
+ ushort hmask;
+ ushort haddr[4];
+ ushort tmp;
+ ushort tmp_mb;
+};
+
+enum {
+ /* SCC events of possible interest here eventually */
+ AB= 1<<9, /* autobaud detected */
+ GRA= 1<<7, /* graceful stop completed */
+ CCR= 1<<3, /* control character detected */
+
+ /* SCC, SMC common interrupt events */
+ BSY= 1<<2, /* receive buffer was busy (overrun) */
+ TXB= 1<<1, /* block sent */
+ RXB= 1<<0, /* block received */
+
+ /* SCC events */
+ TXE = 1<<4, /* transmission error */
+ RXF = 1<<3, /* final block received */
+
+ /* gsmr_l */
+ ENR = 2<<4, /* enable receiver */
+ ENT = 1<<4, /* enable transmitter */
+};
+
+typedef struct Uart Uart;
+struct Uart
+{
+ QLock;
+
+ Uart *elist; /* next enabled interface */
+ char name[NAMELEN];
+
+ int x; /* index: x in SMCx or SCCx */
+ int cpmid; /* eg, SCC1ID, SMC1ID */
+ int opens;
+ uchar bpc; /* bits/char */
+ uchar parity;
+ uchar stopb;
+ uchar setup;
+ uchar enabled;
+ int dev;
+
+ ulong frame; /* framing errors */
+ ulong perror;
+ ulong overrun; /* rcvr overruns */
+ ulong crcerr;
+ ulong interrupts;
+ int baud; /* baud rate */
+
+ /* flow control */
+ int xonoff; /* software flow control on */
+ int blocked;
+ int modem; /* hardware flow control on */
+ int cts; /* ... cts state */
+ int rts; /* ... rts state */
+ Rendez r;
+
+ /* buffers */
+ int (*putc)(Queue*, int);
+ Queue *iq;
+ Queue *oq;
+
+ /* staging areas to avoid some of the per character costs */
+ uchar istage[Rbufsize][2]; /* double buffered */
+ int rdrx; /* last buffer read */
+
+ Lock plock; /* for output variables */
+ Block* outb; /* currently transmitting Block */
+
+ BD* rxb;
+ BD* txb;
+
+ SMC* smc;
+ SCC* scc;
+ IOCparam* param;
+ ushort* brkcr; /* brkcr location in appropriate block */
+ int brgc;
+ int mode;
+ Block* partial;
+ int loopback;
+};
+
+static Uart *uart[Nuart];
+static int nuart;
+
+struct Uartalloc {
+ Lock;
+ Uart *elist; /* list of enabled interfaces */
+} uartalloc;
+
+static void uartintr(Uart*, int);
+static void smcuintr(Ureg*, void*);
+static void sccuintr(Ureg*, void*);
+
+static int sccirq[] = {-1, 0x1E, 0x1D, 0x1C, 0x1B};
+static int sccid[] = {-1, SCC1ID, SCC2ID, SCC3ID, SCC4ID};
+static int sccbase[] = {-1, 0xA00, 0xA20, 0xA40, 0xA60};
+static int sccparam[] = {-1, SCC1P, SCC2P, SCC3P, SCC4P};
+
+static void
+uartsetbuf(Uart *up)
+{
+ IOCparam *p;
+ BD *bd;
+
+ p = up->param;
+ p->rfcr = 0x18;
+ p->tfcr = 0x18;
+ p->mrblr = Rbufsize;
+
+ if((bd = up->rxb) == nil){
+ bd = bdalloc(2);
+ up->rxb = bd;
+ }
+ p->rbase = (ushort)bd;
+ bd->status = BDEmpty|BDInt;
+ bd->length = 0;
+ bd->addr = PADDR(up->istage[0]);
+ bd++;
+ bd->status = BDEmpty|BDInt|BDWrap;
+ bd->length = 0;
+ bd->addr = PADDR(up->istage[1]);
+ dcflush(up->istage, sizeof(up->istage));
+ up->rdrx = 0;
+
+ if((bd = up->txb) == nil){
+ bd = bdalloc(1);
+ up->txb = bd;
+ }
+ p->tbase = (ushort)bd;
+ bd->status = BDWrap|BDInt;
+ bd->length = 0;
+ bd->addr = 0;
+}
+
+static void
+smcsetup(Uart *up)
+{
+ IMM *io;
+ Uartsmc *p;
+ SMC *smc;
+
+ up->brgc = brgalloc();
+ if(up->brgc < 0)
+ error(Eio);
+// m->bcsr[1] &= ~DisableRS232a; /* enable rs232-1 */
+
+ io = ioplock();
+ io->pbpar |= IBIT(23)|IBIT(24)|IBIT(25); /* enable SMC1 TX/RX/SYN */
+ io->pbdir &= ~(IBIT(23)|IBIT(24)|IBIT(25));
+ io->brgc[up->brgc] = baudgen(up->baud, 16) | BaudEnable;
+ io->simode = (io->simode & ~0xF000) | (up->brgc<<12); /* SMC1 to NMSI mode, set Tx/Rx clock */
+ iopunlock();
+
+ up->param = KADDR(SMC1P);
+ uartsetbuf(up);
+
+ cpmop(InitRxTx, SMC1ID, 0);
+
+ /* SMC protocol parameters */
+ p = (Uartsmc*)up->param;
+ up->brkcr = &p->brkcr;
+ p->maxidl = 1;
+ p->brkln = 0;
+ p->brkec = 0;
+ p->brkcr = 1;
+ smc = IOREGS(0xA80, SMC);
+ smc->smce = 0xff; /* clear events */
+ smc->smcm = BSY|RXB|TXB; /* enable all possible interrupts */
+ up->smc = smc;
+ smc->smcmr = ((1+8+1-1)<<11)|(2<<4); /* 8-bit, 1 stop, no parity; UART mode */
+// intrenable(VectorCPIC+4, smcuintr, up, BUSUNKNOWN);
+ smc->smcmr |= 3; /* enable rx/tx */
+}
+
+static void
+smcuintr(Ureg*, void *a)
+{
+ Uart *up;
+ int events;
+
+ up = a;
+ events = up->smc->smce;
+ eieio();
+ up->smc->smce = events;
+ uartintr(up, events&(BSY|RXB|TXB));
+}
+
+static void
+sccustop(void *a)
+{
+ Uart *up;
+
+ up = a;
+ if(up->setup){
+ scc2stop(up->scc);
+ brgfree(up->brgc);
+ up->brgc = -1;
+ up->setup = 0;
+ }
+}
+
+static void
+sccsetup(Uart *up)
+{
+ IMM *io;
+ SCC *scc;
+ ulong bg;
+ int i;
+
+ scc = IOREGS(sccbase[up->x], SCC);
+ if(up->x == 2){ /* BUG: 823FADS-specific */
+ if(scc->gsmrl & (ENT|ENR))
+ scc2stop(scc);
+ scc->gsmrl &= ~(ENT|ENR);
+ scc2claim(1, up->mode&SccIR? DisableIR: DisableRS232b, sccustop, scc);
+ }
+ up->scc = scc;
+ if(up->brgc < 0){
+ up->brgc = brgalloc();
+ if(up->brgc < 0)
+ error(Eio);
+ }
+ bg = baudgen(up->baud, 16) | BaudEnable;
+
+ io = ioplock();
+ io->papar |= SIBIT(12)|SIBIT(13); /* enable TXD2 and RXD2 pins */
+ io->padir &= ~(SIBIT(12)|SIBIT(13));
+ if((up->mode & SccIR) == 0)
+ io->paodr |= SIBIT(12); /* TO DO: is this right? */
+ else
+ io->paodr &= ~(SIBIT(12)|SIBIT(13)); /* TO DO: is this right? */
+
+ io->pbpar &= ~IBIT(18); /* disable RTS2 */
+ io->pbdir &= ~IBIT(18);
+ if((up->mode&SccIR) == 0)
+ io->pcpar |= SIBIT(14); /* RTS2~ */
+ else
+ io->pcpar &= ~SIBIT(14);
+ io->pcpar &= ~(SIBIT(9)|SIBIT(8)); /* CTS2~ and CD2~ */
+ io->pcdir &= ~(SIBIT(14)|SIBIT(9)|SIBIT(8));
+ if(FADS823 || up->mode)
+ io->pcso &= ~(SIBIT(9)|SIBIT(8)); /* 82xFADS: force CTS and CD on */
+ else
+ io->pcso |= SIBIT(9)|SIBIT(8);
+ eieio();
+
+ io->brgc[up->brgc] = bg;
+ iopunlock();
+
+ sccnmsi(2, up->brgc, up->brgc);
+
+ up->param = KADDR(sccparam[up->x]);
+ uartsetbuf(up);
+
+ cpmop(InitRxTx, up->cpmid, 0);
+
+ /* SCC protocol parameters */
+ if((up->mode & (SccAHDLC|SccHDLC)) == 0){
+ Uartscc *sp;
+ sp = (Uartscc*)up->param;
+ sp->max_idl = 1;
+ sp->brkcr = 1;
+ sp->parec = 0;
+ sp->frmec = 0;
+ sp->nosec = 0;
+ sp->brkec = 0;
+ sp->brkln = 0;
+ sp->brkec = 0;
+ sp->uaddr1 = 0;
+ sp->uaddr2 = 0;
+ sp->toseq = 0;
+ for(i=0; i<8; i++)
+ sp->character[i] = 0x8000;
+ sp->rccm = 0xC0FF;
+ up->brkcr = &sp->brkcr;
+ scc->irmode = 0;
+ scc->dsr = ~0;
+ scc->gsmrh = 1<<5; /* 8-bit oriented receive fifo */
+ scc->gsmrl = 0x28004; /* UART mode */
+ }else{
+ UartAHDLC *hp;
+ hp = (UartAHDLC*)up->param;
+ hp->c_mask = 0x0000F0B8;
+ hp->c_pres = 0x0000FFFF;
+ if(up->mode & SccIR){
+ hp->bof = 0xC0;
+ hp->eof = 0xC1;
+ //scc->dsr = 0xC0C0;
+ scc->dsr = 0x7E7E;
+ }else{
+ hp->bof = 0x7E;
+ hp->eof = 0x7E;
+ scc->dsr = 0x7E7E;
+ }
+ hp->esc = 0x7D;
+ hp->zero = 0;
+ if(up->mode & SccHDLC)
+ hp->rfthr = 1;
+ else
+ hp->rfthr = 0; /* receive threshold of 1 doesn't work properly for Async HDLC */
+ hp->txctl_tbl = 0;
+ hp->rxctl_tbl = 0;
+ if(up->mode & SccIR){
+ /* low-speed infrared */
+ hp->nof = 12-1; /* 12 flags */
+ scc->irsip = 0;
+ scc->irmode = (2<<8) | 1;
+// m->bcsr[1] |= DisableIR;
+// microdelay(2);
+// m->bcsr[1] &= ~DisableIR; /* put TFDS6000 xcvr in low-speed mode (see 4.9.2.1 in FADS manual) */
+ if(up->loopback)
+ scc->irmode = (3<<4)|1; /* loopback */
+ }else{
+ scc->irmode = 0;
+ hp->txctl_tbl = ~0;
+ hp->rxctl_tbl = ~0;
+ hp->nof = 1-1; /* one opening flag */
+ }
+ up->brkcr = nil;
+ scc->gsmrh = 1<<5; /* 8-bit oriented receive fifo */
+ if(up->mode & SccHDLC)
+ scc->gsmrl = 0x28000; /* HDLC */
+ else
+ scc->gsmrl = 0x28006; /* async HDLC/IrDA */
+ }
+ scc->scce = ~0; /* clear events */
+ scc->sccm = TXE|BSY|RXF|TXB|RXB; /* enable all interesting interrupts */
+ intrenable(VectorCPIC+sccirq[up->x], sccuintr, up, BUSUNKNOWN);
+ scc->psmr = 3<<12; /* 8-bit, 1 stop, no parity; UART mode */
+ if(up->loopback && (up->mode & SccIR) == 0)
+ scc->gsmrl |= 1<<6; /* internal loop back */
+ scc->gsmrl |= ENT|ENR; /* enable rx/tx */
+ if(0){
+ print("gsmrl=%8.8lux gsmrh=%8.8lux dsr=%4.4ux irmode=%4.4ux\n", scc->gsmrl, scc->gsmrh, scc->dsr, scc->irmode);
+ for(i=0; i<sizeof(Uartscc); i+=4)
+ print("%2.2lux %8.8lux\n", i, *(ulong*)((uchar*)up->param+i));
+ }
+}
+
+static void
+sccuintr(Ureg*, void *a)
+{
+ Uart *up;
+ int events;
+
+ up = a;
+ if(/*(m->bcsr[1] & (DisableRS232b|DisableIR)) == (DisableRS232b|DisableIR) ||*/ up->scc == nil)
+ return;
+ events = up->scc->scce;
+ eieio();
+ up->scc->scce = events;
+ if(up->enabled){
+ if(0)
+ print("#%ux|", events);
+ uartintr(up, events);
+ }
+}
+
+static void
+uartsetbaud(Uart *p, int rate)
+{
+ if(rate <= 0 || p->brgc < 0)
+ return;
+ p->baud = rate;
+ m->iomem->brgc[p->brgc] = baudgen(rate, 16) | BaudEnable;
+}
+
+static void
+uartsetmode(Uart *p)
+{
+ int r, clen;
+
+ ilock(&p->plock);
+ clen = p->bpc;
+ if(p->parity == 'e' || p->parity == 'o')
+ clen++;
+ clen++; /* stop bit */
+ if(p->stopb == 2)
+ clen++;
+ if(p->smc){
+ r = p->smc->smcmr & 0x3F; /* keep mode, enable bits */
+ r |= (clen<<11);
+ if(p->parity == 'e')
+ r |= 3<<8;
+ else if(p->parity == 'o')
+ r |= 2<<8;
+ if(p->stopb == 2)
+ r |= 1<<10;
+ eieio();
+ p->smc->smcmr = r;
+ }else if(p->scc && p->mode == 0){
+ r = p->scc->psmr & 0x8FE0; /* keep mode bits */
+ r |= ((p->bpc-5)&3)<<12;
+ if(p->parity == 'e')
+ r |= (6<<2)|2;
+ else if(p->parity == 'o')
+ r |= (4<<2)|0;
+ if(p->stopb == 2)
+ r |= 1<<14;
+ eieio();
+ p->scc->psmr = r;
+ }
+ iunlock(&p->plock);
+}
+
+static void
+uartparity(Uart *p, char type)
+{
+ ilock(&p->plock);
+ p->parity = type;
+ iunlock(&p->plock);
+ uartsetmode(p);
+}
+
+/*
+ * set bits/character
+ */
+static void
+uartbits(Uart *p, int bits)
+{
+ if(bits < 5 || bits > 14 || bits > 8 && p->scc)
+ error(Ebadarg);
+
+ ilock(&p->plock);
+ p->bpc = bits;
+ iunlock(&p->plock);
+ uartsetmode(p);
+}
+
+
+/*
+ * toggle DTR
+ */
+static void
+uartdtr(Uart *p, int n)
+{
+ if(p->scc == nil)
+ return; /* not possible */
+ USED(n); /* not possible on FADS */
+}
+
+/*
+ * toggle RTS
+ */
+static void
+uartrts(Uart *p, int n)
+{
+ p->rts = n;
+ if(p->scc == nil)
+ return; /* not possible */
+ USED(n); /* not possible on FADS */
+}
+
+/*
+ * send break
+ */
+static void
+uartbreak(Uart *p, int ms)
+{
+ if(p->brkcr == nil)
+ return;
+
+ if(ms <= 0)
+ ms = 200;
+
+ if(waserror()){
+ ilock(&p->plock);
+ *p->brkcr = 1;
+ cpmop(RestartTx, p->cpmid, 0);
+ iunlock(&p->plock);
+ nexterror();
+ }
+ ilock(&p->plock);
+ *p->brkcr = ((p->baud/(p->bpc+2))*ms+500)/1000;
+ cpmop(StopTx, p->cpmid, 0);
+ iunlock(&p->plock);
+
+ tsleep(&up->sleep, return0, 0, ms);
+
+ poperror();
+ ilock(&p->plock);
+ *p->brkcr = 1;
+ cpmop(RestartTx, p->cpmid, 0);
+ iunlock(&p->plock);
+}
+
+/*
+ * modem flow control on/off (rts/cts)
+ */
+static void
+uartmflow(Uart *p, int n)
+{
+ if(p->scc == nil)
+ return; /* not possible */
+ if(n){
+ p->modem = 1;
+ /* enable status interrupts ... */
+ p->scc->psmr |= 1<<15; /* enable async flow control */
+ p->cts = 1;
+ /* could change maxidl */
+ }else{
+ p->modem = 0;
+ /* stop status interrupts ... */
+ p->scc->psmr &= ~(1<<15);
+ p->cts = 1;
+ }
+}
+
+/*
+ * turn on a port's interrupts. set DTR and RTS
+ */
+void
+uartenable(Uart *p)
+{
+ Uart **l;
+
+ if(p->enabled)
+ return;
+
+ if(p->setup == 0){
+ if(p->cpmid == SMC1ID || p->cpmid == SMC2ID)
+ smcsetup(p);
+ else
+ sccsetup(p);
+ p->setup = 1;
+ }
+
+ /*
+ * turn on interrupts
+ */
+ if(p->smc){
+ cpmop(RestartTx, p->cpmid, 0);
+ p->smc->smcmr |= 3;
+ p->smc->smcm = BSY|TXB|RXB;
+ eieio();
+ }else if(p->scc){
+ cpmop(RestartTx, p->cpmid, 0);
+ p->scc->gsmrl |= ENT|ENR;
+ p->scc->sccm = BSY|TXB|RXB;
+ eieio();
+ }
+
+ /*
+ * turn on DTR and RTS
+ */
+ uartdtr(p, 1);
+ uartrts(p, 1);
+
+ /*
+ * assume we can send
+ */
+ p->cts = 1;
+ p->blocked = 0;
+
+ /*
+ * set baud rate to the last used
+ */
+ uartsetbaud(p, p->baud);
+
+ lock(&uartalloc);
+ for(l = &uartalloc.elist; *l; l = &(*l)->elist){
+ if(*l == p)
+ break;
+ }
+ if(*l == 0){
+ p->elist = uartalloc.elist;
+ uartalloc.elist = p;
+ }
+ p->enabled = 1;
+ unlock(&uartalloc);
+ p->cts = 1;
+ p->blocked = 0;
+ p->xonoff = 0;
+ p->enabled = 1;
+}
+
+/*
+ * turn off a port's interrupts. reset DTR and RTS
+ */
+void
+uartdisable(Uart *p)
+{
+ Uart **l;
+
+ /*
+ * turn off interrpts
+ */
+ if(p->smc){
+ cpmop(StopTx, p->cpmid, 0);
+ cpmop(CloseRxBD, p->cpmid, 0);
+ delay(1);
+ p->smc->smcmr &= ~3;
+ eieio();
+ p->smc->smcm = 0;
+ }else if(p->scc){
+ cpmop(GracefulStopTx, p->cpmid, 0);
+ delay(1);
+ cpmop(CloseRxBD, p->cpmid, 0);
+ p->scc->gsmrl &= ~(ENT|ENR);
+ eieio();
+ p->scc->sccm = 0;
+ }
+
+ /*
+ * revert to default settings
+ */
+ p->bpc = 8;
+ p->parity = 0;
+ p->stopb = 0;
+
+ /*
+ * turn off DTR, RTS, hardware flow control & fifo's
+ */
+ uartdtr(p, 0);
+ uartrts(p, 0);
+ uartmflow(p, 0);
+ p->xonoff = p->blocked = 0;
+
+ lock(&uartalloc);
+ for(l = &uartalloc.elist; *l; l = &(*l)->elist){
+ if(*l == p){
+ *l = p->elist;
+ break;
+ }
+ }
+ p->enabled = 0;
+ unlock(&uartalloc);
+}
+
+/*
+ * set the next output buffer going
+ */
+static void
+txstart(Uart *p)
+{
+ Block *b;
+ int n, flags;
+
+ if(!p->cts || p->blocked || p->txb->status & BDReady)
+ return;
+ if((b = p->outb) == nil){
+ if((b = qget(p->oq)) == nil)
+ return;
+ if(p->mode & SccPPP &&
+ p->mode & SccAHDLC &&
+ BLEN(b) >= 8){ /* strip framing data */
+ UartAHDLC *hp;
+ hp = (UartAHDLC*)p->param;
+ if(hp != nil && (p->mode & SccIR) == 0){
+ hp->txctl_tbl = nhgetl(b->rp);
+ hp->rxctl_tbl = nhgetl(b->rp+4);
+ }
+ b->rp += 8;
+ if(0)
+ print("tx #%lux rx #%lux\n", hp->txctl_tbl, hp->rxctl_tbl);
+ }
+ }
+ n = BLEN(b);
+ if(n <= 0)
+ print("txstart: 0\n");
+ if(p->bpc > 8){
+ /* half-word alignment and length if chars are long */
+ if(PADDR(b->rp)&1){ /* must be even if chars are long */
+ memmove(b->base, b->rp, n);
+ b->rp = b->base;
+ b->wp = b->rp+n;
+ }
+ if(n & 1)
+ n++;
+ }
+ dcflush(b->rp, n);
+ p->outb = b;
+ if(n > 0xFFFF)
+ n = 0xFFFE;
+ if(p->mode & SccHDLC)
+ flags = BDLast | TxTC;
+ else if(p->mode)
+ flags = BDLast;
+ else
+ flags = 0;
+ p->txb->addr = PADDR(b->rp);
+ p->txb->length = n;
+ eieio();
+ p->txb->status = (p->txb->status & BDWrap) | flags | BDReady/*|BDInt */;
+ eieio();
+
+ while(p->txb->status & BDReady)
+ flash();
+}
+
+/*
+ * (re)start output
+ */
+static void
+uartkick(Uart *p)
+{
+ ilock(&p->plock);
+ if(p->outb == nil)
+ txstart(p);
+ iunlock(&p->plock);
+}
+
+/*
+ * restart input if its off
+ */
+static void
+uartflow(Uart *p)
+{
+ if(p->modem)
+ uartrts(p, 1);
+}
+
+static void
+uartsetup(int x, int cpmid, char *name)
+{
+ Uart *p;
+
+ if(nuart >= Nuart)
+ return;
+
+ p = xalloc(sizeof(Uart));
+ uart[nuart] = p;
+ strcpy(p->name, name);
+ p->dev = nuart;
+ nuart++;
+ p->x = x;
+ p->cpmid = cpmid;
+ p->brgc = -1;
+ p->mode = 0;
+
+ /*
+ * set rate to 9600 baud.
+ * 8 bits/character.
+ * 1 stop bit.
+ * interrupts enabled.
+ */
+ p->bpc = 8;
+ p->parity = 0;
+ p->baud = 9600;
+
+ p->iq = qopen(4*1024, 0, uartflow, p);
+ p->oq = qopen(4*1024, 0, uartkick, p);
+}
+
+/*
+ * called by main() to configure a duart port as a console or a mouse
+ */
+void
+uartspecial(int port, int baud, Queue **in, Queue **out, int (*putc)(Queue*, int))
+{
+ Uart *p = uart[port];
+
+ uartenable(p);
+ if(baud)
+ uartsetbaud(p, baud);
+ p->putc = putc;
+ if(in)
+ *in = p->iq;
+ if(out)
+ *out = p->oq;
+ p->opens++;
+}
+
+static int
+uartinput(Uart *p, BD *bd)
+{
+ int ch, dokick, i, l;
+ uchar *bp;
+
+ dokick = 0;
+ if(bd->status & RxFR)
+ p->frame++;
+ if(bd->status & RxOV)
+ p->overrun++;
+ l = bd->length;
+ if(bd->status & RxPR){
+ p->perror++;
+ l--; /* it's the last character */
+ }
+ bp = KADDR(bd->addr);
+ if(p->xonoff || p->putc){
+ for(i=0; i<l; i++){
+ ch = bp[i];
+ if(p->xonoff){
+ if(ch == CTLS){
+ p->blocked = 1;
+ cpmop(StopTx, p->cpmid, 0);
+ }else if (ch == CTLQ){
+ p->blocked = 0;
+ dokick = 1;
+ }
+ /* BUG? should discard on/off char? */
+ }
+ if(p->putc)
+ (*p->putc)(p->iq, ch);
+ }
+ }
+ if(p->putc == nil && l > 0)
+ qproduce(p->iq, bp, l);
+ return dokick;
+}
+
+static void
+framedinput(Uart *p, BD *bd)
+{
+ Block *pkt;
+ int l;
+
+ pkt = p->partial;
+ p->partial = nil;
+ if(bd->status & RxOV){
+ p->overrun++;
+ goto Discard;
+ }
+ if(bd->status & (RxAB|RxCR|RxCD|RxLG|RxNO|RxDE|RxBOF|RxBRK)){
+ if(bd->status & RxCR)
+ p->crcerr++;
+ else
+ p->frame++;
+ goto Discard;
+ }
+ if(pkt == nil){
+ pkt = iallocb(1500); /* TO DO: allocate less if possible */
+ if(pkt == nil)
+ return;
+ }
+ l = bd->length;
+ if(bd->status & BDLast)
+ l -= BLEN(pkt); /* last one gives size of entire frame */
+ if(l > 0){
+ if(pkt->wp+l > pkt->lim)
+ goto Discard;
+ memmove(pkt->wp, KADDR(bd->addr), l);
+ pkt->wp += l;
+ }
+ if(0)
+ print("#%ux|", bd->status);
+ if(bd->status & BDLast){
+ if(p->mode & (SccHDLC|SccAHDLC)){
+ if(BLEN(pkt) <= 2){
+ p->frame++;
+ goto Discard;
+ }
+ pkt->wp -= 2; /* strip CRC */
+ }
+ qpass(p->iq, pkt);
+ }else
+ p->partial = pkt;
+ return;
+
+Discard:
+ if(pkt != nil)
+ freeb(pkt);
+}
+
+/*
+ * handle an interrupt to a single uart
+ */
+static void
+uartintr(Uart *p, int events)
+{
+ int dokick;
+ BD *bd;
+ Block *b;
+
+ if(events & BSY)
+ p->overrun++;
+ p->interrupts++;
+ dokick = 0;
+ while(p->rxb != nil && ((bd = &p->rxb[p->rdrx])->status & BDEmpty) == 0){
+ if(p->mode)
+ framedinput(p, bd);
+ else if(uartinput(p, bd))
+ dokick = 1;
+ dcflush(KADDR(bd->addr), bd->length);
+ eieio();
+ bd->status = (bd->status & BDWrap) | BDEmpty|BDInt;
+ p->rdrx ^= 1;
+ }
+ if((bd = p->txb) != nil){
+ if((bd->status & BDReady) == 0){
+ ilock(&p->plock);
+ if((b = p->outb) != nil){
+ b->rp += bd->length;
+ if(b->rp >= b->wp){
+ p->outb = nil;
+ freeb(b);
+ }
+ }
+ txstart(p);
+ iunlock(&p->plock);
+ }
+ }
+ eieio();
+ /* TO DO: modem status isn't available on 82xFADS */
+ if(dokick && p->cts && !p->blocked){
+ if(p->outb == nil){
+ ilock(&p->plock);
+ txstart(p);
+ iunlock(&p->plock);
+ }
+ cpmop(RestartTx, p->cpmid, 0);
+ } else if (events & TXE)
+ cpmop(RestartTx, p->cpmid, 0);
+}
+
+/*
+ * used to ensure uart console output when debugging
+ */
+void
+uartwait(void)
+{
+ Uart *p = uart[0];
+ int s;
+
+ while(p && p->outb){
+ s = splhi();
+ if((p->txb->status & BDReady) == 0){
+ p->blocked = 0;
+ p->cts = 1;
+ if(p->cpmid == SMC1ID || p->cpmid == SMC2ID)
+ smcuintr(nil, p);
+ else
+ sccuintr(nil, p);
+ }
+ splx(s);
+ }
+}
+
+static Dirtab *uartdir;
+static int ndir;
+
+static void
+setlength(int i)
+{
+ Uart *p;
+
+ if(i > 0){
+ p = uart[i];
+ if(p && p->opens && p->iq)
+ uartdir[3*i].length = qlen(p->iq);
+ } else for(i = 0; i < nuart; i++){
+ p = uart[i];
+ if(p && p->opens && p->iq)
+ uartdir[3*i].length = qlen(p->iq);
+ }
+
+}
+
+void
+uartinstall(void)
+{
+ int port;
+ char *p, *q;
+ static int already;
+
+ if(already)
+ return;
+ already = 1;
+ uartsetup(1, SMC1ID, "eia0");
+/*
+ if((p = getconf("console")) || (p = "0")){
+ if(USESMC2)
+ port = strtol(p, &q, 0);
+ else
+ port = 0;
+ if(p != q && (port == 0 || port == 1))
+ uartspecial(port, 9600, &kbdq, &printq, kbdcr2nl);
+ }
+*/
+ uartspecial(0, 19200, &kbdq, &printq, kbdcr2nl);
+
+// if(USESMC2)
+// uartsetup(2, SMC2ID, "eia1");
+// if(USESCC2)
+// uartsetup(2, SCC2ID, "eia2");
+}
+
+/*
+ * all uarts must be uartsetup() by this point or inside of uartinstall()
+ */
+static void
+uartreset(void)
+{
+ int i;
+ Dirtab *dp;
+
+ uartinstall(); /* architecture specific */
+
+ ndir = 4*nuart;
+ uartdir = xalloc(ndir * sizeof(Dirtab));
+ dp = uartdir;
+ for(i = 0; i < nuart; i++){
+ /* 3 directory entries per port */
+ strcpy(dp->name, uart[i]->name);
+ dp->qid.path = NETQID(i, Ndataqid);
+ dp->perm = 0660;
+ dp++;
+ sprint(dp->name, "%sctl", uart[i]->name);
+ dp->qid.path = NETQID(i, Nctlqid);
+ dp->perm = 0660;
+ dp++;
+ sprint(dp->name, "%sstat", uart[i]->name);
+ dp->qid.path = NETQID(i, Nstatqid);
+ dp->perm = 0444;
+ dp++;
+ sprint(dp->name, "%smode", uart[i]->name);
+ dp->qid.path = NETQID(i, Ntypeqid);
+ dp->perm = 0660;
+ dp++;
+ }
+}
+
+static Chan*
+uartattach(char *spec)
+{
+ return devattach('t', spec);
+}
+
+static int
+uartwalk(Chan *c, char *name)
+{
+ return devwalk(c, name, uartdir, ndir, devgen);
+}
+
+static void
+uartstat(Chan *c, char *dp)
+{
+ if(NETTYPE(c->qid.path) == Ndataqid)
+ setlength(NETID(c->qid.path));
+ devstat(c, dp, uartdir, ndir, devgen);
+}
+
+static Chan*
+uartopen(Chan *c, int omode)
+{
+ Uart *p;
+
+ c = devopen(c, omode, uartdir, ndir, devgen);
+
+ switch(NETTYPE(c->qid.path)){
+ case Nctlqid:
+ case Ndataqid:
+ p = uart[NETID(c->qid.path)];
+ qlock(p);
+ if(p->opens++ == 0){
+ uartenable(p);
+ qreopen(p->iq);
+ qreopen(p->oq);
+ }
+ qunlock(p);
+ break;
+ }
+
+ return c;
+}
+
+static void
+uartclose(Chan *c)
+{
+ Uart *p;
+
+ if(c->qid.path & CHDIR)
+ return;
+ if((c->flag & COPEN) == 0)
+ return;
+ switch(NETTYPE(c->qid.path)){
+ case Ndataqid:
+ case Nctlqid:
+ p = uart[NETID(c->qid.path)];
+ qlock(p);
+ if(--(p->opens) == 0){
+ uartdisable(p);
+ qclose(p->iq);
+ qclose(p->oq);
+ }
+ qunlock(p);
+ break;
+ }
+}
+
+static long
+uartstatus(Chan*, Uart *p, void *buf, long n, long offset)
+{
+ IMM *io;
+ char str[256];
+
+ sprint(str, "opens %d ferr %lud oerr %lud crcerr %lud baud %lud perr %lud intr %lud", p->opens,
+ p->frame, p->overrun, p->crcerr, p->baud, p->perror, p->interrupts);
+ /* TO DO: cts, dsr, ring, dcd, dtr, rts aren't all available on 82xFADS */
+ io = m->iomem;
+ if(p->scc){
+ if((io->pcdat & SIBIT(9)) == 0)
+ strcat(str, " cts");
+ if((io->pcdat & SIBIT(8)) == 0)
+ strcat(str, " dcd");
+ if((io->pbdat & IBIT(22)) == 0)
+ strcat(str, " dtr");
+ }else if(p->smc){
+ if((io->pbdat & IBIT(23)) == 0)
+ strcat(str, " dtr");
+ }
+ strcat(str, "\n");
+ return readstr(offset, buf, n, str);
+}
+
+static long
+uartread(Chan *c, void *buf, long n, vlong offset)
+{
+ Uart *p;
+
+ if(c->qid.path & CHDIR){
+ setlength(-1);
+ return devdirread(c, buf, n, uartdir, ndir, devgen);
+ }
+
+ p = uart[NETID(c->qid.path)];
+ switch(NETTYPE(c->qid.path)){
+ case Ndataqid:
+ return qread(p->iq, buf, n);
+ case Nctlqid:
+ return readnum(offset, buf, n, NETID(c->qid.path), NUMSIZE);
+ case Nstatqid:
+ return uartstatus(c, p, buf, n, offset);
+ case Ntypeqid:
+ return readnum(offset, buf, n, p->mode, NUMSIZE);
+ }
+
+ return 0;
+}
+
+static Block*
+uartbread(Chan *c, long n, ulong offset)
+{
+ if(c->qid.path & CHDIR || NETTYPE(c->qid.path) != Ndataqid)
+ return devbread(c, n, offset);
+ return qbread(uart[NETID(c->qid.path)]->iq, n);
+}
+
+static void
+uartctl(Uart *p, char *cmd)
+{
+ int i, n;
+
+ /* let output drain for a while */
+ for(i = 0; i < 16 && qlen(p->oq); i++)
+ tsleep(&p->r, qlen, p->oq, 125);
+
+ if(strncmp(cmd, "break", 5) == 0){
+ uartbreak(p, 0);
+ return;
+ }
+
+ n = atoi(cmd+1);
+ switch(*cmd){
+ case 'B':
+ case 'b':
+ uartsetbaud(p, n);
+ break;
+ case 'D':
+ case 'd':
+ uartdtr(p, n);
+ break;
+ case 'f':
+ case 'F':
+ qflush(p->oq);
+ break;
+ case 'H':
+ case 'h':
+ qhangup(p->iq, 0);
+ qhangup(p->oq, 0);
+ break;
+ case 'L':
+ case 'l':
+ uartbits(p, n);
+ break;
+ case 'm':
+ case 'M':
+ uartmflow(p, n);
+ break;
+ case 'n':
+ case 'N':
+ qnoblock(p->oq, n);
+ break;
+ case 'P':
+ case 'p':
+ uartparity(p, *(cmd+1));
+ break;
+ case 'K':
+ case 'k':
+ uartbreak(p, n);
+ break;
+ case 'R':
+ case 'r':
+ uartrts(p, n);
+ break;
+ case 'Q':
+ case 'q':
+ qsetlimit(p->iq, n);
+ qsetlimit(p->oq, n);
+ break;
+ case 'W':
+ case 'w':
+ /* obsolete */
+ break;
+ case 'X':
+ case 'x':
+ p->xonoff = n;
+ break;
+ case 'Z':
+ case 'z':
+ p->loopback = n;
+ break;
+ }
+}
+
+static long
+uartwrite(Chan *c, void *buf, long n, vlong offset)
+{
+ Uart *p;
+ char cmd[32];
+ int m, inuse;
+
+ USED(offset);
+
+ if(c->qid.path & CHDIR)
+ error(Eperm);
+
+ p = uart[NETID(c->qid.path)];
+
+ switch(NETTYPE(c->qid.path)){
+ case Ndataqid:
+ return qwrite(p->oq, buf, n);
+ case Nctlqid:
+ if(n >= sizeof(cmd))
+ n = sizeof(cmd)-1;
+ memmove(cmd, buf, n);
+ cmd[n] = 0;
+ uartctl(p, cmd);
+ return n;
+ case Ntypeqid:
+ if(p->smc || p->putc)
+ error(Ebadarg);
+ if(n >= sizeof(cmd))
+ n = sizeof(cmd)-1;
+ memmove(cmd, buf, n);
+ cmd[n] = 0;
+ m = strtoul(cmd, nil, 0);
+ inuse = 0;
+ qlock(p);
+ if(p->opens == 0){
+ p->mode = m & 0x7F;
+ p->loopback = (m&0x80)!=0;
+ p->setup = 0;
+ }else
+ inuse = 1;
+ qunlock(p);
+ if(inuse)
+ error(Einuse);
+ return n;
+ }
+}
+
+static long
+uartbwrite(Chan *c, Block *bp, ulong offset)
+{
+ /* TO DO: better */
+ return devbwrite(c, bp, offset);
+}
+
+static void
+uartwstat(Chan *c, char *dp)
+{
+ Dir d;
+ Dirtab *dt;
+
+ if(!iseve())
+ error(Eperm);
+ if(CHDIR & c->qid.path)
+ error(Eperm);
+ if(NETTYPE(c->qid.path) == Nstatqid)
+ error(Eperm);
+
+ dt = &uartdir[3 * NETID(c->qid.path)];
+ convM2D(dp, &d);
+ d.mode &= 0666;
+ dt[0].perm = dt[1].perm = d.mode;
+}
+
+Dev uartdevtab = {
+ 't',
+ "uart",
+
+ uartreset,
+ devinit,
+ uartattach,
+ devclone,
+ uartwalk,
+ uartstat,
+ uartopen,
+ devcreate,
+ uartclose,
+ uartread,
+ uartbread,
+ uartwrite,
+ uartbwrite,
+ devremove,
+ uartwstat,
+};
A mpc/etherscc.c => mpc/etherscc.c +552 -0
@@ 0,0 1,552 @@
+/*
+ * SCCn ethernet
+ */
+
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+#include "../port/error.h"
+#include "../port/netif.h"
+
+#include "etherif.h"
+
+enum {
+ Nrdre = 16, /* receive descriptor ring entries */
+ Ntdre = 16, /* transmit descriptor ring entries */
+
+ Rbsize = ETHERMAXTU+4, /* ring buffer size (+4 for CRC) */
+ Bufsize = (Rbsize+7)&~7, /* aligned */
+};
+
+enum {
+ /* ether-specific Rx BD bits */
+ RxMiss= 1<<8,
+ RxeLG= 1<<5,
+ RxeNO= 1<<4,
+ RxeSH= 1<<3,
+ RxeCR= 1<<2,
+ RxeOV= 1<<1,
+ RxeCL= 1<<0,
+ RxError= (RxeLG|RxeNO|RxeSH|RxeCR|RxeOV|RxeCL), /* various error flags */
+
+ /* ether-specific Tx BD bits */
+ TxPad= 1<<14, /* pad short frames */
+ TxTC= 1<<10, /* transmit CRC */
+ TxeDEF= 1<<9,
+ TxeHB= 1<<8,
+ TxeLC= 1<<7,
+ TxeRL= 1<<6,
+ TxeUN= 1<<1,
+ TxeCSL= 1<<0,
+
+ /* scce */
+ RXB= 1<<0,
+ TXB= 1<<1,
+ BSY= 1<<2,
+ RXF= 1<<3,
+ TXE= 1<<4,
+
+ /* psmr */
+ PRO= 1<<9, /* promiscuous mode */
+
+ /* gsmrl */
+ ENR= 1<<5,
+ ENT= 1<<4,
+};
+
+typedef struct Etherparam Etherparam;
+struct Etherparam {
+ SCCparam;
+ ulong c_pres; /* preset CRC */
+ ulong c_mask; /* constant mask for CRC */
+ ulong crcec; /* CRC error counter */
+ ulong alec; /* alighnment error counter */
+ ulong disfc; /* discard frame counter */
+ ushort pads; /* short frame PAD characters */
+ ushort ret_lim; /* retry limit threshold */
+ ushort ret_cnt; /* retry limit counter */
+ ushort mflr; /* maximum frame length reg */
+ ushort minflr; /* minimum frame length reg */
+ ushort maxd1; /* maximum DMA1 length reg */
+ ushort maxd2; /* maximum DMA2 length reg */
+ ushort maxd; /* rx max DMA */
+ ushort dma_cnt; /* rx dma counter */
+ ushort max_b; /* max bd byte count */
+ ushort gaddr[4]; /* group address filter */
+ ulong tbuf0_data0; /* save area 0 - current frm */
+ ulong tbuf0_data1; /* save area 1 - current frm */
+ ulong tbuf0_rba0;
+ ulong tbuf0_crc;
+ ushort tbuf0_bcnt;
+ ushort paddr[3]; /* physical address LSB to MSB increasing */
+ ushort p_per; /* persistence */
+ ushort rfbd_ptr; /* rx first bd pointer */
+ ushort tfbd_ptr; /* tx first bd pointer */
+ ushort tlbd_ptr; /* tx last bd pointer */
+ ulong tbuf1_data0; /* save area 0 - next frame */
+ ulong tbuf1_data1; /* save area 1 - next frame */
+ ulong tbuf1_rba0;
+ ulong tbuf1_crc;
+ ushort tbuf1_bcnt;
+ ushort tx_len; /* tx frame length counter */
+ ushort iaddr[4]; /* individual address filter*/
+ ushort boff_cnt; /* back-off counter */
+ ushort taddr[3]; /* temp address */
+};
+
+typedef struct {
+ Lock;
+ int sccid;
+ int port;
+ int init;
+ int active;
+ SCC* scc;
+
+ Ring;
+
+ ulong interrupts; /* statistics */
+ ulong deferred;
+ ulong heartbeat;
+ ulong latecoll;
+ ulong retrylim;
+ ulong underrun;
+ ulong overrun;
+ ulong carrierlost;
+ ulong retrycount;
+} Ctlr;
+
+static int sccirq[] = {-1, 0x1E, 0x1D, 0x1C, 0x1B};
+static int sccid[] = {-1, SCC1ID, SCC2ID, SCC3ID, SCC4ID};
+static int sccbase[] = {-1, 0xA00, 0xA20, 0xA40, 0xA60};
+static int sccparam[] = {-1, SCC1P, SCC2P, SCC3P, SCC4P};
+
+static void
+attach(Ether *ether)
+{
+ Ctlr *ctlr;
+
+ ctlr = ether->ctlr;
+ ctlr->active = 1;
+ ctlr->scc->gsmrl |= ENR|ENT;
+ eieio();
+// m->bcsr[1] &= ~DisableEther;
+}
+
+static void
+closed(Ether *ether)
+{
+ Ctlr *ctlr;
+
+ ctlr = ether->ctlr;
+ if(0){
+ if(ether->port == 2)
+ scc2stop(ctlr->scc);
+ ilock(ctlr);
+ ctlr->active = 0;
+ iunlock(ctlr);
+ print("Ether closed\n");
+ }
+}
+
+static void
+promiscuous(void* arg, int on)
+{
+ Ether *ether;
+ Ctlr *ctlr;
+
+ ether = (Ether*)arg;
+ ctlr = ether->ctlr;
+
+ ilock(ctlr);
+ if(on || ether->nmaddr)
+ ctlr->scc->psmr |= PRO;
+ else
+ ctlr->scc->psmr &= ~PRO;
+ iunlock(ctlr);
+}
+
+static void
+multicast(void* arg, uchar *addr, int on)
+{
+ Ether *ether;
+ Ctlr *ctlr;
+
+ USED(addr, on); /* if on, could SetGroupAddress; if !on, it's hard */
+
+ ether = (Ether*)arg;
+ ctlr = ether->ctlr;
+
+ ilock(ctlr);
+ if(ether->prom || ether->nmaddr)
+ ctlr->scc->psmr |= PRO;
+ else
+ ctlr->scc->psmr &= ~PRO;
+ iunlock(ctlr);
+}
+
+static void
+txstart(Ether *ether)
+{
+ int len;
+ Ctlr *ctlr;
+ Block *b;
+ BD *dre;
+
+ ctlr = ether->ctlr;
+ if(ctlr->init)
+ return;
+ while(ctlr->ntq < Ntdre-1){
+ b = qget(ether->oq);
+ if(b == 0)
+ break;
+
+ dre = &ctlr->tdr[ctlr->tdrh];
+ if(dre->status & BDReady)
+ panic("ether: txstart");
+
+ /*
+ * Give ownership of the descriptor to the chip, increment the
+ * software ring descriptor pointer and tell the chip to poll.
+ */
+ len = BLEN(b);
+ dcflush(b->rp, len);
+ if(ctlr->txb[ctlr->tdrh] != nil)
+ panic("scc/ether: txstart");
+ ctlr->txb[ctlr->tdrh] = b;
+ if((ulong)b->rp&1)
+ panic("scc/ether: txstart align"); /* TO DO: ensure alignment */
+ dre->addr = PADDR(b->rp);
+ dre->length = len;
+ eieio();
+ dre->status = (dre->status & BDWrap) | BDReady|TxPad|BDInt|BDLast|TxTC;
+ eieio();
+ ctlr->scc->todr = 1<<15; /* transmit now */
+ eieio();
+ ctlr->ntq++;
+ ctlr->tdrh = NEXT(ctlr->tdrh, Ntdre);
+ }
+}
+
+static void
+transmit(Ether* ether)
+{
+ Ctlr *ctlr;
+
+ ctlr = ether->ctlr;
+ ilock(ctlr);
+ txstart(ether);
+ iunlock(ctlr);
+}
+
+static void
+interrupt(Ureg*, Ether *ether)
+{
+ int len, events, status;
+ Ctlr *ctlr;
+ BD *dre;
+ Block *b;
+
+ ctlr = ether->ctlr;
+ if(!ctlr->active)
+ return; /* not ours */
+
+ /*
+ * Acknowledge all interrupts and whine about those that shouldn't
+ * happen.
+ */
+ events = ctlr->scc->scce;
+ eieio();
+ ctlr->scc->scce = events;
+ eieio();
+ ctlr->interrupts++;
+
+ if(events & (TXE|BSY|RXB)){
+ if(events & RXB)
+ ctlr->overrun++;
+ if(events & TXE)
+ ether->oerrs++;
+ if(0 || events & TXE)
+ print("ETHER.SCC#%d: scce = 0x%uX\n", ether->ctlrno, events);
+ }
+ /*
+ * Receiver interrupt: run round the descriptor ring logging
+ * errors and passing valid receive data up to the higher levels
+ * until we encounter a descriptor still owned by the chip.
+ */
+ if(events & (RXF|RXB) || 1){
+ dre = &ctlr->rdr[ctlr->rdrx];
+ while(((status = dre->status) & BDEmpty) == 0){
+ if(status & RxError || (status & (BDFirst|BDLast)) != (BDFirst|BDLast)){
+ if(status & (RxeLG|RxeSH))
+ ether->buffs++;
+ if(status & RxeNO)
+ ether->frames++;
+ if(status & RxeCR)
+ ether->crcs++;
+ if(status & RxeOV)
+ ether->overflows++;
+ //print("eth rx: %ux\n", status);
+ }
+ else{
+ /*
+ * We have a packet. Read it in.
+ */
+ len = dre->length-4;
+ if((b = iallocb(len)) != 0){
+ memmove(b->wp, KADDR(dre->addr), len);
+ b->wp += len;
+ etheriq(ether, b, 1);
+ dcflush(KADDR(dre->addr), len);
+ }else
+ ether->soverflows++;
+ }
+
+ /*
+ * Finished with this descriptor, reinitialise it,
+ * give it back to the chip, then on to the next...
+ */
+ dre->length = 0;
+ dre->status = (status & BDWrap) | BDEmpty | BDInt;
+ eieio();
+
+ ctlr->rdrx = NEXT(ctlr->rdrx, Nrdre);
+ dre = &ctlr->rdr[ctlr->rdrx];
+ }
+ }
+
+ /*
+ * Transmitter interrupt: handle anything queued for a free descriptor.
+ */
+ if(events & TXB){
+ lock(ctlr);
+ while(ctlr->ntq){
+ dre = &ctlr->tdr[ctlr->tdri];
+ status = dre->status;
+ if(status & BDReady)
+ break;
+ if(status & TxeDEF)
+ ctlr->deferred++;
+ if(status & TxeHB)
+ ctlr->heartbeat++;
+ if(status & TxeLC)
+ ctlr->latecoll++;
+ if(status & TxeRL)
+ ctlr->retrylim++;
+ if(status & TxeUN)
+ ctlr->underrun++;
+ if(status & TxeCSL)
+ ctlr->carrierlost++;
+ ctlr->retrycount += (status>>2)&0xF;
+ b = ctlr->txb[ctlr->tdri];
+ if(b == nil)
+ panic("scce/interrupt: bufp");
+ ctlr->txb[ctlr->tdri] = nil;
+ freeb(b);
+ ctlr->ntq--;
+ ctlr->tdri = NEXT(ctlr->tdri, Ntdre);
+ }
+ txstart(ether);
+ unlock(ctlr);
+ }
+ if(events & TXE)
+ cpmop(RestartTx, ctlr->sccid, 0);
+}
+
+static long
+ifstat(Ether* ether, void* a, long n, ulong offset)
+{
+ char *p;
+ int len;
+ Ctlr *ctlr;
+
+ if(n == 0)
+ return 0;
+
+ ctlr = ether->ctlr;
+
+ p = malloc(READSTR);
+ len = snprint(p, READSTR, "interrupts: %lud\n", ctlr->interrupts);
+ len += snprint(p+len, READSTR-len, "carrierlost: %lud\n", ctlr->carrierlost);
+ len += snprint(p+len, READSTR-len, "heartbeat: %lud\n", ctlr->heartbeat);
+ len += snprint(p+len, READSTR-len, "retrylimit: %lud\n", ctlr->retrylim);
+ len += snprint(p+len, READSTR-len, "retrycount: %lud\n", ctlr->retrycount);
+ len += snprint(p+len, READSTR-len, "latecollisions: %lud\n", ctlr->latecoll);
+ len += snprint(p+len, READSTR-len, "rxoverruns: %lud\n", ctlr->overrun);
+ len += snprint(p+len, READSTR-len, "txunderruns: %lud\n", ctlr->underrun);
+ snprint(p+len, READSTR-len, "framesdeferred: %lud\n", ctlr->deferred);
+ n = readstr(offset, a, n, p);
+ free(p);
+
+ return n;
+}
+
+/*
+ * This follows the MPC823 user guide: section16.9.23.7's initialisation sequence,
+ * except that it sets the right bits for the MPC823ADS board when SCC2 is used,
+ * and those for the 860/821 development board for SCC1.
+ */
+static void
+sccsetup(Ctlr *ctlr, SCC *scc, uchar *ea)
+{
+ int i, rcs, tcs;
+ Etherparam *p;
+ IMM *io;
+
+ io = ioplock();
+ if(ctlr->port == 2){
+ io->papar |= SIBIT(12)|SIBIT(13); /* enable TXD2 and RXD2 pins */
+ io->padir &= ~(SIBIT(12)|SIBIT(13));
+ io->paodr &= ~SIBIT(12);
+
+ io->pcpar &= ~(SIBIT(9)|SIBIT(8)); /* enable CLSN (CTS2) and RENA (CD2) */
+ io->pcdir &= ~(SIBIT(9)|SIBIT(8));
+ io->pcso |= SIBIT(9)|SIBIT(8);
+
+ io->papar |= SIBIT(6)|SIBIT(5); /* enable CLK2 and CLK3 */
+ io->padir &= ~(SIBIT(6)|SIBIT(5));
+ eieio();
+
+ rcs = CLK2;
+ tcs = CLK3;
+ }else{
+ io->papar |= SIBIT(14)|SIBIT(15); /* enable TXD1 and RXD1 pins */
+ io->padir &= ~(SIBIT(14)|SIBIT(15));
+ io->paodr &= ~SIBIT(14);
+
+ io->pcpar &= ~(SIBIT(10)|SIBIT(11)); /* enable CLSN (CTS1) and RENA (CD1) */
+ io->pcdir &= ~(SIBIT(10)|SIBIT(11));
+ io->pcso |= SIBIT(10)|SIBIT(11);
+ eieio();
+
+ io->papar |= SIBIT(6)|SIBIT(7); /* enable CLK2 and CLK1 */
+ io->padir &= ~(SIBIT(6)|SIBIT(7));
+ eieio();
+
+ io->pcpar &= ~(SIBIT(4)|SIBIT(5)|SIBIT(6)); /* ETHLOOP, TPFULDL~, TPSQEL~ */
+ io->pcdir |= SIBIT(4)|SIBIT(5)|SIBIT(6);
+ io->pcdat &= ~SIBIT(4);
+ io->pcdat |= SIBIT(5)|SIBIT(6);
+ eieio();
+
+ rcs = CLK2;
+ tcs = CLK1;
+ }
+ iopunlock();
+
+ sccnmsi(ctlr->port, rcs, tcs); /* connect the clocks */
+
+ p = (Etherparam*)KADDR(ctlr->sccid==SCC1ID? SCC1P: SCC2P);
+ memset(p, 0, sizeof(*p));
+ p->rfcr = 0x18;
+ p->tfcr = 0x18;
+ p->mrblr = Bufsize;
+ p->rbase = PADDR(ctlr->rdr);
+ p->tbase = PADDR(ctlr->tdr);
+
+ cpmop(InitRxTx, ctlr->sccid, 0);
+
+ p->c_pres = ~0;
+ p->c_mask = 0xDEBB20E3;
+ p->crcec = 0;
+ p->alec = 0;
+ p->disfc = 0;
+ p->pads = 0x8888;
+ p->ret_lim = 0xF;
+ p->mflr = Rbsize;
+ p->minflr = ETHERMINTU+4;
+ p->maxd1 = Bufsize;
+ p->maxd2 = Bufsize;
+ p->p_per = 0; /* only moderate aggression */
+
+ for(i=0; i<Eaddrlen; i+=2)
+ p->paddr[2-i/2] = (ea[i+1]<<8)|ea[i]; /* it's not the obvious byte order */
+
+ scc->psmr = (2<<10)|(5<<1); /* 32-bit CRC, ignore 22 bits before SFD */
+ scc->dsr = 0xd555;
+ scc->gsmrh = 0; /* normal operation */
+ scc->gsmrl = (1<<28)|(4<<21)|(1<<19)|0xC; /* transmit clock invert, 48 bit preamble, repetitive 10 preamble, ethernet */
+ eieio();
+ scc->scce = ~0; /* clear all events */
+ eieio();
+ scc->sccm = TXE | RXF | TXB; /* enable interrupts */
+ eieio();
+
+ if(ctlr->sccid == SCC2ID){
+ io->pbpar |= IBIT(18); /* enable TENA pin (RTS2) */
+ io->pbdir |= IBIT(18);
+ }else{
+ io->pbpar |= IBIT(19); /* enable TENA pin (RTS1) */
+ io->pbdir |= IBIT(19);
+ }
+ eieio();
+
+ /* enable is deferred until attach */
+}
+
+static int
+reset(Ether* ether)
+{
+ uchar ea[Eaddrlen];
+ Ctlr *ctlr;
+ SCC *scc;
+
+ if(m->speed < 24){
+ print("%s ether: system speed must be >= 24MHz for ether use\n", ether->type);
+ return -1;
+ }
+
+ if(!(ether->port >= 1 && ether->port <= 4)){
+ print("%s ether: no SCC port %d\n", ether->type, ether->port);
+ return -1;
+ }
+
+ ether->irq = VectorCPIC + sccirq[ether->port];
+ scc = IOREGS(sccbase[ether->port], SCC);
+ if(ether->port == 2)
+ scc2claim(1, DisableEther, scc2stop, scc);
+
+ ctlr = malloc(sizeof(*ctlr));
+ ether->ctlr = ctlr;
+ memset(ctlr, 0, sizeof(*ctlr));
+ ctlr->scc = scc;
+ ctlr->port = ether->port;
+ ctlr->sccid = sccid[ether->port];
+
+ if(ioringinit(ctlr, Nrdre, Ntdre, Bufsize) < 0)
+ panic("etherscc init");
+
+ sccsetup(ctlr, scc, ether->ea);
+
+ ether->mbps = 10; /* TO DO: could be 100mbps on 860T */
+ ether->attach = attach;
+ ether->closed = closed;
+ ether->transmit = transmit;
+ ether->interrupt = interrupt;
+ ether->ifstat = ifstat;
+
+ ether->arg = ether;
+ ether->promiscuous = promiscuous;
+ ether->multicast = multicast;
+
+ /*
+ * Until we know where to find it, insist that the plan9.ini
+ * entry holds the Ethernet address.
+ */
+ memset(ea, 0, Eaddrlen);
+ if(memcmp(ea, ether->ea, Eaddrlen) == 0){
+ print("no ether address");
+ return -1;
+ }
+
+ return 0;
+}
+
+void
+etherscclink(void)
+{
+ addethercard("SCC", reset);
+ addethercard("SCC2", reset);
+}
M mpc/fns.h => mpc/fns.h +2 -0
@@ 89,3 89,5 @@ ulong getcallerpc(void*);
/* compatibility with inf2.1 */
#define bpenumenv(n) ((char*)0)
+
+#define IOREGS(x, T) ((T*)((char*)m->iomem+(x)))
M mpc/l.s => mpc/l.s +2 -11
@@ 122,17 122,15 @@
MOVW R4, SPR(IMMR) /* set internal memory base */
MOVW $mach0(SB), R(MACH)
- ADD $(MACHSIZE-8), R(MACH), R1
+ ADD $(MACHSIZE-8), R(MACH), R1 /* set stack */
SUB $4, R(MACH), R3
ADD $4, R1, R4
+
clrmach:
MOVWU R0, 4(R3)
CMP R3, R4
BNE clrmach
- MOVW R0, R(USER)
- MOVW R0, 0(R(MACH))
-
MOVW $edata(SB), R3
MOVW $end(SB), R4
ADD $4, R4
@@ 630,13 628,6 @@ TEXT powerupled(SB), $0
MOVW R7,0(R11)
RETURN
-TEXT reset(SB), $-4
- MOVW $0,R4
- MOVW 0(R4), R5
-loop:
- BR loop
-
-
GLOBL mach0+0(SB), $MACHSIZE
GLOBL spltbl+0(SB), $4
GLOBL intrtbl+0(SB), $4
M mpc/main.c => mpc/main.c +59 -0
@@ 16,9 16,35 @@ int nconf;
Conf conf;
void
+flash(void)
+{
+ int i;
+ *(uchar*)(NIMMEM+0x2200) = 0;
+ for(i=0; i<1000000; i++)
+ ;
+ *(uchar*)(NIMMEM+0x2200) = 0x2;
+ for(i=0; i<1000000; i++)
+ ;
+}
+
+void
main(void)
{
machinit();
+ confinit();
+ xinit();
+ printinit();
+ cpminit();
+ uartinstall();
+ print("hello world\n");
+
+ delay(100);
+
+ reset();
+
+ *(uchar*)0 = 0;
+ for(;;)
+ ;
}
void
@@ 37,6 63,8 @@ machinit(void)
mf = io->plprcr >> 20;
m->oscclk = osc;
m->speed = osc*(mf+1);
+ m->cpuhz = m->speed*MHz; /* general system clock (cycles) */
+ m->clockgen = osc*MHz; /* clock generator frequency (cycles) */
}
void
@@ 110,6 138,37 @@ iprint(char *fmt, ...)
return n;
}
+void
+confinit(void)
+{
+ int nbytes;
+ ulong pa;
+
+ conf.nmach = 1; /* processors */
+ conf.nproc = 200; /* processes */
+
+ // hard wire for now
+ pa = 0xff200000; // leave 2 Meg for kernel
+ nbytes = 10*1024*1024; // leave room at the top as well
+
+ conf.npage0 = nbytes/BY2PG;
+ conf.base0 = pa;
+
+ conf.npage1 = 0;
+ conf.base1 = 0;
+
+ conf.npage = conf.npage0 + conf.npage1;
+
+ conf.upages = (conf.npage*50)/100;
+ conf.ialloc = ((conf.npage-conf.upages)/2)*BY2PG;
+
+ /* set up other configuration parameters */
+ conf.nswap = conf.npage*3;
+ conf.nswppo = 4096;
+ conf.nimage = 200;
+
+ conf.copymode = 0; /* copy on write */
+}
int
isaconfig(char *class, int ctlrno, ISAConf *isa)
M mpc/mem.h => mpc/mem.h +5 -0
@@ 18,6 18,8 @@
#define CACHELINELOG 4
#define CACHELINESZ (1<<CACHELINELOG)
+#define MHz 1000000
+
#define MAXMACH 1 /* max # cpus system can run */
#define MACHSIZE BY2PG
#define KSTACK 4096 /* Size of kernel stack */
@@ 146,8 148,11 @@
#define SCC2P (INTMEM+0x3D00)
#define SPIP (INTMEM+0x3D80)
#define TIMERP (INTMEM+0x3DB0)
+#define IDMA2P (INTMEM+0x3DC0)
+#define SCC3P (INTMEM+0x3E00)
#define SMC1P (INTMEM+0x3E80)
#define DSP1P (INTMEM+0x3EC0)
+#define SCC4P (INTMEM+0x3F00)
#define SMC2P (INTMEM+0x3F80)
#define DSP2P (INTMEM+0x3FC0)
M mpc/trap.c => mpc/trap.c +13 -0
@@ 131,3 131,16 @@ intrenable(int v, void (*r)(Ureg*, void*), void *arg, int)
{
USED(v, r, arg);
}
+
+void
+reset(void)
+{
+ IMM *io;
+
+ io = m->iomem;
+ io->plprcrk = KEEP_ALIVE_KEY; // unlock
+ io->plprcr |= IBIT(24); // enable checkstop reset
+ putmsr(getmsr() & ~MSR_ME);
+ // cause checkstop -> causes reset
+ *(ulong*)(0) = 0;
+}
M port/chan.c => port/chan.c +2 -2
@@ 688,7 688,7 @@ namec(char *name, int amode, int omode, ulong perm)
if(omode == OEXEC)
c->flag &= ~CCACHE;
- c = devtab[c->type]->open(c, omode);
+ c = devtab[c->type]->open(c, omode&~OCEXEC);
if(omode & OCEXEC)
c->flag |= CCEXEC;
@@ 749,7 749,7 @@ namec(char *name, int amode, int omode, ulong perm)
omode |= OTRUNC;
goto Open;
}
- devtab[c->type]->create(c, elem, omode, perm);
+ devtab[c->type]->create(c, elem, omode&~OCEXEC, perm);
if(omode & OCEXEC)
c->flag |= CCEXEC;
if(omode & ORCLOSE)
M port/dev.c => port/dev.c +2 -2
@@ 159,7 159,7 @@ devstat(Chan *c, char *db, Dirtab *tab, int ntab, Devgen *gen)
case 0:
break;
case 1:
- if(eqqid(c->qid, dir.qid)) {
+ if(c->qid.path == dir.qid.path) {
if(c->flag&CMSG)
dir.mode |= CHMOUNT;
convD2M(&dir, db);
@@ 211,7 211,7 @@ devopen(Chan *c, int omode, Dirtab *tab, int ntab, Devgen *gen)
case 0:
break;
case 1:
- if(eqqid(c->qid, dir.qid)) {
+ if(c->qid.path == dir.qid.path) {
if(strcmp(up->user, dir.uid) == 0)
mode = dir.mode;
else
M port/devenv.c => port/devenv.c +37 -23
@@ 28,11 28,21 @@ envgen(Chan *c, Dirtab*, int, int s, Dir *dp)
return -1;
}
- devdir(c, (Qid){e->path, 0}, e->name, e->len, eve, 0666, dp);
+ devdir(c, e->qid, e->name, e->len, eve, 0666, dp);
qunlock(eg);
return 1;
}
+static Evalue*
+envlookup(Egrp *eg, char *name, ulong qidpath)
+{
+ Evalue *e;
+ for(e = eg->entries; e; e = e->link)
+ if(e->qid.path == qidpath || (name && strcmp(e->name, name) == 0))
+ return e;
+ return nil;
+}
+
static Chan*
envattach(char *spec)
{
@@ 48,6 58,8 @@ envwalk(Chan *c, char *name)
static void
envstat(Chan *c, char *db)
{
+ if(c->qid.path & CHDIR)
+ c->qid.vers = up->egrp->vers;
devstat(c, db, 0, 0, envgen);
}
@@ 64,15 76,13 @@ envopen(Chan *c, int omode)
}
else {
qlock(eg);
- for(e = eg->entries; e; e = e->link)
- if(e->path == c->qid.path)
- break;
-
+ e = envlookup(eg, nil, c->qid.path);
if(e == 0) {
qunlock(eg);
error(Enonexist);
}
- if(omode == (OWRITE|OTRUNC) && e->value) {
+ if((omode & OTRUNC) && e->value) {
+ e->qid.vers++;
free(e->value);
e->value = 0;
e->len = 0;
@@ 103,18 113,19 @@ envcreate(Chan *c, char *name, int omode, ulong)
nexterror();
}
- for(e = eg->entries; e; e = e->link)
- if(strcmp(e->name, name) == 0)
- error(Einuse);
+ if(envlookup(eg, name, -1))
+ error(Eexist);
e = smalloc(sizeof(Evalue));
e->name = smalloc(strlen(name)+1);
strcpy(e->name, name);
- e->path = ++eg->path;
+ e->qid.path = ++eg->path;
+ e->qid.vers = 0;
+ eg->vers++;
e->link = eg->entries;
eg->entries = e;
- c->qid = (Qid){e->path, 0};
+ c->qid = e->qid;
qunlock(eg);
poperror();
@@ 135,10 146,9 @@ envremove(Chan *c)
eg = up->egrp;
qlock(eg);
-
l = &eg->entries;
for(e = *l; e; e = e->link) {
- if(e->path == c->qid.path)
+ if(e->qid.path == c->qid.path)
break;
l = &e->link;
}
@@ 149,6 159,7 @@ envremove(Chan *c)
}
*l = e->link;
+ eg->vers++;
qunlock(eg);
free(e->name);
if(e->value)
@@ 157,8 168,15 @@ envremove(Chan *c)
}
static void
-envclose(Chan*)
+envclose(Chan *c)
{
+ /*
+ * close can't fail, so errors from remove will be ignored anyway.
+ * since permissions aren't checked,
+ * envremove can't not remove it if its there.
+ */
+ if(c->flag & CRCLOSE)
+ envremove(c);
}
static long
@@ 173,10 191,7 @@ envread(Chan *c, void *a, long n, vlong off)
eg = up->egrp;
qlock(eg);
- for(e = eg->entries; e; e = e->link)
- if(e->path == c->qid.path)
- break;
-
+ e = envlookup(eg, nil, c->qid.path);
if(e == 0) {
qunlock(eg);
error(Enonexist);
@@ 210,10 225,7 @@ envwrite(Chan *c, void *a, long n, vlong off)
eg = up->egrp;
qlock(eg);
- for(e = eg->entries; e; e = e->link)
- if(e->path == c->qid.path)
- break;
-
+ e = envlookup(eg, nil, c->qid.path);
if(e == 0) {
qunlock(eg);
error(Enonexist);
@@ 228,6 240,8 @@ envwrite(Chan *c, void *a, long n, vlong off)
e->len = vend;
}
memmove(e->value+offset, a, n);
+ e->qid.vers++;
+ eg->vers++;
qunlock(eg);
return n;
}
@@ 269,7 283,7 @@ envcpy(Egrp *to, Egrp *from)
memmove(ne->value, e->value, e->len);
ne->len = e->len;
}
- ne->path = ++to->path;
+ ne->qid.path = ++to->path;
*l = ne;
l = &ne->link;
}
M port/devsrv.c => port/devsrv.c +40 -20
@@ 63,12 63,24 @@ srvstat(Chan *c, char *db)
devstat(c, db, 0, 0, srvgen);
}
+static Srv*
+srvlookup(char *name, ulong qidpath)
+{
+ Srv *sp;
+ for(sp = srv; sp; sp = sp->link)
+ if(sp->path == qidpath || (name && strcmp(sp->name, name) == 0))
+ return sp;
+ return nil;
+}
+
static Chan*
srvopen(Chan *c, int omode)
{
Srv *sp;
if(c->qid.path == CHDIR){
+ if(omode & ORCLOSE)
+ error(Eperm);
if(omode != OREAD)
error(Eisdir);
c->mode = omode;
@@ 82,16 94,13 @@ srvopen(Chan *c, int omode)
nexterror();
}
- for(sp = srv; sp; sp = sp->link)
- if(sp->path == c->qid.path)
- break;
-
+ sp = srvlookup(nil, c->qid.path);
if(sp == 0 || sp->chan == 0)
error(Eshutdown);
if(omode&OTRUNC)
error(Eperm);
- if(omode!=sp->chan->mode && sp->chan->mode!=ORDWR)
+ if(openmode(omode)!=sp->chan->mode && sp->chan->mode!=ORDWR)
error(Eperm);
cclose(c);
@@ 106,9 115,12 @@ srvcreate(Chan *c, char *name, int omode, ulong perm)
{
Srv *sp;
- if(omode != OWRITE)
+ if(openmode(omode) != OWRITE)
error(Eperm);
+ if(omode & OCEXEC) /* can't happen */
+ panic("someone broke namec");
+
sp = malloc(sizeof(Srv));
if(sp == 0)
error(Enomem);
@@ 118,6 130,9 @@ srvcreate(Chan *c, char *name, int omode, ulong perm)
qunlock(&srvlk);
nexterror();
}
+ if(srvlookup(name, -1))
+ error(Eexist);
+
sp->path = qidpath++;
sp->link = srv;
c->qid.path = sp->path;
@@ 174,9 189,7 @@ srvwstat(Chan *c, char *dp)
Dir d;
Srv *sp;
- if(!iseve())
- error(Eperm);
- if(CHDIR & c->qid.path)
+ if(c->qid.path & CHDIR)
error(Eperm);
qlock(&srvlk);
@@ 185,11 198,13 @@ srvwstat(Chan *c, char *dp)
nexterror();
}
- for(sp = srv; sp; sp = sp->link)
- if(sp->path == c->qid.path)
- break;
- if(sp == 0 || sp->chan == 0)
- error(Eshutdown);
+ sp = srvlookup(nil, c->qid.path);
+ if(sp == 0)
+ error(Enonexist);
+
+ if(strcmp(sp->owner, up->user) && !iseve())
+ error(Eperm);
+
convM2D(dp, &d);
d.mode &= 0777;
sp->perm = d.mode;
@@ 199,8 214,16 @@ srvwstat(Chan *c, char *dp)
}
static void
-srvclose(Chan*)
+srvclose(Chan *c)
{
+ /*
+ * errors from srvremove will be caught by cclose and ignored.
+ * in theory we need to override any changes in removability
+ * since open, but since all that's checked is the owner,
+ * which is immutable, all is well.
+ */
+ if(c->flag & CRCLOSE)
+ srvremove(c);
}
static long
@@ 232,15 255,12 @@ srvwrite(Chan *c, void *va, long n, vlong)
cclose(c1);
nexterror();
}
- for(sp = srv; sp; sp = sp->link)
- if(sp->path == c->qid.path)
- break;
-
+ sp = srvlookup(nil, c->qid.path);
if(sp == 0)
error(Enonexist);
if(sp->chan)
- panic("srvwrite");
+ error(Ebadusefd);
sp->chan = c1;
qunlock(&srvlk);
M port/error.h => port/error.h +1 -0
@@ 6,6 6,7 @@ extern char Emountrpc[]; /* mount rpc error */
extern char Eshutdown[]; /* mounted device shut down */
extern char Enocreate[]; /* mounted directory forbids creation */
extern char Enonexist[]; /* file does not exist */
+extern char Eexist[]; /* file already exists */
extern char Ebadsharp[]; /* unknown device in # filename */
extern char Enotdir[]; /* not a directory */
extern char Eisdir[]; /* file is a directory */
M port/portdat.h => port/portdat.h +3 -2
@@ 422,7 422,8 @@ struct Egrp
Ref;
QLock;
Evalue *entries;
- ulong path;
+ ulong path; /* qid.path of next Evalue to be allocated */
+ ulong vers; /* of Egrp */
};
struct Evalue
@@ 430,8 431,8 @@ struct Evalue
char *name;
char *value;
int len;
- ulong path;
Evalue *link;
+ Qid qid;
};
struct Fgrp
M port/portfns.h => port/portfns.h +0 -3
@@ 258,9 258,6 @@ long rtctime(void);
void runlock(RWlock*);
Proc* runproc(void);
void savefpregs(FPsave*);
-void sccclock(void);
-int sccintr(void);
-void sccsetup(void*, ulong, int);
void sched(void);
void scheddump(void);
void schedinit(void);
M port/sysfile.c => port/sysfile.c +0 -2
@@ 96,8 96,6 @@ fdtochan(int fd, int mode, int chkmnt, int iref)
int
openmode(ulong o)
{
- if(o >= (OTRUNC|OCEXEC|ORCLOSE|OEXEC))
- error(Ebadarg);
o &= ~(OTRUNC|OCEXEC|ORCLOSE);
if(o > OEXEC)
error(Ebadarg);