1*3de6a9c0SDavid du Colombier #include "u.h" 2*3de6a9c0SDavid du Colombier #include "../port/lib.h" 3*3de6a9c0SDavid du Colombier #include "mem.h" 4*3de6a9c0SDavid du Colombier #include "dat.h" 5*3de6a9c0SDavid du Colombier #include "fns.h" 6*3de6a9c0SDavid du Colombier #include "io.h" 7*3de6a9c0SDavid du Colombier #include "../port/error.h" 8*3de6a9c0SDavid du Colombier 9*3de6a9c0SDavid du Colombier #include "../port/netif.h" 10*3de6a9c0SDavid du Colombier 11*3de6a9c0SDavid du Colombier enum 12*3de6a9c0SDavid du Colombier { 13*3de6a9c0SDavid du Colombier /* soft flow control chars */ 14*3de6a9c0SDavid du Colombier CTLS= 023, 15*3de6a9c0SDavid du Colombier CTLQ= 021, 16*3de6a9c0SDavid du Colombier }; 17*3de6a9c0SDavid du Colombier 18*3de6a9c0SDavid du Colombier extern Dev uartdevtab; 19*3de6a9c0SDavid du Colombier extern PhysUart* physuart[]; 20*3de6a9c0SDavid du Colombier 21*3de6a9c0SDavid du Colombier static Uart* uartlist; 22*3de6a9c0SDavid du Colombier static Uart** uart; 23*3de6a9c0SDavid du Colombier static int uartnuart; 24*3de6a9c0SDavid du Colombier static Dirtab *uartdir; 25*3de6a9c0SDavid du Colombier static int uartndir; 26*3de6a9c0SDavid du Colombier static Timer *uarttimer; 27*3de6a9c0SDavid du Colombier 28*3de6a9c0SDavid du Colombier struct Uartalloc { 29*3de6a9c0SDavid du Colombier Lock; 30*3de6a9c0SDavid du Colombier Uart *elist; /* list of enabled interfaces */ 31*3de6a9c0SDavid du Colombier } uartalloc; 32*3de6a9c0SDavid du Colombier 33*3de6a9c0SDavid du Colombier static void uartclock(void); 34*3de6a9c0SDavid du Colombier static void uartflow(void*); 35*3de6a9c0SDavid du Colombier 36*3de6a9c0SDavid du Colombier /* 37*3de6a9c0SDavid du Colombier * enable/disable uart and add/remove to list of enabled uarts 38*3de6a9c0SDavid du Colombier */ 39*3de6a9c0SDavid du Colombier //static 40*3de6a9c0SDavid du Colombier Uart* 41*3de6a9c0SDavid du Colombier uartenable(Uart *p) 42*3de6a9c0SDavid du Colombier { 43*3de6a9c0SDavid du Colombier Uart **l; 44*3de6a9c0SDavid du Colombier 45*3de6a9c0SDavid du Colombier if (up == nil) 46*3de6a9c0SDavid du Colombier return p; /* too soon; try again later */ 47*3de6a9c0SDavid du Colombier // return nil; 48*3de6a9c0SDavid du Colombier 49*3de6a9c0SDavid du Colombier if(p->iq == nil){ 50*3de6a9c0SDavid du Colombier if((p->iq = qopen(8*1024, 0, uartflow, p)) == nil) 51*3de6a9c0SDavid du Colombier return nil; 52*3de6a9c0SDavid du Colombier } 53*3de6a9c0SDavid du Colombier else 54*3de6a9c0SDavid du Colombier qreopen(p->iq); 55*3de6a9c0SDavid du Colombier if(p->oq == nil){ 56*3de6a9c0SDavid du Colombier if((p->oq = qopen(8*1024, 0, uartkick, p)) == nil){ 57*3de6a9c0SDavid du Colombier qfree(p->iq); 58*3de6a9c0SDavid du Colombier p->iq = nil; 59*3de6a9c0SDavid du Colombier return nil; 60*3de6a9c0SDavid du Colombier } 61*3de6a9c0SDavid du Colombier } 62*3de6a9c0SDavid du Colombier else 63*3de6a9c0SDavid du Colombier qreopen(p->oq); 64*3de6a9c0SDavid du Colombier 65*3de6a9c0SDavid du Colombier p->ir = p->istage; 66*3de6a9c0SDavid du Colombier p->iw = p->istage; 67*3de6a9c0SDavid du Colombier p->ie = &p->istage[Stagesize]; 68*3de6a9c0SDavid du Colombier p->op = p->ostage; 69*3de6a9c0SDavid du Colombier p->oe = p->ostage; 70*3de6a9c0SDavid du Colombier 71*3de6a9c0SDavid du Colombier p->hup_dsr = p->hup_dcd = 0; 72*3de6a9c0SDavid du Colombier p->dsr = p->dcd = 0; 73*3de6a9c0SDavid du Colombier 74*3de6a9c0SDavid du Colombier /* assume we can send */ 75*3de6a9c0SDavid du Colombier p->cts = 1; 76*3de6a9c0SDavid du Colombier p->ctsbackoff = 0; 77*3de6a9c0SDavid du Colombier 78*3de6a9c0SDavid du Colombier if (up) { 79*3de6a9c0SDavid du Colombier if(p->bits == 0) 80*3de6a9c0SDavid du Colombier uartctl(p, "l8"); 81*3de6a9c0SDavid du Colombier if(p->stop == 0) 82*3de6a9c0SDavid du Colombier uartctl(p, "s1"); 83*3de6a9c0SDavid du Colombier if(p->parity == 0) 84*3de6a9c0SDavid du Colombier uartctl(p, "pn"); 85*3de6a9c0SDavid du Colombier if(p->baud == 0) 86*3de6a9c0SDavid du Colombier uartctl(p, "b9600"); 87*3de6a9c0SDavid du Colombier (*p->phys->enable)(p, 1); 88*3de6a9c0SDavid du Colombier } 89*3de6a9c0SDavid du Colombier 90*3de6a9c0SDavid du Colombier /* 91*3de6a9c0SDavid du Colombier * use ilock because uartclock can otherwise interrupt here 92*3de6a9c0SDavid du Colombier * and would hang on an attempt to lock uartalloc. 93*3de6a9c0SDavid du Colombier */ 94*3de6a9c0SDavid du Colombier ilock(&uartalloc); 95*3de6a9c0SDavid du Colombier for(l = &uartalloc.elist; *l; l = &(*l)->elist){ 96*3de6a9c0SDavid du Colombier if(*l == p) 97*3de6a9c0SDavid du Colombier break; 98*3de6a9c0SDavid du Colombier } 99*3de6a9c0SDavid du Colombier if(*l == 0){ 100*3de6a9c0SDavid du Colombier p->elist = uartalloc.elist; 101*3de6a9c0SDavid du Colombier uartalloc.elist = p; 102*3de6a9c0SDavid du Colombier } 103*3de6a9c0SDavid du Colombier p->enabled = 1; 104*3de6a9c0SDavid du Colombier iunlock(&uartalloc); 105*3de6a9c0SDavid du Colombier 106*3de6a9c0SDavid du Colombier return p; 107*3de6a9c0SDavid du Colombier } 108*3de6a9c0SDavid du Colombier 109*3de6a9c0SDavid du Colombier static void 110*3de6a9c0SDavid du Colombier uartdisable(Uart *p) 111*3de6a9c0SDavid du Colombier { 112*3de6a9c0SDavid du Colombier Uart **l; 113*3de6a9c0SDavid du Colombier 114*3de6a9c0SDavid du Colombier (*p->phys->disable)(p); 115*3de6a9c0SDavid du Colombier 116*3de6a9c0SDavid du Colombier ilock(&uartalloc); 117*3de6a9c0SDavid du Colombier for(l = &uartalloc.elist; *l; l = &(*l)->elist){ 118*3de6a9c0SDavid du Colombier if(*l == p){ 119*3de6a9c0SDavid du Colombier *l = p->elist; 120*3de6a9c0SDavid du Colombier break; 121*3de6a9c0SDavid du Colombier } 122*3de6a9c0SDavid du Colombier } 123*3de6a9c0SDavid du Colombier p->enabled = 0; 124*3de6a9c0SDavid du Colombier iunlock(&uartalloc); 125*3de6a9c0SDavid du Colombier } 126*3de6a9c0SDavid du Colombier 127*3de6a9c0SDavid du Colombier void 128*3de6a9c0SDavid du Colombier uartmouse(Uart* p, int (*putc)(Queue*, int), int setb1200) 129*3de6a9c0SDavid du Colombier { 130*3de6a9c0SDavid du Colombier qlock(p); 131*3de6a9c0SDavid du Colombier if(p->opens++ == 0 && uartenable(p) == nil){ 132*3de6a9c0SDavid du Colombier qunlock(p); 133*3de6a9c0SDavid du Colombier error(Enodev); 134*3de6a9c0SDavid du Colombier } 135*3de6a9c0SDavid du Colombier if(setb1200) 136*3de6a9c0SDavid du Colombier uartctl(p, "b1200"); 137*3de6a9c0SDavid du Colombier p->putc = putc; 138*3de6a9c0SDavid du Colombier p->special = 1; 139*3de6a9c0SDavid du Colombier qunlock(p); 140*3de6a9c0SDavid du Colombier } 141*3de6a9c0SDavid du Colombier 142*3de6a9c0SDavid du Colombier void 143*3de6a9c0SDavid du Colombier uartsetmouseputc(Uart* p, int (*putc)(Queue*, int)) 144*3de6a9c0SDavid du Colombier { 145*3de6a9c0SDavid du Colombier qlock(p); 146*3de6a9c0SDavid du Colombier if(p->opens == 0 || p->special == 0){ 147*3de6a9c0SDavid du Colombier qunlock(p); 148*3de6a9c0SDavid du Colombier error(Enodev); 149*3de6a9c0SDavid du Colombier } 150*3de6a9c0SDavid du Colombier p->putc = putc; 151*3de6a9c0SDavid du Colombier qunlock(p); 152*3de6a9c0SDavid du Colombier } 153*3de6a9c0SDavid du Colombier 154*3de6a9c0SDavid du Colombier static void 155*3de6a9c0SDavid du Colombier setlength(int i) 156*3de6a9c0SDavid du Colombier { 157*3de6a9c0SDavid du Colombier Uart *p; 158*3de6a9c0SDavid du Colombier 159*3de6a9c0SDavid du Colombier if(i > 0){ 160*3de6a9c0SDavid du Colombier p = uart[i]; 161*3de6a9c0SDavid du Colombier if(p && p->opens && p->iq) 162*3de6a9c0SDavid du Colombier uartdir[1+3*i].length = qlen(p->iq); 163*3de6a9c0SDavid du Colombier } else for(i = 0; i < uartnuart; i++){ 164*3de6a9c0SDavid du Colombier p = uart[i]; 165*3de6a9c0SDavid du Colombier if(p && p->opens && p->iq) 166*3de6a9c0SDavid du Colombier uartdir[1+3*i].length = qlen(p->iq); 167*3de6a9c0SDavid du Colombier } 168*3de6a9c0SDavid du Colombier } 169*3de6a9c0SDavid du Colombier 170*3de6a9c0SDavid du Colombier /* 171*3de6a9c0SDavid du Colombier * set up the '#t' directory 172*3de6a9c0SDavid du Colombier */ 173*3de6a9c0SDavid du Colombier static void 174*3de6a9c0SDavid du Colombier uartreset(void) 175*3de6a9c0SDavid du Colombier { 176*3de6a9c0SDavid du Colombier int i; 177*3de6a9c0SDavid du Colombier Dirtab *dp; 178*3de6a9c0SDavid du Colombier Uart *p, *tail; 179*3de6a9c0SDavid du Colombier 180*3de6a9c0SDavid du Colombier tail = nil; 181*3de6a9c0SDavid du Colombier for(i = 0; physuart[i] != nil; i++){ 182*3de6a9c0SDavid du Colombier if(physuart[i]->pnp == nil) 183*3de6a9c0SDavid du Colombier continue; 184*3de6a9c0SDavid du Colombier if((p = physuart[i]->pnp()) == nil) 185*3de6a9c0SDavid du Colombier continue; 186*3de6a9c0SDavid du Colombier if(uartlist != nil) 187*3de6a9c0SDavid du Colombier tail->next = p; 188*3de6a9c0SDavid du Colombier else 189*3de6a9c0SDavid du Colombier uartlist = p; 190*3de6a9c0SDavid du Colombier for(tail = p; tail->next != nil; tail = tail->next) 191*3de6a9c0SDavid du Colombier uartnuart++; 192*3de6a9c0SDavid du Colombier uartnuart++; 193*3de6a9c0SDavid du Colombier } 194*3de6a9c0SDavid du Colombier 195*3de6a9c0SDavid du Colombier if(uartnuart) 196*3de6a9c0SDavid du Colombier uart = xalloc(uartnuart*sizeof(Uart*)); 197*3de6a9c0SDavid du Colombier 198*3de6a9c0SDavid du Colombier uartndir = 1 + 3*uartnuart; 199*3de6a9c0SDavid du Colombier uartdir = xalloc(uartndir * sizeof(Dirtab)); 200*3de6a9c0SDavid du Colombier if (uart == nil || uartdir == nil) 201*3de6a9c0SDavid du Colombier panic("uartreset: no memory"); 202*3de6a9c0SDavid du Colombier dp = uartdir; 203*3de6a9c0SDavid du Colombier strcpy(dp->name, "."); 204*3de6a9c0SDavid du Colombier mkqid(&dp->qid, 0, 0, QTDIR); 205*3de6a9c0SDavid du Colombier dp->length = 0; 206*3de6a9c0SDavid du Colombier dp->perm = DMDIR|0555; 207*3de6a9c0SDavid du Colombier dp++; 208*3de6a9c0SDavid du Colombier p = uartlist; 209*3de6a9c0SDavid du Colombier for(i = 0; i < uartnuart; i++){ 210*3de6a9c0SDavid du Colombier /* 3 directory entries per port */ 211*3de6a9c0SDavid du Colombier snprint(dp->name, sizeof dp->name, "eia%d", i); 212*3de6a9c0SDavid du Colombier dp->qid.path = NETQID(i, Ndataqid); 213*3de6a9c0SDavid du Colombier dp->perm = 0660; 214*3de6a9c0SDavid du Colombier dp++; 215*3de6a9c0SDavid du Colombier snprint(dp->name, sizeof dp->name, "eia%dctl", i); 216*3de6a9c0SDavid du Colombier dp->qid.path = NETQID(i, Nctlqid); 217*3de6a9c0SDavid du Colombier dp->perm = 0660; 218*3de6a9c0SDavid du Colombier dp++; 219*3de6a9c0SDavid du Colombier snprint(dp->name, sizeof dp->name, "eia%dstatus", i); 220*3de6a9c0SDavid du Colombier dp->qid.path = NETQID(i, Nstatqid); 221*3de6a9c0SDavid du Colombier dp->perm = 0444; 222*3de6a9c0SDavid du Colombier dp++; 223*3de6a9c0SDavid du Colombier 224*3de6a9c0SDavid du Colombier uart[i] = p; 225*3de6a9c0SDavid du Colombier p->dev = i; 226*3de6a9c0SDavid du Colombier if(p->console || p->special){ 227*3de6a9c0SDavid du Colombier if(uartenable(p) != nil){ 228*3de6a9c0SDavid du Colombier if(p->console && up){ 229*3de6a9c0SDavid du Colombier kbdq = p->iq; 230*3de6a9c0SDavid du Colombier serialoq = p->oq; 231*3de6a9c0SDavid du Colombier p->putc = kbdcr2nl; 232*3de6a9c0SDavid du Colombier } 233*3de6a9c0SDavid du Colombier p->opens++; 234*3de6a9c0SDavid du Colombier } 235*3de6a9c0SDavid du Colombier } 236*3de6a9c0SDavid du Colombier p = p->next; 237*3de6a9c0SDavid du Colombier } 238*3de6a9c0SDavid du Colombier 239*3de6a9c0SDavid du Colombier if(uartnuart){ 240*3de6a9c0SDavid du Colombier /* 241*3de6a9c0SDavid du Colombier * at 115200 baud, the 1024 char buffer takes 56 ms to process, 242*3de6a9c0SDavid du Colombier * processing it every 22 ms should be fine. 243*3de6a9c0SDavid du Colombier */ 244*3de6a9c0SDavid du Colombier uarttimer = addclock0link(uartclock, 22); 245*3de6a9c0SDavid du Colombier } 246*3de6a9c0SDavid du Colombier } 247*3de6a9c0SDavid du Colombier 248*3de6a9c0SDavid du Colombier 249*3de6a9c0SDavid du Colombier static Chan* 250*3de6a9c0SDavid du Colombier uartattach(char *spec) 251*3de6a9c0SDavid du Colombier { 252*3de6a9c0SDavid du Colombier return devattach('t', spec); 253*3de6a9c0SDavid du Colombier } 254*3de6a9c0SDavid du Colombier 255*3de6a9c0SDavid du Colombier static Walkqid* 256*3de6a9c0SDavid du Colombier uartwalk(Chan *c, Chan *nc, char **name, int nname) 257*3de6a9c0SDavid du Colombier { 258*3de6a9c0SDavid du Colombier return devwalk(c, nc, name, nname, uartdir, uartndir, devgen); 259*3de6a9c0SDavid du Colombier } 260*3de6a9c0SDavid du Colombier 261*3de6a9c0SDavid du Colombier static int 262*3de6a9c0SDavid du Colombier uartstat(Chan *c, uchar *dp, int n) 263*3de6a9c0SDavid du Colombier { 264*3de6a9c0SDavid du Colombier if(NETTYPE(c->qid.path) == Ndataqid) 265*3de6a9c0SDavid du Colombier setlength(NETID(c->qid.path)); 266*3de6a9c0SDavid du Colombier return devstat(c, dp, n, uartdir, uartndir, devgen); 267*3de6a9c0SDavid du Colombier } 268*3de6a9c0SDavid du Colombier 269*3de6a9c0SDavid du Colombier static Chan* 270*3de6a9c0SDavid du Colombier uartopen(Chan *c, int omode) 271*3de6a9c0SDavid du Colombier { 272*3de6a9c0SDavid du Colombier Uart *p; 273*3de6a9c0SDavid du Colombier 274*3de6a9c0SDavid du Colombier c = devopen(c, omode, uartdir, uartndir, devgen); 275*3de6a9c0SDavid du Colombier 276*3de6a9c0SDavid du Colombier switch(NETTYPE(c->qid.path)){ 277*3de6a9c0SDavid du Colombier case Nctlqid: 278*3de6a9c0SDavid du Colombier case Ndataqid: 279*3de6a9c0SDavid du Colombier p = uart[NETID(c->qid.path)]; 280*3de6a9c0SDavid du Colombier qlock(p); 281*3de6a9c0SDavid du Colombier if(p->opens++ == 0 && uartenable(p) == nil){ 282*3de6a9c0SDavid du Colombier qunlock(p); 283*3de6a9c0SDavid du Colombier c->flag &= ~COPEN; 284*3de6a9c0SDavid du Colombier error(Enodev); 285*3de6a9c0SDavid du Colombier } 286*3de6a9c0SDavid du Colombier qunlock(p); 287*3de6a9c0SDavid du Colombier break; 288*3de6a9c0SDavid du Colombier } 289*3de6a9c0SDavid du Colombier 290*3de6a9c0SDavid du Colombier c->iounit = qiomaxatomic; 291*3de6a9c0SDavid du Colombier return c; 292*3de6a9c0SDavid du Colombier } 293*3de6a9c0SDavid du Colombier 294*3de6a9c0SDavid du Colombier static int 295*3de6a9c0SDavid du Colombier uartdrained(void* arg) 296*3de6a9c0SDavid du Colombier { 297*3de6a9c0SDavid du Colombier Uart *p; 298*3de6a9c0SDavid du Colombier 299*3de6a9c0SDavid du Colombier p = arg; 300*3de6a9c0SDavid du Colombier return qlen(p->oq) == 0 && p->op == p->oe; 301*3de6a9c0SDavid du Colombier } 302*3de6a9c0SDavid du Colombier 303*3de6a9c0SDavid du Colombier static void 304*3de6a9c0SDavid du Colombier uartdrainoutput(Uart *p) 305*3de6a9c0SDavid du Colombier { 306*3de6a9c0SDavid du Colombier if(!p->enabled || up == nil) 307*3de6a9c0SDavid du Colombier return; 308*3de6a9c0SDavid du Colombier 309*3de6a9c0SDavid du Colombier p->drain = 1; 310*3de6a9c0SDavid du Colombier if(waserror()){ 311*3de6a9c0SDavid du Colombier p->drain = 0; 312*3de6a9c0SDavid du Colombier nexterror(); 313*3de6a9c0SDavid du Colombier } 314*3de6a9c0SDavid du Colombier sleep(&p->r, uartdrained, p); 315*3de6a9c0SDavid du Colombier poperror(); 316*3de6a9c0SDavid du Colombier } 317*3de6a9c0SDavid du Colombier 318*3de6a9c0SDavid du Colombier static void 319*3de6a9c0SDavid du Colombier uartclose(Chan *c) 320*3de6a9c0SDavid du Colombier { 321*3de6a9c0SDavid du Colombier Uart *p; 322*3de6a9c0SDavid du Colombier 323*3de6a9c0SDavid du Colombier if(c->qid.type & QTDIR) 324*3de6a9c0SDavid du Colombier return; 325*3de6a9c0SDavid du Colombier if((c->flag & COPEN) == 0) 326*3de6a9c0SDavid du Colombier return; 327*3de6a9c0SDavid du Colombier switch(NETTYPE(c->qid.path)){ 328*3de6a9c0SDavid du Colombier case Ndataqid: 329*3de6a9c0SDavid du Colombier case Nctlqid: 330*3de6a9c0SDavid du Colombier p = uart[NETID(c->qid.path)]; 331*3de6a9c0SDavid du Colombier qlock(p); 332*3de6a9c0SDavid du Colombier if(--(p->opens) == 0){ 333*3de6a9c0SDavid du Colombier qclose(p->iq); 334*3de6a9c0SDavid du Colombier ilock(&p->rlock); 335*3de6a9c0SDavid du Colombier p->ir = p->iw = p->istage; 336*3de6a9c0SDavid du Colombier iunlock(&p->rlock); 337*3de6a9c0SDavid du Colombier 338*3de6a9c0SDavid du Colombier /* 339*3de6a9c0SDavid du Colombier */ 340*3de6a9c0SDavid du Colombier qhangup(p->oq, nil); 341*3de6a9c0SDavid du Colombier if(!waserror()){ 342*3de6a9c0SDavid du Colombier uartdrainoutput(p); 343*3de6a9c0SDavid du Colombier poperror(); 344*3de6a9c0SDavid du Colombier } 345*3de6a9c0SDavid du Colombier qclose(p->oq); 346*3de6a9c0SDavid du Colombier uartdisable(p); 347*3de6a9c0SDavid du Colombier p->dcd = p->dsr = p->dohup = 0; 348*3de6a9c0SDavid du Colombier } 349*3de6a9c0SDavid du Colombier qunlock(p); 350*3de6a9c0SDavid du Colombier break; 351*3de6a9c0SDavid du Colombier } 352*3de6a9c0SDavid du Colombier } 353*3de6a9c0SDavid du Colombier 354*3de6a9c0SDavid du Colombier static long 355*3de6a9c0SDavid du Colombier uartread(Chan *c, void *buf, long n, vlong off) 356*3de6a9c0SDavid du Colombier { 357*3de6a9c0SDavid du Colombier Uart *p; 358*3de6a9c0SDavid du Colombier ulong offset = off; 359*3de6a9c0SDavid du Colombier 360*3de6a9c0SDavid du Colombier if(c->qid.type & QTDIR){ 361*3de6a9c0SDavid du Colombier setlength(-1); 362*3de6a9c0SDavid du Colombier return devdirread(c, buf, n, uartdir, uartndir, devgen); 363*3de6a9c0SDavid du Colombier } 364*3de6a9c0SDavid du Colombier 365*3de6a9c0SDavid du Colombier p = uart[NETID(c->qid.path)]; 366*3de6a9c0SDavid du Colombier switch(NETTYPE(c->qid.path)){ 367*3de6a9c0SDavid du Colombier case Ndataqid: 368*3de6a9c0SDavid du Colombier return qread(p->iq, buf, n); 369*3de6a9c0SDavid du Colombier case Nctlqid: 370*3de6a9c0SDavid du Colombier return readnum(offset, buf, n, NETID(c->qid.path), NUMSIZE); 371*3de6a9c0SDavid du Colombier case Nstatqid: 372*3de6a9c0SDavid du Colombier return (*p->phys->status)(p, buf, n, offset); 373*3de6a9c0SDavid du Colombier } 374*3de6a9c0SDavid du Colombier 375*3de6a9c0SDavid du Colombier return 0; 376*3de6a9c0SDavid du Colombier } 377*3de6a9c0SDavid du Colombier 378*3de6a9c0SDavid du Colombier int 379*3de6a9c0SDavid du Colombier uartctl(Uart *p, char *cmd) 380*3de6a9c0SDavid du Colombier { 381*3de6a9c0SDavid du Colombier char *f[16]; 382*3de6a9c0SDavid du Colombier int i, n, nf; 383*3de6a9c0SDavid du Colombier 384*3de6a9c0SDavid du Colombier nf = tokenize(cmd, f, nelem(f)); 385*3de6a9c0SDavid du Colombier for(i = 0; i < nf; i++){ 386*3de6a9c0SDavid du Colombier if(strncmp(f[i], "break", 5) == 0){ 387*3de6a9c0SDavid du Colombier (*p->phys->dobreak)(p, 0); 388*3de6a9c0SDavid du Colombier continue; 389*3de6a9c0SDavid du Colombier } 390*3de6a9c0SDavid du Colombier 391*3de6a9c0SDavid du Colombier n = atoi(f[i]+1); 392*3de6a9c0SDavid du Colombier switch(*f[i]){ 393*3de6a9c0SDavid du Colombier case 'B': 394*3de6a9c0SDavid du Colombier case 'b': 395*3de6a9c0SDavid du Colombier uartdrainoutput(p); 396*3de6a9c0SDavid du Colombier if((*p->phys->baud)(p, n) < 0) 397*3de6a9c0SDavid du Colombier return -1; 398*3de6a9c0SDavid du Colombier break; 399*3de6a9c0SDavid du Colombier case 'C': 400*3de6a9c0SDavid du Colombier case 'c': 401*3de6a9c0SDavid du Colombier p->hup_dcd = n; 402*3de6a9c0SDavid du Colombier break; 403*3de6a9c0SDavid du Colombier case 'D': 404*3de6a9c0SDavid du Colombier case 'd': 405*3de6a9c0SDavid du Colombier uartdrainoutput(p); 406*3de6a9c0SDavid du Colombier (*p->phys->dtr)(p, n); 407*3de6a9c0SDavid du Colombier break; 408*3de6a9c0SDavid du Colombier case 'E': 409*3de6a9c0SDavid du Colombier case 'e': 410*3de6a9c0SDavid du Colombier p->hup_dsr = n; 411*3de6a9c0SDavid du Colombier break; 412*3de6a9c0SDavid du Colombier case 'f': 413*3de6a9c0SDavid du Colombier case 'F': 414*3de6a9c0SDavid du Colombier if(p->oq != nil) 415*3de6a9c0SDavid du Colombier qflush(p->oq); 416*3de6a9c0SDavid du Colombier break; 417*3de6a9c0SDavid du Colombier case 'H': 418*3de6a9c0SDavid du Colombier case 'h': 419*3de6a9c0SDavid du Colombier if(p->iq != nil) 420*3de6a9c0SDavid du Colombier qhangup(p->iq, 0); 421*3de6a9c0SDavid du Colombier if(p->oq != nil) 422*3de6a9c0SDavid du Colombier qhangup(p->oq, 0); 423*3de6a9c0SDavid du Colombier break; 424*3de6a9c0SDavid du Colombier case 'i': 425*3de6a9c0SDavid du Colombier case 'I': 426*3de6a9c0SDavid du Colombier uartdrainoutput(p); 427*3de6a9c0SDavid du Colombier (*p->phys->fifo)(p, n); 428*3de6a9c0SDavid du Colombier break; 429*3de6a9c0SDavid du Colombier case 'K': 430*3de6a9c0SDavid du Colombier case 'k': 431*3de6a9c0SDavid du Colombier uartdrainoutput(p); 432*3de6a9c0SDavid du Colombier (*p->phys->dobreak)(p, n); 433*3de6a9c0SDavid du Colombier break; 434*3de6a9c0SDavid du Colombier case 'L': 435*3de6a9c0SDavid du Colombier case 'l': 436*3de6a9c0SDavid du Colombier uartdrainoutput(p); 437*3de6a9c0SDavid du Colombier if((*p->phys->bits)(p, n) < 0) 438*3de6a9c0SDavid du Colombier return -1; 439*3de6a9c0SDavid du Colombier break; 440*3de6a9c0SDavid du Colombier case 'm': 441*3de6a9c0SDavid du Colombier case 'M': 442*3de6a9c0SDavid du Colombier uartdrainoutput(p); 443*3de6a9c0SDavid du Colombier (*p->phys->modemctl)(p, n); 444*3de6a9c0SDavid du Colombier break; 445*3de6a9c0SDavid du Colombier case 'n': 446*3de6a9c0SDavid du Colombier case 'N': 447*3de6a9c0SDavid du Colombier if(p->oq != nil) 448*3de6a9c0SDavid du Colombier qnoblock(p->oq, n); 449*3de6a9c0SDavid du Colombier break; 450*3de6a9c0SDavid du Colombier case 'P': 451*3de6a9c0SDavid du Colombier case 'p': 452*3de6a9c0SDavid du Colombier uartdrainoutput(p); 453*3de6a9c0SDavid du Colombier if((*p->phys->parity)(p, *(f[i]+1)) < 0) 454*3de6a9c0SDavid du Colombier return -1; 455*3de6a9c0SDavid du Colombier break; 456*3de6a9c0SDavid du Colombier case 'Q': 457*3de6a9c0SDavid du Colombier case 'q': 458*3de6a9c0SDavid du Colombier if(p->iq != nil) 459*3de6a9c0SDavid du Colombier qsetlimit(p->iq, n); 460*3de6a9c0SDavid du Colombier if(p->oq != nil) 461*3de6a9c0SDavid du Colombier qsetlimit(p->oq, n); 462*3de6a9c0SDavid du Colombier break; 463*3de6a9c0SDavid du Colombier case 'R': 464*3de6a9c0SDavid du Colombier case 'r': 465*3de6a9c0SDavid du Colombier uartdrainoutput(p); 466*3de6a9c0SDavid du Colombier (*p->phys->rts)(p, n); 467*3de6a9c0SDavid du Colombier break; 468*3de6a9c0SDavid du Colombier case 'S': 469*3de6a9c0SDavid du Colombier case 's': 470*3de6a9c0SDavid du Colombier uartdrainoutput(p); 471*3de6a9c0SDavid du Colombier if((*p->phys->stop)(p, n) < 0) 472*3de6a9c0SDavid du Colombier return -1; 473*3de6a9c0SDavid du Colombier break; 474*3de6a9c0SDavid du Colombier case 'W': 475*3de6a9c0SDavid du Colombier case 'w': 476*3de6a9c0SDavid du Colombier if(uarttimer == nil || n < 1) 477*3de6a9c0SDavid du Colombier return -1; 478*3de6a9c0SDavid du Colombier uarttimer->tns = (vlong)n * 100000LL; 479*3de6a9c0SDavid du Colombier break; 480*3de6a9c0SDavid du Colombier case 'X': 481*3de6a9c0SDavid du Colombier case 'x': 482*3de6a9c0SDavid du Colombier if(p->enabled){ 483*3de6a9c0SDavid du Colombier ilock(&p->tlock); 484*3de6a9c0SDavid du Colombier p->xonoff = n; 485*3de6a9c0SDavid du Colombier iunlock(&p->tlock); 486*3de6a9c0SDavid du Colombier } 487*3de6a9c0SDavid du Colombier break; 488*3de6a9c0SDavid du Colombier } 489*3de6a9c0SDavid du Colombier } 490*3de6a9c0SDavid du Colombier return 0; 491*3de6a9c0SDavid du Colombier } 492*3de6a9c0SDavid du Colombier 493*3de6a9c0SDavid du Colombier static long 494*3de6a9c0SDavid du Colombier uartwrite(Chan *c, void *buf, long n, vlong) 495*3de6a9c0SDavid du Colombier { 496*3de6a9c0SDavid du Colombier Uart *p; 497*3de6a9c0SDavid du Colombier char *cmd; 498*3de6a9c0SDavid du Colombier 499*3de6a9c0SDavid du Colombier if(c->qid.type & QTDIR) 500*3de6a9c0SDavid du Colombier error(Eperm); 501*3de6a9c0SDavid du Colombier 502*3de6a9c0SDavid du Colombier p = uart[NETID(c->qid.path)]; 503*3de6a9c0SDavid du Colombier 504*3de6a9c0SDavid du Colombier switch(NETTYPE(c->qid.path)){ 505*3de6a9c0SDavid du Colombier case Ndataqid: 506*3de6a9c0SDavid du Colombier qlock(p); 507*3de6a9c0SDavid du Colombier if(waserror()){ 508*3de6a9c0SDavid du Colombier qunlock(p); 509*3de6a9c0SDavid du Colombier nexterror(); 510*3de6a9c0SDavid du Colombier } 511*3de6a9c0SDavid du Colombier 512*3de6a9c0SDavid du Colombier n = qwrite(p->oq, buf, n); 513*3de6a9c0SDavid du Colombier 514*3de6a9c0SDavid du Colombier qunlock(p); 515*3de6a9c0SDavid du Colombier poperror(); 516*3de6a9c0SDavid du Colombier break; 517*3de6a9c0SDavid du Colombier case Nctlqid: 518*3de6a9c0SDavid du Colombier cmd = malloc(n+1); 519*3de6a9c0SDavid du Colombier memmove(cmd, buf, n); 520*3de6a9c0SDavid du Colombier cmd[n] = 0; 521*3de6a9c0SDavid du Colombier qlock(p); 522*3de6a9c0SDavid du Colombier if(waserror()){ 523*3de6a9c0SDavid du Colombier qunlock(p); 524*3de6a9c0SDavid du Colombier free(cmd); 525*3de6a9c0SDavid du Colombier nexterror(); 526*3de6a9c0SDavid du Colombier } 527*3de6a9c0SDavid du Colombier 528*3de6a9c0SDavid du Colombier /* let output drain */ 529*3de6a9c0SDavid du Colombier if(uartctl(p, cmd) < 0) 530*3de6a9c0SDavid du Colombier error(Ebadarg); 531*3de6a9c0SDavid du Colombier 532*3de6a9c0SDavid du Colombier qunlock(p); 533*3de6a9c0SDavid du Colombier poperror(); 534*3de6a9c0SDavid du Colombier free(cmd); 535*3de6a9c0SDavid du Colombier break; 536*3de6a9c0SDavid du Colombier } 537*3de6a9c0SDavid du Colombier 538*3de6a9c0SDavid du Colombier return n; 539*3de6a9c0SDavid du Colombier } 540*3de6a9c0SDavid du Colombier 541*3de6a9c0SDavid du Colombier static int 542*3de6a9c0SDavid du Colombier uartwstat(Chan *c, uchar *dp, int n) 543*3de6a9c0SDavid du Colombier { 544*3de6a9c0SDavid du Colombier Dir d; 545*3de6a9c0SDavid du Colombier Dirtab *dt; 546*3de6a9c0SDavid du Colombier 547*3de6a9c0SDavid du Colombier if(!iseve()) 548*3de6a9c0SDavid du Colombier error(Eperm); 549*3de6a9c0SDavid du Colombier if(QTDIR & c->qid.type) 550*3de6a9c0SDavid du Colombier error(Eperm); 551*3de6a9c0SDavid du Colombier if(NETTYPE(c->qid.path) == Nstatqid) 552*3de6a9c0SDavid du Colombier error(Eperm); 553*3de6a9c0SDavid du Colombier 554*3de6a9c0SDavid du Colombier dt = &uartdir[1 + 3 * NETID(c->qid.path)]; 555*3de6a9c0SDavid du Colombier n = convM2D(dp, n, &d, nil); 556*3de6a9c0SDavid du Colombier if(n == 0) 557*3de6a9c0SDavid du Colombier error(Eshortstat); 558*3de6a9c0SDavid du Colombier if(d.mode != ~0UL) 559*3de6a9c0SDavid du Colombier dt[0].perm = dt[1].perm = d.mode; 560*3de6a9c0SDavid du Colombier return n; 561*3de6a9c0SDavid du Colombier } 562*3de6a9c0SDavid du Colombier 563*3de6a9c0SDavid du Colombier void 564*3de6a9c0SDavid du Colombier uartpower(int on) 565*3de6a9c0SDavid du Colombier { 566*3de6a9c0SDavid du Colombier Uart *p; 567*3de6a9c0SDavid du Colombier 568*3de6a9c0SDavid du Colombier for(p = uartlist; p != nil; p = p->next) { 569*3de6a9c0SDavid du Colombier if(p->phys->power) 570*3de6a9c0SDavid du Colombier (*p->phys->power)(p, on); 571*3de6a9c0SDavid du Colombier } 572*3de6a9c0SDavid du Colombier } 573*3de6a9c0SDavid du Colombier 574*3de6a9c0SDavid du Colombier Dev uartdevtab = { 575*3de6a9c0SDavid du Colombier 't', 576*3de6a9c0SDavid du Colombier "uart", 577*3de6a9c0SDavid du Colombier 578*3de6a9c0SDavid du Colombier uartreset, 579*3de6a9c0SDavid du Colombier devinit, 580*3de6a9c0SDavid du Colombier devshutdown, 581*3de6a9c0SDavid du Colombier uartattach, 582*3de6a9c0SDavid du Colombier uartwalk, 583*3de6a9c0SDavid du Colombier uartstat, 584*3de6a9c0SDavid du Colombier uartopen, 585*3de6a9c0SDavid du Colombier devcreate, 586*3de6a9c0SDavid du Colombier uartclose, 587*3de6a9c0SDavid du Colombier uartread, 588*3de6a9c0SDavid du Colombier devbread, 589*3de6a9c0SDavid du Colombier uartwrite, 590*3de6a9c0SDavid du Colombier devbwrite, 591*3de6a9c0SDavid du Colombier devremove, 592*3de6a9c0SDavid du Colombier uartwstat, 593*3de6a9c0SDavid du Colombier uartpower, 594*3de6a9c0SDavid du Colombier }; 595*3de6a9c0SDavid du Colombier 596*3de6a9c0SDavid du Colombier /* 597*3de6a9c0SDavid du Colombier * restart input if it's off 598*3de6a9c0SDavid du Colombier */ 599*3de6a9c0SDavid du Colombier static void 600*3de6a9c0SDavid du Colombier uartflow(void *v) 601*3de6a9c0SDavid du Colombier { 602*3de6a9c0SDavid du Colombier Uart *p; 603*3de6a9c0SDavid du Colombier 604*3de6a9c0SDavid du Colombier p = v; 605*3de6a9c0SDavid du Colombier if(p->modem) 606*3de6a9c0SDavid du Colombier (*p->phys->rts)(p, 1); 607*3de6a9c0SDavid du Colombier } 608*3de6a9c0SDavid du Colombier 609*3de6a9c0SDavid du Colombier /* 610*3de6a9c0SDavid du Colombier * put some bytes into the local queue to avoid calling 611*3de6a9c0SDavid du Colombier * qconsume for every character 612*3de6a9c0SDavid du Colombier */ 613*3de6a9c0SDavid du Colombier int 614*3de6a9c0SDavid du Colombier uartstageoutput(Uart *p) 615*3de6a9c0SDavid du Colombier { 616*3de6a9c0SDavid du Colombier int n; 617*3de6a9c0SDavid du Colombier 618*3de6a9c0SDavid du Colombier n = qconsume(p->oq, p->ostage, Stagesize); 619*3de6a9c0SDavid du Colombier if(n <= 0) 620*3de6a9c0SDavid du Colombier // n = 0; /* experiment */ 621*3de6a9c0SDavid du Colombier return 0; 622*3de6a9c0SDavid du Colombier p->op = p->ostage; 623*3de6a9c0SDavid du Colombier p->oe = p->ostage + n; 624*3de6a9c0SDavid du Colombier return n; 625*3de6a9c0SDavid du Colombier } 626*3de6a9c0SDavid du Colombier 627*3de6a9c0SDavid du Colombier /* 628*3de6a9c0SDavid du Colombier * restart output 629*3de6a9c0SDavid du Colombier */ 630*3de6a9c0SDavid du Colombier void 631*3de6a9c0SDavid du Colombier uartkick(void *v) 632*3de6a9c0SDavid du Colombier { 633*3de6a9c0SDavid du Colombier Uart *p = v; 634*3de6a9c0SDavid du Colombier 635*3de6a9c0SDavid du Colombier if(p->blocked) 636*3de6a9c0SDavid du Colombier return; 637*3de6a9c0SDavid du Colombier 638*3de6a9c0SDavid du Colombier ilock(&p->tlock); 639*3de6a9c0SDavid du Colombier (*p->phys->kick)(p); 640*3de6a9c0SDavid du Colombier iunlock(&p->tlock); 641*3de6a9c0SDavid du Colombier 642*3de6a9c0SDavid du Colombier if(p->drain && uartdrained(p)){ 643*3de6a9c0SDavid du Colombier p->drain = 0; 644*3de6a9c0SDavid du Colombier wakeup(&p->r); 645*3de6a9c0SDavid du Colombier } 646*3de6a9c0SDavid du Colombier } 647*3de6a9c0SDavid du Colombier 648*3de6a9c0SDavid du Colombier /* 649*3de6a9c0SDavid du Colombier * Move data from the interrupt staging area to 650*3de6a9c0SDavid du Colombier * the input Queue. 651*3de6a9c0SDavid du Colombier */ 652*3de6a9c0SDavid du Colombier static void 653*3de6a9c0SDavid du Colombier uartstageinput(Uart *p) 654*3de6a9c0SDavid du Colombier { 655*3de6a9c0SDavid du Colombier int n; 656*3de6a9c0SDavid du Colombier uchar *ir, *iw; 657*3de6a9c0SDavid du Colombier 658*3de6a9c0SDavid du Colombier while(p->ir != p->iw){ 659*3de6a9c0SDavid du Colombier ir = p->ir; 660*3de6a9c0SDavid du Colombier if(p->ir > p->iw){ 661*3de6a9c0SDavid du Colombier iw = p->ie; 662*3de6a9c0SDavid du Colombier p->ir = p->istage; 663*3de6a9c0SDavid du Colombier } 664*3de6a9c0SDavid du Colombier else{ 665*3de6a9c0SDavid du Colombier iw = p->iw; 666*3de6a9c0SDavid du Colombier p->ir = p->iw; 667*3de6a9c0SDavid du Colombier } 668*3de6a9c0SDavid du Colombier if((n = qproduce(p->iq, ir, iw - ir)) < 0){ 669*3de6a9c0SDavid du Colombier p->serr++; 670*3de6a9c0SDavid du Colombier (*p->phys->rts)(p, 0); 671*3de6a9c0SDavid du Colombier } 672*3de6a9c0SDavid du Colombier else if(n == 0) 673*3de6a9c0SDavid du Colombier p->berr++; 674*3de6a9c0SDavid du Colombier } 675*3de6a9c0SDavid du Colombier } 676*3de6a9c0SDavid du Colombier 677*3de6a9c0SDavid du Colombier /* 678*3de6a9c0SDavid du Colombier * receive a character at interrupt time 679*3de6a9c0SDavid du Colombier */ 680*3de6a9c0SDavid du Colombier void 681*3de6a9c0SDavid du Colombier uartrecv(Uart *p, char ch) 682*3de6a9c0SDavid du Colombier { 683*3de6a9c0SDavid du Colombier uchar *next; 684*3de6a9c0SDavid du Colombier 685*3de6a9c0SDavid du Colombier /* software flow control */ 686*3de6a9c0SDavid du Colombier if(p->xonoff){ 687*3de6a9c0SDavid du Colombier if(ch == CTLS){ 688*3de6a9c0SDavid du Colombier p->blocked = 1; 689*3de6a9c0SDavid du Colombier }else if(ch == CTLQ){ 690*3de6a9c0SDavid du Colombier p->blocked = 0; 691*3de6a9c0SDavid du Colombier p->ctsbackoff = 2; /* clock gets output going again */ 692*3de6a9c0SDavid du Colombier } 693*3de6a9c0SDavid du Colombier } 694*3de6a9c0SDavid du Colombier 695*3de6a9c0SDavid du Colombier /* receive the character */ 696*3de6a9c0SDavid du Colombier if(p->putc) 697*3de6a9c0SDavid du Colombier p->putc(p->iq, ch); 698*3de6a9c0SDavid du Colombier else if (p->iw) { /* maybe the line isn't enabled yet */ 699*3de6a9c0SDavid du Colombier ilock(&p->rlock); 700*3de6a9c0SDavid du Colombier next = p->iw + 1; 701*3de6a9c0SDavid du Colombier if(next == p->ie) 702*3de6a9c0SDavid du Colombier next = p->istage; 703*3de6a9c0SDavid du Colombier if(next == p->ir) 704*3de6a9c0SDavid du Colombier uartstageinput(p); 705*3de6a9c0SDavid du Colombier if(next != p->ir){ 706*3de6a9c0SDavid du Colombier *p->iw = ch; 707*3de6a9c0SDavid du Colombier p->iw = next; 708*3de6a9c0SDavid du Colombier } 709*3de6a9c0SDavid du Colombier iunlock(&p->rlock); 710*3de6a9c0SDavid du Colombier } 711*3de6a9c0SDavid du Colombier } 712*3de6a9c0SDavid du Colombier 713*3de6a9c0SDavid du Colombier /* 714*3de6a9c0SDavid du Colombier * we save up input characters till clock time to reduce 715*3de6a9c0SDavid du Colombier * per character interrupt overhead. 716*3de6a9c0SDavid du Colombier */ 717*3de6a9c0SDavid du Colombier static void 718*3de6a9c0SDavid du Colombier uartclock(void) 719*3de6a9c0SDavid du Colombier { 720*3de6a9c0SDavid du Colombier Uart *p; 721*3de6a9c0SDavid du Colombier 722*3de6a9c0SDavid du Colombier ilock(&uartalloc); 723*3de6a9c0SDavid du Colombier for(p = uartalloc.elist; p; p = p->elist){ 724*3de6a9c0SDavid du Colombier 725*3de6a9c0SDavid du Colombier /* this hopefully amortizes cost of qproduce to many chars */ 726*3de6a9c0SDavid du Colombier if(p->iw != p->ir){ 727*3de6a9c0SDavid du Colombier ilock(&p->rlock); 728*3de6a9c0SDavid du Colombier uartstageinput(p); 729*3de6a9c0SDavid du Colombier iunlock(&p->rlock); 730*3de6a9c0SDavid du Colombier } 731*3de6a9c0SDavid du Colombier 732*3de6a9c0SDavid du Colombier /* hang up if requested */ 733*3de6a9c0SDavid du Colombier if(p->dohup){ 734*3de6a9c0SDavid du Colombier qhangup(p->iq, 0); 735*3de6a9c0SDavid du Colombier qhangup(p->oq, 0); 736*3de6a9c0SDavid du Colombier p->dohup = 0; 737*3de6a9c0SDavid du Colombier } 738*3de6a9c0SDavid du Colombier 739*3de6a9c0SDavid du Colombier /* this adds hysteresis to hardware/software flow control */ 740*3de6a9c0SDavid du Colombier if(p->ctsbackoff){ 741*3de6a9c0SDavid du Colombier ilock(&p->tlock); 742*3de6a9c0SDavid du Colombier if(p->ctsbackoff){ 743*3de6a9c0SDavid du Colombier if(--(p->ctsbackoff) == 0) 744*3de6a9c0SDavid du Colombier (*p->phys->kick)(p); 745*3de6a9c0SDavid du Colombier } 746*3de6a9c0SDavid du Colombier iunlock(&p->tlock); 747*3de6a9c0SDavid du Colombier } 748*3de6a9c0SDavid du Colombier uartkick(p); /* keep it moving */ 749*3de6a9c0SDavid du Colombier } 750*3de6a9c0SDavid du Colombier iunlock(&uartalloc); 751*3de6a9c0SDavid du Colombier } 752*3de6a9c0SDavid du Colombier 753*3de6a9c0SDavid du Colombier /* 754*3de6a9c0SDavid du Colombier * polling console input, output 755*3de6a9c0SDavid du Colombier */ 756*3de6a9c0SDavid du Colombier 757*3de6a9c0SDavid du Colombier Uart* consuart; 758*3de6a9c0SDavid du Colombier 759*3de6a9c0SDavid du Colombier int 760*3de6a9c0SDavid du Colombier uartgetc(void) 761*3de6a9c0SDavid du Colombier { 762*3de6a9c0SDavid du Colombier if(consuart == nil || consuart->phys->getc == nil) 763*3de6a9c0SDavid du Colombier return -1; 764*3de6a9c0SDavid du Colombier return consuart->phys->getc(consuart); 765*3de6a9c0SDavid du Colombier } 766*3de6a9c0SDavid du Colombier 767*3de6a9c0SDavid du Colombier void 768*3de6a9c0SDavid du Colombier uartputc(int c) 769*3de6a9c0SDavid du Colombier { 770*3de6a9c0SDavid du Colombier char c2; 771*3de6a9c0SDavid du Colombier 772*3de6a9c0SDavid du Colombier if(consuart == nil || consuart->phys->putc == nil) { 773*3de6a9c0SDavid du Colombier c2 = c; 774*3de6a9c0SDavid du Colombier _uartputs(&c2, 1); 775*3de6a9c0SDavid du Colombier return; 776*3de6a9c0SDavid du Colombier } 777*3de6a9c0SDavid du Colombier consuart->phys->putc(consuart, c); 778*3de6a9c0SDavid du Colombier } 779*3de6a9c0SDavid du Colombier 780*3de6a9c0SDavid du Colombier void 781*3de6a9c0SDavid du Colombier uartputs(char *s, int n) 782*3de6a9c0SDavid du Colombier { 783*3de6a9c0SDavid du Colombier char *e; 784*3de6a9c0SDavid du Colombier 785*3de6a9c0SDavid du Colombier if(consuart == nil || consuart->phys->putc == nil) { 786*3de6a9c0SDavid du Colombier _uartputs(s, n); 787*3de6a9c0SDavid du Colombier return; 788*3de6a9c0SDavid du Colombier } 789*3de6a9c0SDavid du Colombier 790*3de6a9c0SDavid du Colombier e = s+n; 791*3de6a9c0SDavid du Colombier for(; s<e; s++){ 792*3de6a9c0SDavid du Colombier if(*s == '\n') 793*3de6a9c0SDavid du Colombier consuart->phys->putc(consuart, '\r'); 794*3de6a9c0SDavid du Colombier consuart->phys->putc(consuart, *s); 795*3de6a9c0SDavid du Colombier } 796*3de6a9c0SDavid du Colombier } 797