|
|
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.2 92/08/04 12:54:52 bin ! 11: * upd for ker59 ! 12: * ! 13: * Revision 1.12 92/06/06 12:39:28 hal ! 14: * Last before adding termio field to tty struct. ! 15: * ! 16: * Revision 1.11 92/04/30 08:58:50 hal ! 17: * Add asy. Remove silos from tty struct. ! 18: * ! 19: * Revision 1.10 92/04/13 10:14:01 hal ! 20: * Kernel #52. ! 21: * ! 22: * Revision 1.9 92/03/18 07:44:47 hal ! 23: * ttwrite0() needed to break pty deadlock. ! 24: * ! 25: * Revision 1.8 92/03/18 05:27:05 hal ! 26: * Add ttrtp(), ttinp(), ttoutp(). ! 27: * Fix ctrl-s/ctrl-q transposition in termio routine. ! 28: * TIOCSET[PN] now sets RAW depending on RAWIN&RAWOUT & vice versa. ! 29: * ! 30: * Revision 1.7 92/02/20 20:25:36 hal ! 31: * Minor fixes ! 32: * ! 33: * Revision 1.6 92/02/20 19:43:30 piggy ! 34: * Add "mode" arg to ttsetgrp() for NOCTTY support. ! 35: * ! 36: * Revision 1.5 92/02/16 23:14:23 hal ! 37: * Initial termio support. ! 38: * ! 39: * Revision 1.4 92/02/16 18:27:33 hal ! 40: * Binary compatibility with Sys V sgtty ! 41: * ! 42: * Revision 1.3 92/02/15 15:43:46 root ! 43: * Merge with 286 kernel tty.c. ! 44: */ ! 45: ! 46: /* ! 47: * About STOP flag bits: ! 48: * T_ISTOP is set when the tty module's input queue is in danger of ! 49: * overflow. It is up to the device driver to check this flag ! 50: * and do something about it. If ttin() is called with a ! 51: * character from the device while T_ISTOP is set, the character ! 52: * is discarded. T_ISTOP is cleared when the input queue is ! 53: * sufficiently empty. The device driver can monitor this bit for ! 54: * hardware flow control. ! 55: * T_TSTOP is the "Tandem" flow control flag for input. If TANDEM is set ! 56: * and the input queue is in danger of overflow, t_stopc is sent ! 57: * and T_TSTOP is set. When the input queue is empty enough, ! 58: * t_startc is sent and T_TSTOP is cleared. ! 59: * T_STOP is the flow control bit for output. No output will be ! 60: * written to the output queue while this bit is true. ! 61: * Except for initialization of flags in the TTY struct, by ! 62: * ttopen(), this bit is not written by tty.c. ! 63: * 91/09/15 - hal ! 64: */ ! 65: ! 66: /* ! 67: * Includes. ! 68: */ ! 69: #include <sys/clist.h> ! 70: #include <sys/coherent.h> ! 71: #include <sys/con.h> ! 72: #include <sys/deftty.h> ! 73: #include <sys/io.h> ! 74: #include <sys/proc.h> ! 75: #include <sys/sched.h> ! 76: #include <sys/stat.h> ! 77: #include <sys/tty.h> ! 78: #include <errno.h> ! 79: #ifdef _I386 ! 80: #include <termio.h> ! 81: #include <sys/inode.h> ! 82: #else ! 83: #endif ! 84: ! 85: #ifdef TRACER ! 86: #define DUMPSGTTY(sp) dumpsgtty(sp) ! 87: ! 88: static void dumpsgtty(sp) ! 89: struct sgttyb * sp; ! 90: { ! 91: T_HAL(2, printf("S:%x:%x ", sp->sg_ispeed, sp->sg_flags)); ! 92: } ! 93: #else ! 94: #define DUMPSGTTY(sp) ! 95: #endif ! 96: ! 97: /* ! 98: * Definitions. ! 99: * Constants. ! 100: * Macros with argument lists. ! 101: * Typedefs. ! 102: * Enums. ! 103: */ ! 104: ! 105: #define SGTTY_CPY_LEN (sizeof (struct sgttyb)) ! 106: ! 107: /* NEAR_OR_FAR_CALL is for invoking t_param and t_start */ ! 108: #ifdef _I386 ! 109: #define NEAR_OR_FAR_CALL(tp_fn) { (*tp->tp_fn)(tp); } ! 110: #define SET_HPCL { \ ! 111: if (tp->t_termio.c_cflag & HUPCL) \ ! 112: tp->t_flags |= T_HPCL; \ ! 113: else \ ! 114: tp->t_flags &= ~T_HPCL; } ! 115: #else ! 116: #define NEAR_OR_FAR_CALL(tp_fn) {\ ! 117: if (tp->t_cs_sel) \ ! 118: ld_call(tp->t_cs_sel, tp->tp_fn, tp); \ ! 119: else \ ! 120: (*tp->tp_fn)(tp); } ! 121: #define SET_HPCL ! 122: #endif ! 123: ! 124: /* ! 125: * Functions. ! 126: * Import Functions. ! 127: * Export Functions. ! 128: * Local Functions. ! 129: */ ! 130: void ttclose(); ! 131: void ttflush(); ! 132: void tthup(); ! 133: void ttin(); ! 134: int ttinp(); ! 135: void ttioctl(); ! 136: void ttopen(); ! 137: int ttout(); ! 138: int ttoutp(); ! 139: int ttpoll(); ! 140: void ttread(); ! 141: void ttread0(); ! 142: void ttsetgrp(); ! 143: void ttsignal(); ! 144: void ttstart(); ! 145: void ttwrite(); ! 146: void ttwrite0(); ! 147: ! 148: static void ttstash(); ! 149: static void ttrtp(); ! 150: ! 151: #ifdef _I386 ! 152: static void make_termio(); ! 153: static void make_sg(); ! 154: #else ! 155: #define make_termio(a1,a2,a3) ! 156: #define make_sg(a1,a2,a3) ! 157: #endif ! 158: ! 159: /* ! 160: * Global Data. ! 161: * Import Variables. ! 162: * Export Variables. ! 163: * Local Variables. ! 164: */ ! 165: extern int wakeup(); ! 166: extern void pollwake(); ! 167: ! 168: /* ! 169: * ttopen() ! 170: * ! 171: * Called by driver on first open. ! 172: * Set up defaults. ! 173: */ ! 174: void ! 175: ttopen(tp) ! 176: register TTY *tp; ! 177: { ! 178: tp->t_escape = 0; ! 179: tp->t_sgttyb.sg_ispeed = tp->t_dispeed; ! 180: tp->t_sgttyb.sg_ospeed = tp->t_dospeed; ! 181: tp->t_sgttyb.sg_erase = DEF_SG_ERASE; ! 182: tp->t_sgttyb.sg_kill = DEF_SG_KILL; ! 183: tp->t_sgttyb.sg_flags = DEF_SG_FLAGS; ! 184: tp->t_tchars.t_intrc = DEF_T_INTRC; ! 185: tp->t_tchars.t_quitc = DEF_T_QUITC; ! 186: tp->t_tchars.t_startc = DEF_T_STARTC; ! 187: tp->t_tchars.t_stopc = DEF_T_STOPC; ! 188: tp->t_tchars.t_eofc = DEF_T_EOFC; ! 189: tp->t_tchars.t_brkc = DEF_T_BRKC; ! 190: #ifdef _I386 ! 191: make_termio(&tp->t_sgttyb, &tp->t_tchars, &tp->t_termio); ! 192: if (tp->t_flags & T_HPCL) ! 193: tp->t_termio.c_cflag |= HUPCL; ! 194: else ! 195: tp->t_termio.c_cflag &= ~HUPCL; ! 196: tp->t_termio.c_cflag |= (CS8|CREAD); ! 197: #endif ! 198: if (tp->t_param) ! 199: NEAR_OR_FAR_CALL(t_param) ! 200: } ! 201: ! 202: /* ! 203: * ttsetgrp() ! 204: * ! 205: * If process is a group leader without a control terminal, ! 206: * make its control terminal this device. ! 207: * ! 208: * If process is a group leader and this device does not have ! 209: * a process group, give it the group of the current process. ! 210: */ ! 211: void ttsetgrp(tp, ctdev, mode) ! 212: register TTY *tp; ! 213: dev_t ctdev; ! 214: int mode; ! 215: { ! 216: register PROC *pp; ! 217: ! 218: pp = SELF; ! 219: #ifdef _I386 ! 220: if (pp->p_group == pp->p_pid && 0 == (mode & IPNOCTTY)) { ! 221: #else ! 222: if (pp->p_group == pp->p_pid) { ! 223: #endif ! 224: if (pp->p_ttdev == NODEV) ! 225: pp->p_ttdev = ctdev; ! 226: if (tp->t_group == 0) ! 227: tp->t_group = pp->p_pid; ! 228: } ! 229: } ! 230: ! 231: /* ! 232: * ttyclose() ! 233: * ! 234: * Called by driver on the last close. ! 235: * Wait for all pending output to go out. ! 236: * Kill input. ! 237: */ ! 238: void ttclose(tp) ! 239: register TTY *tp; ! 240: { ! 241: register int s; ! 242: ! 243: while (tp->t_oq.cq_cc) { ! 244: s = sphi(); ! 245: if (tp->t_oq.cq_cc) { ! 246: tp->t_flags |= T_DRAIN; ! 247: v_sleep((char *)&tp->t_oq, CVTTOUT, IVTTOUT, SVTTOUT, ! 248: "ttydrain"); ! 249: /* The line discipline is waiting for the tty to drain. */ ! 250: } ! 251: spl(s); ! 252: if (SELF->p_ssig && nondsig()) ! 253: break; ! 254: } ! 255: ttflush(tp); ! 256: tp->t_flags = tp->t_group = 0; ! 257: } ! 258: ! 259: /* ! 260: * ttread() ! 261: * ! 262: * The read routine for a tty device driver will call this function. ! 263: * ! 264: * Move data from tp->t_iq to io segment iop. ! 265: * Number of characters to copy is in iop->ioc. ! 266: * ! 267: * In cooked mode, copy up to the first newline or break character, or ! 268: * until the count runs out. ! 269: * In CBREAK or RAW modes, return when count runs out or when input clist ! 270: * is empty and we're returning at least one byte. ! 271: */ ! 272: ! 273: void ttread(tp, iop) ! 274: register TTY *tp; ! 275: register IO *iop; ! 276: { ! 277: ttread0(tp, iop, 0, 0, 0, 0); ! 278: } ! 279: ! 280: /* ! 281: * ttread0() ! 282: * ! 283: * Move data from user (in IO struct) to clists. ! 284: * Do wakeups on functions supplied when read is blocked or completed. ! 285: */ ! 286: void ttread0(tp, iop, func1, arg1, func2, arg2) ! 287: register TTY *tp; ! 288: register IO *iop; ! 289: int (*func1)(), arg1, (*func2)(), arg2; ! 290: { ! 291: register int c; ! 292: int o; ! 293: int sioc = iop->io_ioc; /* number of bytes to read */ ! 294: ! 295: while (iop->io_ioc) { ! 296: o = sphi(); ! 297: while ((c = getq(&tp->t_iq)) < 0) { ! 298: if ((tp->t_flags & T_CARR) == 0) { ! 299: u.u_error = EIO; /* error since no carrier */ ! 300: spl(o); ! 301: return; ! 302: } ! 303: ! 304: /* If we're in CBREAK or RAW mode, and we don't */ ! 305: /* have the special "blocking read" bit set for */ ! 306: /* these modes, and we read at least one byte */ ! 307: /* of input, return immediately, since we have */ ! 308: /* run out of characters from the clist. */ ! 309: ! 310: if (ISBBYB && ((tp->t_flags & T_BRD) == 0) ! 311: && iop->io_ioc < sioc) { ! 312: spl(o); ! 313: return; ! 314: } ! 315: ! 316: /* ! 317: * Non-blocking reads. ! 318: * Tell user process to try again later. ! 319: */ ! 320: if (iop->io_flag & IONDLY) { ! 321: u.u_error = EAGAIN; ! 322: spl(o); ! 323: return; ! 324: } ! 325: ! 326: tp->t_flags |= T_INPUT; /* wait for more data */ ! 327: if (func1) ! 328: (*func1)(arg1); ! 329: if (func2) ! 330: (*func2)(arg2); ! 331: v_sleep((char *)&tp->t_iq, CVTTIN, IVTTIN, SVTTIN, ! 332: "ttywait"); ! 333: /* The line discipline is waiting for more data. */ ! 334: ! 335: if (SELF->p_ssig && nondsig()) { ! 336: if (iop->io_ioc == sioc) ! 337: u.u_error = EINTR; ! 338: spl(o); ! 339: return; ! 340: } ! 341: } ! 342: /* ! 343: * Flow control - can we turn on input from the driver yet? ! 344: */ ! 345: if (tp->t_iq.cq_cc <= ILOLIM) { ! 346: if (tp->t_flags & T_ISTOP) ! 347: tp->t_flags &= ~T_ISTOP; ! 348: if (ISTAND && (tp->t_flags&T_TSTOP)) { ! 349: tp->t_flags &= ~T_TSTOP; ! 350: while (putq(&tp->t_oq, startc) < 0) { ! 351: ttstart(tp); ! 352: waitq(); ! 353: } ! 354: ttstart(tp); ! 355: } ! 356: } ! 357: spl(o); ! 358: if (!ISBBYB && ISEOF) ! 359: goto read_done; ! 360: if (ioputc(c, iop) < 0) ! 361: goto read_done; ! 362: if (!ISBBYB && (c=='\n' || ISBRK)) ! 363: goto read_done; ! 364: } ! 365: read_done: ! 366: if (func1) ! 367: (*func1)(arg1); ! 368: if (func2) ! 369: (*func2)(arg2); ! 370: } ! 371: ! 372: /* ! 373: * ttwrite() ! 374: * ! 375: * Write routine. ! 376: */ ! 377: void ttwrite(tp, iop) ! 378: register TTY *tp; ! 379: register IO *iop; ! 380: { ! 381: ttwrite0(tp, iop, 0, 0, 0, 0); ! 382: } ! 383: ! 384: /* ! 385: * ttwrite0() ! 386: * ! 387: * Move data from user (in IO struct) to clists. ! 388: * Do wakeups on functions supplied when write is blocked or completed. ! 389: */ ! 390: void ttwrite0(tp, iop, func1, arg1, func2, arg2) ! 391: register TTY *tp; ! 392: register IO *iop; ! 393: int (*func1)(), arg1, (*func2)(), arg2; ! 394: { ! 395: register int c; ! 396: int o; ! 397: ! 398: /* ! 399: * Non-blocking writes which can fit. ! 400: * NOTE: exhaustion of clists can still cause blocking writes. ! 401: */ ! 402: if ((iop->io_flag & IONDLY) && (OHILIM >= iop->io_ioc)) { ! 403: ! 404: /* ! 405: * No room. ! 406: */ ! 407: if (tp->t_oq.cq_cc >= OHILIM-iop->io_ioc) { ! 408: u.u_error = EAGAIN; ! 409: return; ! 410: } ! 411: } ! 412: ! 413: while ((c = iogetc(iop)) >= 0) { ! 414: if ((tp->t_flags & T_CARR) == 0) { ! 415: u.u_error = EIO; /* error since no carrier */ ! 416: return; ! 417: } ! 418: o = sphi(); ! 419: while (tp->t_oq.cq_cc >= OHILIM) { ! 420: ttstart(tp); ! 421: if (tp->t_oq.cq_cc < OHILIM) ! 422: break; ! 423: tp->t_flags |= T_HILIM; ! 424: if (func1) ! 425: (*func1)(arg1); ! 426: if (func2) ! 427: (*func2)(arg2); ! 428: v_sleep((char *)&tp->t_oq, CVTTOUT, IVTTOUT, SVTTOUT, ! 429: "ttyoq"); ! 430: /* ! 431: * The line discipline is waiting for an output ! 432: * queue to drain. ! 433: */ ! 434: if (SELF->p_ssig && nondsig()) { ! 435: u.u_error = EINTR; ! 436: spl(o); ! 437: return; ! 438: } ! 439: } ! 440: while (putq(&tp->t_oq, c) < 0) { ! 441: ttstart(tp); ! 442: waitq(); ! 443: } ! 444: spl(o); ! 445: } ! 446: o = sphi(); ! 447: ttstart(tp); ! 448: spl(o); ! 449: if (func1) ! 450: (*func1)(arg1); ! 451: if (func2) ! 452: (*func2)(arg2); ! 453: } ! 454: ! 455: /* ! 456: * ttioctl() ! 457: * ! 458: * This routine handles common typewriter ioctl functions. ! 459: * Note that flushing the stream now means drain the output ! 460: * and clear the input. ! 461: */ ! 462: void ttioctl(tp, com, vec) ! 463: register TTY *tp; ! 464: int com; ! 465: register struct sgttyb *vec; ! 466: { ! 467: register int flush = 0; ! 468: register int drain = 0; ! 469: int s; ! 470: int rload = 0; ! 471: int was_bbyb; ! 472: ! 473: /* ! 474: * Keep sgttyb, t_chars, AND termio structs for each tty device. ! 475: * ! 476: * TCSET* writes a new termio and converts so as to update ! 477: * sgttyb and t_chars as well. ! 478: * ! 479: * TIOCSET[NP] writes new sgttyb and converts so as to update termio. ! 480: * ! 481: * TIOCSETC writes new t_chars and converts so as to update termio. ! 482: */ ! 483: switch (com) { ! 484: #ifdef _I386 ! 485: case TCGETA: ! 486: kucopy(&tp->t_termio, vec, sizeof(struct termio)); ! 487: break; ! 488: case TCSETA: ! 489: ukcopy(vec, &tp->t_termio, sizeof(struct termio)); ! 490: was_bbyb = ISBBYB; /* previous mode */ ! 491: make_sg(vec, &tp->t_sgttyb, &tp->t_tchars); ! 492: SET_HPCL; ! 493: ++rload; ! 494: if (!was_bbyb && ISBBYB) ! 495: ttrtp(tp); ! 496: break; ! 497: case TCSETAW: ! 498: ukcopy(vec, &tp->t_termio, sizeof(struct termio)); ! 499: make_sg(vec, &tp->t_sgttyb, &tp->t_tchars); ! 500: SET_HPCL; ! 501: ++drain; /* delay for output */ ! 502: ++rload; ! 503: break; ! 504: case TCSETAF: ! 505: ukcopy(vec, &tp->t_termio, sizeof(struct termio)); ! 506: make_sg(vec, &tp->t_sgttyb, &tp->t_tchars); ! 507: SET_HPCL; ! 508: ++flush; /* flush input */ ! 509: ++drain; /* delay for output */ ! 510: ++rload; ! 511: break; ! 512: #endif ! 513: case TIOCQUERY: ! 514: kucopy(&tp->t_iq.cq_cc, vec, sizeof(int)); ! 515: break; ! 516: case TIOCGETP: ! 517: kucopy(&tp->t_sgttyb, vec, SGTTY_CPY_LEN); ! 518: break; ! 519: case TIOCSETP: ! 520: DUMPSGTTY(&tp->t_sgttyb); ! 521: ++flush; /* flush input */ ! 522: ++drain; /* delay for output */ ! 523: ++rload; ! 524: ukcopy(vec, &tp->t_sgttyb, SGTTY_CPY_LEN); ! 525: make_termio(&tp->t_sgttyb, &tp->t_tchars, &tp->t_termio); ! 526: break; ! 527: case TIOCSETN: ! 528: DUMPSGTTY(&tp->t_sgttyb); ! 529: was_bbyb = ISBBYB; /* previous mode */ ! 530: ++rload; ! 531: ukcopy(vec, &tp->t_sgttyb, SGTTY_CPY_LEN); ! 532: make_termio(&tp->t_sgttyb, &tp->t_tchars, &tp->t_termio); ! 533: if (!was_bbyb && ISBBYB) ! 534: ttrtp(tp); ! 535: break; ! 536: case TIOCGETC: ! 537: kucopy(&tp->t_tchars, vec, sizeof (struct tchars)); ! 538: break; ! 539: case TIOCSETC: ! 540: ++rload; ! 541: ++drain; ! 542: ukcopy(vec, &tp->t_tchars, sizeof (struct tchars)); ! 543: make_termio(&tp->t_sgttyb, &tp->t_tchars, &tp->t_termio); ! 544: break; ! 545: case TIOCEXCL: ! 546: s = sphi(); ! 547: tp->t_flags |= T_EXCL; ! 548: spl(s); ! 549: break; ! 550: case TIOCNXCL: ! 551: s = sphi(); ! 552: tp->t_flags &= ~T_EXCL; ! 553: spl(s); ! 554: break; ! 555: case TIOCHPCL: /* set hangup on last close */ ! 556: s = sphi(); ! 557: tp->t_flags |= T_HPCL; ! 558: spl(s); ! 559: #ifdef _I386 ! 560: tp->t_termio.c_cflag |= HUPCL; ! 561: #endif ! 562: break; ! 563: case TIOCCHPCL: /* don't hangup on last close */ ! 564: if (!super()) /* only superuser may do this */ ! 565: u.u_error = EPERM; /* not su */ ! 566: else { ! 567: s = sphi(); ! 568: tp->t_flags &= ~T_HPCL; /* turn off hangup bit */ ! 569: spl(s); ! 570: #ifdef _I386 ! 571: tp->t_termio.c_cflag &= ~HUPCL; ! 572: #endif ! 573: } ! 574: break; ! 575: case TIOCGETTF: /* get tty flag word */ ! 576: kucopy(&tp->t_flags, (unsigned *) vec, sizeof(unsigned)); ! 577: break; ! 578: #ifdef _I386 ! 579: case TCFLSH: /* sleazy - should look at 2nd arg but don't yet */ ! 580: #endif ! 581: case TIOCFLUSH: ! 582: ++flush; /* flush both input and output */ ! 583: /* ++drain; Why? - hws - 91/11/22 */ ! 584: break; ! 585: case TIOCBREAD: /* blocking read for CBREAK/RAW mode */ ! 586: s = sphi(); ! 587: tp->t_flags |= T_BRD; ! 588: spl(s); ! 589: break; ! 590: case TIOCCBREAD: /* turn off CBREAK/RAW blocking read mode */ ! 591: s = sphi(); ! 592: tp->t_flags &= ~T_BRD; ! 593: spl(s); ! 594: break; ! 595: /* ! 596: * The following is a hack so that the process group for /dev/console ! 597: * contains the current login shell running on it. ! 598: * Only expect /etc/init to use this ugliness. ! 599: */ ! 600: case TIOCSETG: ! 601: if (super()) ! 602: tp->t_group = SELF->p_group; ! 603: break; ! 604: default: ! 605: u.u_error = EINVAL; ! 606: } ! 607: ! 608: /* ! 609: * T_STOP is set under two conditions: ! 610: * - a modem control device is awaiting carrier ! 611: * - a stopc (usually Ctrl-S) character was received. ! 612: * ! 613: * If ioctl just put device into RAWIN mode, make sure device ! 614: * is not still waiting for startc. ! 615: */ ! 616: if (ISRIN && (tp->t_flags & T_STOP) && !(tp->t_flags & T_HOPEN)) { ! 617: s = sphi(); ! 618: tp->t_flags &= ~T_STOP; ! 619: ttstart(tp); ! 620: spl(s); ! 621: } ! 622: ! 623: /* ! 624: * Wait for output to drain, or signal to arrive. ! 625: */ ! 626: if (drain) { ! 627: while (tp->t_oq.cq_cc) { ! 628: s = sphi(); ! 629: tp->t_flags |= T_DRAIN; ! 630: spl(s); ! 631: v_sleep((char *)&tp->t_oq, CVTTOUT, IVTTOUT, SVTTOUT, ! 632: "ttyiodrn"); ! 633: /* A TIOC has asked for tty output to drain. */ ! 634: if (SELF->p_ssig && nondsig()) ! 635: break; ! 636: } ! 637: } ! 638: ! 639: /* ! 640: * Flush input. ! 641: */ ! 642: if (flush) ! 643: ttflush(tp); ! 644: ! 645: /* ! 646: * Re-initialize hardware. ! 647: */ ! 648: if (rload) { ! 649: if ((tp->t_sgttyb.sg_flags & RAWIN) ! 650: && (tp->t_sgttyb.sg_flags & RAWOUT)) ! 651: tp->t_sgttyb.sg_flags |= RAW; ! 652: if (tp->t_sgttyb.sg_flags & RAW) ! 653: tp->t_sgttyb.sg_flags |= (RAWIN|RAWOUT); ! 654: if (tp->t_param) ! 655: NEAR_OR_FAR_CALL(t_param) ! 656: } ! 657: } ! 658: ! 659: /* ! 660: * ttpoll() ! 661: * ! 662: * Polling routine. ! 663: * [System V.3 Compatible] ! 664: */ ! 665: int ttpoll(tp, ev, msec) ! 666: register TTY * tp; ! 667: int ev; ! 668: int msec; ! 669: { ! 670: /* ! 671: * Priority polls not supported. ! 672: */ ! 673: ev &= ~POLLPRI; ! 674: ! 675: /* ! 676: * Input poll with no data present. ! 677: */ ! 678: if ((ev & POLLIN) && (tp->t_iq.cq_cc == 0)) { ! 679: ! 680: /* ! 681: * Blocking input poll. ! 682: */ ! 683: if (msec) ! 684: pollopen(&tp->t_ipolls); ! 685: ! 686: /* ! 687: * Second look to avoid interrupt race. ! 688: */ ! 689: if (tp->t_iq.cq_cc == 0) ! 690: ev &= ~POLLIN; ! 691: } ! 692: ! 693: /* ! 694: * Output poll with no space. ! 695: */ ! 696: if ((ev & POLLOUT) && (tp->t_oq.cq_cc >= OLOLIM)) { ! 697: ! 698: /* ! 699: * Blocking output poll. ! 700: */ ! 701: if (msec) ! 702: pollopen(&tp->t_opolls); ! 703: ! 704: /* ! 705: * Second look to avoid interrupt race. ! 706: */ ! 707: if (tp->t_oq.cq_cc >= OLOLIM) ! 708: ev &= ~POLLIN; ! 709: } ! 710: ! 711: if (((ev & POLLIN) == 0) && ((tp->t_flags & T_CARR) == 0)) ! 712: ev |= POLLHUP; ! 713: ! 714: return ev; ! 715: } ! 716: ! 717: /* ! 718: * ttout() ! 719: * ! 720: * Pull a character from the output queues of the typewriter. ! 721: * Doing fills, newline insert, tab expansion, etc. ! 722: * ! 723: * If the stream is empty return a -1. ! 724: * Called at high priority. ! 725: */ ! 726: int ttout(tp) ! 727: register TTY *tp; ! 728: { ! 729: register int c; ! 730: ! 731: if (tp->t_nfill) { ! 732: --tp->t_nfill; ! 733: c = tp->t_fillb; ! 734: } else if (tp->t_flags & T_INL) { ! 735: tp->t_flags &= ~T_INL; ! 736: c = '\n'; ! 737: } else { ! 738: if ((c=getq(&tp->t_oq)) < 0) ! 739: return -1; ! 740: if (!ISROUT) { ! 741: if (c=='\n' && ISCRMOD) { ! 742: tp->t_flags |= T_INL; ! 743: c = '\r'; ! 744: } else if (c=='\t' && ISXTABS) { ! 745: tp->t_nfill = ~(tp->t_hpos|~07); ! 746: tp->t_fillb = ' '; ! 747: c = ' '; ! 748: } ! 749: } ! 750: } ! 751: if (!ISROUT) { ! 752: if (c == '\b') { ! 753: if (tp->t_hpos) ! 754: --tp->t_hpos; ! 755: } else if (c == '\r') ! 756: tp->t_hpos = 0; ! 757: else if (c == '\t') ! 758: tp->t_hpos = (tp->t_hpos|07) + 1; ! 759: #if NOT_8_BIT ! 760: else if (c >= ' ' && c <= '~') ! 761: #else ! 762: else if ((c >= ' ' && c <= '~') || (c >= 0200 && c <= 0376)) ! 763: #endif ! 764: ++tp->t_hpos; ! 765: } ! 766: return c; ! 767: } ! 768: ! 769: /* ! 770: * ttin() ! 771: * ! 772: * Pass a character to the device independent typewriter routines. ! 773: * Handle erase and kill, tandem flow control, and other magic. ! 774: * Often called at high priority from the driver's interrupt routine. ! 775: */ ! 776: void ! 777: ttin(tp, c) ! 778: register TTY *tp; ! 779: register int c; ! 780: { ! 781: int dc, i, n; ! 782: int s; ! 783: ! 784: if (!ISRIN) { ! 785: #if NOT_8_BIT ! 786: c &= 0177; ! 787: #endif ! 788: if (ISINTR) { ! 789: ttsignal(tp, SIGINT); ! 790: goto ttin_ret; ! 791: } ! 792: if (ISQUIT) { ! 793: ttsignal(tp, SIGQUIT); ! 794: goto ttin_ret; ! 795: } ! 796: } ! 797: if (tp->t_flags & T_ISTOP) ! 798: goto ttin_ret; ! 799: if (!ISRIN) { ! 800: if (c=='\r' && ISCRMOD) ! 801: c = '\n'; ! 802: if (tp->t_escape) { ! 803: if (c == ESC) ! 804: ++tp->t_escape; ! 805: else { ! 806: if (ISERASE || ISKILL) { ! 807: c |= 0200; ! 808: --tp->t_escape; ! 809: } ! 810: while (tp->t_escape && tp->t_ibx<NCIB-1) { ! 811: tp->t_ib[tp->t_ibx++] = ESC; ! 812: --tp->t_escape; ! 813: } ! 814: ttstash(tp, c); ! 815: } ! 816: if (ISECHO) { ! 817: #if NOT_8_BIT ! 818: putq(&tp->t_oq, c&0177); ! 819: #else ! 820: putq(&tp->t_oq, c); /* no strip for 8-bit */ ! 821: #endif ! 822: ttstart(tp); ! 823: } ! 824: goto ttin_ret; ! 825: } ! 826: if (ISERASE && !ISCBRK) { ! 827: while (tp->t_escape && tp->t_ibx<NCIB-1) { ! 828: tp->t_ib[tp->t_ibx++] = ESC; ! 829: --tp->t_escape; ! 830: } ! 831: if (tp->t_ibx == 0) ! 832: goto ttin_ret; ! 833: dc = tp->t_ib[--tp->t_ibx]; ! 834: if (ISECHO) { ! 835: if (!ISCRT) ! 836: putq(&tp->t_oq, c); ! 837: /* don't erase for bell, null, or rubout */ ! 838: #if NOT_8_BIT ! 839: else if (((c = dc&0177) == '\007') ! 840: || c == 0 || c == 0177) ! 841: #else ! 842: else if (((c = dc) == '\007') ! 843: || c == 0 || c == 0177 || c == 0377) ! 844: #endif ! 845: goto ttin_ret; ! 846: else if (c != '\b' && c != '\t') { ! 847: putq(&tp->t_oq, '\b'); ! 848: putq(&tp->t_oq, ' '); ! 849: putq(&tp->t_oq, '\b'); ! 850: } else if (c == '\t') { ! 851: n = tp->t_opos + tp->t_escape; ! 852: for (i=0; i<tp->t_ibx; ++i) { ! 853: c = tp->t_ib[i]; ! 854: #if NOT_8_BIT ! 855: if (c & 0200) { ! 856: ++n; ! 857: c &= 0177; ! 858: } ! 859: #endif ! 860: if (c == '\b') ! 861: --n; ! 862: else { ! 863: if (c == '\t') ! 864: n |= 07; ! 865: ++n; ! 866: } ! 867: } ! 868: while (n++ < tp->t_hpos) ! 869: putq(&tp->t_oq, '\b'); ! 870: } ! 871: #if NOT_8_BIT ! 872: if (dc & 0200) { ! 873: if ((dc&0177) != '\b') ! 874: putq(&tp->t_oq, '\b'); ! 875: putq(&tp->t_oq, ' '); ! 876: putq(&tp->t_oq, '\b'); ! 877: } ! 878: #endif ! 879: ttstart(tp); ! 880: } ! 881: goto ttin_ret; ! 882: } ! 883: if (ISKILL && !ISCBRK) { ! 884: tp->t_ibx = 0; ! 885: tp->t_escape = 0; ! 886: if (ISECHO) { ! 887: if (c < 0x20) { ! 888: putq(&tp->t_oq, '^'); ! 889: c += 0x40; ! 890: } ! 891: putq(&tp->t_oq, c); ! 892: putq(&tp->t_oq, '\n'); ! 893: ttstart(tp); ! 894: } ! 895: goto ttin_ret; ! 896: } ! 897: } ! 898: if (ISBBYB) { ! 899: putq(&tp->t_iq, c); ! 900: if (tp->t_flags & T_INPUT) { ! 901: s = sphi(); ! 902: tp->t_flags &= ~T_INPUT; ! 903: spl(s); ! 904: defer(wakeup, (char *) &tp->t_iq); ! 905: } ! 906: if (tp->t_ipolls.e_procp) { ! 907: tp->t_ipolls.e_procp = 0; ! 908: defer(pollwake, (char *) &tp->t_ipolls); ! 909: } ! 910: } else { ! 911: if (tp->t_ibx == 0) ! 912: tp->t_opos = tp->t_hpos; ! 913: if (c == ESC) ! 914: ++tp->t_escape; ! 915: else ! 916: ttstash(tp, c); ! 917: } ! 918: if (ISECHO) { ! 919: if (ISRIN || !ISEOF) { ! 920: putq(&tp->t_oq, c); ! 921: ttstart(tp); ! 922: } ! 923: } ! 924: if ((n=tp->t_iq.cq_cc)>=IHILIM) { ! 925: s = sphi(); ! 926: tp->t_flags |= T_ISTOP; ! 927: spl(s); ! 928: } else if (ISTAND && (tp->t_flags&T_TSTOP)==0 && n>=ITSLIM) { ! 929: s = sphi(); ! 930: tp->t_flags |= T_TSTOP; ! 931: spl(s); ! 932: putq(&tp->t_oq, stopc); ! 933: ttstart(tp); ! 934: } ! 935: ! 936: ttin_ret: ! 937: return; ! 938: } ! 939: ! 940: /* ! 941: * ttstash() ! 942: * ! 943: * Cooked mode. ! 944: * Put character in the buffer and check for end of line. ! 945: * Only a legal end of line can take the last character position. ! 946: * ! 947: * Only called from ttin(), and ttin() is called at high priority. ! 948: */ ! 949: static void ttstash(tp, c) ! 950: register TTY *tp; ! 951: { ! 952: register char *p1, *p2; ! 953: ! 954: if (c=='\n' || ISEOF || ISBRK) { ! 955: p1 = &tp->t_ib[0]; ! 956: p2 = &tp->t_ib[tp->t_ibx]; ! 957: *p2++ = c; /* Always room */ ! 958: while (p1 < p2) ! 959: #if NOT_8_BIT ! 960: putq(&tp->t_iq, (*p1++)&0177); ! 961: #else ! 962: putq(&tp->t_iq, (*p1++)); ! 963: #endif ! 964: tp->t_ibx = 0; ! 965: tp->t_escape = 0; ! 966: ! 967: if (tp->t_flags & T_INPUT) { ! 968: tp->t_flags &= ~T_INPUT; ! 969: defer(wakeup, (char *) &tp->t_iq); ! 970: } ! 971: ! 972: if (tp->t_ipolls.e_procp) { ! 973: tp->t_ipolls.e_procp = 0; ! 974: defer(pollwake, (char *) &tp->t_ipolls); ! 975: } ! 976: ! 977: } else if (tp->t_ibx < NCIB-1) ! 978: tp->t_ib[tp->t_ibx++] = c; ! 979: } ! 980: ! 981: /* ! 982: * ttstart() ! 983: * ! 984: * Start output on a tty. ! 985: * Duck out if stopped. Do wakeups. ! 986: */ ! 987: void ttstart(tp) ! 988: register TTY *tp; ! 989: { ! 990: register int n; ! 991: int s; ! 992: ! 993: n = tp->t_flags; ! 994: if (n & T_STOP) ! 995: goto stdone; ! 996: ! 997: if ((n&T_DRAIN) && tp->t_oq.cq_cc==0 ! 998: && (n&T_INL)==0 && tp->t_nfill==0) { ! 999: s = sphi(); ! 1000: tp->t_flags &= ~T_DRAIN; ! 1001: spl(s); ! 1002: defer(wakeup, (char *) &tp->t_oq); ! 1003: goto stdone; ! 1004: } ! 1005: ! 1006: NEAR_OR_FAR_CALL(t_start) ! 1007: ! 1008: if (tp->t_oq.cq_cc > OLOLIM) ! 1009: goto stdone; ! 1010: ! 1011: if (n & T_HILIM) { ! 1012: s = sphi(); ! 1013: tp->t_flags &= ~T_HILIM; ! 1014: spl(s); ! 1015: defer(wakeup, (char *) &tp->t_oq); ! 1016: } ! 1017: ! 1018: if (tp->t_opolls.e_procp) { ! 1019: tp->t_opolls.e_procp = 0; ! 1020: defer(pollwake, (char *) &tp->t_opolls); ! 1021: } ! 1022: stdone: ! 1023: return; ! 1024: } ! 1025: ! 1026: /* ! 1027: * ttflush() ! 1028: * ! 1029: * Flush a tty. ! 1030: * Called to clear out queues. ! 1031: */ ! 1032: void ttflush(tp) ! 1033: register TTY *tp; ! 1034: { ! 1035: int s; ! 1036: ! 1037: clrq(&tp->t_iq); ! 1038: clrq(&tp->t_oq); ! 1039: ! 1040: if (tp->t_flags & T_INPUT) { ! 1041: defer(wakeup, (char *) &tp->t_iq); ! 1042: } ! 1043: ! 1044: if (tp->t_flags & (T_DRAIN|T_HILIM)) { ! 1045: defer(wakeup, (char *) &tp->t_oq); ! 1046: } ! 1047: ! 1048: if (tp->t_ipolls.e_procp) { ! 1049: tp->t_ipolls.e_procp = 0; ! 1050: defer(pollwake, (char *) &tp->t_ipolls); ! 1051: } ! 1052: ! 1053: if (tp->t_opolls.e_procp) { ! 1054: tp->t_opolls.e_procp = 0; ! 1055: defer(pollwake, (char *) &tp->t_opolls); ! 1056: } ! 1057: ! 1058: tp->t_ibx = 0; ! 1059: tp->t_escape = 0; ! 1060: s = sphi(); ! 1061: tp->t_flags &= T_SAVE; /* reset most flag bits */ ! 1062: spl(s); ! 1063: } ! 1064: ! 1065: /* ! 1066: * ttsignal() ! 1067: * ! 1068: * Send a signal to every process in the given process group. ! 1069: */ ! 1070: void ! 1071: ttsignal(tp, sig) ! 1072: TTY *tp; ! 1073: int sig; ! 1074: { ! 1075: register int g; ! 1076: register PROC *pp; ! 1077: ! 1078: g = tp->t_group; ! 1079: if (g == 0) ! 1080: goto sigdone; ! 1081: ttflush(tp); ! 1082: pp = &procq; ! 1083: while ((pp=pp->p_nforw) != &procq) ! 1084: if (pp->p_group == g) { ! 1085: sendsig(sig, pp); ! 1086: } ! 1087: sigdone: ! 1088: return; ! 1089: } ! 1090: ! 1091: /* ! 1092: * tthup() ! 1093: * ! 1094: * Flag hangup internally to force errors on tty read/write, flush tty, ! 1095: * then send hangup signal. ! 1096: */ ! 1097: void tthup(tp) ! 1098: register TTY *tp; ! 1099: { ! 1100: ttflush(tp); ! 1101: ttsignal(tp, SIGHUP); ! 1102: } ! 1103: ! 1104: #ifdef _I386 ! 1105: /* ! 1106: * Convert from sgttyb and tchars structs to termio. ! 1107: */ ! 1108: static void ! 1109: make_termio(sgp, tcp, trp) ! 1110: struct sgttyb * sgp; ! 1111: struct tchars * tcp; ! 1112: struct termio * trp; ! 1113: { ! 1114: trp->c_cc[VINTR] = tcp->t_intrc; ! 1115: trp->c_cc[VQUIT] = tcp->t_quitc; ! 1116: trp->c_cc[VEOF ] = tcp->t_eofc; ! 1117: trp->c_cc[VEOL ] = '\n'; ! 1118: trp->c_cc[VERASE] = sgp->sg_erase; ! 1119: trp->c_cc[VKILL ] = sgp->sg_kill; ! 1120: ! 1121: trp->c_iflag = BRKINT | ISTRIP | IXON | IGNPAR | INPCK | ISTRIP; ! 1122: trp->c_oflag = OPOST; ! 1123: trp->c_cflag &= (CSIZE|HUPCL|CLOCAL|CREAD); ! 1124: trp->c_lflag = ICANON | ISIG | ECHONL | ECHOK; ! 1125: ! 1126: if (sgp->sg_flags & TANDEM) ! 1127: trp->c_iflag |= IXOFF; ! 1128: ! 1129: if (sgp->sg_flags & CRMOD) ! 1130: trp->c_iflag |= ICRNL; ! 1131: ! 1132: if (sgp->sg_flags & LCASE) { ! 1133: trp->c_lflag |= XCASE; ! 1134: trp->c_iflag |= IUCLC; ! 1135: trp->c_oflag |= OLCUC; ! 1136: } ! 1137: ! 1138: if (sgp->sg_flags & RAWIN) ! 1139: trp->c_iflag &= ~IXON; ! 1140: ! 1141: if (sgp->sg_flags & RAWOUT) ! 1142: trp->c_oflag &= ~OPOST; ! 1143: ! 1144: if (sgp->sg_flags & XTABS) ! 1145: trp->c_oflag |= XTABS; ! 1146: ! 1147: if (sgp->sg_flags & CRMOD) ! 1148: trp->c_oflag |= ONLCR; ! 1149: ! 1150: if (sgp->sg_flags & (EVENP|ODDP)) { ! 1151: trp->c_cflag |= PARENB; ! 1152: if (sgp->sg_flags & ODDP) ! 1153: trp->c_cflag |= PARODD; ! 1154: } ! 1155: trp->c_cflag |= sgp->sg_ispeed; ! 1156: ! 1157: if (sgp->sg_flags & CRT) ! 1158: trp->c_lflag |= ECHOE; ! 1159: ! 1160: if (sgp->sg_flags & RAWIN) ! 1161: trp->c_lflag &= ~(ISIG|ICANON); ! 1162: ! 1163: if (sgp->sg_flags & CBREAK) ! 1164: trp->c_lflag &= ~ICANON; ! 1165: ! 1166: if (sgp->sg_flags & ECHO) ! 1167: trp->c_lflag |= ECHO; ! 1168: } ! 1169: ! 1170: /* ! 1171: * Convert from termio struct to sgttyb and tchars. ! 1172: */ ! 1173: static void ! 1174: make_sg(trp, sgp, tcp) ! 1175: struct termio * trp; ! 1176: struct sgttyb * sgp; ! 1177: struct tchars * tcp; ! 1178: { ! 1179: T_HAL(1, { printf("T:%x:%x:%x:%x ", trp->c_iflag, trp->c_oflag, \ ! 1180: trp->c_cflag, trp->c_lflag);}); ! 1181: tcp->t_intrc = trp->c_cc[VINTR]; ! 1182: tcp->t_quitc = trp->c_cc[VQUIT]; ! 1183: tcp->t_startc= '\021'; /* Ctrl-Q */ ! 1184: tcp->t_stopc = '\023'; /* Ctrl-S */ ! 1185: tcp->t_eofc = trp->c_cc[VEOF]; ! 1186: tcp->t_brkc = -1; ! 1187: ! 1188: sgp->sg_erase = trp->c_cc[VERASE]; ! 1189: sgp->sg_kill = trp->c_cc[VKILL ]; ! 1190: sgp->sg_ispeed = trp->c_cflag & CBAUD; ! 1191: sgp->sg_ospeed = sgp->sg_ispeed; ! 1192: sgp->sg_flags = RAWIN | RAWOUT | CBREAK; ! 1193: ! 1194: if (trp->c_lflag & ECHO) ! 1195: sgp->sg_flags |= ECHO; ! 1196: ! 1197: if (trp->c_lflag & ECHOE) ! 1198: sgp->sg_flags |= CRT; ! 1199: ! 1200: if ( (trp->c_lflag & XCASE) ! 1201: || (trp->c_oflag & OLCUC) ! 1202: || (trp->c_iflag & IUCLC)) ! 1203: sgp->sg_flags |= LCASE; ! 1204: ! 1205: if (trp->c_iflag & IXOFF) ! 1206: sgp->sg_flags |= TANDEM; ! 1207: ! 1208: if (trp->c_iflag & ICRNL) ! 1209: sgp->sg_flags |= CRMOD; ! 1210: ! 1211: if (trp->c_oflag & ONLCR) ! 1212: sgp->sg_flags |= CRMOD; ! 1213: ! 1214: if (trp->c_oflag & OPOST) ! 1215: sgp->sg_flags &= ~RAWOUT; ! 1216: ! 1217: if (trp->c_oflag & XTABS) ! 1218: sgp->sg_flags |= XTABS; ! 1219: ! 1220: if (trp->c_cflag & PARENB) { ! 1221: if (trp->c_cflag & PARODD) ! 1222: sgp->sg_flags |= ODDP; ! 1223: else ! 1224: sgp->sg_flags |= EVENP; ! 1225: } ! 1226: ! 1227: if (trp->c_lflag & ISIG) ! 1228: sgp->sg_flags &= ~RAWIN; ! 1229: ! 1230: if (trp->c_lflag & ICANON) ! 1231: sgp->sg_flags &= ~CBREAK; ! 1232: } ! 1233: #endif ! 1234: ! 1235: /* ! 1236: * ttrtp() ! 1237: * ! 1238: * Recover contents of typeahead when changing modes. ! 1239: * Called for ioctls of TIOCSETP and TCSETA, ! 1240: * when going from not byte-by-byte input to BBYB. ! 1241: */ ! 1242: static void ! 1243: ttrtp(tp) ! 1244: TTY * tp; ! 1245: { ! 1246: register char *p1, *p2; ! 1247: ! 1248: if (tp->t_ibx) { ! 1249: p1 = &tp->t_ib[0]; ! 1250: p2 = &tp->t_ib[tp->t_ibx]; ! 1251: while (p1 < p2) { ! 1252: #if NOT_8_BIT ! 1253: putq(&tp->t_iq, (*p1++) & 0177); ! 1254: #else ! 1255: putq(&tp->t_iq, (*p1++)); ! 1256: #endif ! 1257: } ! 1258: tp->t_ibx = 0; ! 1259: } ! 1260: } ! 1261: ! 1262: /* ! 1263: * ttinp() ! 1264: * ! 1265: * Return nonzero if ttin() may be called to send data for pickup by ttread(), ! 1266: * or 0 if not. ! 1267: */ ! 1268: int ! 1269: ttinp(tp) ! 1270: TTY * tp; ! 1271: { ! 1272: return ((tp->t_flags&T_ISTOP) == 0); ! 1273: } ! 1274: ! 1275: /* ! 1276: * ttoutp() ! 1277: * ! 1278: * Return nonzero if ttout() may be called to fetch data stored by ttwrite(), ! 1279: * or 0 if not. ! 1280: */ ! 1281: int ! 1282: ttoutp(tp) ! 1283: TTY * tp; ! 1284: { ! 1285: return (tp->t_nfill || (tp->t_flags&T_INL) || tp->t_oq.cq_cc); ! 1286: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.