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