193631029SDavid du Colombier #include "u.h" 293631029SDavid du Colombier #include "../port/lib.h" 393631029SDavid du Colombier #include "mem.h" 493631029SDavid du Colombier #include "dat.h" 593631029SDavid du Colombier #include "fns.h" 693631029SDavid du Colombier #include "io.h" 793631029SDavid du Colombier #include "../port/error.h" 893631029SDavid du Colombier 993631029SDavid du Colombier #include "../port/netif.h" 1093631029SDavid du Colombier 1193631029SDavid du Colombier enum 1293631029SDavid du Colombier { 1393631029SDavid du Colombier /* soft flow control chars */ 1493631029SDavid du Colombier CTLS= 023, 1593631029SDavid du Colombier CTLQ= 021, 1693631029SDavid du Colombier }; 1793631029SDavid du Colombier 1893631029SDavid du Colombier extern Dev uartdevtab; 1993631029SDavid du Colombier extern PhysUart* physuart[]; 2093631029SDavid du Colombier 2193631029SDavid du Colombier static Uart* uartlist; 2293631029SDavid du Colombier static Uart** uart; 2393631029SDavid du Colombier static int uartnuart; 2493631029SDavid du Colombier static Dirtab *uartdir; 2593631029SDavid du Colombier static int uartndir; 2693631029SDavid du Colombier static Timer *uarttimer; 2793631029SDavid du Colombier 2893631029SDavid du Colombier struct Uartalloc { 2993631029SDavid du Colombier Lock; 3093631029SDavid du Colombier Uart *elist; /* list of enabled interfaces */ 3193631029SDavid du Colombier } uartalloc; 3293631029SDavid du Colombier 3393631029SDavid du Colombier static void uartclock(void); 3493631029SDavid du Colombier static void uartflow(void*); 3593631029SDavid du Colombier 3693631029SDavid du Colombier /* 3793631029SDavid du Colombier * enable/disable uart and add/remove to list of enabled uarts 3893631029SDavid du Colombier */ 3993631029SDavid du Colombier //static 4093631029SDavid du Colombier Uart* 4193631029SDavid du Colombier uartenable(Uart *p) 4293631029SDavid du Colombier { 4393631029SDavid du Colombier Uart **l; 4493631029SDavid du Colombier 4593631029SDavid du Colombier if (up == nil) 4693631029SDavid du Colombier return p; /* too soon; try again later */ 4793631029SDavid du Colombier // return nil; 4893631029SDavid du Colombier 4993631029SDavid du Colombier if(p->iq == nil){ 5093631029SDavid du Colombier if((p->iq = qopen(8*1024, 0, uartflow, p)) == nil) 5193631029SDavid du Colombier return nil; 5293631029SDavid du Colombier } 5393631029SDavid du Colombier else 5493631029SDavid du Colombier qreopen(p->iq); 5593631029SDavid du Colombier if(p->oq == nil){ 5693631029SDavid du Colombier if((p->oq = qopen(8*1024, 0, uartkick, p)) == nil){ 5793631029SDavid du Colombier qfree(p->iq); 5893631029SDavid du Colombier p->iq = nil; 5993631029SDavid du Colombier return nil; 6093631029SDavid du Colombier } 6193631029SDavid du Colombier } 6293631029SDavid du Colombier else 6393631029SDavid du Colombier qreopen(p->oq); 6493631029SDavid du Colombier 6593631029SDavid du Colombier p->ir = p->istage; 6693631029SDavid du Colombier p->iw = p->istage; 6793631029SDavid du Colombier p->ie = &p->istage[Stagesize]; 6893631029SDavid du Colombier p->op = p->ostage; 6993631029SDavid du Colombier p->oe = p->ostage; 7093631029SDavid du Colombier 7193631029SDavid du Colombier p->hup_dsr = p->hup_dcd = 0; 7293631029SDavid du Colombier p->dsr = p->dcd = 0; 7393631029SDavid du Colombier 7493631029SDavid du Colombier /* assume we can send */ 7593631029SDavid du Colombier p->cts = 1; 7693631029SDavid du Colombier p->ctsbackoff = 0; 7793631029SDavid du Colombier 7893631029SDavid du Colombier if (up) { 7993631029SDavid du Colombier if(p->bits == 0) 8093631029SDavid du Colombier uartctl(p, "l8"); 8193631029SDavid du Colombier if(p->stop == 0) 8293631029SDavid du Colombier uartctl(p, "s1"); 8393631029SDavid du Colombier if(p->parity == 0) 8493631029SDavid du Colombier uartctl(p, "pn"); 8593631029SDavid du Colombier if(p->baud == 0) 8693631029SDavid du Colombier uartctl(p, "b9600"); 8793631029SDavid du Colombier (*p->phys->enable)(p, 1); 8893631029SDavid du Colombier } 8993631029SDavid du Colombier 9093631029SDavid du Colombier /* 9193631029SDavid du Colombier * use ilock because uartclock can otherwise interrupt here 9293631029SDavid du Colombier * and would hang on an attempt to lock uartalloc. 9393631029SDavid du Colombier */ 9493631029SDavid du Colombier ilock(&uartalloc); 9593631029SDavid du Colombier for(l = &uartalloc.elist; *l; l = &(*l)->elist){ 9693631029SDavid du Colombier if(*l == p) 9793631029SDavid du Colombier break; 9893631029SDavid du Colombier } 9993631029SDavid du Colombier if(*l == 0){ 10093631029SDavid du Colombier p->elist = uartalloc.elist; 10193631029SDavid du Colombier uartalloc.elist = p; 10293631029SDavid du Colombier } 10393631029SDavid du Colombier p->enabled = 1; 10493631029SDavid du Colombier iunlock(&uartalloc); 10593631029SDavid du Colombier 10693631029SDavid du Colombier return p; 10793631029SDavid du Colombier } 10893631029SDavid du Colombier 10993631029SDavid du Colombier static void 11093631029SDavid du Colombier uartdisable(Uart *p) 11193631029SDavid du Colombier { 11293631029SDavid du Colombier Uart **l; 11393631029SDavid du Colombier 11493631029SDavid du Colombier (*p->phys->disable)(p); 11593631029SDavid du Colombier 11693631029SDavid du Colombier ilock(&uartalloc); 11793631029SDavid du Colombier for(l = &uartalloc.elist; *l; l = &(*l)->elist){ 11893631029SDavid du Colombier if(*l == p){ 11993631029SDavid du Colombier *l = p->elist; 12093631029SDavid du Colombier break; 12193631029SDavid du Colombier } 12293631029SDavid du Colombier } 12393631029SDavid du Colombier p->enabled = 0; 12493631029SDavid du Colombier iunlock(&uartalloc); 12593631029SDavid du Colombier } 12693631029SDavid du Colombier 12793631029SDavid du Colombier void 12893631029SDavid du Colombier uartmouse(Uart* p, int (*putc)(Queue*, int), int setb1200) 12993631029SDavid du Colombier { 13093631029SDavid du Colombier qlock(p); 13193631029SDavid du Colombier if(p->opens++ == 0 && uartenable(p) == nil){ 13293631029SDavid du Colombier qunlock(p); 13393631029SDavid du Colombier error(Enodev); 13493631029SDavid du Colombier } 13593631029SDavid du Colombier if(setb1200) 13693631029SDavid du Colombier uartctl(p, "b1200"); 13793631029SDavid du Colombier p->putc = putc; 13893631029SDavid du Colombier p->special = 1; 13993631029SDavid du Colombier qunlock(p); 14093631029SDavid du Colombier } 14193631029SDavid du Colombier 14293631029SDavid du Colombier void 14393631029SDavid du Colombier uartsetmouseputc(Uart* p, int (*putc)(Queue*, int)) 14493631029SDavid du Colombier { 14593631029SDavid du Colombier qlock(p); 14693631029SDavid du Colombier if(p->opens == 0 || p->special == 0){ 14793631029SDavid du Colombier qunlock(p); 14893631029SDavid du Colombier error(Enodev); 14993631029SDavid du Colombier } 15093631029SDavid du Colombier p->putc = putc; 15193631029SDavid du Colombier qunlock(p); 15293631029SDavid du Colombier } 15393631029SDavid du Colombier 15493631029SDavid du Colombier static void 15593631029SDavid du Colombier setlength(int i) 15693631029SDavid du Colombier { 15793631029SDavid du Colombier Uart *p; 15893631029SDavid du Colombier 15993631029SDavid du Colombier if(i > 0){ 16093631029SDavid du Colombier p = uart[i]; 16193631029SDavid du Colombier if(p && p->opens && p->iq) 16293631029SDavid du Colombier uartdir[1+3*i].length = qlen(p->iq); 16393631029SDavid du Colombier } else for(i = 0; i < uartnuart; i++){ 16493631029SDavid du Colombier p = uart[i]; 16593631029SDavid du Colombier if(p && p->opens && p->iq) 16693631029SDavid du Colombier uartdir[1+3*i].length = qlen(p->iq); 16793631029SDavid du Colombier } 16893631029SDavid du Colombier } 16993631029SDavid du Colombier 17093631029SDavid du Colombier /* 17193631029SDavid du Colombier * set up the '#t' directory 17293631029SDavid du Colombier */ 17393631029SDavid du Colombier static void 17493631029SDavid du Colombier uartreset(void) 17593631029SDavid du Colombier { 17693631029SDavid du Colombier int i; 17793631029SDavid du Colombier Dirtab *dp; 17893631029SDavid du Colombier Uart *p, *tail; 17993631029SDavid du Colombier 18093631029SDavid du Colombier tail = nil; 18193631029SDavid du Colombier for(i = 0; physuart[i] != nil; i++){ 18293631029SDavid du Colombier if(physuart[i]->pnp == nil) 18393631029SDavid du Colombier continue; 18493631029SDavid du Colombier if((p = physuart[i]->pnp()) == nil) 18593631029SDavid du Colombier continue; 18693631029SDavid du Colombier if(uartlist != nil) 18793631029SDavid du Colombier tail->next = p; 18893631029SDavid du Colombier else 18993631029SDavid du Colombier uartlist = p; 19093631029SDavid du Colombier for(tail = p; tail->next != nil; tail = tail->next) 19193631029SDavid du Colombier uartnuart++; 19293631029SDavid du Colombier uartnuart++; 19393631029SDavid du Colombier } 19493631029SDavid du Colombier 19593631029SDavid du Colombier if(uartnuart) 19693631029SDavid du Colombier uart = xalloc(uartnuart*sizeof(Uart*)); 19793631029SDavid du Colombier 19893631029SDavid du Colombier uartndir = 1 + 3*uartnuart; 19993631029SDavid du Colombier uartdir = xalloc(uartndir * sizeof(Dirtab)); 20093631029SDavid du Colombier if (uart == nil || uartdir == nil) 20193631029SDavid du Colombier panic("uartreset: no memory"); 20293631029SDavid du Colombier dp = uartdir; 20393631029SDavid du Colombier strcpy(dp->name, "."); 20493631029SDavid du Colombier mkqid(&dp->qid, 0, 0, QTDIR); 20593631029SDavid du Colombier dp->length = 0; 20693631029SDavid du Colombier dp->perm = DMDIR|0555; 20793631029SDavid du Colombier dp++; 20893631029SDavid du Colombier p = uartlist; 20993631029SDavid du Colombier for(i = 0; i < uartnuart; i++){ 21093631029SDavid du Colombier /* 3 directory entries per port */ 211*57d98441SDavid du Colombier snprint(dp->name, sizeof dp->name, "eia%d", i); 21293631029SDavid du Colombier dp->qid.path = NETQID(i, Ndataqid); 21393631029SDavid du Colombier dp->perm = 0660; 21493631029SDavid du Colombier dp++; 215*57d98441SDavid du Colombier snprint(dp->name, sizeof dp->name, "eia%dctl", i); 21693631029SDavid du Colombier dp->qid.path = NETQID(i, Nctlqid); 21793631029SDavid du Colombier dp->perm = 0660; 21893631029SDavid du Colombier dp++; 219*57d98441SDavid du Colombier snprint(dp->name, sizeof dp->name, "eia%dstatus", i); 22093631029SDavid du Colombier dp->qid.path = NETQID(i, Nstatqid); 22193631029SDavid du Colombier dp->perm = 0444; 22293631029SDavid du Colombier dp++; 22393631029SDavid du Colombier 22493631029SDavid du Colombier uart[i] = p; 22593631029SDavid du Colombier p->dev = i; 22693631029SDavid du Colombier if(p->console || p->special){ 22793631029SDavid du Colombier if(uartenable(p) != nil){ 22893631029SDavid du Colombier if(p->console && up){ 22993631029SDavid du Colombier kbdq = p->iq; 23093631029SDavid du Colombier serialoq = p->oq; 23193631029SDavid du Colombier p->putc = kbdcr2nl; 23293631029SDavid du Colombier } 23393631029SDavid du Colombier p->opens++; 23493631029SDavid du Colombier } 23593631029SDavid du Colombier } 23693631029SDavid du Colombier p = p->next; 23793631029SDavid du Colombier } 23893631029SDavid du Colombier 23993631029SDavid du Colombier if(uartnuart){ 24093631029SDavid du Colombier /* 24193631029SDavid du Colombier * at 115200 baud, the 1024 char buffer takes 56 ms to process, 24293631029SDavid du Colombier * processing it every 22 ms should be fine. 24393631029SDavid du Colombier */ 24493631029SDavid du Colombier uarttimer = addclock0link(uartclock, 22); 24593631029SDavid du Colombier } 24693631029SDavid du Colombier } 24793631029SDavid du Colombier 24893631029SDavid du Colombier 24993631029SDavid du Colombier static Chan* 25093631029SDavid du Colombier uartattach(char *spec) 25193631029SDavid du Colombier { 25293631029SDavid du Colombier return devattach('t', spec); 25393631029SDavid du Colombier } 25493631029SDavid du Colombier 25593631029SDavid du Colombier static Walkqid* 25693631029SDavid du Colombier uartwalk(Chan *c, Chan *nc, char **name, int nname) 25793631029SDavid du Colombier { 25893631029SDavid du Colombier return devwalk(c, nc, name, nname, uartdir, uartndir, devgen); 25993631029SDavid du Colombier } 26093631029SDavid du Colombier 26193631029SDavid du Colombier static int 26293631029SDavid du Colombier uartstat(Chan *c, uchar *dp, int n) 26393631029SDavid du Colombier { 26493631029SDavid du Colombier if(NETTYPE(c->qid.path) == Ndataqid) 26593631029SDavid du Colombier setlength(NETID(c->qid.path)); 26693631029SDavid du Colombier return devstat(c, dp, n, uartdir, uartndir, devgen); 26793631029SDavid du Colombier } 26893631029SDavid du Colombier 26993631029SDavid du Colombier static Chan* 27093631029SDavid du Colombier uartopen(Chan *c, int omode) 27193631029SDavid du Colombier { 27293631029SDavid du Colombier Uart *p; 27393631029SDavid du Colombier 27493631029SDavid du Colombier c = devopen(c, omode, uartdir, uartndir, devgen); 27593631029SDavid du Colombier 27693631029SDavid du Colombier switch(NETTYPE(c->qid.path)){ 27793631029SDavid du Colombier case Nctlqid: 27893631029SDavid du Colombier case Ndataqid: 27993631029SDavid du Colombier p = uart[NETID(c->qid.path)]; 28093631029SDavid du Colombier qlock(p); 28193631029SDavid du Colombier if(p->opens++ == 0 && uartenable(p) == nil){ 28293631029SDavid du Colombier qunlock(p); 28393631029SDavid du Colombier c->flag &= ~COPEN; 28493631029SDavid du Colombier error(Enodev); 28593631029SDavid du Colombier } 28693631029SDavid du Colombier qunlock(p); 28793631029SDavid du Colombier break; 28893631029SDavid du Colombier } 28993631029SDavid du Colombier 29093631029SDavid du Colombier c->iounit = qiomaxatomic; 29193631029SDavid du Colombier return c; 29293631029SDavid du Colombier } 29393631029SDavid du Colombier 29493631029SDavid du Colombier static int 29593631029SDavid du Colombier uartdrained(void* arg) 29693631029SDavid du Colombier { 29793631029SDavid du Colombier Uart *p; 29893631029SDavid du Colombier 29993631029SDavid du Colombier p = arg; 30093631029SDavid du Colombier return qlen(p->oq) == 0 && p->op == p->oe; 30193631029SDavid du Colombier } 30293631029SDavid du Colombier 30393631029SDavid du Colombier static void 30493631029SDavid du Colombier uartdrainoutput(Uart *p) 30593631029SDavid du Colombier { 30693631029SDavid du Colombier if(!p->enabled || up == nil) 30793631029SDavid du Colombier return; 30893631029SDavid du Colombier 30993631029SDavid du Colombier p->drain = 1; 31093631029SDavid du Colombier if(waserror()){ 31193631029SDavid du Colombier p->drain = 0; 31293631029SDavid du Colombier nexterror(); 31393631029SDavid du Colombier } 31493631029SDavid du Colombier sleep(&p->r, uartdrained, p); 31593631029SDavid du Colombier poperror(); 31693631029SDavid du Colombier } 31793631029SDavid du Colombier 31893631029SDavid du Colombier static void 31993631029SDavid du Colombier uartclose(Chan *c) 32093631029SDavid du Colombier { 32193631029SDavid du Colombier Uart *p; 32293631029SDavid du Colombier 32393631029SDavid du Colombier if(c->qid.type & QTDIR) 32493631029SDavid du Colombier return; 32593631029SDavid du Colombier if((c->flag & COPEN) == 0) 32693631029SDavid du Colombier return; 32793631029SDavid du Colombier switch(NETTYPE(c->qid.path)){ 32893631029SDavid du Colombier case Ndataqid: 32993631029SDavid du Colombier case Nctlqid: 33093631029SDavid du Colombier p = uart[NETID(c->qid.path)]; 33193631029SDavid du Colombier qlock(p); 33293631029SDavid du Colombier if(--(p->opens) == 0){ 33393631029SDavid du Colombier qclose(p->iq); 33493631029SDavid du Colombier ilock(&p->rlock); 33593631029SDavid du Colombier p->ir = p->iw = p->istage; 33693631029SDavid du Colombier iunlock(&p->rlock); 33793631029SDavid du Colombier 33893631029SDavid du Colombier /* 33993631029SDavid du Colombier */ 34093631029SDavid du Colombier qhangup(p->oq, nil); 34193631029SDavid du Colombier if(!waserror()){ 34293631029SDavid du Colombier uartdrainoutput(p); 34393631029SDavid du Colombier poperror(); 34493631029SDavid du Colombier } 34593631029SDavid du Colombier qclose(p->oq); 34693631029SDavid du Colombier uartdisable(p); 34793631029SDavid du Colombier p->dcd = p->dsr = p->dohup = 0; 34893631029SDavid du Colombier } 34993631029SDavid du Colombier qunlock(p); 35093631029SDavid du Colombier break; 35193631029SDavid du Colombier } 35293631029SDavid du Colombier } 35393631029SDavid du Colombier 35493631029SDavid du Colombier static long 35593631029SDavid du Colombier uartread(Chan *c, void *buf, long n, vlong off) 35693631029SDavid du Colombier { 35793631029SDavid du Colombier Uart *p; 35893631029SDavid du Colombier ulong offset = off; 35993631029SDavid du Colombier 36093631029SDavid du Colombier if(c->qid.type & QTDIR){ 36193631029SDavid du Colombier setlength(-1); 36293631029SDavid du Colombier return devdirread(c, buf, n, uartdir, uartndir, devgen); 36393631029SDavid du Colombier } 36493631029SDavid du Colombier 36593631029SDavid du Colombier p = uart[NETID(c->qid.path)]; 36693631029SDavid du Colombier switch(NETTYPE(c->qid.path)){ 36793631029SDavid du Colombier case Ndataqid: 36893631029SDavid du Colombier return qread(p->iq, buf, n); 36993631029SDavid du Colombier case Nctlqid: 37093631029SDavid du Colombier return readnum(offset, buf, n, NETID(c->qid.path), NUMSIZE); 37193631029SDavid du Colombier case Nstatqid: 37293631029SDavid du Colombier return (*p->phys->status)(p, buf, n, offset); 37393631029SDavid du Colombier } 37493631029SDavid du Colombier 37593631029SDavid du Colombier return 0; 37693631029SDavid du Colombier } 37793631029SDavid du Colombier 37893631029SDavid du Colombier int 37993631029SDavid du Colombier uartctl(Uart *p, char *cmd) 38093631029SDavid du Colombier { 38193631029SDavid du Colombier char *f[16]; 38293631029SDavid du Colombier int i, n, nf; 38393631029SDavid du Colombier 38493631029SDavid du Colombier nf = tokenize(cmd, f, nelem(f)); 38593631029SDavid du Colombier for(i = 0; i < nf; i++){ 38693631029SDavid du Colombier if(strncmp(f[i], "break", 5) == 0){ 38793631029SDavid du Colombier (*p->phys->dobreak)(p, 0); 38893631029SDavid du Colombier continue; 38993631029SDavid du Colombier } 39093631029SDavid du Colombier 39193631029SDavid du Colombier n = atoi(f[i]+1); 39293631029SDavid du Colombier switch(*f[i]){ 39393631029SDavid du Colombier case 'B': 39493631029SDavid du Colombier case 'b': 39593631029SDavid du Colombier uartdrainoutput(p); 39693631029SDavid du Colombier if((*p->phys->baud)(p, n) < 0) 39793631029SDavid du Colombier return -1; 39893631029SDavid du Colombier break; 39993631029SDavid du Colombier case 'C': 40093631029SDavid du Colombier case 'c': 40193631029SDavid du Colombier p->hup_dcd = n; 40293631029SDavid du Colombier break; 40393631029SDavid du Colombier case 'D': 40493631029SDavid du Colombier case 'd': 40593631029SDavid du Colombier uartdrainoutput(p); 40693631029SDavid du Colombier (*p->phys->dtr)(p, n); 40793631029SDavid du Colombier break; 40893631029SDavid du Colombier case 'E': 40993631029SDavid du Colombier case 'e': 41093631029SDavid du Colombier p->hup_dsr = n; 41193631029SDavid du Colombier break; 41293631029SDavid du Colombier case 'f': 41393631029SDavid du Colombier case 'F': 41493631029SDavid du Colombier if(p->oq != nil) 41593631029SDavid du Colombier qflush(p->oq); 41693631029SDavid du Colombier break; 41793631029SDavid du Colombier case 'H': 41893631029SDavid du Colombier case 'h': 41993631029SDavid du Colombier if(p->iq != nil) 42093631029SDavid du Colombier qhangup(p->iq, 0); 42193631029SDavid du Colombier if(p->oq != nil) 42293631029SDavid du Colombier qhangup(p->oq, 0); 42393631029SDavid du Colombier break; 42493631029SDavid du Colombier case 'i': 42593631029SDavid du Colombier case 'I': 42693631029SDavid du Colombier uartdrainoutput(p); 42793631029SDavid du Colombier (*p->phys->fifo)(p, n); 42893631029SDavid du Colombier break; 42993631029SDavid du Colombier case 'K': 43093631029SDavid du Colombier case 'k': 43193631029SDavid du Colombier uartdrainoutput(p); 43293631029SDavid du Colombier (*p->phys->dobreak)(p, n); 43393631029SDavid du Colombier break; 43493631029SDavid du Colombier case 'L': 43593631029SDavid du Colombier case 'l': 43693631029SDavid du Colombier uartdrainoutput(p); 43793631029SDavid du Colombier if((*p->phys->bits)(p, n) < 0) 43893631029SDavid du Colombier return -1; 43993631029SDavid du Colombier break; 44093631029SDavid du Colombier case 'm': 44193631029SDavid du Colombier case 'M': 44293631029SDavid du Colombier uartdrainoutput(p); 44393631029SDavid du Colombier (*p->phys->modemctl)(p, n); 44493631029SDavid du Colombier break; 44593631029SDavid du Colombier case 'n': 44693631029SDavid du Colombier case 'N': 44793631029SDavid du Colombier if(p->oq != nil) 44893631029SDavid du Colombier qnoblock(p->oq, n); 44993631029SDavid du Colombier break; 45093631029SDavid du Colombier case 'P': 45193631029SDavid du Colombier case 'p': 45293631029SDavid du Colombier uartdrainoutput(p); 45393631029SDavid du Colombier if((*p->phys->parity)(p, *(f[i]+1)) < 0) 45493631029SDavid du Colombier return -1; 45593631029SDavid du Colombier break; 45693631029SDavid du Colombier case 'Q': 45793631029SDavid du Colombier case 'q': 45893631029SDavid du Colombier if(p->iq != nil) 45993631029SDavid du Colombier qsetlimit(p->iq, n); 46093631029SDavid du Colombier if(p->oq != nil) 46193631029SDavid du Colombier qsetlimit(p->oq, n); 46293631029SDavid du Colombier break; 46393631029SDavid du Colombier case 'R': 46493631029SDavid du Colombier case 'r': 46593631029SDavid du Colombier uartdrainoutput(p); 46693631029SDavid du Colombier (*p->phys->rts)(p, n); 46793631029SDavid du Colombier break; 46893631029SDavid du Colombier case 'S': 46993631029SDavid du Colombier case 's': 47093631029SDavid du Colombier uartdrainoutput(p); 47193631029SDavid du Colombier if((*p->phys->stop)(p, n) < 0) 47293631029SDavid du Colombier return -1; 47393631029SDavid du Colombier break; 47493631029SDavid du Colombier case 'W': 47593631029SDavid du Colombier case 'w': 47693631029SDavid du Colombier if(uarttimer == nil || n < 1) 47793631029SDavid du Colombier return -1; 47893631029SDavid du Colombier uarttimer->tns = (vlong)n * 100000LL; 47993631029SDavid du Colombier break; 48093631029SDavid du Colombier case 'X': 48193631029SDavid du Colombier case 'x': 48293631029SDavid du Colombier if(p->enabled){ 48393631029SDavid du Colombier ilock(&p->tlock); 48493631029SDavid du Colombier p->xonoff = n; 48593631029SDavid du Colombier iunlock(&p->tlock); 48693631029SDavid du Colombier } 48793631029SDavid du Colombier break; 48893631029SDavid du Colombier } 48993631029SDavid du Colombier } 49093631029SDavid du Colombier return 0; 49193631029SDavid du Colombier } 49293631029SDavid du Colombier 49393631029SDavid du Colombier static long 49493631029SDavid du Colombier uartwrite(Chan *c, void *buf, long n, vlong) 49593631029SDavid du Colombier { 49693631029SDavid du Colombier Uart *p; 49793631029SDavid du Colombier char *cmd; 49893631029SDavid du Colombier 49993631029SDavid du Colombier if(c->qid.type & QTDIR) 50093631029SDavid du Colombier error(Eperm); 50193631029SDavid du Colombier 50293631029SDavid du Colombier p = uart[NETID(c->qid.path)]; 50393631029SDavid du Colombier 50493631029SDavid du Colombier switch(NETTYPE(c->qid.path)){ 50593631029SDavid du Colombier case Ndataqid: 50693631029SDavid du Colombier qlock(p); 50793631029SDavid du Colombier if(waserror()){ 50893631029SDavid du Colombier qunlock(p); 50993631029SDavid du Colombier nexterror(); 51093631029SDavid du Colombier } 51193631029SDavid du Colombier 51293631029SDavid du Colombier n = qwrite(p->oq, buf, n); 51393631029SDavid du Colombier 51493631029SDavid du Colombier qunlock(p); 51593631029SDavid du Colombier poperror(); 51693631029SDavid du Colombier break; 51793631029SDavid du Colombier case Nctlqid: 51893631029SDavid du Colombier cmd = malloc(n+1); 51993631029SDavid du Colombier memmove(cmd, buf, n); 52093631029SDavid du Colombier cmd[n] = 0; 52193631029SDavid du Colombier qlock(p); 52293631029SDavid du Colombier if(waserror()){ 52393631029SDavid du Colombier qunlock(p); 52493631029SDavid du Colombier free(cmd); 52593631029SDavid du Colombier nexterror(); 52693631029SDavid du Colombier } 52793631029SDavid du Colombier 52893631029SDavid du Colombier /* let output drain */ 52993631029SDavid du Colombier if(uartctl(p, cmd) < 0) 53093631029SDavid du Colombier error(Ebadarg); 53193631029SDavid du Colombier 53293631029SDavid du Colombier qunlock(p); 53393631029SDavid du Colombier poperror(); 53493631029SDavid du Colombier free(cmd); 53593631029SDavid du Colombier break; 53693631029SDavid du Colombier } 53793631029SDavid du Colombier 53893631029SDavid du Colombier return n; 53993631029SDavid du Colombier } 54093631029SDavid du Colombier 54193631029SDavid du Colombier static int 54293631029SDavid du Colombier uartwstat(Chan *c, uchar *dp, int n) 54393631029SDavid du Colombier { 54493631029SDavid du Colombier Dir d; 54593631029SDavid du Colombier Dirtab *dt; 54693631029SDavid du Colombier 54793631029SDavid du Colombier if(!iseve()) 54893631029SDavid du Colombier error(Eperm); 54993631029SDavid du Colombier if(QTDIR & c->qid.type) 55093631029SDavid du Colombier error(Eperm); 55193631029SDavid du Colombier if(NETTYPE(c->qid.path) == Nstatqid) 55293631029SDavid du Colombier error(Eperm); 55393631029SDavid du Colombier 55493631029SDavid du Colombier dt = &uartdir[1 + 3 * NETID(c->qid.path)]; 55593631029SDavid du Colombier n = convM2D(dp, n, &d, nil); 55693631029SDavid du Colombier if(n == 0) 55793631029SDavid du Colombier error(Eshortstat); 55893631029SDavid du Colombier if(d.mode != ~0UL) 55993631029SDavid du Colombier dt[0].perm = dt[1].perm = d.mode; 56093631029SDavid du Colombier return n; 56193631029SDavid du Colombier } 56293631029SDavid du Colombier 56393631029SDavid du Colombier void 56493631029SDavid du Colombier uartpower(int on) 56593631029SDavid du Colombier { 56693631029SDavid du Colombier Uart *p; 56793631029SDavid du Colombier 56893631029SDavid du Colombier for(p = uartlist; p != nil; p = p->next) { 56993631029SDavid du Colombier if(p->phys->power) 57093631029SDavid du Colombier (*p->phys->power)(p, on); 57193631029SDavid du Colombier } 57293631029SDavid du Colombier } 57393631029SDavid du Colombier 57493631029SDavid du Colombier Dev uartdevtab = { 57593631029SDavid du Colombier 't', 57693631029SDavid du Colombier "uart", 57793631029SDavid du Colombier 57893631029SDavid du Colombier uartreset, 57993631029SDavid du Colombier devinit, 58093631029SDavid du Colombier devshutdown, 58193631029SDavid du Colombier uartattach, 58293631029SDavid du Colombier uartwalk, 58393631029SDavid du Colombier uartstat, 58493631029SDavid du Colombier uartopen, 58593631029SDavid du Colombier devcreate, 58693631029SDavid du Colombier uartclose, 58793631029SDavid du Colombier uartread, 58893631029SDavid du Colombier devbread, 58993631029SDavid du Colombier uartwrite, 59093631029SDavid du Colombier devbwrite, 59193631029SDavid du Colombier devremove, 59293631029SDavid du Colombier uartwstat, 59393631029SDavid du Colombier uartpower, 59493631029SDavid du Colombier }; 59593631029SDavid du Colombier 59693631029SDavid du Colombier /* 59793631029SDavid du Colombier * restart input if it's off 59893631029SDavid du Colombier */ 59993631029SDavid du Colombier static void 60093631029SDavid du Colombier uartflow(void *v) 60193631029SDavid du Colombier { 60293631029SDavid du Colombier Uart *p; 60393631029SDavid du Colombier 60493631029SDavid du Colombier p = v; 60593631029SDavid du Colombier if(p->modem) 60693631029SDavid du Colombier (*p->phys->rts)(p, 1); 60793631029SDavid du Colombier } 60893631029SDavid du Colombier 60993631029SDavid du Colombier /* 61093631029SDavid du Colombier * put some bytes into the local queue to avoid calling 61193631029SDavid du Colombier * qconsume for every character 61293631029SDavid du Colombier */ 61393631029SDavid du Colombier int 61493631029SDavid du Colombier uartstageoutput(Uart *p) 61593631029SDavid du Colombier { 61693631029SDavid du Colombier int n; 61793631029SDavid du Colombier 61893631029SDavid du Colombier n = qconsume(p->oq, p->ostage, Stagesize); 61993631029SDavid du Colombier if(n <= 0) 62093631029SDavid du Colombier // n = 0; /* experiment */ 62193631029SDavid du Colombier return 0; 62293631029SDavid du Colombier p->op = p->ostage; 62393631029SDavid du Colombier p->oe = p->ostage + n; 62493631029SDavid du Colombier return n; 62593631029SDavid du Colombier } 62693631029SDavid du Colombier 62793631029SDavid du Colombier /* 62893631029SDavid du Colombier * restart output 62993631029SDavid du Colombier */ 63093631029SDavid du Colombier void 63193631029SDavid du Colombier uartkick(void *v) 63293631029SDavid du Colombier { 63393631029SDavid du Colombier Uart *p = v; 63493631029SDavid du Colombier 63593631029SDavid du Colombier if(p->blocked) 63693631029SDavid du Colombier return; 63793631029SDavid du Colombier 63893631029SDavid du Colombier ilock(&p->tlock); 63993631029SDavid du Colombier (*p->phys->kick)(p); 64093631029SDavid du Colombier iunlock(&p->tlock); 64193631029SDavid du Colombier 64293631029SDavid du Colombier if(p->drain && uartdrained(p)){ 64393631029SDavid du Colombier p->drain = 0; 64493631029SDavid du Colombier wakeup(&p->r); 64593631029SDavid du Colombier } 64693631029SDavid du Colombier } 64793631029SDavid du Colombier 64893631029SDavid du Colombier /* 64993631029SDavid du Colombier * Move data from the interrupt staging area to 65093631029SDavid du Colombier * the input Queue. 65193631029SDavid du Colombier */ 65293631029SDavid du Colombier static void 65393631029SDavid du Colombier uartstageinput(Uart *p) 65493631029SDavid du Colombier { 65593631029SDavid du Colombier int n; 65693631029SDavid du Colombier uchar *ir, *iw; 65793631029SDavid du Colombier 65893631029SDavid du Colombier while(p->ir != p->iw){ 65993631029SDavid du Colombier ir = p->ir; 66093631029SDavid du Colombier if(p->ir > p->iw){ 66193631029SDavid du Colombier iw = p->ie; 66293631029SDavid du Colombier p->ir = p->istage; 66393631029SDavid du Colombier } 66493631029SDavid du Colombier else{ 66593631029SDavid du Colombier iw = p->iw; 66693631029SDavid du Colombier p->ir = p->iw; 66793631029SDavid du Colombier } 66893631029SDavid du Colombier if((n = qproduce(p->iq, ir, iw - ir)) < 0){ 66993631029SDavid du Colombier p->serr++; 67093631029SDavid du Colombier (*p->phys->rts)(p, 0); 67193631029SDavid du Colombier } 67293631029SDavid du Colombier else if(n == 0) 67393631029SDavid du Colombier p->berr++; 67493631029SDavid du Colombier } 67593631029SDavid du Colombier } 67693631029SDavid du Colombier 67793631029SDavid du Colombier /* 67893631029SDavid du Colombier * receive a character at interrupt time 67993631029SDavid du Colombier */ 68093631029SDavid du Colombier void 68193631029SDavid du Colombier uartrecv(Uart *p, char ch) 68293631029SDavid du Colombier { 68393631029SDavid du Colombier uchar *next; 68493631029SDavid du Colombier 68593631029SDavid du Colombier /* software flow control */ 68693631029SDavid du Colombier if(p->xonoff){ 68793631029SDavid du Colombier if(ch == CTLS){ 68893631029SDavid du Colombier p->blocked = 1; 68993631029SDavid du Colombier }else if(ch == CTLQ){ 69093631029SDavid du Colombier p->blocked = 0; 69193631029SDavid du Colombier p->ctsbackoff = 2; /* clock gets output going again */ 69293631029SDavid du Colombier } 69393631029SDavid du Colombier } 69493631029SDavid du Colombier 69593631029SDavid du Colombier /* receive the character */ 69693631029SDavid du Colombier if(p->putc) 69793631029SDavid du Colombier p->putc(p->iq, ch); 69893631029SDavid du Colombier else if (p->iw) { /* maybe the line isn't enabled yet */ 69993631029SDavid du Colombier ilock(&p->rlock); 70093631029SDavid du Colombier next = p->iw + 1; 70193631029SDavid du Colombier if(next == p->ie) 70293631029SDavid du Colombier next = p->istage; 70393631029SDavid du Colombier if(next == p->ir) 70493631029SDavid du Colombier uartstageinput(p); 70593631029SDavid du Colombier if(next != p->ir){ 70693631029SDavid du Colombier *p->iw = ch; 70793631029SDavid du Colombier p->iw = next; 70893631029SDavid du Colombier } 70993631029SDavid du Colombier iunlock(&p->rlock); 71093631029SDavid du Colombier } 71193631029SDavid du Colombier } 71293631029SDavid du Colombier 71393631029SDavid du Colombier /* 71493631029SDavid du Colombier * we save up input characters till clock time to reduce 71593631029SDavid du Colombier * per character interrupt overhead. 71693631029SDavid du Colombier */ 71793631029SDavid du Colombier static void 71893631029SDavid du Colombier uartclock(void) 71993631029SDavid du Colombier { 72093631029SDavid du Colombier Uart *p; 72193631029SDavid du Colombier 72293631029SDavid du Colombier ilock(&uartalloc); 72393631029SDavid du Colombier for(p = uartalloc.elist; p; p = p->elist){ 72493631029SDavid du Colombier 72593631029SDavid du Colombier /* this hopefully amortizes cost of qproduce to many chars */ 72693631029SDavid du Colombier if(p->iw != p->ir){ 72793631029SDavid du Colombier ilock(&p->rlock); 72893631029SDavid du Colombier uartstageinput(p); 72993631029SDavid du Colombier iunlock(&p->rlock); 73093631029SDavid du Colombier } 73193631029SDavid du Colombier 73293631029SDavid du Colombier /* hang up if requested */ 73393631029SDavid du Colombier if(p->dohup){ 73493631029SDavid du Colombier qhangup(p->iq, 0); 73593631029SDavid du Colombier qhangup(p->oq, 0); 73693631029SDavid du Colombier p->dohup = 0; 73793631029SDavid du Colombier } 73893631029SDavid du Colombier 73993631029SDavid du Colombier /* this adds hysteresis to hardware/software flow control */ 74093631029SDavid du Colombier if(p->ctsbackoff){ 74193631029SDavid du Colombier ilock(&p->tlock); 74293631029SDavid du Colombier if(p->ctsbackoff){ 74393631029SDavid du Colombier if(--(p->ctsbackoff) == 0) 74493631029SDavid du Colombier (*p->phys->kick)(p); 74593631029SDavid du Colombier } 74693631029SDavid du Colombier iunlock(&p->tlock); 74793631029SDavid du Colombier } 748bacfa46cSDavid du Colombier uartkick(p); /* keep it moving */ 74993631029SDavid du Colombier } 75093631029SDavid du Colombier iunlock(&uartalloc); 75193631029SDavid du Colombier } 75293631029SDavid du Colombier 75393631029SDavid du Colombier /* 75493631029SDavid du Colombier * polling console input, output 75593631029SDavid du Colombier */ 75693631029SDavid du Colombier 75793631029SDavid du Colombier Uart* consuart; 75893631029SDavid du Colombier 75993631029SDavid du Colombier int 76093631029SDavid du Colombier uartgetc(void) 76193631029SDavid du Colombier { 76293631029SDavid du Colombier if(consuart == nil || consuart->phys->getc == nil) 76393631029SDavid du Colombier return -1; 76493631029SDavid du Colombier return consuart->phys->getc(consuart); 76593631029SDavid du Colombier } 76693631029SDavid du Colombier 76793631029SDavid du Colombier void 76893631029SDavid du Colombier uartputc(int c) 76993631029SDavid du Colombier { 77093631029SDavid du Colombier if(consuart == nil || consuart->phys->putc == nil) 77193631029SDavid du Colombier return; 77293631029SDavid du Colombier consuart->phys->putc(consuart, c); 77393631029SDavid du Colombier } 77493631029SDavid du Colombier 77593631029SDavid du Colombier void 77693631029SDavid du Colombier uartputs(char *s, int n) 77793631029SDavid du Colombier { 77893631029SDavid du Colombier char *e; 77993631029SDavid du Colombier 78093631029SDavid du Colombier if(consuart == nil || consuart->phys->putc == nil) 78193631029SDavid du Colombier return; 78293631029SDavid du Colombier 78393631029SDavid du Colombier e = s+n; 78493631029SDavid du Colombier for(; s<e; s++){ 78593631029SDavid du Colombier if(*s == '\n') 78693631029SDavid du Colombier consuart->phys->putc(consuart, '\r'); 78793631029SDavid du Colombier consuart->phys->putc(consuart, *s); 78893631029SDavid du Colombier } 78993631029SDavid du Colombier } 790