|
|
1.1 ! root 1: /* ! 2: * File: $USRSRC/ttydrv/tty.c ! 3: * ! 4: * Purpose: COHERENT line discipline module. ! 5: * This is the common part of typewriter service. It handles all device- ! 6: * independent aspects of a typewriter, including tandem flow control, ! 7: * erase and kill, stop and start, and common ioctl functions. ! 8: * ! 9: * $Log: tty.c,v $ ! 10: * Revision 1.15 92/01/13 08:58:40 bin ! 11: * update by hal for 321 kernel (looks like just additions of debug stuff) ! 12: * ! 13: * Revision 1.15 92/01/13 08:36:53 hal ! 14: * Add a few DEBUG lines. ! 15: * ! 16: * Revision 1.14 92/01/09 09:42:31 hal ! 17: * Add debug conditionals for sleeps. ! 18: * Fix process group logic, including TIOCSETG hack. ! 19: * ! 20: * Revision 1.13 91/12/10 17:01:56 hal ! 21: * Don't wait for drain on TIOCFLUSH. ! 22: * ! 23: * Revision 1.12 91/11/14 14:28:51 hal ! 24: * Move flow control out of tty.c. ! 25: * Make ttin() run at hi priority. ! 26: * ! 27: * Revision 1.11 91/09/16 18:11:08 hal ! 28: * Update t_flags in ttstart() at high priority. ! 29: * Document that ttstash() is local. ! 30: * ! 31: * Revision 1.10 91/09/16 15:58:26 hal ! 32: * Mask interrrupts when modifying tp->t_flags as some IRQ handlers change this. ! 33: * ! 34: * Revision 1.9 91/09/16 10:27:47 hal ! 35: * Explain T_ISTOP/T_TSTOP/T_STOP. ! 36: * Add check for TANDEM before sending t_startc. ! 37: * ! 38: * Revision 1.8 91/09/13 18:01:39 piggy ! 39: * Only do XON/XOFF flow control if TANDEM is set. ! 40: * ! 41: * Revision 1.7 91/09/13 17:58:00 hal ! 42: * Drop 3rd arg (was writing PSW directly from it!) for ttread/ttwrite. ! 43: * General face lift. ! 44: * ! 45: * Bug: no support for 8-bit characters. ! 46: * Fix: don't strip keyboard input. 01/22/91. (norm) ! 47: * ! 48: * Bug: Switching modes between cooked and CBREAK/RAW left buffered input ! 49: * in the input buffer until returning to cooked mode. 05/13/91 norm ! 50: * ! 51: * Bug: setting speed to default in ttopen() was conditioned to ! 52: * use hard constants. 90/08/28. hws ! 53: * ! 54: * Revision 1.5 91/06/06 18:28:53 norm ! 55: * Restore 8-bit fix. ! 56: * ! 57: * Revision 1.2 89/07/17 11:51:20 src ! 58: * Bug: Terminal could lock up when setting it to RAWIN mode, if ! 59: * output was suspended due to X-OFF, and output data was present. ! 60: * Fix: Setting terminal to RAWIN mode now clears X-OFF, starts output ! 61: * BEFORE waiting for output to drain. Received signals now cause ! 62: * operation to complete without waiting for drain. (ABC) ! 63: * ! 64: * Revision 1.1 88/03/24 16:18:12 src ! 65: * Initial revision ! 66: * ! 67: * 86/12/12 Allan Cornish /usr/src/sys/drv/tty.c ! 68: * Added 3rd argument to ttpoll() to support non-blocking polls. ! 69: * ! 70: * 86/11/19 Allan Cornish /usr/src/sys/drv/tty.c ! 71: * Made ttread() and ttwrite() recognize the IONDLY flag in iop->io_flag. ! 72: * wakeup() and pollwake() now have delayed invocation by defer(). ! 73: * Added poll [System V.3] capability. ! 74: * ! 75: * 85/06/28 Allan Cornish ! 76: * made ttioctl() clear T_STOP flag if ISRIN. ! 77: * ! 78: * 85/03/04 Allan Cornish ! 79: * made ttread() interruptible. ! 80: * ! 81: * 85/03/01 Allan Cornish ! 82: * made ttclose() interruptible. ! 83: */ ! 84: ! 85: /* ! 86: * About STOP flag bits: ! 87: * T_ISTOP is set when the tty module's input queue is in danger of ! 88: * overflow. It is up to the device driver to check this flag ! 89: * and do something about it. If ttin() is called with a ! 90: * character from the device while T_ISTOP is set, the character ! 91: * is discarded. T_ISTOP is cleared when the input queue is ! 92: * sufficiently empty. The device driver can monitor this bit for ! 93: * hardware flow control. ! 94: * T_TSTOP is the "Tandem" flow control flag for input. If TANDEM is set ! 95: * and the input queue is in danger of overflow, t_stopc is sent ! 96: * and T_TSTOP is set. When the input queue is empty enough, ! 97: * t_startc is sent and T_TSTOP is cleared. ! 98: * T_STOP is the flow control bit for output. No output will be ! 99: * written to the output queue while this bit is true. ! 100: * Except for initialization of flags in the TTY struct, by ! 101: * ttopen(), this bit is not written by tty.c. ! 102: * 91/09/15 - hal ! 103: */ ! 104: ! 105: /* ! 106: * Includes. ! 107: */ ! 108: #include <sys/clist.h> ! 109: #include <sys/coherent.h> ! 110: #include <sys/con.h> ! 111: #include <sys/deftty.h> ! 112: #include <sys/io.h> ! 113: #include <sys/proc.h> ! 114: #include <sys/sched.h> ! 115: #include <sys/stat.h> ! 116: #include <sys/tty.h> ! 117: #include <sys/uproc.h> ! 118: #include <errno.h> ! 119: ! 120: /* ! 121: * Definitions. ! 122: * Constants. ! 123: * Macros with argument lists. ! 124: * Typedefs. ! 125: * Enums. ! 126: */ ! 127: ! 128: /* NEAR_OR_FAR_CALL is for invoking t_param and t_start */ ! 129: #define NEAR_OR_FAR_CALL(tp_fn) {\ ! 130: if (tp->t_cs_sel) \ ! 131: ld_call(tp->t_cs_sel, tp->tp_fn, tp); \ ! 132: else \ ! 133: (*tp->tp_fn)(tp); } ! 134: ! 135: /* ! 136: * Functions. ! 137: * Import Functions. ! 138: * Export Functions. ! 139: * Local Functions. ! 140: */ ! 141: void ttclose(); ! 142: void ttflush(); ! 143: void tthup(); ! 144: void ttin(); ! 145: void ttioctl(); ! 146: void ttopen(); ! 147: int ttout(); ! 148: int ttpoll(); ! 149: void ttread(); ! 150: void ttsetgrp(); ! 151: void ttsignal(); ! 152: void ttstart(); ! 153: void ttwrite(); ! 154: ! 155: static void ttstash(); ! 156: ! 157: /* ! 158: * Global Data. ! 159: * Import Variables. ! 160: * Export Variables. ! 161: * Local Variables. ! 162: */ ! 163: extern int wakeup(); ! 164: extern void pollwake(); ! 165: ! 166: /* ! 167: * ttopen() ! 168: * ! 169: * Called by driver on first open. ! 170: * Set up defaults. ! 171: */ ! 172: void ttopen(tp) ! 173: register TTY *tp; ! 174: { ! 175: tp->t_escape = 0; ! 176: tp->t_sgttyb.sg_ispeed = tp->t_dispeed; ! 177: tp->t_sgttyb.sg_ospeed = tp->t_dospeed; ! 178: tp->t_sgttyb.sg_erase = DEF_SG_ERASE; ! 179: tp->t_sgttyb.sg_kill = DEF_SG_KILL; ! 180: tp->t_sgttyb.sg_flags = DEF_SG_FLAGS; ! 181: tp->t_tchars.t_intrc = DEF_T_INTRC; ! 182: tp->t_tchars.t_quitc = DEF_T_QUITC; ! 183: tp->t_tchars.t_startc = DEF_T_STARTC; ! 184: tp->t_tchars.t_stopc = DEF_T_STOPC; ! 185: tp->t_tchars.t_eofc = DEF_T_EOFC; ! 186: tp->t_tchars.t_brkc = DEF_T_BRKC; ! 187: if (tp->t_param != NULL) { ! 188: NEAR_OR_FAR_CALL(t_param) ! 189: } ! 190: } ! 191: ! 192: /* ! 193: * ttsetgrp() ! 194: * ! 195: * If process is a group leader without a control terminal, ! 196: * make its control terminal this device. ! 197: * ! 198: * If process is a group leader and this device does not have ! 199: * a process group, give it the group of the current process. ! 200: */ ! 201: void ttsetgrp(tp, ctdev) ! 202: register TTY *tp; ! 203: dev_t ctdev; ! 204: { ! 205: register PROC *pp; ! 206: ! 207: pp = SELF; ! 208: #if DEBUG ! 209: printf("ttsetgrp dev=%x pid=%d pg=%d ", ctdev, pp->p_pid, pp->p_group); ! 210: printf("old_ct=%x old_tg=%d ", pp->p_ttdev, tp->t_group); ! 211: #endif ! 212: if (pp->p_group == pp->p_pid) { ! 213: if (pp->p_ttdev == NODEV) ! 214: pp->p_ttdev = ctdev; ! 215: if (tp->t_group == 0) ! 216: tp->t_group = pp->p_pid; ! 217: } ! 218: #if DEBUG ! 219: printf("new_ct=%x new_tg=%d\n", pp->p_ttdev, tp->t_group); ! 220: #endif ! 221: } ! 222: ! 223: /* ! 224: * ttyclose() ! 225: * ! 226: * Called by driver on the last close. ! 227: * Wait for all pending output to go out. ! 228: * Kill input. ! 229: */ ! 230: void ttclose(tp) ! 231: register TTY *tp; ! 232: { ! 233: register int s; ! 234: ! 235: while (tp->t_oq.cq_cc != 0) { ! 236: s = sphi(); ! 237: if (tp->t_oq.cq_cc != 0) { ! 238: tp->t_flags |= T_DRAIN; ! 239: #if DEBUG ! 240: printf("T1 "); ! 241: #endif ! 242: sleep((char *)&tp->t_oq, CVTTOUT, IVTTOUT, SVTTOUT); ! 243: #if DEBUG ! 244: printf("z "); ! 245: #endif ! 246: } ! 247: spl(s); ! 248: if (SELF->p_ssig && nondsig()) ! 249: break; ! 250: } ! 251: ttflush(tp); ! 252: tp->t_flags = tp->t_group = 0; ! 253: } ! 254: ! 255: /* ! 256: * ttread() ! 257: * ! 258: * The read routine for a tty device driver will call this function. ! 259: * ! 260: * Move data from tp->t_iq to io segment iop. ! 261: * Number of characters to copy is in iop->ioc. ! 262: * ! 263: * In cooked mode, copy up to the first newline or break character, or ! 264: * until the count runs out. ! 265: * In CBREAK or RAW modes, return when count runs out or when input clist ! 266: * is empty and we're returning at least one byte. ! 267: */ ! 268: void ttread(tp, iop) ! 269: register TTY *tp; ! 270: register IO *iop; ! 271: { ! 272: register c; ! 273: int o; ! 274: int sioc = iop->io_ioc; /* number of bytes to read */ ! 275: ! 276: while (iop->io_ioc) { ! 277: o = sphi(); ! 278: while ((c = getq(&tp->t_iq)) < 0) { ! 279: if ((tp->t_flags & T_CARR) == 0) { ! 280: u.u_error = EIO; /* error since no carrier */ ! 281: spl(o); ! 282: return; ! 283: } ! 284: ! 285: /* If we're in CBREAK or RAW mode, and we don't */ ! 286: /* have the special "blocking read" bit set for */ ! 287: /* these modes, and we read at least one byte */ ! 288: /* of input, return immediately, since we have */ ! 289: /* run out of characters from the clist. */ ! 290: ! 291: if (ISBBYB && ((tp->t_flags & T_BRD) == 0) ! 292: && iop->io_ioc < sioc) { ! 293: spl(o); ! 294: return; ! 295: } ! 296: ! 297: /* ! 298: * Non-blocking reads. ! 299: * Tell user process to try again later. ! 300: */ ! 301: if (iop->io_flag & IONDLY) { ! 302: u.u_error = EAGAIN; ! 303: spl(o); ! 304: return; ! 305: } ! 306: ! 307: tp->t_flags |= T_INPUT; /* wait for more data */ ! 308: #if DEBUG ! 309: printf("T2 "); ! 310: #endif ! 311: sleep((char *)&tp->t_iq, CVTTIN, IVTTIN, SVTTIN); ! 312: #if DEBUG ! 313: printf("z "); ! 314: #endif ! 315: ! 316: if (SELF->p_ssig && nondsig()) { ! 317: if (iop->io_ioc == sioc) ! 318: u.u_error = EINTR; ! 319: spl(o); ! 320: return; ! 321: } ! 322: } ! 323: /* ! 324: * Flow control - can we turn on input from the driver yet? ! 325: */ ! 326: if (tp->t_iq.cq_cc <= ILOLIM) { ! 327: if ((tp->t_flags&T_ISTOP) != 0) ! 328: tp->t_flags &= ~T_ISTOP; ! 329: if (ISTAND && (tp->t_flags&T_TSTOP) != 0) { ! 330: tp->t_flags &= ~T_TSTOP; ! 331: while (putq(&tp->t_oq, startc) < 0) { ! 332: ttstart(tp); ! 333: waitq(); ! 334: } ! 335: ttstart(tp); ! 336: } ! 337: } ! 338: spl(o); ! 339: if (!ISBBYB && ISEOF) ! 340: return; ! 341: if (ioputc(c, iop) < 0) ! 342: return; ! 343: if (!ISBBYB && (c=='\n' || ISBRK)) ! 344: return; ! 345: } ! 346: } ! 347: ! 348: /* ! 349: * ttwrite() ! 350: * ! 351: * Write routine. ! 352: * Transfer stuff to the character list. ! 353: */ ! 354: void ttwrite(tp, iop) ! 355: register TTY *tp; ! 356: register IO *iop; ! 357: { ! 358: register c; ! 359: int o; ! 360: ! 361: /* ! 362: * Non-blocking writes which can fit. ! 363: * NOTE: exhaustion of clists can still cause blocking writes. ! 364: */ ! 365: if ((iop->io_flag & IONDLY) && (OHILIM >= iop->io_ioc)) { ! 366: ! 367: /* ! 368: * No room. ! 369: */ ! 370: if (tp->t_oq.cq_cc >= OHILIM-iop->io_ioc) { ! 371: u.u_error = EAGAIN; ! 372: return; ! 373: } ! 374: } ! 375: ! 376: while ((c = iogetc(iop)) >= 0) { ! 377: if ((tp->t_flags & T_CARR) == 0) { ! 378: u.u_error = EIO; /* error since no carrier */ ! 379: return; ! 380: } ! 381: o = sphi(); ! 382: while (tp->t_oq.cq_cc >= OHILIM) { ! 383: ttstart(tp); ! 384: if (tp->t_oq.cq_cc < OHILIM) ! 385: break; ! 386: tp->t_flags |= T_HILIM; ! 387: #if DEBUG ! 388: printf("T3 "); ! 389: #endif ! 390: sleep((char *)&tp->t_oq, CVTTOUT, IVTTOUT, SVTTOUT); ! 391: #if DEBUG ! 392: printf("z "); ! 393: #endif ! 394: if (SELF->p_ssig && nondsig()) { ! 395: u.u_error = EINTR; ! 396: spl(o); ! 397: return; ! 398: } ! 399: } ! 400: while (putq(&tp->t_oq, c) < 0) { ! 401: ttstart(tp); ! 402: waitq(); ! 403: } ! 404: spl(o); ! 405: } ! 406: o = sphi(); ! 407: ttstart(tp); ! 408: spl(o); ! 409: } ! 410: ! 411: /* ! 412: * ttioctl() ! 413: * ! 414: * This routine handles common typewriter ioctl functions. ! 415: * Note that flushing the stream now means drain the output ! 416: * and clear the input. ! 417: */ ! 418: void ttioctl(tp, com, vec) ! 419: register TTY *tp; ! 420: register struct sgttyb *vec; ! 421: { ! 422: register int flush = 0; ! 423: register int drain = 0; ! 424: register char *p1, *p2; ! 425: int s; ! 426: int rload = 0; ! 427: int was_bbyb = 0; ! 428: ! 429: switch (com) { ! 430: case TIOCQUERY: ! 431: kucopy(&tp->t_iq.cq_cc, vec, sizeof(int)); ! 432: break; ! 433: case TIOCGETP: ! 434: kucopy(&tp->t_sgttyb, vec, sizeof (struct sgttyb)); ! 435: break; ! 436: case TIOCSETP: ! 437: ++flush; /* flush input */ ! 438: ++drain; /* delay for output */ ! 439: ++rload; ! 440: ukcopy(vec, &tp->t_sgttyb, sizeof (struct sgttyb)); ! 441: break; ! 442: case TIOCSETN: ! 443: was_bbyb = ISBBYB; /* previous mode */ ! 444: ++rload; ! 445: ukcopy(vec, &tp->t_sgttyb, sizeof (struct sgttyb)); ! 446: if (!was_bbyb && ISBBYB && tp->t_ibx != 0) { ! 447: p1 = &tp->t_ib[0]; ! 448: p2 = &tp->t_ib[tp->t_ibx]; ! 449: while (p1 < p2) ! 450: #if NOT_8_BIT ! 451: putq(&tp->t_iq, (*p1++) & 0177); ! 452: #else ! 453: putq(&tp->t_iq, (*p1++)); ! 454: #endif ! 455: tp->t_ibx = 0; ! 456: } ! 457: break; ! 458: case TIOCGETC: ! 459: kucopy(&tp->t_tchars, vec, sizeof (struct tchars)); ! 460: break; ! 461: case TIOCSETC: ! 462: ++rload; ! 463: ++drain; ! 464: ukcopy(vec, &tp->t_tchars, sizeof (struct tchars)); ! 465: break; ! 466: case TIOCEXCL: ! 467: s = sphi(); ! 468: tp->t_flags |= T_EXCL; ! 469: spl(s); ! 470: break; ! 471: case TIOCNXCL: ! 472: s = sphi(); ! 473: tp->t_flags &= ~T_EXCL; ! 474: spl(s); ! 475: break; ! 476: case TIOCHPCL: /* set hangup on last close */ ! 477: s = sphi(); ! 478: tp->t_flags |= T_HPCL; ! 479: spl(s); ! 480: break; ! 481: case TIOCCHPCL: /* don't hangup on last close */ ! 482: if (!super()) /* only superuser may do this */ ! 483: u.u_error = EPERM; /* not su */ ! 484: else { ! 485: s = sphi(); ! 486: tp->t_flags &= ~T_HPCL; /* turn off hangup bit */ ! 487: spl(s); ! 488: } ! 489: break; ! 490: case TIOCGETTF: /* get tty flag word */ ! 491: kucopy(&tp->t_flags, (unsigned *) vec, sizeof(unsigned)); ! 492: break; ! 493: case TIOCFLUSH: ! 494: ++flush; /* flush both input and output */ ! 495: /* ++drain; Why? - hws - 91/11/22 */ ! 496: break; ! 497: case TIOCBREAD: /* blocking read for CBREAK/RAW mode */ ! 498: s = sphi(); ! 499: tp->t_flags |= T_BRD; ! 500: spl(s); ! 501: break; ! 502: case TIOCCBREAD: /* turn off CBREAK/RAW blocking read mode */ ! 503: s = sphi(); ! 504: tp->t_flags &= ~T_BRD; ! 505: spl(s); ! 506: break; ! 507: /* ! 508: * The following is a hack so that the process group for /dev/console ! 509: * contains the current login shell running on it. ! 510: * Only expect /etc/init to use this ugliness. ! 511: */ ! 512: case TIOCSETG: ! 513: if (super()) ! 514: tp->t_group = SELF->p_group; ! 515: break; ! 516: default: ! 517: u.u_error = EINVAL; ! 518: } ! 519: ! 520: /* ! 521: * Wait for output to drain, or signal to arrive. ! 522: */ ! 523: if (drain != 0) { ! 524: ! 525: /* ! 526: * Ensure output is enabled BEFORE waiting for output to drain. ! 527: */ ! 528: if (ISRIN && (tp->t_flags & T_STOP)) { ! 529: s = sphi(); ! 530: tp->t_flags &= ~T_STOP; ! 531: ttstart(tp); ! 532: spl(s); ! 533: } ! 534: ! 535: while (tp->t_oq.cq_cc != 0) { ! 536: s = sphi(); ! 537: tp->t_flags |= T_DRAIN; ! 538: spl(s); ! 539: #if DEBUG ! 540: printf("T4 "); ! 541: #endif ! 542: sleep((char *)&tp->t_oq, CVTTOUT, IVTTOUT, SVTTOUT); ! 543: #if DEBUG ! 544: printf("z "); ! 545: #endif ! 546: if (SELF->p_ssig && nondsig()) ! 547: break; ! 548: } ! 549: } ! 550: ! 551: /* ! 552: * Flush input. ! 553: */ ! 554: if (flush != 0) ! 555: ttflush(tp); ! 556: ! 557: /* ! 558: * Re-initialize hardware. ! 559: */ ! 560: if ((rload != 0) && (tp->t_param != NULL)) ! 561: NEAR_OR_FAR_CALL(t_param) ! 562: } ! 563: ! 564: /* ! 565: * ttpoll() ! 566: * ! 567: * Polling routine. ! 568: * [System V.3 Compatible] ! 569: */ ! 570: int ttpoll(tp, ev, msec) ! 571: register TTY * tp; ! 572: int ev; ! 573: int msec; ! 574: { ! 575: /* ! 576: * Priority polls not supported. ! 577: */ ! 578: ev &= ~POLLPRI; ! 579: ! 580: /* ! 581: * Input poll with no data present. ! 582: */ ! 583: if ((ev & POLLIN) && (tp->t_iq.cq_cc == 0)) { ! 584: ! 585: /* ! 586: * Blocking input poll. ! 587: */ ! 588: if (msec != 0) ! 589: pollopen(&tp->t_ipolls); ! 590: ! 591: /* ! 592: * Second look to avoid interrupt race. ! 593: */ ! 594: if (tp->t_iq.cq_cc == 0) ! 595: ev &= ~POLLIN; ! 596: } ! 597: ! 598: /* ! 599: * Output poll with no space. ! 600: */ ! 601: if ((ev & POLLOUT) && (tp->t_oq.cq_cc >= OLOLIM)) { ! 602: ! 603: /* ! 604: * Blocking output poll. ! 605: */ ! 606: if (msec != 0) ! 607: pollopen(&tp->t_opolls); ! 608: ! 609: /* ! 610: * Second look to avoid interrupt race. ! 611: */ ! 612: if (tp->t_oq.cq_cc >= OLOLIM) ! 613: ev &= ~POLLIN; ! 614: } ! 615: ! 616: if (((ev & POLLIN) == 0) && ((tp->t_flags & T_CARR) == 0)) ! 617: ev |= POLLHUP; ! 618: ! 619: return ev; ! 620: } ! 621: ! 622: /* ! 623: * ttout() ! 624: * ! 625: * Pull a character from the output queues of the typewriter. ! 626: * Doing fills, newline insert, tab expansion, etc. ! 627: * ! 628: * If the stream is empty return a -1. ! 629: * Called at high priority. ! 630: */ ! 631: int ttout(tp) ! 632: register TTY *tp; ! 633: { ! 634: register c; ! 635: ! 636: if (tp->t_nfill) { ! 637: --tp->t_nfill; ! 638: c = tp->t_fillb; ! 639: } else if ((tp->t_flags&T_INL) != 0) { ! 640: tp->t_flags &= ~T_INL; ! 641: c = '\n'; ! 642: } else { ! 643: if ((c=getq(&tp->t_oq)) < 0) ! 644: return -1; ! 645: if (!ISROUT) { ! 646: if (c=='\n' && ISCRMOD) { ! 647: tp->t_flags |= T_INL; ! 648: c = '\r'; ! 649: } else if (c=='\t' && ISXTABS) { ! 650: tp->t_nfill = ~(tp->t_hpos|~07); ! 651: tp->t_fillb = ' '; ! 652: c = ' '; ! 653: } ! 654: } ! 655: } ! 656: if (!ISROUT) { ! 657: if (c == '\b') { ! 658: if (tp->t_hpos) ! 659: --tp->t_hpos; ! 660: } else if (c == '\r') ! 661: tp->t_hpos = 0; ! 662: else if (c == '\t') ! 663: tp->t_hpos = (tp->t_hpos|07) + 1; ! 664: #if NOT_8_BIT ! 665: else if (c >= ' ' && c <= '~') ! 666: #else ! 667: else if ((c >= ' ' && c <= '~') || (c >= 0200 && c <= 0376)) ! 668: #endif ! 669: ++tp->t_hpos; ! 670: } ! 671: return c; ! 672: } ! 673: ! 674: /* ! 675: * ttin() ! 676: * ! 677: * Pass a character to the device independent typewriter routines. ! 678: * Handle erase and kill, tandem flow control, and other magic. ! 679: * Often called at high priority from the driver's interrupt routine. ! 680: */ ! 681: void ttin(tp, c) ! 682: register TTY *tp; ! 683: register c; ! 684: { ! 685: int dc, i, n; ! 686: int s; ! 687: ! 688: if (!ISRIN) { ! 689: #if NOT_8_BIT ! 690: c &= 0177; ! 691: #endif ! 692: if (ISINTR) { ! 693: ttsignal(tp, SIGINT); ! 694: goto ttin_ret; ! 695: } ! 696: if (ISQUIT) { ! 697: ttsignal(tp, SIGQUIT); ! 698: goto ttin_ret; ! 699: } ! 700: } ! 701: if ((tp->t_flags&T_ISTOP) != 0) ! 702: goto ttin_ret; ! 703: if (!ISRIN) { ! 704: if (c=='\r' && ISCRMOD) ! 705: c = '\n'; ! 706: if (tp->t_escape != 0) { ! 707: if (c == ESC) ! 708: ++tp->t_escape; ! 709: else { ! 710: if (ISERASE || ISKILL) { ! 711: c |= 0200; ! 712: --tp->t_escape; ! 713: } ! 714: while (tp->t_escape!=0 && tp->t_ibx<NCIB-1) { ! 715: tp->t_ib[tp->t_ibx++] = ESC; ! 716: --tp->t_escape; ! 717: } ! 718: ttstash(tp, c); ! 719: } ! 720: if (ISECHO) { ! 721: #if NOT_8_BIT ! 722: putq(&tp->t_oq, c&0177); ! 723: #else ! 724: putq(&tp->t_oq, c); /* no strip for 8-bit */ ! 725: #endif ! 726: ttstart(tp); ! 727: } ! 728: goto ttin_ret; ! 729: } ! 730: if (ISERASE && !ISCBRK) { ! 731: while (tp->t_escape!=0 && tp->t_ibx<NCIB-1) { ! 732: tp->t_ib[tp->t_ibx++] = ESC; ! 733: --tp->t_escape; ! 734: } ! 735: if (tp->t_ibx == 0) ! 736: goto ttin_ret; ! 737: dc = tp->t_ib[--tp->t_ibx]; ! 738: if (ISECHO) { ! 739: if (!ISCRT) ! 740: putq(&tp->t_oq, c); ! 741: /* don't erase for bell, null, or rubout */ ! 742: #if NOT_8_BIT ! 743: else if (((c = dc&0177) == '\007') ! 744: || c == 0 || c == 0177) ! 745: #else ! 746: else if (((c = dc) == '\007') ! 747: || c == 0 || c == 0177 || c == 0377) ! 748: #endif ! 749: goto ttin_ret; ! 750: else if (c != '\b' && c != '\t') { ! 751: putq(&tp->t_oq, '\b'); ! 752: putq(&tp->t_oq, ' '); ! 753: putq(&tp->t_oq, '\b'); ! 754: } else if (c == '\t') { ! 755: n = tp->t_opos + tp->t_escape; ! 756: for (i=0; i<tp->t_ibx; ++i) { ! 757: c = tp->t_ib[i]; ! 758: #if NOT_8_BIT ! 759: if ((c&0200) != 0) { ! 760: ++n; ! 761: c &= 0177; ! 762: } ! 763: #endif ! 764: if (c == '\b') ! 765: --n; ! 766: else { ! 767: if (c == '\t') ! 768: n |= 07; ! 769: ++n; ! 770: } ! 771: } ! 772: while (n++ < tp->t_hpos) ! 773: putq(&tp->t_oq, '\b'); ! 774: } ! 775: #if NOT_8_BIT ! 776: if ((dc&0200) != 0) { ! 777: if ((dc&0177) != '\b') ! 778: putq(&tp->t_oq, '\b'); ! 779: putq(&tp->t_oq, ' '); ! 780: putq(&tp->t_oq, '\b'); ! 781: } ! 782: #endif ! 783: ttstart(tp); ! 784: } ! 785: goto ttin_ret; ! 786: } ! 787: if (ISKILL && !ISCBRK) { ! 788: tp->t_ibx = 0; ! 789: tp->t_escape = 0; ! 790: if (ISECHO) { ! 791: if (c < 0x20) { ! 792: putq(&tp->t_oq, '^'); ! 793: c += 0x40; ! 794: } ! 795: putq(&tp->t_oq, c); ! 796: putq(&tp->t_oq, '\n'); ! 797: ttstart(tp); ! 798: } ! 799: goto ttin_ret; ! 800: } ! 801: } ! 802: if (ISBBYB) { ! 803: putq(&tp->t_iq, c); ! 804: if ((tp->t_flags&T_INPUT) != 0) { ! 805: s = sphi(); ! 806: tp->t_flags &= ~T_INPUT; ! 807: spl(s); ! 808: defer(wakeup, (char *) &tp->t_iq); ! 809: } ! 810: if (tp->t_ipolls.e_procp) { ! 811: tp->t_ipolls.e_procp = 0; ! 812: defer(pollwake, (char *) &tp->t_ipolls); ! 813: } ! 814: } else { ! 815: if (tp->t_ibx == 0) ! 816: tp->t_opos = tp->t_hpos; ! 817: if (c == ESC) ! 818: ++tp->t_escape; ! 819: else ! 820: ttstash(tp, c); ! 821: } ! 822: if (ISECHO) { ! 823: if (ISRIN || !ISEOF) { ! 824: putq(&tp->t_oq, c); ! 825: ttstart(tp); ! 826: } ! 827: } ! 828: if ((n=tp->t_iq.cq_cc)>=IHILIM) { ! 829: s = sphi(); ! 830: tp->t_flags |= T_ISTOP; ! 831: spl(s); ! 832: } else if (ISTAND && (tp->t_flags&T_TSTOP)==0 && n>=ITSLIM) { ! 833: s = sphi(); ! 834: tp->t_flags |= T_TSTOP; ! 835: spl(s); ! 836: putq(&tp->t_oq, stopc); ! 837: ttstart(tp); ! 838: } ! 839: ! 840: ttin_ret: ! 841: return; ! 842: } ! 843: ! 844: /* ! 845: * ttstash() ! 846: * ! 847: * Cooked mode. ! 848: * Put character in the buffer and check for end of line. ! 849: * Only a legal end of line can take the last character position. ! 850: * ! 851: * Only called from ttin(), and ttin() is called at high priority. ! 852: */ ! 853: static void ttstash(tp, c) ! 854: register TTY *tp; ! 855: { ! 856: register char *p1, *p2; ! 857: ! 858: if (c=='\n' || ISEOF || ISBRK) { ! 859: p1 = &tp->t_ib[0]; ! 860: p2 = &tp->t_ib[tp->t_ibx]; ! 861: *p2++ = c; /* Always room */ ! 862: while (p1 < p2) ! 863: #if NOT_8_BIT ! 864: putq(&tp->t_iq, (*p1++)&0177); ! 865: #else ! 866: putq(&tp->t_iq, (*p1++)); ! 867: #endif ! 868: tp->t_ibx = 0; ! 869: tp->t_escape = 0; ! 870: ! 871: if (tp->t_flags & T_INPUT) { ! 872: tp->t_flags &= ~T_INPUT; ! 873: defer(wakeup, (char *) &tp->t_iq); ! 874: } ! 875: ! 876: if (tp->t_ipolls.e_procp) { ! 877: tp->t_ipolls.e_procp = 0; ! 878: defer(pollwake, (char *) &tp->t_ipolls); ! 879: } ! 880: ! 881: } else if (tp->t_ibx < NCIB-1) ! 882: tp->t_ib[tp->t_ibx++] = c; ! 883: } ! 884: ! 885: /* ! 886: * ttstart() ! 887: * ! 888: * Start output on a tty. ! 889: * Duck out if stopped. Do wakeups. ! 890: */ ! 891: void ttstart(tp) ! 892: register TTY *tp; ! 893: { ! 894: register int n; ! 895: int s; ! 896: ! 897: n = tp->t_flags; ! 898: if (n & T_STOP) ! 899: goto stdone; ! 900: ! 901: if ((n&T_DRAIN)!=0 && tp->t_oq.cq_cc==0 ! 902: && (n&T_INL)==0 && tp->t_nfill==0) { ! 903: s = sphi(); ! 904: tp->t_flags &= ~T_DRAIN; ! 905: spl(s); ! 906: defer(wakeup, (char *) &tp->t_oq); ! 907: goto stdone; ! 908: } ! 909: ! 910: NEAR_OR_FAR_CALL(t_start) ! 911: ! 912: if (tp->t_oq.cq_cc > OLOLIM) ! 913: goto stdone; ! 914: ! 915: if (n & T_HILIM) { ! 916: s = sphi(); ! 917: tp->t_flags &= ~T_HILIM; ! 918: spl(s); ! 919: defer(wakeup, (char *) &tp->t_oq); ! 920: } ! 921: ! 922: if (tp->t_opolls.e_procp) { ! 923: tp->t_opolls.e_procp = 0; ! 924: defer(pollwake, (char *) &tp->t_opolls); ! 925: } ! 926: stdone: ! 927: return; ! 928: } ! 929: ! 930: /* ! 931: * ttflush() ! 932: * ! 933: * Flush a tty. ! 934: * Called to clear out queues. ! 935: */ ! 936: void ttflush(tp) ! 937: register TTY *tp; ! 938: { ! 939: int s; ! 940: ! 941: clrq(&tp->t_iq); ! 942: clrq(&tp->t_oq); ! 943: ! 944: if (tp->t_flags & T_INPUT) ! 945: defer(wakeup, (char *) &tp->t_iq); ! 946: ! 947: if (tp->t_flags & (T_DRAIN|T_HILIM)) ! 948: defer(wakeup, (char *) &tp->t_oq); ! 949: ! 950: if (tp->t_ipolls.e_procp != 0) { ! 951: tp->t_ipolls.e_procp = 0; ! 952: defer(pollwake, (char *) &tp->t_ipolls); ! 953: } ! 954: ! 955: if (tp->t_opolls.e_procp != 0) { ! 956: tp->t_opolls.e_procp = 0; ! 957: defer(pollwake, (char *) &tp->t_opolls); ! 958: } ! 959: ! 960: tp->t_ibx = 0; ! 961: tp->t_escape = 0; ! 962: s = sphi(); ! 963: tp->t_flags &= T_SAVE; /* reset most flag bits */ ! 964: spl(s); ! 965: } ! 966: ! 967: /* ! 968: * ttsignal() ! 969: * ! 970: * Send a signal to every process in the given process group. ! 971: */ ! 972: void ttsignal(tp, sig) ! 973: TTY *tp; ! 974: int sig; ! 975: { ! 976: register int g; ! 977: register PROC *pp; ! 978: ! 979: g = tp->t_group; ! 980: #if DEBUG ! 981: printf("ttsignal sig=%d gp=%d\n", sig, g); ! 982: #endif ! 983: if (g == 0) ! 984: goto sigdone; ! 985: ttflush(tp); ! 986: pp = &procq; ! 987: while ((pp=pp->p_nforw) != &procq) ! 988: if (pp->p_group == g) { ! 989: sendsig(sig, pp); ! 990: } ! 991: sigdone: ! 992: return; ! 993: } ! 994: ! 995: /* ! 996: * tthup() ! 997: * ! 998: * Flag hangup internally to force errors on tty read/write, flush tty, ! 999: * then send hangup signal. ! 1000: */ ! 1001: void tthup(tp) ! 1002: register TTY *tp; ! 1003: { ! 1004: ttflush(tp); ! 1005: ttsignal(tp, SIGHUP); ! 1006: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.