summaryrefslogtreecommitdiff
path: root/os/mpc/devuart.c
diff options
context:
space:
mode:
Diffstat (limited to 'os/mpc/devuart.c')
-rw-r--r--os/mpc/devuart.c1450
1 files changed, 0 insertions, 1450 deletions
diff --git a/os/mpc/devuart.c b/os/mpc/devuart.c
deleted file mode 100644
index 13adf351..00000000
--- a/os/mpc/devuart.c
+++ /dev/null
@@ -1,1450 +0,0 @@
-#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 {
- Nbuf= 2, /* double buffered */
- Rbufsize= 512,
- Bufsize= (Rbufsize+CACHELINESZ-1)&~(CACHELINESZ-1),
- Nuart= 2+4, /* max in any 8xx architecture (2xSMC, 4xSCC) */
- 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
- */
-
-typedef struct Uartsmc Uartsmc;
-struct Uartsmc {
- IOCparam;
- ushort maxidl;
- ushort idlc;
- ushort brkln;
- ushort brkec;
- ushort brkcr;
- ushort rmask;
-};
-
-/*
- * SCC2 UART parameters
- */
-enum {
- /* 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 = 1<<5, /* enable receiver */
- ENT = 1<<4, /* enable transmitter */
-
- /* port A */
- RXD1= SIBIT(15),
- TXD1= SIBIT(14),
-
- /* port B */
- RTS1B= IBIT(19),
-
- /* port C */
- RTS1C= SIBIT(15),
- CTS1= SIBIT(11),
- CD1= SIBIT(10),
-};
-
-typedef struct Uart Uart;
-struct Uart
-{
- QLock;
-
- Uart *elist; /* next enabled interface */
- char name[KNAMELEN];
-
- int x; /* index: x in SMCx or SCCx */
- int cpmid; /* eg, SCC1ID, SMC1ID */
- CPMdev* cpm;
- 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 */
- /* TO DO: should probably use usual Ring */
- Block* istage[Nbuf]; /* 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 void
-uartsetbuf(Uart *up)
-{
- IOCparam *p;
- BD *bd;
- int i;
- Block *bp;
-
- p = up->param;
- p->rfcr = 0x18;
- p->tfcr = 0x18;
- p->mrblr = Rbufsize;
-
- if((bd = up->rxb) == nil){
- bd = bdalloc(Nbuf);
- up->rxb = bd;
- }
- p->rbase = (ushort)bd;
- for(i=0; i<Nbuf; i++){
- bd->status = BDEmpty|BDInt;
- bd->length = 0;
- if((bp = up->istage[i]) == nil)
- up->istage[i] = bp = allocb(Bufsize);
- bd->addr = PADDR(bp->wp);
- dcflush(bp->wp, Bufsize);
- bd++;
- }
- (bd-1)->status |= BDWrap;
- 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;
- ulong txrx;
-
- archdisableuart(up->cpmid);
- up->brgc = brgalloc();
- if(up->brgc < 0)
- error(Eio);
- m->iomem->brgc[up->brgc] = baudgen(up->baud, 16) | BaudEnable;
- smcnmsi(up->x, up->brgc);
-
- archenableuart(up->cpmid, 0);
-
- if(up->x == 1)
- txrx = IBIT(24)|IBIT(25); /* SMC1 RX/TX */
- else
- txrx = IBIT(20)|IBIT(21); /* SMC2 */
- io = ioplock();
- io->pbpar |= txrx;
- io->pbdir &= ~txrx;
- iopunlock();
-
- up->param = up->cpm->param;
- uartsetbuf(up);
-
- cpmop(up->cpm, InitRxTx, 0);
-
- /* SMC protocol parameters */
- p = (Uartsmc*)up->param;
- up->brkcr = &p->brkcr;
- p->maxidl = 1; /* non-zero so buffer closes when idle before mrblr reached */
- p->brkln = 0;
- p->brkec = 0;
- p->brkcr = 1;
- smc = up->cpm->regs;
- 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+up->cpm->irq, smcuintr, up, BUSUNKNOWN, up->name);
- /* enable when device opened */
-}
-
-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));
-}
-
-/*
- * set the IO ports to enable the control signals for SCCx
- */
-static void
-sccuartpins(int x, int mode)
-{
- IMM *io;
- int i, w;
-
- x--;
- io = ioplock();
- i = 2*x;
- w = (TXD1|RXD1)<<i; /* TXDn and RXDn in port A */
- io->papar |= w; /* enable TXDn and RXDn pins */
- io->padir &= ~w;
- if((mode & SccIR) == 0)
- io->paodr |= TXD1<<i;
- else
- io->paodr &= ~w; /* not open drain */
-
- w = (CD1|CTS1)<<i; /* CDn and CTSn in port C */
- io->pcpar &= ~w;
- io->pcdir &= ~w;
- if(conf.nocts2 || mode)
- io->pcso &= ~w; /* force CTS and CD on */
- else
- io->pcso |= w;
-
- w = RTS1B<<x;
- io->pbpar &= ~w;
- io->pbdir &= ~w;
-
- w = RTS1C<<x; /* RTSn~ */
- if((mode & SccIR) == 0)
- io->pcpar |= w;
- else
- io->pcpar &= ~w; /* don't use for IR */
- iopunlock();
-}
-
-static void
-sccsetup(Uart *up)
-{
- SCC *scc;
- int i;
-
- scc = up->cpm->regs;
- up->scc = scc;
- up->param = up->cpm->param;
- sccxstop(up->cpm);
- archdisableuart(up->cpmid);
- if(up->brgc < 0){
- up->brgc = brgalloc();
- if(up->brgc < 0)
- error(Eio);
- }
- m->iomem->brgc[up->brgc] = baudgen(up->baud, 16) | BaudEnable;
- sccnmsi(up->x, up->brgc, up->brgc);
- sccuartpins(up->x, up->mode);
-
- uartsetbuf(up);
-
- cpmop(up->cpm, InitRxTx, 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;
- archsetirxcvr(0);
- 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 */
- }
- archenableuart(up->cpmid, (up->mode&SccIR)!=0);
- scc->scce = ~0; /* clear events */
- scc->sccm = TXE|BSY|RXF|TXB|RXB; /* enable all interesting interrupts */
- intrenable(VectorCPIC+up->cpm->irq, sccuintr, up, BUSUNKNOWN, up->name);
- 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.2ux %8.8lux\n", i, *(ulong*)((uchar*)up->param+i));
- }
-}
-
-static void
-sccuintr(Ureg*, void *a)
-{
- Uart *up;
- int events;
-
- up = a;
- if(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(p->cpm, RestartTx, 0);
- iunlock(&p->plock);
- nexterror();
- }
- ilock(&p->plock);
- *p->brkcr = ((p->baud/(p->bpc+2))*ms+500)/1000;
- cpmop(p->cpm, StopTx, 0);
- iunlock(&p->plock);
-
- tsleep(&up->sleep, return0, 0, ms);
-
- poperror();
- ilock(&p->plock);
- *p->brkcr = 1;
- cpmop(p->cpm, RestartTx, 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 == CPsmc1 || p->cpmid == CPsmc2)
- smcsetup(p);
- else
- sccsetup(p);
- p->setup = 1;
- }
-
- /*
- * turn on interrupts
- */
- if(p->smc){
- cpmop(p->cpm, RestartTx, 0);
- p->smc->smcmr |= 3;
- p->smc->smcm = BSY|TXB|RXB;
- eieio();
- }else if(p->scc){
- cpmop(p->cpm, RestartTx, 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)
- smcxstop(p->cpm);
- else if(p->scc)
- sccxstop(p->cpm);
-
- /*
- * 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();
-}
-
-/*
- * (re)start output
- */
-static void
-uartkick(void *v)
-{
- Uart *p;
-
- p = v;
- ilock(&p->plock);
- if(p->outb == nil)
- txstart(p);
- iunlock(&p->plock);
-}
-
-/*
- * restart input if it's off
- */
-static void
-uartflow(void *v)
-{
- Uart *p;
-
- p = v;
- if(p->modem)
- uartrts(p, 1);
-}
-
-static void
-uartsetup(int x, int lid, 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 = lid;
- p->cpm = cpmdev(lid);
- 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, Qcoalesce, 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;
-
- if(port < 0 || port >= nuart || (p = uart[port]) == nil)
- return; /* specified port not implemented */
- 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 && p->opens==1){
- for(i=0; i<l; i++){
- ch = bp[i];
- if(p->xonoff){
- if(ch == CTLS){
- p->blocked = 1;
- cpmop(p->cpm, StopTx, 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(l > 0 && (p->putc == nil || p->opens>1))
- 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){
- dcinval(KADDR(bd->addr), bd->length);
- if(p->mode)
- framedinput(p, bd);
- else if(uartinput(p, bd))
- dokick = 1;
- bd->status = (bd->status & BDWrap) | BDEmpty|BDInt;
- eieio();
- if(++p->rdrx >= Nbuf)
- p->rdrx = 0;
- }
- 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(p->cpm, RestartTx, 0);
- } else if (events & TXE)
- cpmop(p->cpm, RestartTx, 0);
-}
-
-/*
- * used to ensure uart console output when debugging
- */
-void
-uartwait(void)
-{
- Uart *p = uart[0];
- int s;
-
- while(p && (p->outb||qlen(p->oq))){
- if(islo())
- continue;
- s = splhi();
- if((p->txb->status & BDReady) == 0){
- p->blocked = 0;
- p->cts = 1;
- if(p->scc == nil)
- 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[1+4*i].length = qlen(p->iq);
- } else for(i = 0; i < nuart; i++){
- p = uart[i];
- if(p && p->opens && p->iq)
- uartdir[1+4*i].length = qlen(p->iq);
- }
-
-}
-
-void
-uartinstall(void)
-{
- static int already;
- int i, n;
- char name[2*KNAMELEN];
- if(already)
- return;
- already = 1;
- n = 0;
- for(i=0; i<2; i++)
- if(conf.smcuarts & (1<<i)){
- snprint(name, sizeof(name), "eia%d", n++);
- uartsetup(i+1, CPsmc1+i, name);
- }
- n = 2;
- for(i=0; i<conf.nscc; i++)
- if(conf.sccuarts & (1<<i)){
- snprint(name, sizeof(name), "eia%d", n++);
- uartsetup(i+1, CPscc1+i, name);
- }
-}
-
-/*
- * all uarts must be uartsetup() by this point or inside of uartinstall()
- */
-static void
-uartreset(void)
-{
- int i;
- Dirtab *dp;
-
- uartinstall(); /* architecture specific */
-
- ndir = 1+4*nuart;
- uartdir = xalloc(ndir * sizeof(Dirtab));
- dp = uartdir;
- strcpy(dp->name, ".");
- mkqid(&dp->qid, 0, 0, QTDIR);
- dp->length = 0;
- dp->perm = DMDIR|0555;
- dp++;
- for(i = 0; i < nuart; i++){
- /* 4 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, "%sstatus", 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 Walkqid*
-uartwalk(Chan *c, Chan *nc, char **name, int nname)
-{
- return devwalk(c, nc, name, nname, uartdir, ndir, devgen);
-}
-
-static int
-uartstat(Chan *c, uchar *dp, int n)
-{
- if(NETTYPE(c->qid.path) == Ndataqid)
- setlength(NETID(c->qid.path));
- return devstat(c, dp, n, 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.type & QTDIR)
- 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];
-
-// TO DO: change to standard format for first line:
-//"b%d c%d d%d e%d l%d m%d p%c r%d s%d i%d\n"
- sprint(str, "opens %d ferr %lud oerr %lud crcerr %lud baud %ud 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.type & QTDIR){
- 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.type & QTDIR || 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, (int(*)(void*))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.type & QTDIR)
- 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)
-{
- if(c->qid.type & QTDIR || NETTYPE(c->qid.path) != Ndataqid)
- return devbwrite(c, bp, offset);
- return qbwrite(uart[NETID(c->qid.path)]->oq, bp);
-}
-
-static int
-uartwstat(Chan *c, uchar *dp, int n)
-{
- Dir d;
- Dirtab *dt;
-
- if(!iseve())
- error(Eperm);
- if(c->qid.type & QTDIR)
- error(Eperm);
- if(NETTYPE(c->qid.path) == Nstatqid)
- error(Eperm);
-
- dt = &uartdir[1+4 * NETID(c->qid.path)];
- n = convM2D(dp, n, &d, nil);
- if(d.mode != ~0UL){
- d.mode &= 0666;
- dt[0].perm = dt[1].perm = d.mode;
- }
- return n;
-}
-
-Dev uartdevtab = {
- 't',
- "uart",
-
- uartreset,
- devinit,
- devshutdown,
- uartattach,
- uartwalk,
- uartstat,
- uartopen,
- devcreate,
- uartclose,
- uartread,
- uartbread,
- uartwrite,
- uartbwrite,
- devremove,
- uartwstat,
-};