#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" /* * currently no DMA or flow control (hardware or software) */ /* * problems fixed from previous vsn: * * - no kick on queue's, so redirections weren't getting * started until the clock tick * * - lots of unnecessary overhead * * - initialization sequencing * * - uart[n] no longer indexed before calling uartinstall() */#define DEBUG if(0)iprint static void uartintr(Ureg*, void*); enum{ Stagesize= 1024, Dmabufsize=Stagesize/2, Nuart=7, /* max per machine */}; typedef struct Uart Uart;struct Uart{ QLock; int opens; int enabled; int port; /* 0 or 1 */ int kickme; /* for kick */ int frame; /* framing errors */ int overrun; /* rcvr overruns */ int perror; /* parity error */ int bps; /* baud rate */ uchar bits; char parity; uchar stop; int inters; /* total interrupt count */ int rinters; /* interrupts due to read */ int winters; /* interrupts due to write */ int rcount; /* total read count */ int wcount; /* total output count */ /* buffers */ int (*putc)(Queue*, int); Queue *iq; Queue *oq; UartReg *reg; /* staging areas to avoid some of the per character costs */ uchar *ip; uchar *ie; uchar *op; uchar *oe; /* put large buffers last to aid register-offset optimizations: */ char name[KNAMELEN]; uchar istage[Stagesize]; uchar ostage[Stagesize];}; #define UCON_ENABLEMASK (UCON_RXMDMASK | UCON_TXMDMASK | UCON_SINTMASK)#define UCON_ENABLESET (UCON_RXMDINT | UCON_TXMDINT | UCON_SINTON)#define UCON_DISABLESET (UCON_RXMDOFF | UCON_TXMDOFF | UCON_SINTOFF) static Uart *uart[Nuart];static int nuart; static ucharreadstatus(Uart *p){ UartReg *reg = p->reg; uchar stat = reg->stat; if (stat & USTAT_OV) p->overrun++; if (stat & USTAT_PE) p->perror++; if (stat & USTAT_FE) p->frame++; return stat;} static voiduartset(Uart *p){ UartReg *reg = p->reg; ulong denom; ulong brdiv; int n; uchar lcon; lcon= ULCON_CLOCKMCLK | ULCON_IROFF; lcon |= ULCON_WL5 + (p->bits - 5); lcon |= p->stop == 1 ? ULCON_STOP1 : ULCON_STOP2; switch (p->parity) { default: case 'n': lcon |= ULCON_PMDNONE; break; case 'o': lcon |= ULCON_PMDODD; break; case 'e': lcon |= ULCON_PMDEVEN; break; } reg->lcon = lcon; /* clear the break and loopback bits; leave everything else alone */ reg->con = (reg->con & ~(UCON_BRKMASK | UCON_LOOPMASK)) | UCON_BRKOFF | UCON_LOOPOFF; denom = 2 * 16 * p->bps; brdiv = (TIMER_HZ + denom / 2) / denom - 1; reg->brdiv = brdiv << 4; /* set buffer length according to speed, to allow * at most a 200ms delay before dumping the staging buffer * into the input queue */ n = p->bps/(10*1000/200); p->ie = &p->istage[n < Stagesize ? n : Stagesize];} /* * send break */static voiduartbreak(Uart *p, int ms){ UartReg *reg = p->reg; if(ms == 0) ms = 200; reg->con |= UCON_BRKON; tsleep(&up->sleep, return0, 0, ms); reg->con &= ~UCON_BRKON;} /* * turn on a port */static voiduartenable(Uart *p){ UartReg *reg = p->reg; if(p->enabled) return; uartset(p); // enable receive, transmit, and receive interrupt: reg->con = (reg->con & UCON_ENABLEMASK) | UCON_ENABLESET; p->enabled = 1;} /* * turn off a port */static voiduartdisable(Uart *p){ p->reg->con = (p->reg->con & UCON_ENABLEMASK) | UCON_DISABLESET; p->enabled = 0;} /* * put some bytes into the local queue to avoid calling * qconsume for every character */static intstageoutput(Uart *p){ int n; Queue *q = p->oq; if(!q) return 0; n = qconsume(q, p->ostage, Stagesize); if(n <= 0) return 0; p->op = p->ostage; p->oe = p->ostage + n; return n;} static voiduartxmit(Uart *p){ UartReg *reg = p->reg; ulong gag = 1; while(p->op < p->oe || stageoutput(p)) { if(readstatus(p) & USTAT_TBE) { DEBUG("T"); reg->txbuf = *(p->op++); p->wcount++; } else { DEBUG("F"); gag = 0; break; } } if (gag) { DEBUG("G"); p->kickme = 1; intrmask(UARTTXbit(p->port), 0); }} static voiduartrecvq(Uart *p){ uchar *cp = p->istage; int n = p->ip - cp; if(n == 0) return; if(p->putc) while(n-- > 0) p->putc(p->iq, *cp++); else if(p->iq) if(qproduce(p->iq, p->istage, n) < n) print("qproduce flow control"); p->ip = p->istage;} static voiduartrecv(Uart *p){ UartReg *reg = p->reg; uchar stat = readstatus(p); DEBUG("R"); if (stat & USTAT_RDR) { int c; c = reg->rxbuf; if (c == '?') { DEBUG("mod 0x%.8lx\n", INTREG->mod); DEBUG("msk 0x%.8lx\n", INTREG->msk); DEBUG("pnd 0x%.8lx\n", INTREG->pnd); } *p->ip++ = c;/* if(p->ip >= p->ie) */ uartrecvq(p); p->rcount++; }} static voiduartkick(void *a){ Uart *p = a; int x = splhi(); DEBUG("k"); if (p->kickme) { p->kickme = 0; DEBUG("K"); intrunmask(UARTTXbit(p->port), 0); } splx(x);} /* * UART Interrupt Handler */static voiduarttxintr(Ureg*, void* arg){ Uart *p = arg; intrclear(UARTTXbit(p->port), 0); p->inters++; p->winters++; uartxmit(p);} static voiduartrxintr(Ureg*, void* arg){ Uart *p = arg; intrclear(UARTRXbit(p->port), 0); p->inters++; p->rinters++; uartrecv(p);} static voiduartsetup(ulong port, char *name){ Uart *p; if(nuart >= Nuart) return; p = xalloc(sizeof(Uart)); uart[nuart++] = p; strcpy(p->name, name); p->reg = &UARTREG[port]; p->bps = 9600; p->bits = 8; p->parity = 'n'; p->stop = 1; p->kickme = 0; p->port = port; p->iq = qopen(4*1024, 0, 0 , p); p->oq = qopen(4*1024, 0, uartkick, p); p->ip = p->istage; p->ie = &p->istage[Stagesize]; p->op = p->ostage; p->oe = p->ostage; intrenable(UARTTXbit(port), uarttxintr, p, 0); intrenable(UARTRXbit(port), uartrxintr, p, 0); } static voiduartinstall(void){ static int already; if(already) return; already = 1; uartsetup(0, "eia0");// uartsetup(1, "eia1");} /* * called by main() to configure a duart port as a console or a mouse */voiduartspecial(int port, int bps, char parity, Queue **in, Queue **out, int (*putc)(Queue*, int)){ Uart *p; uartinstall(); if(port >= nuart) return; p = uart[port]; if(bps) p->bps = bps; if(parity) p->parity = parity; uartenable(p); p->putc = putc; if(in) *in = p->iq; if(out) *out = p->oq; p->opens++;} Dirtab *uartdir;int ndir; static voidsetlength(int i){ Uart *p; if(i > 0){ p = uart[i]; if(p && p->opens && p->iq) uartdir[1+3*i].length = qlen(p->iq); } else for(i = 0; i < nuart; i++){ p = uart[i]; if(p && p->opens && p->iq) uartdir[1+3*i].length = qlen(p->iq); }} /* * all uarts must be uartsetup() by this point or inside of uartinstall() */static voiduartreset(void){ int i; Dirtab *dp; uartinstall(); ndir = 1+3*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++){ /* 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, "%sstatus", uart[i]->name); dp->qid.path = NETQID(i, Nstatqid); dp->perm = 0444; 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 intuartstat(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 voiduartclose(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); p->ip = p->istage; } qunlock(p); break; }} static longuartstatus(Chan *c, Uart *p, void *buf, long n, long offset)Lines 1–500 of 719. Load more
#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" /* * currently no DMA or flow control (hardware or software) */ /* * problems fixed from previous vsn: * * - no kick on queue's, so redirections weren't getting * started until the clock tick * * - lots of unnecessary overhead * * - initialization sequencing * * - uart[n] no longer indexed before calling uartinstall() */ #define DEBUG if(0)iprint static void uartintr(Ureg*, void*); enum { Stagesize= 1024, Dmabufsize=Stagesize/2, Nuart=7, /* max per machine */ }; typedef struct Uart Uart; struct Uart { QLock; int opens; int enabled; int port; /* 0 or 1 */ int kickme; /* for kick */ int frame; /* framing errors */ int overrun; /* rcvr overruns */ int perror; /* parity error */ int bps; /* baud rate */ uchar bits; char parity; uchar stop; int inters; /* total interrupt count */ int rinters; /* interrupts due to read */ int winters; /* interrupts due to write */ int rcount; /* total read count */ int wcount; /* total output count */ /* buffers */ int (*putc)(Queue*, int); Queue *iq; Queue *oq; UartReg *reg; /* staging areas to avoid some of the per character costs */ uchar *ip; uchar *ie; uchar *op; uchar *oe; /* put large buffers last to aid register-offset optimizations: */ char name[KNAMELEN]; uchar istage[Stagesize]; uchar ostage[Stagesize]; }; #define UCON_ENABLEMASK (UCON_RXMDMASK | UCON_TXMDMASK | UCON_SINTMASK) #define UCON_ENABLESET (UCON_RXMDINT | UCON_TXMDINT | UCON_SINTON) #define UCON_DISABLESET (UCON_RXMDOFF | UCON_TXMDOFF | UCON_SINTOFF) static Uart *uart[Nuart]; static int nuart; static uchar readstatus(Uart *p) { UartReg *reg = p->reg; uchar stat = reg->stat; if (stat & USTAT_OV) p->overrun++; if (stat & USTAT_PE) p->perror++; if (stat & USTAT_FE) p->frame++; return stat; } static void uartset(Uart *p) { UartReg *reg = p->reg; ulong denom; ulong brdiv; int n; uchar lcon; lcon= ULCON_CLOCKMCLK | ULCON_IROFF; lcon |= ULCON_WL5 + (p->bits - 5); lcon |= p->stop == 1 ? ULCON_STOP1 : ULCON_STOP2; switch (p->parity) { default: case 'n': lcon |= ULCON_PMDNONE; break; case 'o': lcon |= ULCON_PMDODD; break; case 'e': lcon |= ULCON_PMDEVEN; break; } reg->lcon = lcon; /* clear the break and loopback bits; leave everything else alone */ reg->con = (reg->con & ~(UCON_BRKMASK | UCON_LOOPMASK)) | UCON_BRKOFF | UCON_LOOPOFF; denom = 2 * 16 * p->bps; brdiv = (TIMER_HZ + denom / 2) / denom - 1; reg->brdiv = brdiv << 4; /* set buffer length according to speed, to allow * at most a 200ms delay before dumping the staging buffer * into the input queue */ n = p->bps/(10*1000/200); p->ie = &p->istage[n < Stagesize ? n : Stagesize]; } /* * send break */ static void uartbreak(Uart *p, int ms) { UartReg *reg = p->reg; if(ms == 0) ms = 200; reg->con |= UCON_BRKON; tsleep(&up->sleep, return0, 0, ms); reg->con &= ~UCON_BRKON; } /* * turn on a port */ static void uartenable(Uart *p) { UartReg *reg = p->reg; if(p->enabled) return; uartset(p); // enable receive, transmit, and receive interrupt: reg->con = (reg->con & UCON_ENABLEMASK) | UCON_ENABLESET; p->enabled = 1; } /* * turn off a port */ static void uartdisable(Uart *p) { p->reg->con = (p->reg->con & UCON_ENABLEMASK) | UCON_DISABLESET; p->enabled = 0; } /* * put some bytes into the local queue to avoid calling * qconsume for every character */ static int stageoutput(Uart *p) { int n; Queue *q = p->oq; if(!q) return 0; n = qconsume(q, p->ostage, Stagesize); if(n <= 0) return 0; p->op = p->ostage; p->oe = p->ostage + n; return n; } static void uartxmit(Uart *p) { UartReg *reg = p->reg; ulong gag = 1; while(p->op < p->oe || stageoutput(p)) { if(readstatus(p) & USTAT_TBE) { DEBUG("T"); reg->txbuf = *(p->op++); p->wcount++; } else { DEBUG("F"); gag = 0; break; } } if (gag) { DEBUG("G"); p->kickme = 1; intrmask(UARTTXbit(p->port), 0); } } static void uartrecvq(Uart *p) { uchar *cp = p->istage; int n = p->ip - cp; if(n == 0) return; if(p->putc) while(n-- > 0) p->putc(p->iq, *cp++); else if(p->iq) if(qproduce(p->iq, p->istage, n) < n) print("qproduce flow control"); p->ip = p->istage; } static void uartrecv(Uart *p) { UartReg *reg = p->reg; uchar stat = readstatus(p); DEBUG("R"); if (stat & USTAT_RDR) { int c; c = reg->rxbuf; if (c == '?') { DEBUG("mod 0x%.8lx\n", INTREG->mod); DEBUG("msk 0x%.8lx\n", INTREG->msk); DEBUG("pnd 0x%.8lx\n", INTREG->pnd); } *p->ip++ = c; /* if(p->ip >= p->ie) */ uartrecvq(p); p->rcount++; } } static void uartkick(void *a) { Uart *p = a; int x = splhi(); DEBUG("k"); if (p->kickme) { p->kickme = 0; DEBUG("K"); intrunmask(UARTTXbit(p->port), 0); } splx(x); } /* * UART Interrupt Handler */ static void uarttxintr(Ureg*, void* arg) { Uart *p = arg; intrclear(UARTTXbit(p->port), 0); p->inters++; p->winters++; uartxmit(p); } static void uartrxintr(Ureg*, void* arg) { Uart *p = arg; intrclear(UARTRXbit(p->port), 0); p->inters++; p->rinters++; uartrecv(p); } static void uartsetup(ulong port, char *name) { Uart *p; if(nuart >= Nuart) return; p = xalloc(sizeof(Uart)); uart[nuart++] = p; strcpy(p->name, name); p->reg = &UARTREG[port]; p->bps = 9600; p->bits = 8; p->parity = 'n'; p->stop = 1; p->kickme = 0; p->port = port; p->iq = qopen(4*1024, 0, 0 , p); p->oq = qopen(4*1024, 0, uartkick, p); p->ip = p->istage; p->ie = &p->istage[Stagesize]; p->op = p->ostage; p->oe = p->ostage; intrenable(UARTTXbit(port), uarttxintr, p, 0); intrenable(UARTRXbit(port), uartrxintr, p, 0); } static void uartinstall(void) { static int already; if(already) return; already = 1; uartsetup(0, "eia0"); // uartsetup(1, "eia1"); } /* * called by main() to configure a duart port as a console or a mouse */ void uartspecial(int port, int bps, char parity, Queue **in, Queue **out, int (*putc)(Queue*, int)) { Uart *p; uartinstall(); if(port >= nuart) return; p = uart[port]; if(bps) p->bps = bps; if(parity) p->parity = parity; uartenable(p); p->putc = putc; if(in) *in = p->iq; if(out) *out = p->oq; p->opens++; } Dirtab *uartdir; int ndir; static void setlength(int i) { Uart *p; if(i > 0){ p = uart[i]; if(p && p->opens && p->iq) uartdir[1+3*i].length = qlen(p->iq); } else for(i = 0; i < nuart; i++){ p = uart[i]; if(p && p->opens && p->iq) uartdir[1+3*i].length = qlen(p->iq); } } /* * all uarts must be uartsetup() by this point or inside of uartinstall() */ static void uartreset(void) { int i; Dirtab *dp; uartinstall(); ndir = 1+3*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++){ /* 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, "%sstatus", uart[i]->name); dp->qid.path = NETQID(i, Nstatqid); dp->perm = 0444; 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); p->ip = p->istage; } qunlock(p); break; } } static long uartstatus(Chan *c, Uart *p, void *buf, long n, long offset)