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