1: /* 2: * SCCS id @(#)tty.c 2.1 (Berkeley) 8/5/83 3: */ 4: 5: /* 6: * TTY subroutines common to more than one line discipline 7: */ 8: 9: #include "param.h" 10: #include <sys/systm.h> 11: #include <sys/dir.h> 12: #include <sys/user.h> 13: #include <sys/tty.h> 14: #include <sys/proc.h> 15: #ifdef MPX_FILS 16: #include <sys/mx.h> 17: #endif 18: #include <sys/inode.h> 19: #include <sys/file.h> 20: #include <sys/reg.h> 21: #include <sys/conf.h> 22: #include <sys/buf.h> 23: #include "bk.h" 24: 25: extern char partab[]; 26: 27: /* 28: * Input mapping table-- if an entry is non-zero, when the 29: * corresponding character is typed preceded by "\" the escape 30: * sequence is replaced by the table value. Only used for 31: * upper-case only terminals. 32: */ 33: 34: char maptab[] ={ 35: 000,000,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,'`', 40: '{','}',000,000,000,000,000,000, 41: 000,000,000,000,000,000,000,000, 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,'~',000, 47: 000,'A','B','C','D','E','F','G', 48: 'H','I','J','K','L','M','N','O', 49: 'P','Q','R','S','T','U','V','W', 50: 'X','Y','Z',000,000,000,000,000, 51: }; 52: 53: short tthiwat[16] = 54: { 100,100,100,100,100,100,100,200,200,400,400,400,650,650,650,650 }; 55: short ttlowat[16] = 56: { 30, 30, 30, 30, 30, 30, 30, 50, 50,120,120,120,125,125,125,125 }; 57: 58: #define OBUFSIZ 100 59: 60: /* 61: * routine called on teletype open. 62: * establishes a process group for distribution 63: * of quits and interrupts from the tty. 64: * Then calls open routine for default line discipline. 65: */ 66: ttyopen(dev, tp) 67: dev_t dev; 68: register struct tty *tp; 69: { 70: register struct proc *pp; 71: 72: pp = u.u_procp; 73: tp->t_dev = dev; 74: if(pp->p_pgrp == 0) { 75: u.u_ttyp = tp; 76: u.u_ttyd = dev; 77: if (tp->t_pgrp == 0) 78: tp->t_pgrp = pp->p_pid; 79: pp->p_pgrp = tp->t_pgrp; 80: } 81: tp->t_state &= ~WOPEN; 82: tp->t_state |= ISOPEN; 83: (*linesw[tp->t_line].l_open)(tp); 84: } 85: 86: /* 87: * clean tp on last close 88: */ 89: ttyclose(tp) 90: register struct tty *tp; 91: { 92: (*linesw[tp->t_line].l_close)(tp); 93: tp->t_pgrp = 0; 94: wflushtty(tp); 95: tp->t_state = 0; 96: } 97: /* 98: * set default control characters. 99: */ 100: ttychars(tp) 101: register struct tty *tp; 102: { 103: 104: tun.t_intrc = CINTR; 105: tun.t_quitc = CQUIT; 106: tun.t_startc = CSTART; 107: tun.t_stopc = CSTOP; 108: tun.t_eofc = CEOT; 109: tun.t_brkc = CBRK; 110: tp->t_erase = CERASE; 111: tp->t_kill = CKILL; 112: #ifdef UCB_NTTY 113: tlun.t_suspc = CTRL(z); 114: tlun.t_dsuspc = CTRL(y); 115: tlun.t_rprntc = CTRL(r); 116: tlun.t_flushc = CTRL(o); 117: tlun.t_werasc = CTRL(w); 118: tlun.t_lnextc = CTRL(v); 119: tp->t_local = 0; 120: tp->t_lstate = 0; 121: #endif 122: } 123: 124: /* 125: * Wait for output to drain, then flush input waiting. 126: */ 127: wflushtty(tp) 128: register struct tty *tp; 129: { 130: 131: (void) _spl5(); 132: while (tp->t_outq.c_cc && tp->t_state&CARR_ON) { 133: (*tp->t_oproc)(tp); 134: tp->t_state |= ASLEEP; 135: sleep((caddr_t)&tp->t_outq, TTOPRI); 136: } 137: flushtty(tp, FREAD|FWRITE); 138: (void) _spl0(); 139: } 140: 141: /* 142: * flush all TTY queues 143: */ 144: flushtty(tp, rw) 145: register struct tty *tp; 146: register rw; 147: { 148: register s; 149: 150: #if NBK > 0 151: if (tp->t_line == NETLDISC) 152: return; 153: #endif 154: s = spl6(); 155: if (rw & FREAD) { 156: while (getc(&tp->t_canq) >= 0) 157: ; 158: wakeup((caddr_t)&tp->t_rawq); 159: } 160: if (rw & FWRITE) { 161: tp->t_state &= ~TTSTOP; 162: (*cdevsw[major(tp->t_dev)].d_stop)(tp); 163: while (getc(&tp->t_outq) >= 0) 164: ; 165: wakeup((caddr_t)&tp->t_outq); 166: } 167: if (rw & FREAD) { 168: while (getc(&tp->t_rawq) >= 0) 169: ; 170: tp->t_delct = 0; 171: #ifdef UCB_NTTY 172: tp->t_rocount = 0; 173: tp->t_rocol = 0; 174: tp->t_lstate = 0; 175: #endif 176: } 177: splx(s); 178: } 179: 180: /* 181: * Send stop character on input overflow. 182: */ 183: ttyblock(tp) 184: register struct tty *tp; 185: { 186: register x; 187: x = tp->t_rawq.c_cc + tp->t_canq.c_cc; 188: if (tp->t_rawq.c_cc > TTYHOG) { 189: flushtty(tp, FREAD|FWRITE); 190: tp->t_state &= ~TBLOCK; 191: } 192: /* 193: * Block further input iff: 194: * Current input > threshold AND input is available to user program 195: */ 196: if (x >= TTYHOG/2 && (tp->t_delct>0 || (tp->t_flags&(RAW|CBREAK)))) { 197: if (putc(tun.t_stopc, &tp->t_outq)==0) { 198: tp->t_state |= TBLOCK; 199: ttstart(tp); 200: } 201: } 202: } 203: 204: /* 205: * Restart typewriter output following a delay 206: * timeout. 207: * The name of the routine is passed to the timeout 208: * subroutine and it is called during a clock interrupt. 209: */ 210: ttrstrt(tp) 211: register struct tty *tp; 212: { 213: 214: #ifdef DIAGNOSTIC 215: if (tp == 0) { 216: printf("ttrstrt: arg was 0!\n"); 217: return; 218: } 219: #endif 220: tp->t_state &= ~TIMEOUT; 221: ttstart(tp); 222: } 223: 224: /* 225: * Start output on the typewriter. It is used from the top half 226: * after some characters have been put on the output queue, 227: * from the interrupt routine to transmit the next 228: * character, and after a timeout has finished. 229: */ 230: ttstart(tp) 231: register struct tty *tp; 232: { 233: register s; 234: 235: s = spl5(); 236: if((tp->t_state&(TIMEOUT|TTSTOP|BUSY)) == 0) 237: (*tp->t_oproc)(tp); 238: splx(s); 239: } 240: 241: /* 242: * Common code for tty ioctls. 243: * Return values: 244: * cmd cmd is not done (driver must do some/all) 245: * 0 cmd is done 246: * 0 (u.u_error set) cmd was rejected by line disc. code 247: */ 248: /*ARGSUSED*/ 249: ttioctl(tp, com, addr, flag) 250: register struct tty *tp; 251: caddr_t addr; 252: { 253: register dev_t dev; 254: unsigned t; 255: struct sgttyb iocb; 256: struct clist tq; 257: extern int nldisp; 258: register c; 259: int temp; 260: extern nodev(); 261: 262: /* 263: * First, give the line discipline a chance. 264: * If it returns 0, either the work is done 265: * or the request was refused. 266: * Return 0 to keep the device driver from continuing. 267: */ 268: if ((com = (*linesw[tp->t_line].l_ioctl)(tp,com,addr,flag)) == 0) 269: return(0); 270: /* 271: * This is especially so that isatty() will 272: * fail when carrier is gone. 273: */ 274: if ((tp->t_state&CARR_ON) == 0) { 275: u.u_error = EBADF; 276: return (0); 277: } 278: 279: dev = tp->t_dev; 280: /* 281: * If the ioctl involves modification, 282: * hang if in the background. 283: */ 284: #ifdef MENLO_JCL 285: switch(com) { 286: 287: case TIOCSETD: 288: case TIOCSETP: 289: case TIOCSETN: 290: case TIOCFLUSH: 291: case TIOCSETC: 292: case TIOCSLTC: 293: case TIOCSPGRP: 294: case TIOCLBIS: 295: case TIOCLBIC: 296: case TIOCLSET: 297: case TIOCSTI: 298: while (tp->t_line == NTTYDISC && 299: u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp && 300: #ifdef VIRUS_VFORK 301: (u.u_procp->p_flag&SVFORK) == 0 && 302: #endif 303: u.u_signal[SIGTTOU] != SIG_IGN && 304: u.u_signal[SIGTTOU] != SIG_HOLD && 305: (u.u_procp->p_flag&SDETACH)==0) { 306: gsignal(u.u_procp->p_pgrp, SIGTTOU); 307: sleep((caddr_t)&lbolt, TTOPRI); 308: } 309: break; 310: } 311: #endif 312: 313: /* 314: * Process the ioctl. 315: */ 316: switch(com) { 317: 318: /* 319: * Get discipline number 320: */ 321: case TIOCGETD: 322: t = tp->t_line; 323: if (copyout((caddr_t)&t, addr, sizeof(t))) 324: u.u_error = EFAULT; 325: break; 326: 327: /* 328: * Set line discipline 329: */ 330: case TIOCSETD: 331: if (copyin(addr, (caddr_t)&t, sizeof(t))) { 332: u.u_error = EFAULT; 333: break; 334: } 335: if ((t >= nldisp) || (linesw[t].l_open == nodev)) { 336: u.u_error = ENXIO; 337: break; 338: } 339: if (t != tp->t_line) { 340: (void) _spl5(); 341: (*linesw[tp->t_line].l_close)(tp); 342: (*linesw[t].l_open)(tp); 343: if (u.u_error==0) 344: tp->t_line = t; 345: (void) _spl0(); 346: } 347: break; 348: 349: /* 350: * Prevent more opens on channel 351: */ 352: case TIOCEXCL: 353: tp->t_state |= XCLUDE; 354: break; 355: 356: case TIOCNXCL: 357: tp->t_state &= ~XCLUDE; 358: break; 359: 360: /* 361: * Set new parameters 362: */ 363: case TIOCSETP: 364: case TIOCSETN: 365: if (copyin(addr, (caddr_t)&iocb, sizeof(iocb))) { 366: u.u_error = EFAULT; 367: return(0); 368: } 369: (void) _spl5(); 370: #ifdef OLDTTY 371: if (tp->t_line == OTTYDISC) { 372: if (com == TIOCSETP) 373: wflushtty(tp); 374: while (canon(tp)>=0) 375: ; 376: } 377: #endif OLDTTY 378: #ifdef UCB_NTTY 379: if (tp->t_line == NTTYDISC) { 380: if (tp->t_flags&RAW || iocb.sg_flags&RAW || 381: com == TIOCSETP) 382: wflushtty(tp); 383: else if ((tp->t_flags&CBREAK) != (iocb.sg_flags&CBREAK)) { 384: if (iocb.sg_flags & CBREAK) { 385: catq(&tp->t_rawq, &tp->t_canq); 386: tq = tp->t_rawq; 387: tp->t_rawq = tp->t_canq; 388: tp->t_canq = tq; 389: } else { 390: tp->t_local |= LPENDIN; 391: #ifdef DIAGNOSTIC 392: if (tp->t_canq.c_cc) 393: panic("ttioctl canq"); 394: #endif 395: #ifdef MPX_FILS 396: if (tp->t_chan) 397: (void) sdata(tp->t_chan); 398: else 399: #endif 400: wakeup((caddr_t)&tp->t_rawq); 401: } 402: } 403: #endif 404: } 405: if ((tp->t_state&SPEEDS)==0) { 406: tp->t_ispeed = iocb.sg_ispeed; 407: tp->t_ospeed = iocb.sg_ospeed; 408: } 409: tp->t_erase = iocb.sg_erase; 410: tp->t_kill = iocb.sg_kill; 411: tp->t_flags = iocb.sg_flags; 412: (void) _spl0(); 413: return(com); 414: 415: /* 416: * Send current parameters to user 417: */ 418: case TIOCGETP: 419: iocb.sg_ispeed = tp->t_ispeed; 420: iocb.sg_ospeed = tp->t_ospeed; 421: iocb.sg_erase = tp->t_erase; 422: iocb.sg_kill = tp->t_kill; 423: iocb.sg_flags = tp->t_flags; 424: if (copyout((caddr_t)&iocb, addr, sizeof(iocb))) 425: u.u_error = EFAULT; 426: break; 427: 428: /* 429: * Hang up line on last close 430: */ 431: case TIOCHPCL: 432: tp->t_state |= HUPCLS; 433: break; 434: 435: case TIOCFLUSH: { 436: int flags; 437: if (copyin(addr, (caddr_t) &flags, sizeof (flags))) { 438: u.u_error = EFAULT; 439: return (1); 440: } 441: if (flags == 0) 442: flags = FREAD | FWRITE; 443: else 444: flags &= FREAD | FWRITE; 445: flushtty(tp, flags); 446: break; 447: } 448: 449: #ifdef UCB_NET 450: case FIONBIO: { 451: int nbio; 452: if (copyin(addr, (caddr_t)&nbio, sizeof (nbio))) { 453: u.u_error = EFAULT; 454: return(1); 455: } 456: if (nbio) 457: tp->t_state |= TS_NBIO; 458: else 459: tp->t_state &= ~TS_NBIO; 460: break; 461: } 462: 463: case FIOASYNC: { 464: int async; 465: if (copyin(addr, (caddr_t)&async, sizeof (async))) { 466: u.u_error = EFAULT; 467: return(1); 468: } 469: if (async) 470: tp->t_state |= TS_ASYNC; 471: else 472: tp->t_state &= ~TS_ASYNC; 473: break; 474: } 475: #endif 476: 477: /* 478: * Set and fetch special characters 479: */ 480: case TIOCSETC: 481: if (copyin(addr, (caddr_t)&tun, sizeof(struct tchars))) 482: u.u_error = EFAULT; 483: break; 484: 485: case TIOCGETC: 486: if (copyout((caddr_t)&tun, addr, sizeof(struct tchars))) 487: u.u_error = EFAULT; 488: break; 489: 490: #ifdef UCB_NTTY 491: /* 492: * Set/get local special characters. 493: */ 494: case TIOCSLTC: 495: if (copyin(addr, (caddr_t)&tlun, sizeof (struct ltchars))) 496: u.u_error = EFAULT; 497: break; 498: 499: case TIOCGLTC: 500: if (copyout((caddr_t)&tlun, addr, sizeof (struct ltchars))) 501: u.u_error = EFAULT; 502: break; 503: 504: /* 505: * Return number of characters immediately available. 506: */ 507: case FIONREAD: { 508: off_t nread; 509: 510: switch (tp->t_line) { 511: 512: #if NBK > 0 513: case NETLDISC: 514: nread = tp->t_rec ? tp->t_inbuf : 0; 515: break; 516: #endif 517: 518: #ifdef OLDTTY 519: case OTTYDISC: 520: (void) _spl5(); 521: while (canon(tp)>=0) 522: ; 523: (void) _spl0(); 524: /* fall into ... */ 525: #endif 526: 527: case NTTYDISC: 528: #ifdef UCB_NET 529: nread = ttnread(tp); 530: #else 531: nread = tp->t_canq.c_cc; 532: if (tp->t_flags & (RAW|CBREAK)) 533: nread += tp->t_rawq.c_cc; 534: #endif 535: break; 536: 537: } 538: if (copyout((caddr_t)&nread, addr, sizeof (off_t))) 539: u.u_error = EFAULT; 540: break; 541: } 542: 543: /* 544: * Should allow SPGRP and GPGRP only if tty open for reading. 545: */ 546: case TIOCSPGRP: 547: if (copyin(addr, (caddr_t)&tp->t_pgrp, sizeof (tp->t_pgrp))) 548: u.u_error = EFAULT; 549: break; 550: 551: case TIOCGPGRP: 552: if (copyout((caddr_t)&tp->t_pgrp, addr, sizeof(tp->t_pgrp))) 553: u.u_error = EFAULT; 554: break; 555: 556: /* 557: * Modify local mode word. 558: */ 559: case TIOCLBIS: 560: if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local))) 561: u.u_error = EFAULT; 562: else 563: tp->t_local |= temp; 564: break; 565: 566: case TIOCLBIC: 567: if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local))) 568: u.u_error = EFAULT; 569: else 570: tp->t_local &= ~temp; 571: break; 572: 573: case TIOCLSET: 574: if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local))) 575: u.u_error = EFAULT; 576: else 577: tp->t_local = temp; 578: break; 579: 580: case TIOCLGET: 581: if (copyout((caddr_t)&tp->t_local, addr, sizeof(tp->t_local))) 582: u.u_error = EFAULT; 583: break; 584: 585: /* 586: * Return number of characters in 587: * the output. 588: */ 589: case TIOCOUTQ: 590: if (copyout((caddr_t)&tp->t_outq.c_cc, addr, sizeof(tp->t_outq.c_cc))) 591: u.u_error = EFAULT; 592: break; 593: 594: /* 595: * Simulate typing of a character at the terminal. 596: */ 597: case TIOCSTI: 598: c = fubyte(addr); 599: if (u.u_uid && u.u_ttyp != tp || c < 0) 600: u.u_error = EFAULT; 601: else 602: (*linesw[tp->t_line].l_input)(c, tp); 603: break; 604: #endif 605: 606: #ifdef TEXAS_AUTOBAUD 607: case TIOCSIMG: 608: tp->t_xflags |= LIMAGE; 609: break; 610: 611: case TIOCCIMG: 612: tp->t_xflags &= ~LIMAGE; 613: break; 614: #endif 615: 616: default: 617: return(com); 618: } 619: return(0); 620: } 621: 622: #ifdef UCB_NET 623: ttnread(tp) 624: struct tty *tp; 625: { 626: int nread = 0; 627: 628: if (tp->t_local & LPENDIN) 629: ttypend(tp); 630: nread = tp->t_canq.c_cc; 631: if (tp->t_flags & (RAW|CBREAK)) 632: nread += tp->t_rawq.c_cc; 633: return (nread); 634: } 635: #endif 636: 637: #ifdef UCB_NET 638: ttselect(dev, rw) 639: dev_t dev; 640: int rw; 641: { 642: register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)]; 643: int nread; 644: int s = spl5(); 645: 646: switch (rw) { 647: 648: case FREAD: 649: nread = ttnread(tp); 650: if (nread > 0) 651: goto win; 652: if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait) 653: tp->t_state |= TS_RCOLL; 654: else 655: tp->t_rsel = u.u_procp; 656: break; 657: 658: case FWRITE: 659: if (tp->t_outq.c_cc <= TTLOWAT(tp)) 660: goto win; 661: if (tp->t_wsel && tp->t_wsel->p_wchan == (caddr_t)&selwait) 662: tp->t_state |= TS_WCOLL; 663: else 664: tp->t_wsel = u.u_procp; 665: break; 666: } 667: splx(s); 668: return (0); 669: win: 670: splx(s); 671: return (1); 672: } 673: #endif