#include "u.h"#include "../port/lib.h"#include "mem.h"#include "dat.h"#include "fns.h"#include "io.h"#include "../port/error.h" enum { Qdir = 0, Qdata, Qctl, Qstat,}; #define UARTTYPE(x) (((unsigned)x)&0x1f)#define UARTID(x) ((((unsigned)x))>>5)#define UARTQID(i, t) ((((unsigned)i)<<5)|(t)) 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;static Timer *uarttimer; 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){ int opened; Uart **l; opened = 1; if(p->iq == nil){ if((p->iq = qopen(8*1024, 0, uartflow, p)) == nil) opened = 0; } else qreopen(p->iq); if(p->oq == nil){ if((p->oq = qopen(8*1024, 0, uartkick, p)) == nil){ qfree(p->iq); p->iq = nil; opened = 0; } } 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, opened); if(!opened) return nil; /* * use ilock because uartclock can otherwise interrupt here * and would hang on an attempt to lock uartalloc. */ ilock(&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; iunlock(&uartalloc); return p;} static voiduartdisable(Uart *p){ Uart **l; (*p->phys->disable)(p); ilock(&uartalloc); for(l = &uartalloc.elist; *l; l = &(*l)->elist){ if(*l == p){ *l = p->elist; break; } } p->enabled = 0; iunlock(&uartalloc);} voiduartmouse(Uart* p, int (*putc)(Queue*, int), int setb1200){ qlock(p); if(p->opens == 0 && uartenable(p) == nil){ qunlock(p); error(Enodev); } p->opens++; if(setb1200) uartctl(p, "b1200"); p->putc = putc; p->special = 1; qunlock(p);} voiduartsetmouseputc(Uart* p, int (*putc)(Queue*, int)){ qlock(p); if(p->opens == 0 || p->special == 0){ qunlock(p); error(Enodev); } p->putc = putc; qunlock(p);} static voidsetlength(int i){ Uart *p; if(i > 0){ p = uart[i]; if(p != nil && p->opens && p->iq != nil) uartdir[1+3*i].length = qlen(p->iq); } else for(i = 0; i < uartnuart; i++){ p = uart[i]; if(p != nil && p->opens && p->iq != nil) uartdir[1+3*i].length = qlen(p->iq); }} intuartconsconf(char **cfg){ char *s; int n; *cfg = ""; if((s = getconf("console")) == nil) return -1; n = strtoul(s, cfg, 0); if(s == *cfg) return -1; return n;} /* * set up the '#t' directory */static voiduartreset(void){ char *ccfg; int i, cc; Dirtab *dp; Uart *p, *tail; cc = uartconsconf(&ccfg); 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)); if((uartnuart>0 && uart == nil) || uartdir == nil) panic("uartreset: no memory"); 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 = UARTQID(i, Qdata); dp->perm = 0660; dp++; sprint(dp->name, "eia%dctl", i); dp->qid.path = UARTQID(i, Qctl); dp->perm = 0660; dp++; sprint(dp->name, "eia%dstatus", i); dp->qid.path = UARTQID(i, Qstat); dp->perm = 0444; dp++; uart[i] = p; qlock(p); p->dev = i; if(cc == i && p->console == 0){ uartctl(p, "z"); uartctl(p, ccfg); } if(p->special && uartenable(p) != nil) p->opens++; qunlock(p); p = p->next; } if(uartnuart){ /* * at 115200 baud, the 1024 char buffer takes 56 ms to process, * processing it every 22 ms should be fine. */ uarttimer = addclock0link(uartclock, 22); }} 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 intuartstat(Chan *c, uchar *dp, int n){ if(UARTTYPE(c->qid.path) == Qdata) setlength(UARTID(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(UARTTYPE(c->qid.path)){ case Qctl: case Qdata: p = uart[UARTID(c->qid.path)]; qlock(p); if(p->opens == 0 && uartenable(p) == nil){ qunlock(p); c->flag &= ~COPEN; error(Enodev); } p->opens++; qunlock(p); break; } c->iounit = qiomaxatomic; return c;} static intuartdrained(void* arg){ Uart *p; p = arg; return qlen(p->oq) == 0 && p->op == p->oe;} static voiduartdrainoutput(Uart *p){ if(!p->enabled || up == nil) return; p->drain = 1; if(waserror()){ p->drain = 0; nexterror(); } sleep(&p->r, uartdrained, p); poperror();} static voiduartclose(Chan *c){ Uart *p; if(c->qid.type & QTDIR) return; if((c->flag & COPEN) == 0) return; switch(UARTTYPE(c->qid.path)){ case Qdata: case Qctl: p = uart[UARTID(c->qid.path)]; qlock(p); if(--(p->opens) == 0){ qclose(p->iq); ilock(&p->rlock); p->ir = p->iw = p->istage; iunlock(&p->rlock); /* */ qhangup(p->oq, nil); if(!waserror()){ uartdrainoutput(p); poperror(); } qclose(p->oq); uartdisable(p); p->dcd = p->dsr = p->dohup = 0; } qunlock(p); break; }} static longuartread(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[UARTID(c->qid.path)]; switch(UARTTYPE(c->qid.path)){ case Qdata: return qread(p->iq, buf, n); case Qctl: return readnum(offset, buf, n, UARTID(c->qid.path), NUMSIZE); case Qstat: return (*p->phys->status)(p, buf, n, offset); } return 0;} static intsetupcons(Uart *p, int on){ int r; static Lock conslk; static Queue *lastcons; r = 0; lock(&conslk); if(on && !p->console && lastcons == nil){ if(!p->enabled) uartenable(p); if(!p->enabled){ /* qopen will fail early in boot (no malloc) */ consuart = p; unlock(&conslk); return up == nil? 0: -1; } lastcons = kbdq; kbdq = p->iq; serialoq = p->oq; p->putc = kbdcr2nl; consuart = p; p->opens++; p->console = 1; }else if(!on && p->console){ kbdq = lastcons; lastcons = nil; serialoq = nil; p->putc = nil; consuart = nil; p->opens--; p->console = 0; } else r = -1; unlock(&conslk); return r;} intuartctl(Uart *p, char *cmd){ char *f[16]; int i, n, nf; nf = tokenize(cmd, f, nelem(f)); 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': uartdrainoutput(p); if((*p->phys->baud)(p, n) < 0) return -1; break; case 'C': case 'c': p->hup_dcd = n; break; case 'D': case 'd': uartdrainoutput(p); (*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': uartdrainoutput(p); (*p->phys->fifo)(p, n); break; case 'K': case 'k': uartdrainoutput(p); (*p->phys->dobreak)(p, n); break; case 'L':Lines 1–500 of 868. 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" enum { Qdir = 0, Qdata, Qctl, Qstat, }; #define UARTTYPE(x) (((unsigned)x)&0x1f) #define UARTID(x) ((((unsigned)x))>>5) #define UARTQID(i, t) ((((unsigned)i)<<5)|(t)) 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; static Timer *uarttimer; 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) { int opened; Uart **l; opened = 1; if(p->iq == nil){ if((p->iq = qopen(8*1024, 0, uartflow, p)) == nil) opened = 0; } else qreopen(p->iq); if(p->oq == nil){ if((p->oq = qopen(8*1024, 0, uartkick, p)) == nil){ qfree(p->iq); p->iq = nil; opened = 0; } } 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, opened); if(!opened) return nil; /* * use ilock because uartclock can otherwise interrupt here * and would hang on an attempt to lock uartalloc. */ ilock(&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; iunlock(&uartalloc); return p; } static void uartdisable(Uart *p) { Uart **l; (*p->phys->disable)(p); ilock(&uartalloc); for(l = &uartalloc.elist; *l; l = &(*l)->elist){ if(*l == p){ *l = p->elist; break; } } p->enabled = 0; iunlock(&uartalloc); } void uartmouse(Uart* p, int (*putc)(Queue*, int), int setb1200) { qlock(p); if(p->opens == 0 && uartenable(p) == nil){ qunlock(p); error(Enodev); } p->opens++; if(setb1200) uartctl(p, "b1200"); p->putc = putc; p->special = 1; qunlock(p); } void uartsetmouseputc(Uart* p, int (*putc)(Queue*, int)) { qlock(p); if(p->opens == 0 || p->special == 0){ qunlock(p); error(Enodev); } p->putc = putc; qunlock(p); } static void setlength(int i) { Uart *p; if(i > 0){ p = uart[i]; if(p != nil && p->opens && p->iq != nil) uartdir[1+3*i].length = qlen(p->iq); } else for(i = 0; i < uartnuart; i++){ p = uart[i]; if(p != nil && p->opens && p->iq != nil) uartdir[1+3*i].length = qlen(p->iq); } } int uartconsconf(char **cfg) { char *s; int n; *cfg = ""; if((s = getconf("console")) == nil) return -1; n = strtoul(s, cfg, 0); if(s == *cfg) return -1; return n; } /* * set up the '#t' directory */ static void uartreset(void) { char *ccfg; int i, cc; Dirtab *dp; Uart *p, *tail; cc = uartconsconf(&ccfg); 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)); if((uartnuart>0 && uart == nil) || uartdir == nil) panic("uartreset: no memory"); 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 = UARTQID(i, Qdata); dp->perm = 0660; dp++; sprint(dp->name, "eia%dctl", i); dp->qid.path = UARTQID(i, Qctl); dp->perm = 0660; dp++; sprint(dp->name, "eia%dstatus", i); dp->qid.path = UARTQID(i, Qstat); dp->perm = 0444; dp++; uart[i] = p; qlock(p); p->dev = i; if(cc == i && p->console == 0){ uartctl(p, "z"); uartctl(p, ccfg); } if(p->special && uartenable(p) != nil) p->opens++; qunlock(p); p = p->next; } if(uartnuart){ /* * at 115200 baud, the 1024 char buffer takes 56 ms to process, * processing it every 22 ms should be fine. */ uarttimer = addclock0link(uartclock, 22); } } 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(UARTTYPE(c->qid.path) == Qdata) setlength(UARTID(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(UARTTYPE(c->qid.path)){ case Qctl: case Qdata: p = uart[UARTID(c->qid.path)]; qlock(p); if(p->opens == 0 && uartenable(p) == nil){ qunlock(p); c->flag &= ~COPEN; error(Enodev); } p->opens++; qunlock(p); break; } c->iounit = qiomaxatomic; return c; } static int uartdrained(void* arg) { Uart *p; p = arg; return qlen(p->oq) == 0 && p->op == p->oe; } static void uartdrainoutput(Uart *p) { if(!p->enabled || up == nil) return; p->drain = 1; if(waserror()){ p->drain = 0; nexterror(); } sleep(&p->r, uartdrained, p); poperror(); } static void uartclose(Chan *c) { Uart *p; if(c->qid.type & QTDIR) return; if((c->flag & COPEN) == 0) return; switch(UARTTYPE(c->qid.path)){ case Qdata: case Qctl: p = uart[UARTID(c->qid.path)]; qlock(p); if(--(p->opens) == 0){ qclose(p->iq); ilock(&p->rlock); p->ir = p->iw = p->istage; iunlock(&p->rlock); /* */ qhangup(p->oq, nil); if(!waserror()){ uartdrainoutput(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[UARTID(c->qid.path)]; switch(UARTTYPE(c->qid.path)){ case Qdata: return qread(p->iq, buf, n); case Qctl: return readnum(offset, buf, n, UARTID(c->qid.path), NUMSIZE); case Qstat: return (*p->phys->status)(p, buf, n, offset); } return 0; } static int setupcons(Uart *p, int on) { int r; static Lock conslk; static Queue *lastcons; r = 0; lock(&conslk); if(on && !p->console && lastcons == nil){ if(!p->enabled) uartenable(p); if(!p->enabled){ /* qopen will fail early in boot (no malloc) */ consuart = p; unlock(&conslk); return up == nil? 0: -1; } lastcons = kbdq; kbdq = p->iq; serialoq = p->oq; p->putc = kbdcr2nl; consuart = p; p->opens++; p->console = 1; }else if(!on && p->console){ kbdq = lastcons; lastcons = nil; serialoq = nil; p->putc = nil; consuart = nil; p->opens--; p->console = 0; } else r = -1; unlock(&conslk); return r; } int uartctl(Uart *p, char *cmd) { char *f[16]; int i, n, nf; nf = tokenize(cmd, f, nelem(f)); 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': uartdrainoutput(p); if((*p->phys->baud)(p, n) < 0) return -1; break; case 'C': case 'c': p->hup_dcd = n; break; case 'D': case 'd': uartdrainoutput(p); (*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': uartdrainoutput(p); (*p->phys->fifo)(p, n); break; case 'K': case 'k': uartdrainoutput(p); (*p->phys->dobreak)(p, n); break; case 'L':