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