new timeofday and interval timer stuff; itimers need testing
[unix-history] / usr / src / sys / kern / tty.c
index fd286d6..c407495 100644 (file)
@@ -1,4 +1,4 @@
-/*     tty.c   4.14    81/11/18        */
+/*     tty.c   4.28    82/08/22        */
 
 /*
  * TTY subroutines common to more than one line discipline
 
 /*
  * TTY subroutines common to more than one line discipline
 #include "../h/conf.h"
 #include "../h/buf.h"
 #include "../h/dk.h"
 #include "../h/conf.h"
 #include "../h/buf.h"
 #include "../h/dk.h"
+#include "../h/uio.h"
 
 
-char   partab[];
+/*
+ * Table giving parity for characters and indicating
+ * character classes to tty driver.  In particular,
+ * if the low 6 bits are 0, then the character needs
+ * no special processing on output.
+ */
+
+char partab[] = {
+       0001,0201,0201,0001,0201,0001,0001,0201,
+       0202,0004,0003,0201,0005,0206,0201,0001,
+       0201,0001,0001,0201,0001,0201,0201,0001,
+       0001,0201,0201,0001,0201,0001,0001,0201,
+       0200,0000,0000,0200,0000,0200,0200,0000,
+       0000,0200,0200,0000,0200,0000,0000,0200,
+       0000,0200,0200,0000,0200,0000,0000,0200,
+       0200,0000,0000,0200,0000,0200,0200,0000,
+       0200,0000,0000,0200,0000,0200,0200,0000,
+       0000,0200,0200,0000,0200,0000,0000,0200,
+       0000,0200,0200,0000,0200,0000,0000,0200,
+       0200,0000,0000,0200,0000,0200,0200,0000,
+       0000,0200,0200,0000,0200,0000,0000,0200,
+       0200,0000,0000,0200,0000,0200,0200,0000,
+       0200,0000,0000,0200,0000,0200,0200,0000,
+       0000,0200,0200,0000,0200,0000,0000,0201,
+
+       /*
+        * 7 bit ascii ends with the last character above,
+        * but we contine through all 256 codes for the sake
+        * of the tty output routines which use special vax
+        * instructions which need a 256 character trt table.
+        */
+
+       0007,0007,0007,0007,0007,0007,0007,0007,
+       0007,0007,0007,0007,0007,0007,0007,0007,
+       0007,0007,0007,0007,0007,0007,0007,0007,
+       0007,0007,0007,0007,0007,0007,0007,0007,
+       0007,0007,0007,0007,0007,0007,0007,0007,
+       0007,0007,0007,0007,0007,0007,0007,0007,
+       0007,0007,0007,0007,0007,0007,0007,0007,
+       0007,0007,0007,0007,0007,0007,0007,0007,
+       0007,0007,0007,0007,0007,0007,0007,0007,
+       0007,0007,0007,0007,0007,0007,0007,0007,
+       0007,0007,0007,0007,0007,0007,0007,0007,
+       0007,0007,0007,0007,0007,0007,0007,0007,
+       0007,0007,0007,0007,0007,0007,0007,0007,
+       0007,0007,0007,0007,0007,0007,0007,0007,
+       0007,0007,0007,0007,0007,0007,0007,0007,
+       0007,0007,0007,0007,0007,0007,0007,0007
+};
 
 /*
  * Input mapping table-- if an entry is non-zero, when the
 
 /*
  * Input mapping table-- if an entry is non-zero, when the
@@ -55,7 +104,7 @@ short        ttlowat[16] =
  * set default control characters.
  */
 ttychars(tp)
  * set default control characters.
  */
 ttychars(tp)
-register struct tty *tp;
+       register struct tty *tp;
 {
 
        tun.t_intrc = CINTR;
 {
 
        tun.t_intrc = CINTR;
@@ -82,16 +131,17 @@ register struct tty *tp;
  * Wait for output to drain, then flush input waiting.
  */
 wflushtty(tp)
  * Wait for output to drain, then flush input waiting.
  */
 wflushtty(tp)
-register struct tty *tp;
+       register struct tty *tp;
 {
 
        (void) spl5();
 {
 
        (void) spl5();
-       while (tp->t_outq.c_cc && tp->t_state&CARR_ON) {
+       while (tp->t_outq.c_cc && tp->t_state&TS_CARR_ON
+           && tp->t_oproc) {           /* kludge for pty */
                (*tp->t_oproc)(tp);
                (*tp->t_oproc)(tp);
-               tp->t_state |= ASLEEP;
+               tp->t_state |= TS_ASLEEP;
                sleep((caddr_t)&tp->t_outq, TTOPRI);
        }
                sleep((caddr_t)&tp->t_outq, TTOPRI);
        }
-       flushtty(tp, FREAD|FWRITE);
+       flushtty(tp, FREAD);
        (void) spl0();
 }
 
        (void) spl0();
 }
 
@@ -99,7 +149,7 @@ register struct tty *tp;
  * flush all TTY queues
  */
 flushtty(tp, rw)
  * flush all TTY queues
  */
 flushtty(tp, rw)
-register struct tty *tp;
+       register struct tty *tp;
 {
        register s;
 
 {
        register s;
 
@@ -111,8 +161,8 @@ register struct tty *tp;
        }
        if (rw & FWRITE) {
                wakeup((caddr_t)&tp->t_outq);
        }
        if (rw & FWRITE) {
                wakeup((caddr_t)&tp->t_outq);
-               tp->t_state &= ~TTSTOP;
-               (*cdevsw[major(tp->t_dev)].d_stop)(tp);
+               tp->t_state &= ~TS_TTSTOP;
+               (*cdevsw[major(tp->t_dev)].d_stop)(tp, rw);
                while (getc(&tp->t_outq) >= 0)
                        ;
        }
                while (getc(&tp->t_outq) >= 0)
                        ;
        }
@@ -131,17 +181,17 @@ register struct tty *tp;
  * Send stop character on input overflow.
  */
 ttyblock(tp)
  * Send stop character on input overflow.
  */
 ttyblock(tp)
-register struct tty *tp;
+       register struct tty *tp;
 {
        register x;
        x = tp->t_rawq.c_cc + tp->t_canq.c_cc;
        if (tp->t_rawq.c_cc > TTYHOG) {
                flushtty(tp, FREAD|FWRITE);
 {
        register x;
        x = tp->t_rawq.c_cc + tp->t_canq.c_cc;
        if (tp->t_rawq.c_cc > TTYHOG) {
                flushtty(tp, FREAD|FWRITE);
-               tp->t_state &= ~TBLOCK;
+               tp->t_state &= ~TS_TBLOCK;
        }
        if (x >= TTYHOG/2) {
                if (putc(tun.t_stopc, &tp->t_outq)==0) {
        }
        if (x >= TTYHOG/2) {
                if (putc(tun.t_stopc, &tp->t_outq)==0) {
-                       tp->t_state |= TBLOCK;
+                       tp->t_state |= TS_TBLOCK;
                        tp->t_char++;
                        ttstart(tp);
                }
                        tp->t_char++;
                        ttstart(tp);
                }
@@ -155,14 +205,14 @@ register struct tty *tp;
  * subroutine and it is called during a clock interrupt.
  */
 ttrstrt(tp)
  * subroutine and it is called during a clock interrupt.
  */
 ttrstrt(tp)
-register struct tty *tp;
+       register struct tty *tp;
 {
 
        if (tp == 0) {
                printf("ttrstrt: arg was 0!\n");
                return;
        }
 {
 
        if (tp == 0) {
                printf("ttrstrt: arg was 0!\n");
                return;
        }
-       tp->t_state &= ~TIMEOUT;
+       tp->t_state &= ~TS_TIMEOUT;
        ttstart(tp);
 }
 
        ttstart(tp);
 }
 
@@ -173,12 +223,13 @@ register struct tty *tp;
  * character, and after a timeout has finished.
  */
 ttstart(tp)
  * character, and after a timeout has finished.
  */
 ttstart(tp)
-register struct tty *tp;
+       register struct tty *tp;
 {
        register s;
 
        s = spl5();
 {
        register s;
 
        s = spl5();
-       if((tp->t_state&(TIMEOUT|TTSTOP|BUSY)) == 0)
+       if ((tp->t_state&(TS_TIMEOUT|TS_TTSTOP|TS_BUSY)) == 0 &&
+           tp->t_oproc)                /* kludge for pty */
                (*tp->t_oproc)(tp);
        splx(s);
 }
                (*tp->t_oproc)(tp);
        splx(s);
 }
@@ -187,23 +238,18 @@ register struct tty *tp;
  * Common code for tty ioctls.
  */
 /*ARGSUSED*/
  * Common code for tty ioctls.
  */
 /*ARGSUSED*/
-ttioctl(tp, com, addr, flag)
-register struct tty *tp;
-caddr_t addr;
+ttioctl(tp, com, data, flag)
+       register struct tty *tp;
+       caddr_t data;
 {
        int dev;
 {
        int dev;
-       unsigned t;
-       struct sgttyb iocb;
-       struct clist tq;
        extern int nldisp;
        extern int nldisp;
-       register c;
-       int temp;
 
        /*
         * This is especially so that isatty() will
         * fail when carrier is gone.
         */
 
        /*
         * This is especially so that isatty() will
         * fail when carrier is gone.
         */
-       if ((tp->t_state&CARR_ON) == 0) {
+       if ((tp->t_state&TS_CARR_ON) == 0) {
                u.u_error = EBADF;
                return (1);
        }
                u.u_error = EBADF;
                return (1);
        }
@@ -214,7 +260,7 @@ caddr_t addr;
         * insist on being able to write the device,
         * and hang if in the background.
         */
         * insist on being able to write the device,
         * and hang if in the background.
         */
-       switch(com) {
+       switch (com) {
 
        case TIOCSETD:
        case TIOCSETP:
 
        case TIOCSETD:
        case TIOCSETP:
@@ -226,7 +272,6 @@ caddr_t addr;
        case TIOCLBIS:
        case TIOCLBIC:
        case TIOCLSET:
        case TIOCLBIS:
        case TIOCLBIC:
        case TIOCLSET:
-       case TIOCSTI:
 /* this is reasonable, but impractical... 
                if ((flag & FWRITE) == 0) {
                        u.u_error = EBADF;
 /* this is reasonable, but impractical... 
                if ((flag & FWRITE) == 0) {
                        u.u_error = EBADF;
@@ -237,8 +282,12 @@ caddr_t addr;
                   u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp &&
                   (u.u_procp->p_flag&SVFORK) == 0 &&
                   u.u_signal[SIGTTOU] != SIG_IGN &&
                   u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp &&
                   (u.u_procp->p_flag&SVFORK) == 0 &&
                   u.u_signal[SIGTTOU] != SIG_IGN &&
-                  u.u_signal[SIGTTOU] != SIG_HOLD &&
+                  u.u_signal[SIGTTOU] != SIG_HOLD
+/*
+                                                  &&
                   (u.u_procp->p_flag&SDETACH)==0) {
                   (u.u_procp->p_flag&SDETACH)==0) {
+*/
+                  ) {
                        gsignal(u.u_procp->p_pgrp, SIGTTOU);
                        sleep((caddr_t)&lbolt, TTOPRI);
                }
                        gsignal(u.u_procp->p_pgrp, SIGTTOU);
                        sleep((caddr_t)&lbolt, TTOPRI);
                }
@@ -248,25 +297,21 @@ caddr_t addr;
        /*
         * Process the ioctl.
         */
        /*
         * Process the ioctl.
         */
-       switch(com) {
+       switch (com) {
 
        /*
         * Get discipline number
         */
        case TIOCGETD:
 
        /*
         * Get discipline number
         */
        case TIOCGETD:
-               t = tp->t_line;
-               if (copyout((caddr_t)&t, addr, sizeof(t)))
-                       u.u_error = EFAULT;
+               *(int *)data = tp->t_line;
                break;
 
        /*
         * Set line discipline
         */
                break;
 
        /*
         * Set line discipline
         */
-       case TIOCSETD:
-               if (copyin(addr, (caddr_t)&t, sizeof(t))) {
-                       u.u_error = EFAULT;
-                       break;
-               }
+       case TIOCSETD: {
+               register int t = *(int *)data;
+
                if (t >= nldisp) {
                        u.u_error = ENXIO;
                        break;
                if (t >= nldisp) {
                        u.u_error = ENXIO;
                        break;
@@ -275,27 +320,37 @@ caddr_t addr;
                if (tp->t_line)
                        (*linesw[tp->t_line].l_close)(tp);
                if (t)
                if (tp->t_line)
                        (*linesw[tp->t_line].l_close)(tp);
                if (t)
-                       (*linesw[t].l_open)(dev, tp, addr);
+                       (*linesw[t].l_open)(dev, tp);
                if (u.u_error==0)
                        tp->t_line = t;
                (void) spl0();
                break;
                if (u.u_error==0)
                        tp->t_line = t;
                (void) spl0();
                break;
+       }
+
+       /*
+        * Prevent more opens on channel
+        */
+       case TIOCEXCL:
+               tp->t_state |= TS_XCLUDE;
+               break;
+
+       case TIOCNXCL:
+               tp->t_state &= ~TS_XCLUDE;
+               break;
 
        /*
         * Set new parameters
         */
        case TIOCSETP:
 
        /*
         * Set new parameters
         */
        case TIOCSETP:
-       case TIOCSETN:
-               if (copyin(addr, (caddr_t)&iocb, sizeof(iocb))) {
-                       u.u_error = EFAULT;
-                       return(1);
-               }
+       case TIOCSETN: {
+               register struct sgttyb *sg = (struct sgttyb *)data;
+               struct clist tq;
+
                (void) spl5();
                (void) spl5();
-               if (tp->t_flags&RAW || iocb.sg_flags&RAW ||
-                   com == TIOCSETP)
+               if (tp->t_flags&RAW || sg->sg_flags&RAW || com == TIOCSETP)
                        wflushtty(tp);
                        wflushtty(tp);
-               else if ((tp->t_flags&CBREAK) != (iocb.sg_flags&CBREAK)) {
-                       if (iocb.sg_flags & CBREAK) {
+               else if ((tp->t_flags&CBREAK) != (sg->sg_flags&CBREAK)) {
+                       if (sg->sg_flags & CBREAK) {
                                catq(&tp->t_rawq, &tp->t_canq);
                                tq = tp->t_rawq;
                                tp->t_rawq = tp->t_canq;
                                catq(&tp->t_rawq, &tp->t_canq);
                                tq = tp->t_rawq;
                                tp->t_rawq = tp->t_canq;
@@ -305,61 +360,74 @@ caddr_t addr;
                                ttwakeup(tp);
                        }
                }
                                ttwakeup(tp);
                        }
                }
-               tp->t_ispeed = iocb.sg_ispeed;
-               tp->t_ospeed = iocb.sg_ospeed;
-               tp->t_erase = iocb.sg_erase;
-               tp->t_kill = iocb.sg_kill;
-               tp->t_flags = iocb.sg_flags;
+               tp->t_ispeed = sg->sg_ispeed;
+               tp->t_ospeed = sg->sg_ospeed;
+               tp->t_erase = sg->sg_erase;
+               tp->t_kill = sg->sg_kill;
+               tp->t_flags = sg->sg_flags;
                if (tp->t_flags & RAW) {
                if (tp->t_flags & RAW) {
-                       tp->t_state &= ~TTSTOP;
+                       tp->t_state &= ~TS_TTSTOP;
                        ttstart(tp);
                }
                (void) spl0();
                break;
                        ttstart(tp);
                }
                (void) spl0();
                break;
+       }
 
        /*
         * Send current parameters to user
         */
 
        /*
         * Send current parameters to user
         */
-       case TIOCGETP:
-               iocb.sg_ispeed = tp->t_ispeed;
-               iocb.sg_ospeed = tp->t_ospeed;
-               iocb.sg_erase = tp->t_erase;
-               iocb.sg_kill = tp->t_kill;
-               iocb.sg_flags = tp->t_flags;
-               if (copyout((caddr_t)&iocb, addr, sizeof(iocb)))
-                       u.u_error = EFAULT;
+       case TIOCGETP: {
+               register struct sgttyb *sg = (struct sgttyb *)data;
+
+               sg->sg_ispeed = tp->t_ispeed;
+               sg->sg_ospeed = tp->t_ospeed;
+               sg->sg_erase = tp->t_erase;
+               sg->sg_kill = tp->t_kill;
+               sg->sg_flags = tp->t_flags;
                break;
                break;
+       }
 
        /*
         * Hang up line on last close
         */
        case TIOCHPCL:
 
        /*
         * Hang up line on last close
         */
        case TIOCHPCL:
-               tp->t_state |= HUPCLS;
+               tp->t_state |= TS_HUPCLS;
                break;
 
        case TIOCFLUSH: {
                break;
 
        case TIOCFLUSH: {
-               int flags;
-               if (addr == 0)
+               register int flags = *(int *)data;
+
+               if (flags == 0)
                        flags = FREAD|FWRITE;
                        flags = FREAD|FWRITE;
-               else if (copyin(addr, (caddr_t)&flags, sizeof (flags))) {
-                       u.u_error = EFAULT;
-                       return(1);
-               }
+               else
+                       flags &= FREAD|FWRITE;
                flushtty(tp, flags);
                break;
        }
 
                flushtty(tp, flags);
                break;
        }
 
+       case FIONBIO:
+               if (*(int *)data)
+                       tp->t_state |= TS_NBIO;
+               else
+                       tp->t_state &= ~TS_NBIO;
+               break;
+
+       case FIOASYNC:
+               if (*(int *)data)
+                       tp->t_state |= TS_ASYNC;
+               else
+                       tp->t_state &= ~TS_ASYNC;
+               break;
+
        /*
         * Set and fetch special characters
         */
        case TIOCSETC:
        /*
         * Set and fetch special characters
         */
        case TIOCSETC:
-               if (copyin(addr, (caddr_t)&tun, sizeof(struct tchars)))
-                       u.u_error = EFAULT;
+               bcopy(data, (caddr_t)&tun, sizeof (struct tchars));
                break;
 
        case TIOCGETC:
                break;
 
        case TIOCGETC:
-               if (copyout((caddr_t)&tun, addr, sizeof(struct tchars)))
-                       u.u_error = EFAULT;
+               bcopy((caddr_t)&tun, data, sizeof (struct tchars));
                break;
 
 /* local ioctls */
                break;
 
 /* local ioctls */
@@ -367,92 +435,79 @@ caddr_t addr;
         * Set/get local special characters.
         */
        case TIOCSLTC:
         * Set/get local special characters.
         */
        case TIOCSLTC:
-               if (copyin(addr, (caddr_t)&tlun, sizeof (struct ltchars)))
-                       u.u_error = EFAULT;
+               bcopy(data, (caddr_t)&tlun, sizeof (struct ltchars));
                break;
 
        case TIOCGLTC:
                break;
 
        case TIOCGLTC:
-               if (copyout((caddr_t)&tlun, addr, sizeof (struct ltchars)))
-                       u.u_error = EFAULT;
+               bcopy((caddr_t)&tlun, data, sizeof (struct ltchars));
                break;
 
        /*
         * Return number of characters immediately available.
         */
                break;
 
        /*
         * Return number of characters immediately available.
         */
-       case FIONREAD: {
-               off_t nread = ttnread(tp);
-               if (copyout((caddr_t)&nread, addr, sizeof (off_t)))
-                       u.u_error = EFAULT;
+       case FIONREAD:
+               *(off_t *)data = ttnread(tp);
                break;
                break;
-               }
 
        /*
         * Should allow SPGRP and GPGRP only if tty open for reading.
         */
        case TIOCSPGRP:
 
        /*
         * Should allow SPGRP and GPGRP only if tty open for reading.
         */
        case TIOCSPGRP:
-               if (copyin(addr, (caddr_t)&tp->t_pgrp, sizeof (tp->t_pgrp)))
-                       u.u_error = EFAULT;
+               tp->t_pgrp = *(int *)data;
                break;
 
        case TIOCGPGRP:
                break;
 
        case TIOCGPGRP:
-               if (copyout((caddr_t)&tp->t_pgrp, addr, sizeof(tp->t_pgrp)))
-                       u.u_error = EFAULT;
+               *(int *)data = tp->t_pgrp;
                break;
 
        /*
         * Modify local mode word.
         */
        case TIOCLBIS:
                break;
 
        /*
         * Modify local mode word.
         */
        case TIOCLBIS:
-               if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local)))
-                       u.u_error = EFAULT;
-               else
-                       tp->t_local |= temp;
+               tp->t_local |= *(int *)data;
                break;
 
        case TIOCLBIC:
                break;
 
        case TIOCLBIC:
-               if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local)))
-                       u.u_error = EFAULT;
-               else
-                       tp->t_local &= ~temp;
+               tp->t_local &= ~(*(int *)data);
                break;
 
        case TIOCLSET:
                break;
 
        case TIOCLSET:
-               if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local)))
-                       u.u_error = EFAULT;
-               else
-                       tp->t_local = temp;
+               tp->t_local = *(int *)data;
                break;
 
        case TIOCLGET:
                break;
 
        case TIOCLGET:
-               if (copyout((caddr_t)&tp->t_local, addr, sizeof(tp->t_local)))
-                       u.u_error = EFAULT;
+               *(int *)data = tp->t_local;
                break;
 
                break;
 
-       /*
-        * Return number of characters in
-        * the output.
-        */
-       case TIOCOUTQ:
-               if (copyout((caddr_t)&tp->t_outq.c_cc, addr, sizeof(tp->t_outq.c_cc)))
-                       u.u_error = EFAULT;
+       case TIOCSTOP: {
+               int s = spl5();
+
+               if ((tp->t_state & TS_TTSTOP) == 0) {
+                       tp->t_state |= TS_TTSTOP;
+                       (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
+               }
+               splx(s);
                break;
                break;
+       }
 
 
-       /*
-        * Simulate typing of a character at the terminal.
-        */
-       case TIOCSTI:
-               c = fubyte(addr);
-               if (u.u_uid && u.u_ttyp != tp || c < 0)
-                       u.u_error = EFAULT;
-               else
-                       (*linesw[tp->t_line].l_rint)(c, tp);
+       case TIOCSTART: {
+               int s = spl5();
+
+               if ((tp->t_state & TS_TTSTOP) || (tp->t_local & LFLUSHO)) {
+                       tp->t_state &= ~TS_TTSTOP;
+                       tp->t_local &= ~LFLUSHO;
+                       ttstart(tp);
+               }
+               splx(s);
                break;
                break;
+       }
+
 /* end of locals */
 
        default:
 /* end of locals */
 
        default:
-               return(0);
+               return (0);
        }
        }
-       return(1);
+       return (1);
 }
 
 ttnread(tp)
 }
 
 ttnread(tp)
@@ -468,26 +523,875 @@ ttnread(tp)
        return (nread);
 }
 
        return (nread);
 }
 
-ttselect(dev, flag)
+ttselect(dev, rw)
        dev_t dev;
        dev_t dev;
-       int flag;
+       int rw;
 {
        register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)];
        int nread;
 {
        register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)];
        int nread;
+       int s = spl5();
 
 
-       switch (flag) {
+       switch (rw) {
 
        case FREAD:
                nread = ttnread(tp);
                if (nread > 0)
 
        case FREAD:
                nread = ttnread(tp);
                if (nread > 0)
-                       return (1);
+                       goto win;
                if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait)
                if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait)
-                       tp->t_state |= RCOLL;
+                       tp->t_state |= TS_RCOLL;
                else
                        tp->t_rsel = u.u_procp;
                else
                        tp->t_rsel = u.u_procp;
+               break;
+
+       case FWRITE:
+               if (tp->t_outq.c_cc <= TTLOWAT(tp))
+                       goto win;
+               if (tp->t_wsel && tp->t_wsel->p_wchan == (caddr_t)&selwait)
+                       tp->t_state |= TS_WCOLL;
+               else
+                       tp->t_wsel = u.u_procp;
+               break;
+       }
+       splx(s);
+       return (0);
+win:
+       splx(s);
+       return (1);
+}
+
+#define        OBUFSIZ 100
+
+/*
+ * routine called on opens while tp->t_line == NTTYDISC
+ * establishes a process group for distribution of
+ * quits and interrupts from the tty.
+ * (actually, pp->p_pgrp can't be 0 when this routine
+ * is called since NTTYDISC is not the default discipline)
+ */
+ttyopen(dev, tp)
+       dev_t dev;
+       register struct tty *tp;
+{
+       register struct proc *pp;
+
+       pp = u.u_procp;
+       tp->t_dev = dev;
+       if (pp->p_pgrp == 0) {
+               u.u_ttyp = tp;
+               u.u_ttyd = dev;
+               if (tp->t_pgrp == 0)
+                       tp->t_pgrp = pp->p_pid;
+               pp->p_pgrp = tp->t_pgrp;
+       }
+       tp->t_state &= ~TS_WOPEN;
+       tp->t_state |= TS_ISOPEN;
+       if (tp->t_line != NTTYDISC)
+               wflushtty(tp);
+}
+
+/*
+ * clean tp on last close
+ */
+ttyclose(tp)
+       register struct tty *tp;
+{
+
+       if (tp->t_line) {
+               wflushtty(tp);
+               tp->t_line = 0;
+               return;
+       }
+       tp->t_pgrp = 0;
+       wflushtty(tp);
+       tp->t_state = 0;
+}
+
+/*
+ * reinput pending characters after state switch
+ * call at spl5().
+ */
+ttypend(tp)
+       register struct tty *tp;
+{
+       struct clist tq;
+       register c;
+
+       tp->t_local &= ~LPENDIN;
+       tp->t_lstate |= LSTYPEN;
+       tq = tp->t_rawq;
+       tp->t_rawq.c_cc = 0;
+       tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0;
+       while ((c = getc(&tq)) >= 0)
+               ttyinput(c, tp);
+       tp->t_lstate &= ~LSTYPEN;
+}
+
+/*
+ * Place a character on raw TTY input queue, putting in delimiters
+ * and waking up top half as needed.
+ * Also echo if required.
+ * The arguments are the character and the appropriate
+ * tty structure.
+ */
+ttyinput(c, tp)
+       register c;
+       register struct tty *tp;
+{
+       register int t_flags;
+       int i;
+
+       if (tp->t_local&LPENDIN)
+               ttypend(tp);
+       tk_nin++;
+       c &= 0377;
+       t_flags = tp->t_flags;
+       if (t_flags&TANDEM)
+               ttyblock(tp);
+       if ((t_flags&RAW)==0) {
+               if ((tp->t_lstate&LSTYPEN) == 0)
+                       c &= 0177;
+       /* check for literal nexting very first */
+               if (tp->t_lstate&LSLNCH) {
+                       c |= 0200;
+                       tp->t_lstate &= ~LSLNCH;
+               }
+               if (tp->t_line == NTTYDISC && c==tlun.t_lnextc) {
+                       if (tp->t_flags&ECHO)
+                               ttyout("^\b", tp);
+                       tp->t_lstate |= LSLNCH;
+       /* check for output control functions */
+               } else if (c==tun.t_stopc) {
+                       if ((tp->t_state&TS_TTSTOP)==0) {
+                               tp->t_state |= TS_TTSTOP;
+                               (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
+                               return;
+                       }
+                       if (c!=tun.t_startc)
+                               return;
+               } else if (c==tun.t_startc) {
+                       tp->t_state &= ~TS_TTSTOP;
+                       tp->t_local &= ~LFLUSHO;
+                       ttstart(tp);
+                       return;
+               } else if (tp->t_line == NTTYDISC && c==tlun.t_flushc) {
+                       if (tp->t_local & LFLUSHO)
+                               tp->t_local &= ~LFLUSHO;
+                       else {
+                               flushtty(tp, FWRITE);
+                               ttyecho(c, tp);
+                               if (tp->t_rawq.c_cc+tp->t_canq.c_cc)
+                                       ttyretype(tp);
+                               tp->t_local |= LFLUSHO;
+                       }
+                       ttstart(tp);
+                       return;
+               } else if (c==tun.t_intrc || c==tun.t_quitc ||
+                   (tp->t_line == NTTYDISC && c==tlun.t_suspc)) {
+                       if ((tp->t_local & LNOFLSH) == 0)
+                               flushtty(tp,
+                                   c==tlun.t_suspc ? FREAD : FREAD|FWRITE);
+                       ttyecho(c, tp);
+                       c = c==tun.t_intrc ? SIGINT :
+                               ((c==tun.t_quitc) ? SIGQUIT : SIGTSTP);
+                       ttsignal(tp, c);
+       /* check for buffer editing functions - cooked mode */
+               } else if ((t_flags&CBREAK) == 0) {
+                       if ((tp->t_lstate&LSQUOT) &&
+                           (c==tp->t_erase||c==tp->t_kill)) {
+                               ttyrub(unputc(&tp->t_rawq), tp);
+                               c |= 0200;
+                       }
+                       if (c==tp->t_erase) {
+                               if (tp->t_rawq.c_cc)
+                                       ttyrub(unputc(&tp->t_rawq), tp);
+                       } else if (c==tp->t_kill) {
+                               if (tp->t_local&LCRTKIL &&
+                                   tp->t_rawq.c_cc == tp->t_rocount) {
+                                       while (tp->t_rawq.c_cc)
+                                               ttyrub(unputc(&tp->t_rawq), tp);
+                               } else {
+                                       ttyecho(c, tp);
+                                       ttyecho('\n', tp);
+                                       while (getc(&tp->t_rawq) > 0)
+                                               ;
+                                       tp->t_rocount = 0;
+                               }
+                               tp->t_lstate = 0;
+                       } else if (tp->t_line == NTTYDISC && c==tlun.t_werasc) {
+                               if (tp->t_rawq.c_cc == 0)
+                                       goto out;
+                               do {
+                                       c = unputc(&tp->t_rawq);
+                                       if (c != ' ' && c != '\t')
+                                               goto erasenb;
+                                       ttyrub(c, tp);
+                               } while (tp->t_rawq.c_cc);
+                               goto out;
+                           erasenb:
+                               do {
+                                       ttyrub(c, tp);
+                                       if (tp->t_rawq.c_cc == 0)
+                                               goto out;
+                                       c = unputc(&tp->t_rawq);
+                               } while (c != ' ' && c != '\t');
+                               (void) putc(c, &tp->t_rawq);
+                       } else if (tp->t_line == NTTYDISC && c==tlun.t_rprntc) {
+                               ttyretype(tp);
+       /* check for cooked mode input buffer overflow */
+                       } else if (tp->t_rawq.c_cc+tp->t_canq.c_cc >= TTYHOG) {
+                               ;
+       /* put data char in q for user and wakeup if a break char */
+                       } else if (putc(c, &tp->t_rawq) >= 0) {
+                               if (tp->t_rawq.c_cc+tp->t_canq.c_cc==TTYHOG
+                                   && tp->t_line == NTTYDISC)
+                                       (void) ttyoutput(CTRL(g), tp);
+                               if (!ttbreakc(c, tp)) {
+                                       if (tp->t_rocount++ == 0)
+                                               tp->t_rocol = tp->t_col;
+                               } else {
+                                       tp->t_rocount = 0;
+                                       catq(&tp->t_rawq, &tp->t_canq);
+                                       /* IF (TP->T_CHAN) (VOID) SDATA(TP->T_CHAN); */
+                                       ttwakeup(tp);
+                               }
+                               tp->t_lstate &= ~LSQUOT;
+                               if (c == '\\')
+                                       tp->t_lstate |= LSQUOT;
+                               if (tp->t_lstate&LSERASE) {
+                                       tp->t_lstate &= ~LSERASE;
+                                       (void) ttyoutput('/', tp);
+                               }
+                               i = tp->t_col;
+                               ttyecho(c, tp);
+                               if (c==tun.t_eofc && tp->t_flags&ECHO) {
+                                       i = MIN(2, tp->t_col - i);
+                                       while (i > 0) {
+                                               (void) ttyoutput('\b', tp);
+                                               i--;
+                                       }
+                               }
+                       }
+       /* CBREAK mode */
+               } else if (tp->t_rawq.c_cc > TTYHOG) {
+                       if (tp->t_outq.c_cc < TTHIWAT(tp) &&
+                           tp->t_line == NTTYDISC)
+                               (void) ttyoutput(CTRL(g), tp);
+               } else if (putc(c, &tp->t_rawq) >= 0) {
+                       ttwakeup(tp);
+                       ttyecho(c, tp);
+               }
+       /* RAW mode */
+       } else if (tp->t_rawq.c_cc > TTYHOG) 
+               flushtty(tp, FREAD|FWRITE);
+       else {
+               if (putc(c, &tp->t_rawq) >= 0)
+                       ttwakeup(tp);
+               ttyecho(c, tp);
+       }
+out:
+       if (tp->t_local & LDECCTQ && tp->t_state & TS_TTSTOP &&
+           tun.t_startc != tun.t_stopc)
+               return;
+       tp->t_state &= ~TS_TTSTOP;
+       tp->t_local &= ~LFLUSHO;
+       ttstart(tp);
+}
+
+/*
+ * put character on TTY output queue, adding delays,
+ * expanding tabs, and handling the CR/NL bit.
+ * It is called both from the top half for output, and from
+ * interrupt level for echoing.
+ * The arguments are the character and the tty structure.
+ * Returns < 0 if putc succeeds, otherwise returns char to resend
+ * Must be recursive.
+ */
+ttyoutput(c, tp)
+       register c;
+       register struct tty *tp;
+{
+       register char *colp;
+       register ctype;
+
+       if (tp->t_flags&RAW || tp->t_local&LLITOUT) {
+               if (tp->t_local&LFLUSHO)
+                       return (-1);
+               if (putc(c, &tp->t_outq))
+                       return (c);
+               tk_nout++;
+               return (-1);
+       }
+       /*
+        * Ignore EOT in normal mode to avoid hanging up
+        * certain terminals.
+        */
+       c &= 0177;
+       if (c==CEOT && (tp->t_flags&CBREAK)==0)
+               return (-1);
+       /*
+        * Turn tabs to spaces as required
+        */
+       if (c=='\t' && (tp->t_flags&TBDELAY)==XTABS) {
+               register int s;
+
+               c = 8 - (tp->t_col&7);
+               if ((tp->t_local&LFLUSHO) == 0) {
+                       s = spl5();             /* don't interrupt tabs */
+                       c -= b_to_q("        ", c, &tp->t_outq);
+                       tk_nout += c;
+                       splx(s);
+               }
+               tp->t_col += c;
+               return (c ? -1 : '\t');
+       }
+       tk_nout++;
+       /*
+        * for upper-case-only terminals,
+        * generate escapes.
+        */
+       if (tp->t_flags&LCASE) {
+               colp = "({)}!|^~'`";
+               while (*colp++)
+                       if (c == *colp++) {
+                               if (ttyoutput('\\', tp) >= 0)
+                                       return (c);
+                               c = colp[-2];
+                               break;
+                       }
+               if ('A'<=c && c<='Z') {
+                       if (ttyoutput('\\', tp) >= 0)
+                               return (c);
+               } else if ('a'<=c && c<='z')
+                       c += 'A' - 'a';
+       }
+       /*
+        * turn <nl> to <cr><lf> if desired.
+        */
+       if (c=='\n' && tp->t_flags&CRMOD)
+               if (ttyoutput('\r', tp) >= 0)
+                       return (c);
+       if (c=='~' && tp->t_local&LTILDE)
+               c = '`';
+       if ((tp->t_local&LFLUSHO) == 0 && putc(c, &tp->t_outq))
+               return (c);
+       /*
+        * Calculate delays.
+        * The numbers here represent clock ticks
+        * and are not necessarily optimal for all terminals.
+        * The delays are indicated by characters above 0200.
+        * In raw mode there are no delays and the
+        * transmission path is 8 bits wide.
+        */
+       colp = &tp->t_col;
+       ctype = partab[c];
+       c = 0;
+       switch (ctype&077) {
+
+       case ORDINARY:
+               (*colp)++;
+
+       case CONTROL:
+               break;
+
+       case BACKSPACE:
+               if (*colp)
+                       (*colp)--;
+               break;
+
+       case NEWLINE:
+               ctype = (tp->t_flags >> 8) & 03;
+               if (ctype == 1) { /* tty 37 */
+                       if (*colp)
+                               c = max(((unsigned)*colp>>4) + 3, (unsigned)6);
+               } else
+               if (ctype == 2) { /* vt05 */
+                       c = 6;
+               }
+               *colp = 0;
+               break;
+
+       case TAB:
+               ctype = (tp->t_flags >> 10) & 03;
+               if (ctype == 1) { /* tty 37 */
+                       c = 1 - (*colp | ~07);
+                       if (c < 5)
+                               c = 0;
+               }
+               *colp |= 07;
+               (*colp)++;
+               break;
+
+       case VTAB:
+               if (tp->t_flags & VTDELAY) /* tty 37 */
+                       c = 0177;
+               break;
+
+       case RETURN:
+               ctype = (tp->t_flags >> 12) & 03;
+               if (ctype == 1) { /* tn 300 */
+                       c = 5;
+               } else if (ctype == 2) { /* ti 700 */
+                       c = 10;
+               } else if (ctype == 3) { /* concept 100 */
+                       int i;
+                       if ((i = *colp) >= 0)
+                               for (; i<9; i++)
+                                       (void) putc(0177, &tp->t_outq);
+               }
+               *colp = 0;
+       }
+       if (c && (tp->t_local&LFLUSHO) == 0)
+               (void) putc(c|0200, &tp->t_outq);
+       return (-1);
+}
+
+/*
+ * Called from device's read routine after it has
+ * calculated the tty-structure given as argument.
+ */
+ttread(tp, uio)
+       register struct tty *tp;
+       struct uio *uio;
+{
+       register struct clist *qp;
+       register c, first;
+
+       if ((tp->t_state&TS_CARR_ON)==0)
                return (0);
                return (0);
+loop:
+       (void) spl5();
+       if (tp->t_local&LPENDIN)
+               ttypend(tp);
+       (void) spl0();
+       while (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) {
+               if (u.u_signal[SIGTTIN] == SIG_IGN ||
+                   u.u_signal[SIGTTIN] == SIG_HOLD ||
+/*
+                   (u.u_procp->p_flag&SDETACH) ||
+*/
+                   u.u_procp->p_flag&SVFORK)
+                       return (0);
+               gsignal(u.u_procp->p_pgrp, SIGTTIN);
+               sleep((caddr_t)&lbolt, TTIPRI);
+       }
+       if (tp->t_flags&RAW) {
+               (void) spl5();
+               if (tp->t_rawq.c_cc <= 0) {
+                       if ((tp->t_state&TS_CARR_ON)==0 ||
+                           (tp->t_state&TS_NBIO)) {
+                               (void) spl0();
+                               return (0);
+                       }
+                       sleep((caddr_t)&tp->t_rawq, TTIPRI);
+                       (void) spl0();
+                       goto loop;
+               }
+               (void) spl0();
+               while (tp->t_rawq.c_cc && uio->uio_iovcnt) {
+                       u.u_error = passuc(getc(&tp->t_rawq), uio);
+                       if (u.u_error)
+                               break;
+               }
+               return (0);
+       } else {
+               qp = tp->t_flags & CBREAK ? &tp->t_rawq : &tp->t_canq;
+               (void) spl5();
+               if (qp->c_cc <= 0) {
+                       if ((tp->t_state&TS_CARR_ON)==0 ||
+                           (tp->t_state&TS_NBIO)) {
+                               (void) spl0();
+                               return (0);
+                       }
+                       sleep((caddr_t)&tp->t_rawq, TTIPRI);
+                       (void) spl0();
+                       goto loop;
+               }
+               (void) spl0();
+               first = 1;
+               while ((c = getc(qp)) >= 0) {
+                       if (tp->t_flags&CRMOD && c == '\r')
+                               c = '\n';
+                       if (tp->t_flags&LCASE && c <= 0177)
+                               if (tp->t_lstate&LSBKSL) {
+                                       if (maptab[c])
+                                               c = maptab[c];
+                                       tp->t_lstate &= ~LSBKSL;
+                               } else if (c >= 'A' && c <= 'Z')
+                                       c += 'a' - 'A';
+                               else if (c == '\\') {
+                                       tp->t_lstate |= LSBKSL;
+                                       continue;
+                               }
+                       if (tp->t_line == NTTYDISC && c == tlun.t_dsuspc) {
+                               ttsignal(tp, SIGTSTP);
+                               if (first) {
+                                       sleep((caddr_t)&lbolt, TTIPRI);
+                                       goto loop;
+                               }
+                               break;
+                       }
+                       if (c == tun.t_eofc && (tp->t_flags&CBREAK)==0)
+                               break;
+                       u.u_error = passuc(c & 0177, uio);
+                       if (u.u_error)
+                               break;
+                       if (uio->uio_iovcnt == 0)
+                               break;
+                       if ((tp->t_flags&CBREAK)==0 && ttbreakc(c, tp))
+                               break;
+                       first = 0;
+               }
+               tp->t_lstate &= ~LSBKSL;
+       }
 
 
-       default:
-               return (1);
+       if (tp->t_state&TS_TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) {
+               if (putc(tun.t_startc, &tp->t_outq)==0) {
+                       tp->t_state &= ~TS_TBLOCK;
+                       ttstart(tp);
+               }
+               tp->t_char = 0;
+       }
+
+       return (tp->t_rawq.c_cc + tp->t_canq.c_cc);
+}
+
+/*
+ * Called from the device's write routine after it has
+ * calculated the tty-structure given as argument.
+ */
+caddr_t
+ttwrite(tp, uio)
+       register struct tty *tp;
+       struct uio *uio;
+{
+#ifdef vax
+       /*
+        * THE POSITIONING OF CP, CC, AND CE ARE CRITICAL
+        * AND MUST NOT BE CHANGED WITHOUT PATCHING
+        * THE 'ASM' INLINES BELOW.  WATCH OUT.
+        */
+#endif
+       register char *cp;
+       register int cc, ce;
+       register i;
+       char obuf[OBUFSIZ];
+       register c;
+       int hiwat = TTHIWAT(tp);
+       int cnt = uio->uio_resid;
+
+       if ((tp->t_state&TS_CARR_ON)==0)
+               return (NULL);
+loop:
+       while (u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp &&
+           (tp->t_local&LTOSTOP) && (u.u_procp->p_flag&SVFORK)==0 &&
+           u.u_signal[SIGTTOU] != SIG_IGN &&
+           u.u_signal[SIGTTOU] != SIG_HOLD
+/*
+                                            &&
+           (u.u_procp->p_flag&SDETACH)==0) {
+*/
+           ) {
+               gsignal(u.u_procp->p_pgrp, SIGTTOU);
+               sleep((caddr_t)&lbolt, TTIPRI);
+       }
+       while (uio->uio_resid > 0) {
+               cc = uio->uio_iov->iov_len;
+               if (cc == 0) {
+                       uio->uio_iovcnt--;
+                       uio->uio_iov++;
+                       if (uio->uio_iovcnt < 0)
+                               panic("ttwrite");
+                       continue;
+               }
+               if (cc > OBUFSIZ)
+                       cc = OBUFSIZ;
+               cp = obuf;
+               u.u_error = uiomove(cp, cc, UIO_WRITE, uio);
+               if (u.u_error)
+                       break;
+               if (tp->t_outq.c_cc > hiwat)
+                       goto ovhiwat;
+               if (tp->t_local&LFLUSHO)
+                       continue;
+               if (tp->t_flags&LCASE || tp->t_local&LTILDE) {
+                       while (cc) {
+                               c = *cp++;
+                               tp->t_rocount = 0;
+                               while ((c = ttyoutput(c, tp)) >= 0) {
+                                       /* out of clists, wait a bit */
+                                       ttstart(tp);
+                                       sleep((caddr_t)&lbolt, TTOPRI);
+                                       tp->t_rocount = 0;
+                               }
+                               --cc;
+                               if (tp->t_outq.c_cc > hiwat)
+                                       goto ovhiwat;
+                       }
+                       continue;
+               }
+               while (cc) {
+                       if (tp->t_flags&RAW || tp->t_local&LLITOUT)
+                               ce = cc;
+                       else {
+#ifdef vax
+                               asm("   scanc   r9,(r10),_partab,$077");
+                               asm("   subl3   r0,r9,r8");
+#else
+                               ce=0;
+                               while (((partab[*(unsigned char *)(cp+ce)]&077)==0)&&(ce<cc))
+                                       ce++;
+#endif
+                               if (ce==0) {
+                                       tp->t_rocount = 0;
+                                       if (ttyoutput(*cp, tp) >= 0) {
+                                               ttstart(tp);
+                                               sleep((caddr_t)&lbolt, TTOPRI);
+                                               continue;
+                                       }
+                                       cp++;
+                                       cc--;
+                                       if (tp->t_outq.c_cc > hiwat)
+                                               goto ovhiwat;
+                               }
+                       }
+                       tp->t_rocount = 0;
+                       i=b_to_q(cp,ce,&tp->t_outq);
+                       ce-=i;
+                       tk_nout+=ce;
+                       tp->t_col+=ce;
+                       cp+=ce;
+                       cc-=ce;
+                       if (i) {
+                               ttstart(tp);
+                               sleep((caddr_t)&lbolt, TTOPRI);
+                       }
+                       if (ce || tp->t_outq.c_cc > hiwat)
+                               goto ovhiwat;
+               }
+       }
+       ttstart(tp);
+       return (NULL);
+
+ovhiwat:
+       (void) spl5();
+       uio->uio_iov->iov_base -= cc;
+       uio->uio_iov->iov_len += cc;
+       uio->uio_resid += cc;
+       uio->uio_offset -= cc;
+       if (tp->t_outq.c_cc <= hiwat) {
+               (void) spl0();
+               goto loop;
+       }
+       ttstart(tp);
+       if (tp->t_state & TS_NBIO) {
+               if (uio->uio_resid == cnt)
+                       u.u_error = EWOULDBLOCK;
+               return (NULL);
+       }
+       tp->t_state |= TS_ASLEEP;
+       sleep((caddr_t)&tp->t_outq, TTOPRI);
+       (void) spl0();
+       goto loop;
+}
+
+/*
+ * Rubout one character from the rawq of tp
+ * as cleanly as possible.
+ */
+ttyrub(c, tp)
+       register c;
+       register struct tty *tp;
+{
+       register char *cp;
+       register int savecol;
+       int s;
+       char *nextc();
+
+       if ((tp->t_flags&ECHO)==0)
+               return;
+       tp->t_local &= ~LFLUSHO;
+       c &= 0377;
+       if (tp->t_local&LCRTBS) {
+               if (tp->t_rocount == 0) {
+                       /*
+                        * Screwed by ttwrite; retype
+                        */
+                       ttyretype(tp);
+                       return;
+               }
+               if (c==('\t'|0200) || c==('\n'|0200))
+                       ttyrubo(tp, 2);
+               else switch (partab[c&=0177] & 0177) {
+
+               case ORDINARY:
+                       if (tp->t_flags&LCASE && c >= 'A' && c <= 'Z')
+                               ttyrubo(tp, 2);
+                       else
+                               ttyrubo(tp, 1);
+                       break;
+
+               case VTAB:
+               case BACKSPACE:
+               case CONTROL:
+               case RETURN:
+                       if (tp->t_local & LCTLECH)
+                               ttyrubo(tp, 2);
+                       break;
+
+               case TAB:
+                       if (tp->t_rocount < tp->t_rawq.c_cc) {
+                               ttyretype(tp);
+                               return;
+                       }
+                       s = spl5();
+                       savecol = tp->t_col;
+                       tp->t_lstate |= LSCNTTB;
+                       tp->t_local |= LFLUSHO;
+                       tp->t_col = tp->t_rocol;
+                       for (cp = tp->t_rawq.c_cf; cp; cp = nextc(&tp->t_rawq, cp))
+                               ttyecho(*cp, tp);
+                       tp->t_local &= ~LFLUSHO;
+                       tp->t_lstate &= ~LSCNTTB;
+                       splx(s);
+                       /*
+                        * savecol will now be length of the tab
+                        */
+                       savecol -= tp->t_col;
+                       tp->t_col += savecol;
+                       if (savecol > 8)
+                               savecol = 8;            /* overflow screw */
+                       while (--savecol >= 0)
+                               (void) ttyoutput('\b', tp);
+                       break;
+
+               default:
+                       panic("ttyrub");
+               }
+       } else if (tp->t_local&LPRTERA) {
+               if ((tp->t_lstate&LSERASE) == 0) {
+                       (void) ttyoutput('\\', tp);
+                       tp->t_lstate |= LSERASE;
+               }
+               ttyecho(c, tp);
+       } else
+               ttyecho(tp->t_erase, tp);
+       tp->t_rocount--;
+}
+
+/*
+ * Crt back over cnt chars perhaps
+ * erasing them.
+ */
+ttyrubo(tp, cnt)
+       register struct tty *tp;
+       int cnt;
+{
+
+       while (--cnt >= 0)
+               ttyout(tp->t_local&LCRTERA ? "\b \b" : "\b", tp);
+}
+
+/*
+ * Reprint the rawq line.
+ * We assume c_cc has already been checked.
+ */
+ttyretype(tp)
+       register struct tty *tp;
+{
+       register char *cp;
+       char *nextc();
+       int s;
+
+       if (tlun.t_rprntc != 0377)
+               ttyecho(tlun.t_rprntc, tp);
+       (void) ttyoutput('\n', tp);
+       s = spl5();
+       for (cp = tp->t_canq.c_cf; cp; cp = nextc(&tp->t_canq, cp))
+               ttyecho(*cp, tp);
+       for (cp = tp->t_rawq.c_cf; cp; cp = nextc(&tp->t_rawq, cp))
+               ttyecho(*cp, tp);
+       tp->t_lstate &= ~LSERASE;
+       splx(s);
+       tp->t_rocount = tp->t_rawq.c_cc;
+       tp->t_rocol = 0;
+}
+
+/*
+ * Echo a typed character to the terminal
+ */
+ttyecho(c, tp)
+       register c;
+       register struct tty *tp;
+{
+
+       if ((tp->t_lstate & LSCNTTB) == 0)
+               tp->t_local &= ~LFLUSHO;
+       if ((tp->t_flags&ECHO) == 0)
+               return;
+       c &= 0377;
+       if (tp->t_flags&RAW) {
+               (void) ttyoutput(c, tp);
+               return;
+       }
+       if (c == '\r' && tp->t_flags&CRMOD)
+               c = '\n';
+       if (tp->t_local&LCTLECH) {
+               if ((c&0177) <= 037 && c!='\t' && c!='\n' || (c&0177)==0177) {
+                       (void) ttyoutput('^', tp);
+                       c &= 0177;
+                       if (c == 0177)
+                               c = '?';
+                       else if (tp->t_flags&LCASE)
+                               c += 'a' - 1;
+                       else
+                               c += 'A' - 1;
+               }
+       }
+       if ((tp->t_flags&LCASE) && (c >= 'A' && c <= 'Z'))
+               c += 'a' - 'A';
+       (void) ttyoutput(c & 0177, tp);
+}
+
+/*
+ * Is c a break char for tp?
+ */
+ttbreakc(c, tp)
+       register c;
+       register struct tty *tp;
+{
+       return (c == '\n' || c == tun.t_eofc || c == tun.t_brkc ||
+               c == '\r' && (tp->t_flags&CRMOD));
+}
+
+/*
+ * send string cp to tp
+ */
+ttyout(cp, tp)
+       register char *cp;
+       register struct tty *tp;
+{
+       register char c;
+
+       while (c = *cp++)
+               (void) ttyoutput(c, tp);
+}
+
+ttwakeup(tp)
+       struct tty *tp;
+{
+
+       if (tp->t_rsel) {
+               selwakeup(tp->t_rsel, tp->t_state&TS_RCOLL);
+               tp->t_state &= ~TS_RCOLL;
+               tp->t_rsel = 0;
        }
        }
+       wakeup((caddr_t)&tp->t_rawq);
+}
+
+ttsignal(tp, signo)
+       struct tty *tp;
+       int signo;
+{
+
+       gsignal(tp->t_pgrp, signo);
 }
 }