## diffname port/devuart.c 2001/0527 ## diff -e /dev/null /n/emeliedump/2001/0527/sys/src/9/port/devuart.c 0a #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 { /* soft flow control chars */ CTLS= 023, CTLQ= 021, }; extern Dev uartdevtab; extern PhysUart* physuart[]; static Uart* uartlist; static Uart** uart; static int uartnuart; static Dirtab *uartdir; static int uartndir; struct Uartalloc { Lock; Uart *elist; /* list of enabled interfaces */ } uartalloc; static void uartclock(void); static void uartflow(void*); /* * enable/disable uart and add/remove to list of enabled uarts */ static Uart* uartenable(Uart *p) { Uart **l; if(p->iq == nil){ if((p->iq = qopen(4*1024, 0, uartflow, p)) == nil) return nil; } else qreopen(p->iq); if(p->oq == nil){ if((p->oq = qopen(4*1024, 0, uartkick, p)) == nil){ qfree(p->iq); p->iq = nil; return nil; } } else qreopen(p->oq); p->ir = p->istage; p->iw = p->istage; p->ie = &p->istage[Stagesize]; p->op = p->ostage; p->oe = p->ostage; p->hup_dsr = p->hup_dcd = 0; p->dsr = p->dcd = 0; /* assume we can send */ p->cts = 1; p->ctsbackoff = 0; if(p->bits == 0) uartctl(p, "l8"); if(p->stop == 0) uartctl(p, "s1"); if(p->parity == 0) uartctl(p, "pn"); if(p->baud == 0) uartctl(p, "b9600"); (*p->phys->enable)(p, 1); 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); return p; } static void uartdisable(Uart *p) { Uart **l; (*p->phys->disable)(p); lock(&uartalloc); for(l = &uartalloc.elist; *l; l = &(*l)->elist){ if(*l == p){ *l = p->elist; break; } } p->enabled = 0; unlock(&uartalloc); } 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 < uartnuart; i++){ p = uart[i]; if(p && p->opens && p->iq) uartdir[1+3*i].length = qlen(p->iq); } } /* * set up the '#t' directory */ static void uartreset(void) { int i; Dirtab *dp; Uart *p, *tail; tail = nil; for(i = 0; physuart[i] != nil; i++){ if(physuart[i]->pnp == nil) continue; if((p = physuart[i]->pnp()) == nil) continue; if(uartlist != nil) tail->next = p; else uartlist = p; for(tail = p; tail->next != nil; tail = tail->next) uartnuart++; uartnuart++; } if(uartnuart) uart = xalloc(uartnuart*sizeof(Uart)); uartndir = 1 + 3*uartnuart; uartdir = xalloc(uartndir * sizeof(Dirtab)); dp = uartdir; strcpy(dp->name, "."); mkqid(&dp->qid, 0, 0, QTDIR); dp->length = 0; dp->perm = DMDIR|0555; dp++; p = uartlist; for(i = 0; i < uartnuart; i++){ /* 3 directory entries per port */ sprint(dp->name, "eia%d", i); dp->qid.path = NETQID(i, Ndataqid); dp->perm = 0660; dp++; sprint(dp->name, "eia%dctl", i); dp->qid.path = NETQID(i, Nctlqid); dp->perm = 0660; dp++; sprint(dp->name, "eia%dstatus", i); dp->qid.path = NETQID(i, Nstatqid); dp->perm = 0444; dp++; uart[i] = p; p->dev = i; if(p->console && uartenable(p) != nil){ kbdq = p->iq; serialoq = p->oq; p->putc = kbdcr2nl; p->opens++; } p = p->next; } if(uartnuart) addclock0link(uartclock); } 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, uartndir, 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, uartndir, devgen); } static Chan* uartopen(Chan *c, int omode) { Uart *p; c = devopen(c, omode, uartdir, uartndir, devgen); switch(NETTYPE(c->qid.path)){ case Nctlqid: case Ndataqid: p = uart[NETID(c->qid.path)]; qlock(p); if(p->opens++ == 0 && uartenable(p) == nil){ qunlock(p); c->flag &= ~COPEN; error(Enodev); } qunlock(p); break; } return c; } static int uartdrained(void* arg) { Uart *p; p = arg; return qlen(p->oq) == 0 && p->op == p->oe; } 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){ qclose(p->iq); p->ir = p->iw = p->istage; /* */ qhangup(p->oq, nil); if(!waserror()){ sleep(&p->r, uartdrained, p); poperror(); } qclose(p->oq); uartdisable(p); p->dcd = p->dsr = p->dohup = 0; } qunlock(p); break; } } static long uartread(Chan *c, void *buf, long n, vlong off) { Uart *p; ulong offset = off; if(c->qid.type & QTDIR){ setlength(-1); return devdirread(c, buf, n, uartdir, uartndir, 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 (*p->phys->status)(p, buf, n, offset); } return 0; } int uartctl(Uart *p, char *cmd) { char *f[16]; int i, n, nf; nf = getfields(cmd, f, nelem(f), 1, " \t\n"); for(i = 0; i < nf; i++){ if(strncmp(f[i], "break", 5) == 0){ (*p->phys->dobreak)(p, 0); continue; } n = atoi(f[i]+1); switch(*f[i]){ case 'B': case 'b': if((*p->phys->baud)(p, n) < 0) return -1; break; case 'C': case 'c': p->hup_dcd = n; break; case 'D': case 'd': (*p->phys->dtr)(p, n); break; case 'E': case 'e': p->hup_dsr = n; break; case 'f': case 'F': if(p->oq != nil) qflush(p->oq); break; case 'H': case 'h': if(p->iq != nil) qhangup(p->iq, 0); if(p->oq != nil) qhangup(p->oq, 0); break; case 'i': case 'I': (*p->phys->fifo)(p, n); break; case 'K': case 'k': (*p->phys->dobreak)(p, n); break; case 'L': case 'l': if((*p->phys->bits)(p, n) < 0) return -1; break; case 'm': case 'M': (*p->phys->modemctl)(p, n); break; case 'n': case 'N': if(p->oq != nil) qnoblock(p->oq, n); break; case 'P': case 'p': if((*p->phys->parity)(p, *(f[i]+1)) < 0) return -1; break; case 'Q': case 'q': if(p->iq != nil) qsetlimit(p->iq, n); if(p->oq != nil) qsetlimit(p->oq, n); break; case 'R': case 'r': (*p->phys->rts)(p, n); break; case 'S': case 's': if((*p->phys->stop)(p, n) < 0) return -1; break; case 'T': case 't': p->dcdts = n; break; case 'W': case 'w': /* obsolete */ break; case 'X': case 'x': if(p->enabled){ ilock(&p->tlock); p->xonoff = n; iunlock(&p->tlock); } break; } } return 0; } static long uartwrite(Chan *c, void *buf, long n, vlong) { Uart *p; char *cmd; if(c->qid.type & QTDIR) error(Eperm); p = uart[NETID(c->qid.path)]; switch(NETTYPE(c->qid.path)){ case Ndataqid: qlock(p); if(waserror()){ qunlock(p); nexterror(); } n = qwrite(p->oq, buf, n); qunlock(p); poperror(); break; case Nctlqid: cmd = malloc(n+1); memmove(cmd, buf, n); cmd[n] = 0; qlock(p); if(waserror()){ qunlock(p); free(cmd); nexterror(); } /* let output drain */ sleep(&p->r, uartdrained, p); if(uartctl(p, cmd) < 0) error(Ebadarg); qunlock(p); poperror(); free(cmd); break; } return n; } static int uartwstat(Chan *c, uchar *dp, int n) { Dir d; Dirtab *dt; if(!iseve()) error(Eperm); if(QTDIR & c->qid.type) error(Eperm); if(NETTYPE(c->qid.path) == Nstatqid) error(Eperm); dt = &uartdir[1 + 3 * NETID(c->qid.path)]; n = convM2D(dp, n, &d, nil); if(n == 0) error(Eshortstat); dt[0].perm = dt[1].perm = d.mode; return n; } Dev uartdevtab = { 't', "uart", uartreset, devinit, uartattach, uartwalk, uartstat, uartopen, devcreate, uartclose, uartread, devbread, uartwrite, devbwrite, devremove, uartwstat, }; /* * restart input if it's off */ static void uartflow(void *v) { Uart *p; p = v; if(p->modem) (*p->phys->rts)(p, 1); } /* * put some bytes into the local queue to avoid calling * qconsume for every character */ int uartstageoutput(Uart *p) { int n; n = qconsume(p->oq, p->ostage, Stagesize); if(n <= 0) return 0; p->op = p->ostage; p->oe = p->ostage + n; return n; } /* * restart output */ void uartkick(void *v) { Uart *p = v; if(p->blocked) return; ilock(&p->tlock); (*p->phys->kick)(p); iunlock(&p->tlock); if(qisclosed(p->oq) && uartdrained(p)) wakeup(&p->r); } /* * receive a character at interrupt time */ void uartrecv(Uart *p, char ch) { uchar *next; /* software flow control */ if(p->xonoff){ if(ch == CTLS){ p->blocked = 1; }else if (ch == CTLQ){ p->blocked = 0; p->ctsbackoff = 2; /* clock gets output going again */ } } /* receive the character */ if(p->putc) p->putc(p->iq, ch); else { next = p->iw + 1; if(next == p->ie) next = p->istage; if(next != p->ir){ *p->iw = ch; p->iw = next; } } } /* * we save up input characters till clock time to reduce * per character interrupt overhead. */ static void uartclock(void) { Uart *p; uchar *iw; for(p = uartalloc.elist; p; p = p->elist){ /* this amortizes cost of qproduce to many chars */ if(p->iw != p->ir){ iw = p->iw; if(iw < p->ir){ if(qproduce(p->iq, p->ir, p->ie-p->ir) < 0) (*p->phys->rts)(p, 0); p->ir = p->istage; } if(qproduce(p->iq, p->ir, iw-p->ir) < 0) (*p->phys->rts)(p, 0); p->ir = iw; } /* hang up if requested */ if(p->dohup){ qhangup(p->iq, 0); qhangup(p->oq, 0); p->dohup = 0; } /* this adds hysteresis to hardware/software flow control */ if(p->ctsbackoff){ ilock(&p->tlock); if(p->ctsbackoff){ if(--(p->ctsbackoff) == 0) (*p->phys->kick)(p); } iunlock(&p->tlock); } } } . ## diffname port/devuart.c 2001/0606 ## diff -e /n/emeliedump/2001/0527/sys/src/9/port/devuart.c /n/emeliedump/2001/0606/sys/src/9/port/devuart.c 186,190c if(p->console || p->special){ if(uartenable(p) != nil){ if(p->console){ kbdq = p->iq; serialoq = p->oq; p->putc = kbdcr2nl; } p->opens++; } . ## diffname port/devuart.c 2001/0619 ## diff -e /n/emeliedump/2001/0606/sys/src/9/port/devuart.c /n/emeliedump/2001/0619/sys/src/9/port/devuart.c 510a uartpower, . 492a void uartpower(int on) { Uart *p; for(p = uartlist; p != nil; p = p->next) { if (p->phys->power) (*p->phys->power)(p, on); } } . ## diffname port/devuart.c 2001/0725 ## diff -e /n/emeliedump/2001/0619/sys/src/9/port/devuart.c /n/emeliedump/2001/0725/sys/src/9/port/devuart.c 626,627c if(iw > p->ir) if(qproduce(p->iq, p->ir, iw-p->ir) < 0) (*p->phys->rts)(p, 0); . ## diffname port/devuart.c 2001/1106 ## diff -e /n/emeliedump/2001/0725/sys/src/9/port/devuart.c /n/emeliedump/2001/1106/sys/src/9/port/devuart.c 489c if(d.mode != ~0UL) dt[0].perm = dt[1].perm = d.mode; . ## diffname port/devuart.c 2001/1117 ## diff -e /n/emeliedump/2001/1106/sys/src/9/port/devuart.c /n/emeliedump/2001/1117/sys/src/9/port/devuart.c 321c nf = tokenize(cmd, f, nelem(f)); . ## diffname port/devuart.c 2001/1207 ## diff -e /n/emeliedump/2001/1117/sys/src/9/port/devuart.c /n/emeliedump/2001/1207/sys/src/9/port/devuart.c 244a c->iounit = qiomaxatomic; . ## diffname port/devuart.c 2002/0109 ## diff -e /n/emeliedump/2001/1207/sys/src/9/port/devuart.c /n/emeliedump/2002/0109/sys/src/9/port/devuart.c 511a devshutdown, . ## diffname port/devuart.c 2002/0412 ## diff -e /n/emeliedump/2002/0109/sys/src/9/port/devuart.c /n/emeliedump/2002/0412/sys/src/9/port/devuart.c 652a /* * polling console input, output */ Uart* consuart; int uartgetc(void) { if(consuart == nil || consuart->phys->getc == nil) return -1; return consuart->phys->getc(consuart); } void uartputc(int c) { if(consuart == nil || consuart->phys->putc == nil) return; consuart->phys->putc(consuart, c); } void uartputs(char *s, int n) { char *e; if(consuart == nil || consuart->phys->putc == nil) return; e = s+n; for(; sphys->putc(consuart, '\r'); consuart->phys->putc(consuart, *s); } } . ## diffname port/devuart.c 2002/0503 ## diff -e /n/emeliedump/2002/0412/sys/src/9/port/devuart.c /n/emeliedump/2002/0503/sys/src/9/port/devuart.c 114a void uartmouse(Uart* p, int (*putc)(Queue*, int), int setb1200) { qlock(p); if(p->opens++ == 0 && uartenable(p) == nil){ qunlock(p); error(Enodev); } if(setb1200) uartctl(p, "b1200"); p->putc = putc; p->special = 1; qunlock(p); } . ## diffname port/devuart.c 2002/0730 ## diff -e /n/emeliedump/2002/0503/sys/src/9/port/devuart.c /n/emeliedump/2002/0730/sys/src/9/port/devuart.c 215a } . 214c if(uartnuart){ . 172c uart = xalloc(uartnuart*sizeof(Uart*)); . ## diffname port/devuart.c 2002/0928 ## diff -e /n/emeliedump/2002/0730/sys/src/9/port/devuart.c /n/emeliedump/2002/0928/sys/src/9/port/devuart.c 215c /* * at 115200 baud, the 1024 char buffer takes 56 ms to process, * processing it every 22 ms should be fine */ addclock0link(uartclock, 22); . ## diffname port/devuart.c 2003/0124 ## diff -e /n/emeliedump/2002/0928/sys/src/9/port/devuart.c /n/emeliedump/2003/0124/sys/src/9/port/devuart.c 480d 419a sleep(&p->r, uartdrained, p); . 415a sleep(&p->r, uartdrained, p); . 403a sleep(&p->r, uartdrained, p); . 394a sleep(&p->r, uartdrained, p); . 389a sleep(&p->r, uartdrained, p); . 385a sleep(&p->r, uartdrained, p); . 381a sleep(&p->r, uartdrained, p); . 361a sleep(&p->r, uartdrained, p); . 352a sleep(&p->r, uartdrained, p); . ## diffname port/devuart.c 2003/0125 ## diff -e /n/emeliedump/2003/0124/sys/src/9/port/devuart.c /n/emeliedump/2003/0125/sys/src/9/port/devuart.c 428c if(p->enabled) sleep(&p->r, uartdrained, p); . 423c if(p->enabled) sleep(&p->r, uartdrained, p); . 410c if(p->enabled) sleep(&p->r, uartdrained, p); . 400c if(p->enabled) sleep(&p->r, uartdrained, p); . 394c if(p->enabled) sleep(&p->r, uartdrained, p); . 389c if(p->enabled) sleep(&p->r, uartdrained, p); . 384c if(p->enabled) sleep(&p->r, uartdrained, p); . 363c if(p->enabled) sleep(&p->r, uartdrained, p); . 353c if(p->enabled) sleep(&p->r, uartdrained, p); . ## diffname port/devuart.c 2003/0402 ## diff -e /n/emeliedump/2003/0125/sys/src/9/port/devuart.c /n/emeliedump/2003/0402/sys/src/9/port/devuart.c 42a dbgputc('E'); . ## diffname port/devuart.c 2003/0403 ## diff -e /n/emeliedump/2003/0402/sys/src/9/port/devuart.c /n/emeliedump/2003/0403/sys/src/9/port/devuart.c 183d 43d ## diffname port/devuart.c 2003/0406 ## diff -e /n/emeliedump/2003/0403/sys/src/9/port/devuart.c /n/emeliedump/2003/0406/sys/src/9/port/devuart.c 634c else{ . 625c }else if(ch == CTLQ){ . 537c if(p->phys->power) .