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