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 #include "../port/netif.h" 9 10 /* 11 * currently no DMA or flow control (hardware or software) 12 */ 13 14 enum 15 { 16 Stagesize= 1024, 17 Dmabufsize=Stagesize/2, 18 Nuart=7, /* max per machine */ 19 20 CTLS= 023, 21 CTLQ= 021, 22 }; 23 24 typedef struct Uart Uart; 25 struct Uart 26 { 27 QLock; 28 29 int opens; 30 31 int enabled; 32 33 int frame; /* framing errors */ 34 int overrun; /* rcvr overruns */ 35 int soverrun; /* software overruns */ 36 int perror; /* parity error */ 37 int bps; /* baud rate */ 38 uchar bits; 39 char parity; 40 41 int inters; /* total interrupt count */ 42 int rinters; /* interrupts due to read */ 43 int winters; /* interrupts due to write */ 44 45 int rcount; /* total read count */ 46 int wcount; /* total output count */ 47 48 int xonoff; /* software flow control on */ 49 int blocked; /* output blocked */ 50 51 /* buffers */ 52 int (*putc)(Queue*, int); 53 Queue *iq; 54 Queue *oq; 55 56 int port; 57 UartReg *reg; 58 59 /* staging areas to avoid some of the per character costs */ 60 uchar *ip; 61 uchar *ie; 62 uchar *op; 63 uchar *oe; 64 65 /* put large buffers last to aid register-offset optimizations: */ 66 char name[KNAMELEN]; 67 uchar istage[Stagesize]; 68 uchar ostage[Stagesize]; 69 }; 70 71 enum { 72 UTCR0_PE= 0x01, 73 UTCR0_OES= 0x02, 74 UTCR0_SBS= 0x04, 75 UTCR0_DSS= 0x08, 76 UTCR0_SCE= 0x10, 77 UTCR0_RCE= 0x20, 78 UTCR0_TCE= 0x40, 79 80 UTCR3_RXE= 0x01, 81 UTCR3_TXE= 0x02, 82 UTCR3_BRK= 0x04, 83 UTCR3_RIM= 0x08, 84 UTCR3_TIM= 0x10, 85 UTCR3_LBM= 0x20, 86 87 UTSR0_TFS= 0x01, 88 UTSR0_RFS= 0x02, 89 UTSR0_RID= 0x04, 90 UTSR0_RBB= 0x08, 91 UTSR0_REB= 0x10, 92 UTSR0_EIF= 0x20, 93 94 UTSR1_TBY= 0x01, 95 UTSR1_RNE= 0x02, 96 UTSR1_TNF= 0x04, 97 UTSR1_PRE= 0x08, 98 UTSR1_FRE= 0x10, 99 UTSR1_ROR= 0x20, 100 }; 101 102 static Uart *uart[Nuart]; 103 static int nuart; 104 static int uartspcl; 105 int redirectconsole; 106 107 static void 108 uartset(Uart *p) 109 { 110 UartReg *reg = p->reg; 111 ulong ocr3; 112 ulong brdiv; 113 int n; 114 115 brdiv = CLOCKFREQ/16/p->bps - 1; 116 ocr3 = reg->utcr3; 117 reg->utcr3 = ocr3&~(UTCR3_RXE|UTCR3_TXE); 118 reg->utcr1 = brdiv >> 8; 119 reg->utcr2 = brdiv & 0xff; 120 /* set PE and OES appropriately for o/e/n: */ 121 reg->utcr0 = ((p->parity&3)^UTCR0_OES)|(p->bits&UTCR0_DSS); 122 reg->utcr3 = ocr3; 123 124 /* set buffer length according to speed, to allow 125 * at most a 200ms delay before dumping the staging buffer 126 * into the input queue 127 */ 128 n = p->bps/(10*1000/200); 129 p->ie = &p->istage[n < Stagesize ? n : Stagesize]; 130 } 131 132 /* 133 * send break 134 */ 135 static void 136 uartbreak(Uart *p, int ms) 137 { 138 UartReg *reg = p->reg; 139 if(ms == 0) 140 ms = 200; 141 reg->utcr3 |= UTCR3_BRK; 142 tsleep(&up->sleep, return0, 0, ms); 143 reg->utcr3 &= ~UTCR3_BRK; 144 } 145 146 /* 147 * turn on a port 148 */ 149 static void 150 uartenable(Uart *p) 151 { 152 UartReg *reg = p->reg; 153 154 if(p->enabled) 155 return; 156 157 archuartpower(p->port, 1); 158 uartset(p); 159 reg->utsr0 = 0xff; // clear all sticky status bits 160 // enable receive, transmit, and receive interrupt: 161 reg->utcr3 = UTCR3_RXE|UTCR3_TXE|UTCR3_RIM; 162 p->blocked = 0; 163 p->xonoff = 0; 164 p->enabled = 1; 165 } 166 167 /* 168 * turn off a port 169 */ 170 static void 171 uartdisable(Uart *p) 172 { 173 p->reg->utcr3 = 0; // disable TX, RX, and ints 174 p->blocked = 0; 175 p->xonoff = 0; 176 p->enabled = 0; 177 archuartpower(p->port, 0); 178 } 179 180 /* 181 * put some bytes into the local queue to avoid calling 182 * qconsume for every character 183 */ 184 static int 185 stageoutput(Uart *p) 186 { 187 int n; 188 Queue *q = p->oq; 189 190 if(q == nil) 191 return 0; 192 n = qconsume(q, p->ostage, Stagesize); 193 if(n <= 0) 194 return 0; 195 p->op = p->ostage; 196 p->oe = p->ostage + n; 197 return n; 198 } 199 200 static void 201 uartxmit(Uart *p) 202 { 203 UartReg *reg = p->reg; 204 ulong e = 0; 205 206 if(!p->blocked) { 207 while(p->op < p->oe || stageoutput(p)) { 208 if(reg->utsr1 & UTSR1_TNF) { 209 reg->utdr = *(p->op++); 210 p->wcount++; 211 } else { 212 e = UTCR3_TIM; 213 break; 214 } 215 } 216 } 217 reg->utcr3 = (reg->utcr3&~UTCR3_TIM)|e; 218 } 219 220 static void 221 uartrecvq(Uart *p) 222 { 223 uchar *cp = p->istage; 224 int n = p->ip - cp; 225 226 if(n == 0) 227 return; 228 if(p->putc) 229 while(n-- > 0) 230 p->putc(p->iq, *cp++); 231 else if(p->iq) 232 if(qproduce(p->iq, p->istage, n) < n){ 233 /* if xonoff, should send XOFF when qwindow(p->iq) < threshold */ 234 p->soverrun++; 235 //print("qproduce flow control"); 236 } 237 p->ip = p->istage; 238 } 239 240 static void 241 uartrecv(Uart *p) 242 { 243 UartReg *reg = p->reg; 244 ulong n; 245 while(reg->utsr1 & UTSR1_RNE) { 246 int c; 247 n = reg->utsr1; 248 c = reg->utdr; 249 if(n & (UTSR1_PRE|UTSR1_FRE|UTSR1_ROR)) { 250 if(n & UTSR1_PRE) 251 p->perror++; 252 if(n & UTSR1_FRE) 253 p->frame++; 254 if(n & UTSR1_ROR) 255 p->overrun++; 256 continue; 257 } 258 if(p->xonoff){ 259 if(c == CTLS){ 260 p->blocked = 1; 261 }else if (c == CTLQ){ 262 p->blocked = 0; 263 } 264 } 265 *p->ip++ = c; 266 if(p->ip >= p->ie) 267 uartrecvq(p); 268 p->rcount++; 269 } 270 if(reg->utsr0 & UTSR0_RID) { 271 reg->utsr0 = UTSR0_RID; 272 uartrecvq(p); 273 } 274 } 275 276 static void 277 uartclock(void) 278 { 279 Uart *p; 280 int i; 281 282 for(i=0; i<nuart; i++){ 283 p = uart[i]; 284 if(p != nil) 285 uartrecvq(p); 286 } 287 } 288 289 static void 290 uartkick(void *a) 291 { 292 Uart *p = a; 293 int x; 294 295 x = splhi(); 296 uartxmit(p); 297 splx(x); 298 } 299 300 /* 301 * UART Interrupt Handler 302 */ 303 static void 304 uartintr(Ureg*, void* arg) 305 { 306 Uart *p = arg; 307 UartReg *reg = p->reg; 308 ulong m = reg->utsr0; 309 int dokick; 310 311 dokick = p->blocked; 312 p->inters++; 313 if(m & (UTSR0_RFS|UTSR0_RID|UTSR0_EIF)) { 314 p->rinters++; 315 uartrecv(p); 316 } 317 if(p->blocked) 318 dokick = 0; 319 if((m & UTSR0_TFS) && (reg->utcr3&UTCR3_TIM || dokick)) { 320 p->winters++; 321 uartxmit(p); 322 } 323 324 if(m & (UTSR0_RBB|UTSR0_REB)) { 325 //print("<BREAK>"); 326 /* reg->utsr0 = UTSR0_RBB|UTSR0_REB; */ 327 reg->utsr0 = m & (UTSR0_RBB|UTSR0_REB); 328 /* what to do? if anything */ 329 } 330 } 331 332 static void 333 uartsetup(ulong port, char *name) 334 { 335 Uart *p; 336 337 if(nuart >= Nuart) 338 return; 339 340 p = xalloc(sizeof(Uart)); 341 uart[nuart++] = p; 342 strcpy(p->name, name); 343 344 p->port = port; 345 p->reg = UARTREG(port); 346 p->bps = 9600; 347 p->bits = 8; 348 p->parity = 'n'; 349 350 p->iq = qopen(4*1024, 0, 0 , p); 351 p->oq = qopen(4*1024, 0, uartkick, p); 352 353 p->ip = p->istage; 354 p->ie = &p->istage[Stagesize]; 355 p->op = p->ostage; 356 p->oe = p->ostage; 357 if(port == 1) 358 GPCLKREG->gpclkr0 |= 1; /* SUS=1 for uart on serial 1 */ 359 360 intrenable(UARTbit(port), uartintr, p, BusCPU, name); 361 } 362 363 static void 364 uartinstall(void) 365 { 366 static int already; 367 368 if(already) 369 return; 370 already = 1; 371 372 uartsetup(3, "eia0"); 373 uartsetup(1, "eia1"); 374 addclock0link(uartclock, 22); 375 } 376 377 /* 378 * called by main() to configure a duart port as a console or a mouse 379 */ 380 void 381 uartspecial(int port, int bps, char parity, Queue **in, Queue **out, int (*putc)(Queue*, int)) 382 { 383 Uart *p; 384 385 uartinstall(); 386 if(port >= nuart) 387 return; 388 p = uart[port]; 389 if(bps) 390 p->bps = bps; 391 if(parity) 392 p->parity = parity; 393 uartenable(p); 394 p->putc = putc; 395 if(in) 396 *in = p->iq; 397 if(out) 398 *out = p->oq; 399 p->opens++; 400 uartspcl = 1; 401 } 402 403 Dirtab *uartdir; 404 int ndir; 405 406 static void 407 setlength(int i) 408 { 409 Uart *p; 410 411 if(i > 0){ 412 p = uart[i]; 413 if(p && p->opens && p->iq) 414 uartdir[1+3*i].length = qlen(p->iq); 415 } else for(i = 0; i < nuart; i++){ 416 p = uart[i]; 417 if(p && p->opens && p->iq) 418 uartdir[1+3*i].length = qlen(p->iq); 419 } 420 } 421 422 /* 423 * all uarts must be uartsetup() by this point or inside of uartinstall() 424 */ 425 static void 426 uartreset(void) 427 { 428 int i; 429 Dirtab *dp; 430 431 uartinstall(); 432 433 ndir = 1+3*nuart; 434 uartdir = xalloc(ndir * sizeof(Dirtab)); 435 dp = uartdir; 436 strcpy(dp->name, "."); 437 mkqid(&dp->qid, 0, 0, QTDIR); 438 dp->length = 0; 439 dp->perm = DMDIR|0555; 440 dp++; 441 for(i = 0; i < nuart; i++){ 442 /* 3 directory entries per port */ 443 strcpy(dp->name, uart[i]->name); 444 dp->qid.path = NETQID(i, Ndataqid); 445 dp->perm = 0660; 446 dp++; 447 sprint(dp->name, "%sctl", uart[i]->name); 448 dp->qid.path = NETQID(i, Nctlqid); 449 dp->perm = 0660; 450 dp++; 451 sprint(dp->name, "%sstatus", uart[i]->name); 452 dp->qid.path = NETQID(i, Nstatqid); 453 dp->perm = 0444; 454 dp++; 455 } 456 } 457 458 static Chan* 459 uartattach(char *spec) 460 { 461 return devattach('t', spec); 462 } 463 464 static Walkqid* 465 uartwalk(Chan *c, Chan *nc, char **name, int nname) 466 { 467 return devwalk(c, nc, name, nname, uartdir, ndir, devgen); 468 } 469 470 static int 471 uartstat(Chan *c, uchar *dp, int n) 472 { 473 if(NETTYPE(c->qid.path) == Ndataqid) 474 setlength(NETID(c->qid.path)); 475 return devstat(c, dp, n, uartdir, ndir, devgen); 476 } 477 478 static Chan* 479 uartopen(Chan *c, int omode) 480 { 481 Uart *p; 482 483 c = devopen(c, omode, uartdir, ndir, devgen); 484 485 switch(NETTYPE(c->qid.path)){ 486 case Nctlqid: 487 case Ndataqid: 488 p = uart[NETID(c->qid.path)]; 489 qlock(p); 490 if(p->opens++ == 0){ 491 uartenable(p); 492 qreopen(p->iq); 493 qreopen(p->oq); 494 } 495 qunlock(p); 496 break; 497 } 498 499 return c; 500 } 501 502 static void 503 uartclose(Chan *c) 504 { 505 Uart *p; 506 507 if(c->qid.type & QTDIR) 508 return; 509 if((c->flag & COPEN) == 0) 510 return; 511 switch(NETTYPE(c->qid.path)){ 512 case Ndataqid: 513 case Nctlqid: 514 p = uart[NETID(c->qid.path)]; 515 qlock(p); 516 if(--(p->opens) == 0){ 517 uartdisable(p); 518 qclose(p->iq); 519 qclose(p->oq); 520 p->ip = p->istage; 521 } 522 qunlock(p); 523 break; 524 } 525 } 526 527 static long 528 uartstatus(Chan *c, Uart *p, void *buf, long n, long offset) 529 { 530 char str[256]; 531 USED(c); 532 533 str[0] = 0; 534 snprint(str, sizeof(str), 535 "b%d l%d p%c s%d x%d\n" 536 "opens %d ferr %d oerr %d perr %d baud %d parity %c" 537 " intr %d rintr %d wintr %d" 538 " rcount %d wcount %d", 539 p->bps, p->bits, p->parity, (p->reg->utcr0&UTCR0_SBS)?2:1, p->xonoff, 540 p->opens, p->frame, p->overrun+p->soverrun, p->perror, p->bps, p->parity, 541 p->inters, p->rinters, p->winters, 542 p->rcount, p->wcount); 543 544 strcat(str, "\n"); 545 return readstr(offset, buf, n, str); 546 } 547 548 static long 549 uartread(Chan *c, void *buf, long n, vlong offset) 550 { 551 Uart *p; 552 553 if(c->qid.type & QTDIR){ 554 setlength(-1); 555 return devdirread(c, buf, n, uartdir, ndir, devgen); 556 } 557 558 p = uart[NETID(c->qid.path)]; 559 switch(NETTYPE(c->qid.path)){ 560 case Ndataqid: 561 return qread(p->iq, buf, n); 562 case Nctlqid: 563 return readnum(offset, buf, n, NETID(c->qid.path), NUMSIZE); 564 case Nstatqid: 565 return uartstatus(c, p, buf, n, offset); 566 } 567 568 return 0; 569 } 570 571 static void 572 uartctl(Uart *p, char *cmd) 573 { 574 int i, n; 575 576 /* let output drain for a while (up to 4 secs) */ 577 for(i = 0; i < 200 && (qlen(p->oq) || p->reg->utsr1 & UTSR1_TBY); i++) 578 tsleep(&up->sleep, return0, 0, 20); 579 580 if(strncmp(cmd, "break", 5) == 0){ 581 uartbreak(p, 0); 582 return; 583 } 584 585 n = atoi(cmd+1); 586 switch(*cmd){ 587 case 'B': 588 case 'b': 589 if(n <= 0) 590 error(Ebadarg); 591 p->bps = n; 592 uartset(p); 593 break; 594 case 'f': 595 case 'F': 596 qflush(p->oq); 597 break; 598 case 'H': 599 case 'h': 600 qhangup(p->iq, 0); 601 qhangup(p->oq, 0); 602 break; 603 case 'L': 604 case 'l': 605 if(n < 7 || n > 8) 606 error(Ebadarg); 607 p->bits = n; 608 uartset(p); 609 break; 610 case 'n': 611 case 'N': 612 qnoblock(p->oq, n); 613 break; 614 case 'P': 615 case 'p': 616 p->parity = *(cmd+1); 617 uartset(p); 618 break; 619 case 'K': 620 case 'k': 621 uartbreak(p, n); 622 break; 623 case 'Q': 624 case 'q': 625 qsetlimit(p->iq, n); 626 qsetlimit(p->oq, n); 627 break; 628 case 'X': 629 case 'x': 630 p->xonoff = n; 631 break; 632 } 633 } 634 635 static long 636 uartwrite(Chan *c, void *buf, long n, vlong offset) 637 { 638 Uart *p; 639 char cmd[32]; 640 641 USED(offset); 642 643 if(c->qid.type & QTDIR) 644 error(Eperm); 645 646 p = uart[NETID(c->qid.path)]; 647 648 switch(NETTYPE(c->qid.path)){ 649 case Ndataqid: 650 return qwrite(p->oq, buf, n); 651 case Nctlqid: 652 653 if(n >= sizeof(cmd)) 654 n = sizeof(cmd)-1; 655 memmove(cmd, buf, n); 656 cmd[n] = 0; 657 uartctl(p, cmd); 658 return n; 659 default: 660 error(Egreg); 661 return 0; 662 } 663 } 664 665 static int 666 uartwstat(Chan *c, uchar *dp, int n) 667 { 668 Dir d; 669 Dirtab *dt; 670 671 if(!iseve()) 672 error(Eperm); 673 if(c->qid.type & QTDIR) 674 error(Eperm); 675 if(NETTYPE(c->qid.path) == Nstatqid) 676 error(Eperm); 677 678 dt = &uartdir[1+3 * NETID(c->qid.path)]; 679 n = convM2D(dp, n, &d, nil); 680 if(d.mode != ~0UL){ 681 d.mode &= 0666; 682 dt[0].perm = dt[1].perm = d.mode; 683 } 684 return n; 685 } 686 687 void 688 uartpower(int on) 689 { 690 Uart *p; 691 int i; 692 693 for(i=0; i<nuart; i++){ 694 p = uart[i]; 695 if(p != nil && p->opens){ 696 if(on && !p->enabled){ 697 p->enabled = 0; 698 uartenable(p); 699 uartkick(p); 700 }else{ 701 if(p->port != 3) /* leave the console */ 702 uartdisable(p); 703 p->enabled = 0; 704 } 705 } 706 } 707 } 708 709 Dev uartdevtab = { 710 't', 711 "uart", 712 713 uartreset, 714 devinit, 715 devshutdown, 716 uartattach, 717 uartwalk, 718 uartstat, 719 uartopen, 720 devcreate, 721 uartclose, 722 uartread, 723 devbread, 724 uartwrite, 725 devbwrite, 726 devremove, 727 uartwstat, 728 uartpower, 729 }; 730 731 /* 732 * for use by iprint 733 */ 734 void 735 uartputc(int c) 736 { 737 UartReg *r; 738 739 if(!uartspcl && !redirectconsole) 740 return; 741 if(c == 0) 742 return; 743 r = UARTREG(3); 744 while((r->utsr1 & UTSR1_TNF) == 0) 745 {} 746 r->utdr = c; 747 if(c == '\n') 748 while(r->utsr1 & UTSR1_TBY) /* flush xmit fifo */ 749 {} 750 } 751 752 void 753 uartputs(char *data, int len) 754 { 755 int s; 756 757 if(!uartspcl && !redirectconsole) 758 return; 759 clockpoll(); 760 s = splfhi(); 761 while(--len >= 0){ 762 if(*data == '\n') 763 uartputc('\r'); 764 uartputc(*data++); 765 } 766 splx(s); 767 } 768 769 /* 770 * for use by debugger 771 */ 772 int 773 uartgetc(void) 774 { 775 UartReg *r; 776 777 if(!uartspcl) 778 return -1; 779 clockcheck(); 780 r = UARTREG(3); 781 while(!(r->utsr1 & UTSR1_RNE)) 782 clockcheck(); 783 return r->utdr; 784 } 785