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