1 /* tty.c 3.3 10/14/12 */ 2 3 /* 4 * general TTY subroutines 5 */ 6 #include "../h/param.h" 7 #include "../h/systm.h" 8 #include "../h/dir.h" 9 #include "../h/user.h" 10 #include "../h/tty.h" 11 #include "../h/proc.h" 12 #include "../h/mx.h" 13 #include "../h/inode.h" 14 #include "../h/file.h" 15 #include "../h/reg.h" 16 #include "../h/conf.h" 17 #include "../h/buf.h" 18 19 char partab[]; 20 21 /* 22 * When running dz's using only SAE (silo alarm) on input 23 * it is necessary to call dzrint() at clock interrupt time. 24 * This is unsafe unless spl5()s in tty code are changed to 25 * spl6()s to block clock interrupts. Note that the dh driver 26 * currently in use works the same way as the dz, even though 27 * we could try to more intelligently manage its silo. 28 * Thus don't take this out if you have no dz's unless you 29 * change clock.c and dhtimer(). 30 */ 31 #define spl5 spl6 32 33 /* 34 * Input mapping table-- if an entry is non-zero, when the 35 * corresponding character is typed preceded by "\" the escape 36 * sequence is replaced by the table value. Mostly used for 37 * upper-case only terminals. 38 */ 39 40 char maptab[] ={ 41 000,000,000,000,000,000,000,000, 42 000,000,000,000,000,000,000,000, 43 000,000,000,000,000,000,000,000, 44 000,000,000,000,000,000,000,000, 45 000,'|',000,000,000,000,000,'`', 46 '{','}',000,000,000,000,000,000, 47 000,000,000,000,000,000,000,000, 48 000,000,000,000,000,000,000,000, 49 000,000,000,000,000,000,000,000, 50 000,000,000,000,000,000,000,000, 51 000,000,000,000,000,000,000,000, 52 000,000,000,000,000,000,'~',000, 53 000,'A','B','C','D','E','F','G', 54 'H','I','J','K','L','M','N','O', 55 'P','Q','R','S','T','U','V','W', 56 'X','Y','Z',000,000,000,000,000, 57 }; 58 59 60 /* 61 * shorthand 62 */ 63 #define q1 tp->t_rawq 64 #define q2 tp->t_canq 65 #define q3 tp->t_outq 66 #define q4 tp->t_un.t_ctlq 67 68 #define OBUFSIZ 100 69 70 /* 71 * routine called on first teletype open. 72 * establishes a process group for distribution 73 * of quits and interrupts from the tty. 74 */ 75 ttyopen(dev, tp) 76 dev_t dev; 77 register struct tty *tp; 78 { 79 register struct proc *pp; 80 81 pp = u.u_procp; 82 tp->t_dev = dev; 83 if(pp->p_pgrp == 0) { 84 u.u_ttyp = tp; 85 u.u_ttyd = dev; 86 if (tp->t_pgrp==0) 87 tp->t_pgrp = pp->p_pid; 88 pp->p_pgrp = tp->t_pgrp; 89 } 90 tp->t_state &= ~WOPEN; 91 tp->t_state |= ISOPEN; 92 } 93 94 95 /* 96 * set default control characters. 97 */ 98 ttychars(tp) 99 register struct tty *tp; 100 { 101 tun.t_intrc = CINTR; 102 tun.t_quitc = CQUIT; 103 tun.t_startc = CSTART; 104 tun.t_stopc = CSTOP; 105 tun.t_eofc = CEOT; 106 tun.t_brkc = CBRK; 107 tp->t_erase = CERASE; 108 tp->t_kill = CKILL; 109 } 110 111 /* 112 * clean tp on last close 113 */ 114 ttyclose(tp) 115 register struct tty *tp; 116 { 117 118 tp->t_pgrp = 0; 119 wflushtty(tp); 120 tp->t_state = 0; 121 } 122 123 /* 124 * stty/gtty writearound 125 */ 126 stty() 127 { 128 u.u_arg[2] = u.u_arg[1]; 129 u.u_arg[1] = TIOCSETP; 130 ioctl(); 131 } 132 133 gtty() 134 { 135 u.u_arg[2] = u.u_arg[1]; 136 u.u_arg[1] = TIOCGETP; 137 ioctl(); 138 } 139 140 /* 141 * Do nothing specific version of line 142 * discipline specific ioctl command. 143 */ 144 nullioctl(tp, cmd, addr) 145 register struct tty *tp; 146 caddr_t addr; 147 { 148 149 return (cmd); 150 } 151 152 /* 153 * ioctl system call 154 * Check legality, execute common code, and switch out to individual 155 * device routine. 156 */ 157 ioctl() 158 { 159 register struct file *fp; 160 register struct inode *ip; 161 register struct a { 162 int fdes; 163 int cmd; 164 caddr_t cmarg; 165 } *uap; 166 register dev_t dev; 167 register fmt; 168 169 uap = (struct a *)u.u_ap; 170 if ((fp = getf(uap->fdes)) == NULL) 171 return; 172 if (uap->cmd==FIOCLEX) { 173 u.u_pofile[uap->fdes] |= EXCLOSE; 174 return; 175 } 176 if (uap->cmd==FIONCLEX) { 177 u.u_pofile[uap->fdes] &= ~EXCLOSE; 178 return; 179 } 180 ip = fp->f_inode; 181 fmt = ip->i_mode & IFMT; 182 if (fmt != IFCHR && fmt != IFMPC) { 183 u.u_error = ENOTTY; 184 return; 185 } 186 dev = ip->i_un.i_rdev; 187 u.u_r.r_val1 = 0; 188 (*cdevsw[major(dev)].d_ioctl)(dev, uap->cmd, uap->cmarg, fp->f_flag); 189 } 190 191 /* 192 * Common code for several tty ioctl commands 193 */ 194 ttioccomm(com, tp, addr, dev) 195 register struct tty *tp; 196 caddr_t addr; 197 { 198 unsigned t; 199 struct ttiocb iocb; 200 extern int nldisp; 201 register s; 202 203 switch(com) { 204 205 /* 206 * get discipline number 207 */ 208 case TIOCGETD: 209 t = tp->t_line; 210 if (copyout((caddr_t)&t, addr, sizeof(t))) 211 u.u_error = EFAULT; 212 break; 213 214 /* 215 * set line discipline 216 */ 217 case TIOCSETD: 218 if (copyin(addr, (caddr_t)&t, sizeof(t))) { 219 u.u_error = EFAULT; 220 break; 221 } 222 if (t >= nldisp) { 223 u.u_error = ENXIO; 224 break; 225 } 226 s = spl5(); 227 if (tp->t_line) 228 (*linesw[tp->t_line].l_close)(tp); 229 if (t) 230 (*linesw[t].l_open)(dev, tp, addr); 231 if (u.u_error==0) 232 tp->t_line = t; 233 splx(s); 234 break; 235 236 /* 237 * prevent more opens on channel 238 */ 239 case TIOCEXCL: 240 tp->t_state |= XCLUDE; 241 break; 242 243 case TIOCNXCL: 244 tp->t_state &= ~XCLUDE; 245 break; 246 247 /* 248 * Set new parameters 249 */ 250 case TIOCSETP: 251 wflushtty(tp); 252 case TIOCSETN: 253 if (copyin(addr, (caddr_t)&iocb, sizeof(iocb))) { 254 u.u_error = EFAULT; 255 return(1); 256 } 257 (void) spl5(); 258 while (canon(tp)>=0) 259 ; 260 if ((tp->t_state&SPEEDS)==0) { 261 tp->t_ispeed = iocb.ioc_ispeed; 262 tp->t_ospeed = iocb.ioc_ospeed; 263 } 264 tp->t_erase = iocb.ioc_erase; 265 tp->t_kill = iocb.ioc_kill; 266 tp->t_flags = iocb.ioc_flags; 267 (void) spl0(); 268 break; 269 270 /* 271 * send current parameters to user 272 */ 273 case TIOCGETP: 274 iocb.ioc_ispeed = tp->t_ispeed; 275 iocb.ioc_ospeed = tp->t_ospeed; 276 iocb.ioc_erase = tp->t_erase; 277 iocb.ioc_kill = tp->t_kill; 278 iocb.ioc_flags = tp->t_flags; 279 if (copyout((caddr_t)&iocb, addr, sizeof(iocb))) 280 u.u_error = EFAULT; 281 break; 282 283 /* 284 * Hang up line on last close 285 */ 286 287 case TIOCHPCL: 288 tp->t_state |= HUPCLS; 289 break; 290 291 case TIOCFLUSH: 292 flushtty(tp); 293 break; 294 295 /* 296 * ioctl entries to line discipline 297 */ 298 case DIOCSETP: 299 case DIOCGETP: 300 if ((*linesw[tp->t_line].l_ioctl)(com, tp, addr)) 301 u.u_error = ENOTTY; 302 break; 303 304 /* 305 * set and fetch special characters 306 */ 307 case TIOCSETC: 308 if (copyin(addr, (caddr_t)&tun, sizeof(struct tc))) 309 u.u_error = EFAULT; 310 break; 311 312 case TIOCGETC: 313 if (copyout((caddr_t)&tun, addr, sizeof(struct tc))) 314 u.u_error = EFAULT; 315 break; 316 317 default: 318 return(0); 319 } 320 return(1); 321 } 322 323 /* 324 * Wait for output to drain, then flush input waiting. 325 */ 326 wflushtty(tp) 327 register struct tty *tp; 328 { 329 330 (void) spl5(); 331 while (tp->t_outq.c_cc && tp->t_state&CARR_ON) { 332 (*tp->t_oproc)(tp); 333 tp->t_state |= ASLEEP; 334 sleep((caddr_t)&tp->t_outq, TTOPRI); 335 } 336 flushtty(tp); 337 (void) spl0(); 338 } 339 340 /* 341 * flush all TTY queues 342 */ 343 flushtty(tp) 344 register struct tty *tp; 345 { 346 register s; 347 348 s = spl6(); 349 while (getc(&tp->t_canq) >= 0) 350 ; 351 wakeup((caddr_t)&tp->t_rawq); 352 wakeup((caddr_t)&tp->t_outq); 353 tp->t_state &= ~TTSTOP; 354 (*cdevsw[major(tp->t_dev)].d_stop)(tp); 355 while (getc(&tp->t_outq) >= 0) 356 ; 357 while (getc(&tp->t_rawq) >= 0) 358 ; 359 tp->t_delct = 0; 360 splx(s); 361 } 362 363 364 365 /* 366 * transfer raw input list to canonical list, 367 * doing erase-kill processing and handling escapes. 368 * It waits until a full line has been typed in cooked mode, 369 * or until any character has been typed in raw mode. 370 */ 371 canon(tp) 372 register struct tty *tp; 373 { 374 register char *bp; 375 char *bp1; 376 register int c; 377 int mc; 378 int s; 379 380 if ((tp->t_flags&(RAW|CBREAK))==0 && tp->t_delct==0 381 || (tp->t_flags&(RAW|CBREAK))!=0 && tp->t_rawq.c_cc==0) { 382 return(-1); 383 } 384 s = spl0(); 385 loop: 386 bp = &canonb[2]; 387 while ((c=getc(&tp->t_rawq)) >= 0) { 388 if ((tp->t_flags&(RAW|CBREAK))==0) { 389 if (c==0377) { 390 tp->t_delct--; 391 break; 392 } 393 if (bp[-1]!='\\') { 394 if (c==tp->t_erase) { 395 if (bp > &canonb[2]) 396 bp--; 397 continue; 398 } 399 if (c==tp->t_kill) 400 goto loop; 401 if (c==tun.t_eofc) 402 continue; 403 } else { 404 mc = maptab[c]; 405 if (c==tp->t_erase || c==tp->t_kill) 406 mc = c; 407 if (mc && (mc==c || (tp->t_flags&LCASE))) { 408 if (bp[-2] != '\\') 409 c = mc; 410 bp--; 411 } 412 } 413 } 414 *bp++ = c; 415 if (bp>=canonb+CANBSIZ) 416 break; 417 } 418 bp1 = &canonb[2]; 419 (void) b_to_q(bp1, bp-bp1, &tp->t_canq); 420 421 if (tp->t_state&TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) { 422 if (putc(tun.t_startc, &tp->t_outq)==0) { 423 tp->t_state &= ~TBLOCK; 424 ttstart(tp); 425 } 426 tp->t_char = 0; 427 } 428 429 splx(s); 430 return(0); 431 } 432 433 434 /* 435 * block transfer input handler. 436 */ 437 ttyrend(tp, pb, pe) 438 register struct tty *tp; 439 register char *pb, *pe; 440 { 441 int tandem; 442 443 tandem = tp->t_flags&TANDEM; 444 if (tp->t_flags&RAW) { 445 (void) b_to_q(pb, pe-pb, &tp->t_rawq); 446 if (tp->t_chan) 447 (void) sdata(tp->t_chan); else 448 wakeup((caddr_t)&tp->t_rawq); 449 } else { 450 tp->t_flags &= ~TANDEM; 451 while (pb < pe) 452 ttyinput(*pb++, tp); 453 tp->t_flags |= tandem; 454 } 455 if (tandem) 456 ttyblock(tp); 457 } 458 459 /* 460 * Place a character on raw TTY input queue, putting in delimiters 461 * and waking up top half as needed. 462 * Also echo if required. 463 * The arguments are the character and the appropriate 464 * tty structure. 465 */ 466 ttyinput(c, tp) 467 register c; 468 register struct tty *tp; 469 { 470 register int t_flags; 471 register struct chan *cp; 472 473 tk_nin += 1; 474 c &= 0377; 475 t_flags = tp->t_flags; 476 if (t_flags&TANDEM) 477 ttyblock(tp); 478 if ((t_flags&RAW)==0) { 479 c &= 0177; 480 if (tp->t_state&TTSTOP) { 481 if (c==tun.t_startc) { 482 tp->t_state &= ~TTSTOP; 483 ttstart(tp); 484 return; 485 } 486 if (c==tun.t_stopc) 487 return; 488 tp->t_state &= ~TTSTOP; 489 ttstart(tp); 490 } else { 491 if (c==tun.t_stopc) { 492 tp->t_state |= TTSTOP; 493 (*cdevsw[major(tp->t_dev)].d_stop)(tp); 494 return; 495 } 496 if (c==tun.t_startc) 497 return; 498 } 499 if (c==tun.t_quitc || c==tun.t_intrc) { 500 flushtty(tp); 501 c = (c==tun.t_intrc) ? SIGINT:SIGQUIT; 502 if (tp->t_chan) 503 scontrol(tp->t_chan, M_SIG, c); 504 else 505 signal(tp->t_pgrp, c); 506 return; 507 } 508 if (c=='\r' && t_flags&CRMOD) 509 c = '\n'; 510 } 511 if (tp->t_rawq.c_cc>TTYHOG) { 512 flushtty(tp); 513 return; 514 } 515 if (t_flags&LCASE && c>='A' && c<='Z') 516 c += 'a'-'A'; 517 (void) putc(c, &tp->t_rawq); 518 if (t_flags&(RAW|CBREAK)||(c=='\n'||c==tun.t_eofc||c==tun.t_brkc)) { 519 if ((t_flags&(RAW|CBREAK))==0 && putc(0377, &tp->t_rawq)==0) 520 tp->t_delct++; 521 if ((cp=tp->t_chan)!=NULL) 522 (void) sdata(cp); else 523 wakeup((caddr_t)&tp->t_rawq); 524 } 525 if (t_flags&ECHO) { 526 ttyoutput(c, tp); 527 if (c==tp->t_kill && (t_flags&(RAW|CBREAK))==0) 528 ttyoutput('\n', tp); 529 ttstart(tp); 530 } 531 } 532 533 534 /* 535 * Send stop character on input overflow. 536 */ 537 ttyblock(tp) 538 register struct tty *tp; 539 { 540 register x; 541 x = q1.c_cc + q2.c_cc; 542 if (q1.c_cc > TTYHOG) { 543 flushtty(tp); 544 tp->t_state &= ~TBLOCK; 545 } 546 if (x >= TTYHOG/2) { 547 if (putc(tun.t_stopc, &tp->t_outq)==0) { 548 tp->t_state |= TBLOCK; 549 tp->t_char++; 550 ttstart(tp); 551 } 552 } 553 } 554 555 /* 556 * put character on TTY output queue, adding delays, 557 * expanding tabs, and handling the CR/NL bit. 558 * It is called both from the top half for output, and from 559 * interrupt level for echoing. 560 * The arguments are the character and the tty structure. 561 */ 562 ttyoutput(c, tp) 563 register c; 564 register struct tty *tp; 565 { 566 register char *colp; 567 register ctype; 568 569 /* 570 * Ignore EOT in normal mode to avoid hanging up 571 * certain terminals. 572 * In raw mode dump the char unchanged. 573 */ 574 if ((tp->t_flags&RAW)==0) { 575 c &= 0177; 576 if ((tp->t_flags&CBREAK)==0 && c==CEOT) 577 return; 578 } else { 579 tk_nout++; 580 (void) putc(c, &tp->t_outq); 581 return; 582 } 583 584 /* 585 * Turn tabs to spaces as required 586 */ 587 if (c=='\t' && (tp->t_flags&TBDELAY)==XTABS) { 588 c = 8 - (tp->t_col & 7); 589 (void) b_to_q(" ", c, &tp->t_outq); 590 tp->t_col += c; 591 tk_nout += c; 592 return; 593 } 594 tk_nout++; 595 /* 596 * for upper-case-only terminals, 597 * generate escapes. 598 */ 599 if (tp->t_flags&LCASE) { 600 colp = "({)}!|^~'`"; 601 while(*colp++) 602 if(c == *colp++) { 603 ttyoutput('\\', tp); 604 c = colp[-2]; 605 break; 606 } 607 if ('a'<=c && c<='z') 608 c += 'A' - 'a'; 609 } 610 /* 611 * turn <nl> to <cr><lf> if desired. 612 */ 613 if (c=='\n' && tp->t_flags&CRMOD) 614 ttyoutput('\r', tp); 615 (void) putc(c, &tp->t_outq); 616 /* 617 * Calculate delays. 618 * The numbers here represent clock ticks 619 * and are not necessarily optimal for all terminals. 620 * The delays are indicated by characters above 0200. 621 * In raw mode there are no delays and the 622 * transmission path is 8 bits wide. 623 */ 624 colp = &tp->t_col; 625 ctype = partab[c]; 626 c = 0; 627 switch (ctype&077) { 628 629 /* ordinary */ 630 case 0: 631 (*colp)++; 632 633 /* non-printing */ 634 case 1: 635 break; 636 637 /* backspace */ 638 case 2: 639 if (*colp) 640 (*colp)--; 641 break; 642 643 /* newline */ 644 case 3: 645 ctype = (tp->t_flags >> 8) & 03; 646 if(ctype == 1) { /* tty 37 */ 647 if (*colp) 648 c = max(((unsigned)*colp>>4) + 3, (unsigned)6); 649 } else 650 if(ctype == 2) { /* vt05 */ 651 c = 6; 652 } 653 *colp = 0; 654 break; 655 656 /* tab */ 657 case 4: 658 ctype = (tp->t_flags >> 10) & 03; 659 if(ctype == 1) { /* tty 37 */ 660 c = 1 - (*colp | ~07); 661 if(c < 5) 662 c = 0; 663 } 664 *colp |= 07; 665 (*colp)++; 666 break; 667 668 /* vertical motion */ 669 case 5: 670 if(tp->t_flags & VTDELAY) /* tty 37 */ 671 c = 0177; 672 break; 673 674 /* carriage return */ 675 case 6: 676 ctype = (tp->t_flags >> 12) & 03; 677 if(ctype == 1) { /* tn 300 */ 678 c = 5; 679 } else if(ctype == 2) { /* ti 700 */ 680 c = 10; 681 } else if(ctype == 3) { /* concept 100 */ 682 int i; 683 for (i= *colp; i<9; i++) 684 (void) putc(0177, &tp->t_outq); 685 } 686 *colp = 0; 687 } 688 if(c) 689 (void) putc(c|0200, &tp->t_outq); 690 } 691 692 /* 693 * Restart typewriter output following a delay 694 * timeout. 695 * The name of the routine is passed to the timeout 696 * subroutine and it is called during a clock interrupt. 697 */ 698 ttrstrt(tp) 699 register struct tty *tp; 700 { 701 702 tp->t_state &= ~TIMEOUT; 703 ttstart(tp); 704 } 705 706 /* 707 * Start output on the typewriter. It is used from the top half 708 * after some characters have been put on the output queue, 709 * from the interrupt routine to transmit the next 710 * character, and after a timeout has finished. 711 */ 712 ttstart(tp) 713 register struct tty *tp; 714 { 715 register s; 716 717 s = spl5(); 718 if((tp->t_state&(TIMEOUT|TTSTOP|BUSY)) == 0) 719 (*tp->t_oproc)(tp); 720 splx(s); 721 } 722 723 /* 724 * Called from device's read routine after it has 725 * calculated the tty-structure given as argument. 726 */ 727 ttread(tp) 728 register struct tty *tp; 729 { 730 register s; 731 732 if ((tp->t_state&CARR_ON)==0) 733 return(-1); 734 s = spl5(); 735 if (tp->t_canq.c_cc==0) 736 while (canon(tp)<0) 737 if (tp->t_chan==NULL) { 738 sleep((caddr_t)&tp->t_rawq, TTIPRI); 739 } else { 740 splx(s); 741 return(0); 742 } 743 splx(s); 744 while (tp->t_canq.c_cc && passc(getc(&tp->t_canq))>=0) 745 ; 746 return(tp->t_rawq.c_cc+tp->t_canq.c_cc); 747 } 748 749 /* 750 * Called from the device's write routine after it has 751 * calculated the tty-structure given as argument. 752 */ 753 caddr_t 754 ttwrite(tp) 755 register struct tty *tp; 756 { 757 /* 758 * THE POSITIONING OF CP, CC, AND CE ARE CRITICAL 759 * AND MUST NOT BE CHANGED WITHOUT PATCHING 760 * THE 'ASM' INLINES BELOW. WATCH OUT. 761 */ 762 register char *cp; 763 register int cc, ce; 764 register i; 765 char obuf[OBUFSIZ]; 766 767 if ((tp->t_state&CARR_ON)==0) 768 return(NULL); 769 while (u.u_count) { 770 cc = MIN(u.u_count, OBUFSIZ); 771 cp = obuf; 772 iomove(cp, (unsigned)cc, B_WRITE); 773 if (u.u_error) 774 break; 775 (void) spl5(); 776 while (tp->t_outq.c_cc > TTHIWAT) { 777 ttstart(tp); 778 tp->t_state |= ASLEEP; 779 if (tp->t_chan) { 780 u.u_base -= cc; 781 u.u_offset -= cc; 782 u.u_count += cc; 783 (void) spl0(); 784 return((caddr_t)&tp->t_outq); 785 } 786 sleep((caddr_t)&tp->t_outq, TTOPRI); 787 } 788 (void) spl0(); 789 if (tp->t_flags&LCASE) { 790 while (cc--) 791 ttyoutput(*cp++,tp); 792 continue; 793 } 794 while (cc) { 795 if (tp->t_flags&RAW) 796 ce=cc; 797 else { 798 #ifdef VAX 799 asm(" scanc r9,(r10),_partab,$077"); 800 asm(" subl3 r0,r9,r8"); 801 #else 802 ce=0; 803 while(((partab[*(cp+ce)]&077)==0)&&(ce<cc)) 804 ce++; 805 #endif 806 if (ce==0) { 807 ttyoutput(*cp++,tp); 808 cc--; 809 goto check; 810 } 811 } 812 i=b_to_q(cp,ce,&tp->t_outq); 813 ce-=i; 814 tk_nout+=ce; 815 tp->t_col+=ce; 816 cp+=ce; 817 cc-=ce; 818 if (i == 0) 819 continue; 820 check: 821 if (tp->t_outq.c_cc > TTHIWAT) { 822 (void) spl5(); 823 while (tp->t_outq.c_cc > TTHIWAT) { 824 ttstart(tp); 825 tp->t_state |= ASLEEP; 826 sleep((caddr_t)&tp->t_outq, TTOPRI); 827 } 828 (void) spl0(); 829 } 830 } 831 } 832 ttstart(tp); 833 return(NULL); 834 } 835