UPAGES 8; dumpstack 96; msgbufmap; kernacc rounding bug fixed
[unix-history] / usr / src / sys / kern / tty.c
index 36e3217..2d61be7 100644 (file)
@@ -1,7 +1,7 @@
-/*     tty.c   3.16    %G%     */
+/*     tty.c   4.3     %G%     */
 
 /*
 
 /*
- * general TTY subroutines
+ * TTY subroutines common to more than one line discipline
  */
 #include "../h/param.h"
 #include "../h/systm.h"
  */
 #include "../h/param.h"
 #include "../h/systm.h"
@@ -57,42 +57,13 @@ char        maptab[] ={
        'X','Y','Z',000,000,000,000,000,
 };
 
        'X','Y','Z',000,000,000,000,000,
 };
 
-
-/*
- * shorthand
- */
-#define        q1      tp->t_rawq
-#define        q2      tp->t_canq
-#define        q3      tp->t_outq
-#define        q4      tp->t_un.t_ctlq
+short  tthiwat[16] =
+   { 100,100,100,100,100,100,100,200,200,400,400,400,650,650,650,650 };
+short  ttlowat[16] =
+   {  30, 30, 30, 30, 30, 30, 30, 50, 50,120,120,120,125,125,125,125 };
 
 #define        OBUFSIZ 100
 
 
 #define        OBUFSIZ 100
 
-/*
- * routine called on first teletype open.
- * establishes a process group for distribution
- * of quits and interrupts from the tty.
- */
-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 &= ~WOPEN;
-       tp->t_state |= ISOPEN;
-       tp->t_line = 0;         /* conservative */
-}
-
 /*
  * set default control characters.
  */
 /*
  * set default control characters.
  */
@@ -115,115 +86,123 @@ register struct tty *tp;
        tlun.t_flushc = CTRL(o);
        tlun.t_werasc = CTRL(w);
        tlun.t_lnextc = CTRL(v);
        tlun.t_flushc = CTRL(o);
        tlun.t_werasc = CTRL(w);
        tlun.t_lnextc = CTRL(v);
-       tlun.t_lintr = CTRL(c);
-       tlun.t_lerase = CTRL(h);
-       tlun.t_lkill = CTRL(u);
        tp->t_local = 0;
        tp->t_lstate = 0;
 /* end local */
 }
 
 /*
        tp->t_local = 0;
        tp->t_lstate = 0;
 /* end local */
 }
 
 /*
- * clean tp on last close
+ * Wait for output to drain, then flush input waiting.
  */
  */
-ttyclose(tp)
+wflushtty(tp)
 register struct tty *tp;
 {
 
 register struct tty *tp;
 {
 
-       tp->t_pgrp = 0;
-       wflushtty(tp);
-       tp->t_state = 0;
-       tp->t_line = 0;
+       (void) spl5();
+       while (tp->t_outq.c_cc && tp->t_state&CARR_ON) {
+               (*tp->t_oproc)(tp);
+               tp->t_state |= ASLEEP;
+               sleep((caddr_t)&tp->t_outq, TTOPRI);
+       }
+       flushtty(tp, FREAD|FWRITE);
+       (void) spl0();
 }
 
 /*
 }
 
 /*
- * stty/gtty writearound
+ * flush all TTY queues
  */
  */
-stty()
+flushtty(tp, rw)
+register struct tty *tp;
 {
 {
-       u.u_arg[2] = u.u_arg[1];
-       u.u_arg[1] = TIOCSETP;
-       ioctl();
+       register s;
+
+       if (tp->t_line == NETLDISC)
+               return;
+       s = spl6();
+       if (rw & FREAD) {
+               while (getc(&tp->t_canq) >= 0)
+                       ;
+               wakeup((caddr_t)&tp->t_rawq);
+       }
+       if (rw & FWRITE) {
+               wakeup((caddr_t)&tp->t_outq);
+               tp->t_state &= ~TTSTOP;
+               (*cdevsw[major(tp->t_dev)].d_stop)(tp);
+               while (getc(&tp->t_outq) >= 0)
+                       ;
+       }
+       if (rw & FREAD) {
+               while (getc(&tp->t_rawq) >= 0)
+                       ;
+               tp->t_delct = 0;
+               tp->t_rocount = 0;              /* local */
+               tp->t_rocol = 0;
+               tp->t_lstate = 0;
+       }
+       splx(s);
 }
 
 }
 
-gtty()
+/*
+ * Send stop character on input overflow.
+ */
+ttyblock(tp)
+register struct tty *tp;
 {
 {
-       u.u_arg[2] = u.u_arg[1];
-       u.u_arg[1] = TIOCGETP;
-       ioctl();
+       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;
+       }
+       if (x >= TTYHOG/2) {
+               if (putc(tun.t_stopc, &tp->t_outq)==0) {
+                       tp->t_state |= TBLOCK;
+                       tp->t_char++;
+                       ttstart(tp);
+               }
+       }
 }
 
 /*
 }
 
 /*
- * Do nothing specific version of line
- * discipline specific ioctl command.
+ * Restart typewriter output following a delay
+ * timeout.
+ * The name of the routine is passed to the timeout
+ * subroutine and it is called during a clock interrupt.
  */
  */
-/*ARGSUSED*/
-nullioctl(tp, cmd, addr)
+ttrstrt(tp)
 register struct tty *tp;
 register struct tty *tp;
-caddr_t addr;
 {
 
 {
 
-       return (cmd);
+       tp->t_state &= ~TIMEOUT;
+       ttstart(tp);
 }
 
 /*
 }
 
 /*
- * ioctl system call
- * Check legality, execute common code, and switch out to individual
- * device routine.
+ * Start output on the typewriter. It is used from the top half
+ * after some characters have been put on the output queue,
+ * from the interrupt routine to transmit the next
+ * character, and after a timeout has finished.
  */
  */
-ioctl()
+ttstart(tp)
+register struct tty *tp;
 {
 {
-       register struct file *fp;
-       register struct inode *ip;
-       register struct a {
-               int     fdes;
-               int     cmd;
-               caddr_t cmarg;
-       } *uap;
-       register dev_t dev;
-       register fmt;
-
-       uap = (struct a *)u.u_ap;
-       if ((fp = getf(uap->fdes)) == NULL)
-               return;
-       if ((fp->f_flag & (FREAD|FWRITE)) == 0) {
-               u.u_error = EBADF;
-               return;
-       }
-       if (uap->cmd==FIOCLEX) {
-               u.u_pofile[uap->fdes] |= EXCLOSE;
-               return;
-       }
-       if (uap->cmd==FIONCLEX) {
-               u.u_pofile[uap->fdes] &= ~EXCLOSE;
-               return;
-       }
-       ip = fp->f_inode;
-       fmt = ip->i_mode & IFMT;
-       if (fmt != IFCHR && fmt != IFMPC) {
-/* begin local */
-               if (uap->cmd==FIONREAD && (fmt == IFREG || fmt == IFDIR)) {
-                       off_t nread = ip->i_size - fp->f_un.f_offset;
+       register s;
 
 
-                       if (copyout((caddr_t)&nread, uap->cmarg, sizeof(off_t)))
-                               u.u_error = EFAULT;
-               } else
-/* end local */
-                       u.u_error = ENOTTY;
-               return;
-       }
-       dev = ip->i_un.i_rdev;
-       u.u_r.r_val1 = 0;
-       (*cdevsw[major(dev)].d_ioctl)(dev, uap->cmd, uap->cmarg, fp->f_flag);
+       s = spl5();
+       if((tp->t_state&(TIMEOUT|TTSTOP|BUSY)) == 0)
+               (*tp->t_oproc)(tp);
+       splx(s);
 }
 
 /*
 }
 
 /*
- * Common code for several tty ioctl commands
+ * Common code for tty ioctls.
  */
  */
-ttioccomm(com, tp, addr, dev)
+/*ARGSUSED*/
+ttioctl(tp, com, addr, flag)
 register struct tty *tp;
 caddr_t addr;
 {
 register struct tty *tp;
 caddr_t addr;
 {
+       int dev;
        unsigned t;
        struct sgttyb iocb;
        struct clist tq;
        unsigned t;
        struct sgttyb iocb;
        struct clist tq;
@@ -231,10 +210,59 @@ caddr_t addr;
        register c;
        int temp;
 
        register c;
        int temp;
 
+       /*
+        * This is especially so that isatty() will
+        * fail when carrier is gone.
+        */
+       if ((tp->t_state&CARR_ON) == 0) {
+               u.u_error = EBADF;
+               return (1);
+       }
+
+       dev = tp->t_dev;
+       /*
+        * If the ioctl involves modification,
+        * insist on being able to write the device,
+        * and hang if in the background.
+        */
+       switch(com) {
+
+       case TIOCSETD:
+       case TIOCSETP:
+       case TIOCSETN:
+       case TIOCFLUSH:
+       case TIOCSETC:
+       case TIOCSLTC:
+       case TIOCSPGRP:
+       case TIOCLBIS:
+       case TIOCLBIC:
+       case TIOCLSET:
+       case TIOCSTI:
+/* this is reasonable, but impractical... 
+               if ((flag & FWRITE) == 0) {
+                       u.u_error = EBADF;
+                       return (1);
+               }
+ */
+               while (tp->t_line == NTTYDISC &&
+                  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_procp->p_flag&SDETACH)==0) {
+                       gsignal(u.u_procp->p_pgrp, SIGTTOU);
+                       sleep((caddr_t)&lbolt, TTOPRI);
+               }
+               break;
+       }
+
+       /*
+        * Process the ioctl.
+        */
        switch(com) {
 
        /*
        switch(com) {
 
        /*
-        * get discipline number
+        * Get discipline number
         */
        case TIOCGETD:
                t = tp->t_line;
         */
        case TIOCGETD:
                t = tp->t_line;
@@ -243,7 +271,7 @@ caddr_t addr;
                break;
 
        /*
                break;
 
        /*
-        * set line discipline
+        * Set line discipline
         */
        case TIOCSETD:
                if (copyin(addr, (caddr_t)&t, sizeof(t))) {
         */
        case TIOCSETD:
                if (copyin(addr, (caddr_t)&t, sizeof(t))) {
@@ -265,7 +293,7 @@ caddr_t addr;
                break;
 
        /*
                break;
 
        /*
-        * prevent more opens on channel
+        * Prevent more opens on channel
         */
        case TIOCEXCL:
                tp->t_state |= XCLUDE;
         */
        case TIOCEXCL:
                tp->t_state |= XCLUDE;
@@ -290,6 +318,9 @@ caddr_t addr;
                                wflushtty(tp);
                        while (canon(tp)>=0) 
                                ;
                                wflushtty(tp);
                        while (canon(tp)>=0) 
                                ;
+#ifdef notdef
+                       wakeup((caddr_t)&tp->t_rawq);
+#endif
                } else if (tp->t_line == NTTYDISC) {
                        if (tp->t_flags&RAW || iocb.sg_flags&RAW ||
                            com == TIOCSETP)
                } else if (tp->t_line == NTTYDISC) {
                        if (tp->t_flags&RAW || iocb.sg_flags&RAW ||
                            com == TIOCSETP)
@@ -304,9 +335,11 @@ caddr_t addr;
                                        tp->t_local |= LPENDIN;
                                        if (tp->t_canq.c_cc)
                                                panic("ioccom canq");
                                        tp->t_local |= LPENDIN;
                                        if (tp->t_canq.c_cc)
                                                panic("ioccom canq");
+#ifdef notdef
                                        if (tp->t_chan)
                                                (void) sdata(tp->t_chan);
                                        else
                                        if (tp->t_chan)
                                                (void) sdata(tp->t_chan);
                                        else
+#endif
                                                wakeup((caddr_t)&tp->t_rawq);
                                }
                        }
                                                wakeup((caddr_t)&tp->t_rawq);
                                }
                        }
@@ -322,7 +355,7 @@ caddr_t addr;
                break;
 
        /*
                break;
 
        /*
-        * send current parameters to user
+        * Send current parameters to user
         */
        case TIOCGETP:
                iocb.sg_ispeed = tp->t_ispeed;
         */
        case TIOCGETP:
                iocb.sg_ispeed = tp->t_ispeed;
@@ -337,7 +370,6 @@ caddr_t addr;
        /*
         * Hang up line on last close
         */
        /*
         * Hang up line on last close
         */
-
        case TIOCHPCL:
                tp->t_state |= HUPCLS;
                break;
        case TIOCHPCL:
                tp->t_state |= HUPCLS;
                break;
@@ -347,16 +379,7 @@ caddr_t addr;
                break;
 
        /*
                break;
 
        /*
-        * ioctl entries to line discipline
-        */
-       case DIOCSETP:
-       case DIOCGETP:
-               if ((*linesw[tp->t_line].l_ioctl)(com, tp, addr))
-                       u.u_error = ENOTTY;
-               break;
-
-       /*
-        * set and fetch special characters
+        * Set and fetch special characters
         */
        case TIOCSETC:
                if (copyin(addr, (caddr_t)&tun, sizeof(struct tchars)))
         */
        case TIOCSETC:
                if (copyin(addr, (caddr_t)&tun, sizeof(struct tchars)))
@@ -369,6 +392,9 @@ caddr_t addr;
                break;
 
 /* local ioctls */
                break;
 
 /* local ioctls */
+       /*
+        * Set/get local special characters.
+        */
        case TIOCSLTC:
                if (copyin(addr, (caddr_t)&tlun, sizeof (struct ltchars)))
                        u.u_error = EFAULT;
        case TIOCSLTC:
                if (copyin(addr, (caddr_t)&tlun, sizeof (struct ltchars)))
                        u.u_error = EFAULT;
@@ -379,6 +405,9 @@ caddr_t addr;
                        u.u_error = EFAULT;
                break;
 
                        u.u_error = EFAULT;
                break;
 
+       /*
+        * Return number of characters immediately available.
+        */
        case FIONREAD: {
                off_t nread;
 
        case FIONREAD: {
                off_t nread;
 
@@ -449,11 +478,18 @@ caddr_t addr;
                        u.u_error = EFAULT;
                break;
 
                        u.u_error = EFAULT;
                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;
                break;
 
        case TIOCOUTQ:
                if (copyout((caddr_t)&tp->t_outq.c_cc, addr, sizeof(tp->t_outq.c_cc)))
                        u.u_error = EFAULT;
                break;
 
+       /*
+        * Simulate typing of a character at the terminal.
+        */
        case TIOCSTI:
                c = fubyte(addr);
                if (u.u_uid && u.u_ttyp != tp || c < 0)
        case TIOCSTI:
                c = fubyte(addr);
                if (u.u_uid && u.u_ttyp != tp || c < 0)
@@ -468,526 +504,3 @@ caddr_t addr;
        }
        return(1);
 }
        }
        return(1);
 }
-
-/*
- * Wait for output to drain, then flush input waiting.
- */
-wflushtty(tp)
-register struct tty *tp;
-{
-
-       (void) spl5();
-       while (tp->t_outq.c_cc && tp->t_state&CARR_ON) {
-               (*tp->t_oproc)(tp);
-               tp->t_state |= ASLEEP;
-               sleep((caddr_t)&tp->t_outq, TTOPRI);
-       }
-       flushtty(tp, FREAD|FWRITE);
-       (void) spl0();
-}
-
-/*
- * flush all TTY queues
- */
-flushtty(tp, rw)
-register struct tty *tp;
-{
-       register s;
-
-       if (tp->t_line == NETLDISC)
-               return;
-       s = spl6();
-       if (rw & FREAD) {
-               while (getc(&tp->t_canq) >= 0)
-                       ;
-               wakeup((caddr_t)&tp->t_rawq);
-       }
-       if (rw & FWRITE) {
-               wakeup((caddr_t)&tp->t_outq);
-               tp->t_state &= ~TTSTOP;
-               (*cdevsw[major(tp->t_dev)].d_stop)(tp);
-               while (getc(&tp->t_outq) >= 0)
-                       ;
-       }
-       if (rw & FREAD) {
-               while (getc(&tp->t_rawq) >= 0)
-                       ;
-               tp->t_delct = 0;
-               tp->t_rocount = 0;              /* local */
-               tp->t_rocol = 0;
-               tp->t_lstate = 0;
-       }
-       splx(s);
-}
-
-
-
-/*
- * transfer raw input list to canonical list,
- * doing erase-kill processing and handling escapes.
- * It waits until a full line has been typed in cooked mode,
- * or until any character has been typed in raw mode.
- */
-canon(tp)
-register struct tty *tp;
-{
-       register char *bp;
-       char *bp1;
-       register int c;
-       int mc;
-       int s;
-
-       if ((tp->t_flags&(RAW|CBREAK))==0 && tp->t_delct==0
-           || (tp->t_flags&(RAW|CBREAK))!=0 && tp->t_rawq.c_cc==0) {
-               return(-1);
-       }
-       s = spl0();
-loop:
-       bp = &canonb[2];
-       while ((c=getc(&tp->t_rawq)) >= 0) {
-               if ((tp->t_flags&(RAW|CBREAK))==0) {
-                       if (c==0377) {
-                               tp->t_delct--;
-                               break;
-                       }
-                       if (bp[-1]!='\\') {
-                               if (c==tp->t_erase) {
-                                       if (bp > &canonb[2])
-                                               bp--;
-                                       continue;
-                               }
-                               if (c==tp->t_kill)
-                                       goto loop;
-                               if (c==tun.t_eofc)
-                                       continue;
-                       } else {
-                               mc = maptab[c];
-                               if (c==tp->t_erase || c==tp->t_kill)
-                                       mc = c;
-                               if (mc && (mc==c || (tp->t_flags&LCASE))) {
-                                       if (bp[-2] != '\\')
-                                               c = mc;
-                                       bp--;
-                               }
-                       }
-               }
-               *bp++ = c;
-               if (bp>=canonb+CANBSIZ)
-                       break;
-       }
-       bp1 = &canonb[2];
-       (void) b_to_q(bp1, bp-bp1, &tp->t_canq);
-
-       if (tp->t_state&TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) {
-               if (putc(tun.t_startc, &tp->t_outq)==0) {
-                       tp->t_state &= ~TBLOCK;
-                       ttstart(tp);
-               }
-               tp->t_char = 0;
-       }
-
-       splx(s);
-       return(0);
-}
-
-
-/*
- * block transfer input handler.
- */
-ttyrend(tp, pb, pe)
-register struct tty *tp;
-register char *pb, *pe;
-{
-       int     tandem;
-
-       tandem = tp->t_flags&TANDEM;
-       if (tp->t_flags&RAW) {
-               (void) b_to_q(pb, pe-pb, &tp->t_rawq);
-               if (tp->t_chan)
-                       (void) sdata(tp->t_chan); else
-                       wakeup((caddr_t)&tp->t_rawq);
-       } else {
-               tp->t_flags &= ~TANDEM;
-               while (pb < pe)
-                       ttyinput(*pb++, tp);
-               tp->t_flags |= tandem;
-       }
-       if (tandem)
-               ttyblock(tp);
-}
-
-/*
- * 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;
-       register struct chan *cp;
-
-       tk_nin += 1;
-       c &= 0377;
-       t_flags = tp->t_flags;
-       if (t_flags&TANDEM)
-               ttyblock(tp);
-       if ((t_flags&RAW)==0) {
-               c &= 0177;
-               if (tp->t_state&TTSTOP) {
-                       if (c==tun.t_startc) {
-                               tp->t_state &= ~TTSTOP;
-                               ttstart(tp);
-                               return;
-                       }
-                       if (c==tun.t_stopc)
-                               return;
-                       tp->t_state &= ~TTSTOP;
-                       ttstart(tp);
-               } else {
-                       if (c==tun.t_stopc) {
-                               tp->t_state |= TTSTOP;
-                               (*cdevsw[major(tp->t_dev)].d_stop)(tp);
-                               return;
-                       }
-                       if (c==tun.t_startc)
-                               return;
-               }
-               if (c==tun.t_quitc || c==tun.t_intrc) {
-                       flushtty(tp, FREAD|FWRITE);
-                       c = (c==tun.t_intrc) ? SIGINT:SIGQUIT;
-                       if (tp->t_chan)
-                               scontrol(tp->t_chan, M_SIG, c);
-                       else
-                               gsignal(tp->t_pgrp, c);
-                       return;
-               }
-               if (c=='\r' && t_flags&CRMOD)
-                       c = '\n';
-       }
-       if (tp->t_rawq.c_cc>TTYHOG) {
-               flushtty(tp, FREAD|FWRITE);
-               return;
-       }
-       if (t_flags&LCASE && c>='A' && c<='Z')
-               c += 'a'-'A';
-       (void) putc(c, &tp->t_rawq);
-       if (t_flags&(RAW|CBREAK)||(c=='\n'||c==tun.t_eofc||c==tun.t_brkc)) {
-               if ((t_flags&(RAW|CBREAK))==0 && putc(0377, &tp->t_rawq)==0)
-                       tp->t_delct++;
-               if ((cp=tp->t_chan)!=NULL)
-                       (void) sdata(cp); else
-                       wakeup((caddr_t)&tp->t_rawq);
-       }
-       if (t_flags&ECHO) {
-               ttyoutput(c, tp);
-               if (c==tp->t_kill && (t_flags&(RAW|CBREAK))==0)
-                       ttyoutput('\n', tp);
-               ttstart(tp);
-       }
-}
-
-
-/*
- * Send stop character on input overflow.
- */
-ttyblock(tp)
-register struct tty *tp;
-{
-       register x;
-       x = q1.c_cc + q2.c_cc;
-       if (q1.c_cc > TTYHOG) {
-               flushtty(tp, FREAD|FWRITE);
-               tp->t_state &= ~TBLOCK;
-       }
-       if (x >= TTYHOG/2) {
-               if (putc(tun.t_stopc, &tp->t_outq)==0) {
-                       tp->t_state |= TBLOCK;
-                       tp->t_char++;
-                       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.
- */
-ttyoutput(c, tp)
-register c;
-register struct tty *tp;
-{
-       register char *colp;
-       register ctype;
-
-       /*
-        * Ignore EOT in normal mode to avoid hanging up
-        * certain terminals.
-        * In raw mode dump the char unchanged.
-        */
-       if ((tp->t_flags&RAW)==0) {
-               c &= 0177;
-               if ((tp->t_flags&CBREAK)==0 && c==CEOT)
-                       return;
-       } else {
-               tk_nout++;
-               (void) putc(c, &tp->t_outq);
-               return;
-       }
-
-       /*
-        * Turn tabs to spaces as required
-        */
-       if (c=='\t' && (tp->t_flags&TBDELAY)==XTABS) {
-               c = 8 - (tp->t_col & 7);
-               (void) b_to_q("        ", c, &tp->t_outq);
-               tp->t_col += c;
-               tk_nout += c;
-               return;
-       }
-       tk_nout++;
-       /*
-        * for upper-case-only terminals,
-        * generate escapes.
-        */
-       if (tp->t_flags&LCASE) {
-               colp = "({)}!|^~'`";
-               while(*colp++)
-                       if(c == *colp++) {
-                               ttyoutput('\\', tp);
-                               c = colp[-2];
-                               break;
-                       }
-               if ('a'<=c && c<='z')
-                       c += 'A' - 'a';
-       }
-       /*
-        * turn <nl> to <cr><lf> if desired.
-        */
-       if (c=='\n' && tp->t_flags&CRMOD)
-               ttyoutput('\r', tp);
-       (void) putc(c, &tp->t_outq);
-       /*
-        * 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) {
-
-       /* ordinary */
-       case 0:
-               (*colp)++;
-
-       /* non-printing */
-       case 1:
-               break;
-
-       /* backspace */
-       case 2:
-               if (*colp)
-                       (*colp)--;
-               break;
-
-       /* newline */
-       case 3:
-               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;
-
-       /* tab */
-       case 4:
-               ctype = (tp->t_flags >> 10) & 03;
-               if(ctype == 1) { /* tty 37 */
-                       c = 1 - (*colp | ~07);
-                       if(c < 5)
-                               c = 0;
-               }
-               *colp |= 07;
-               (*colp)++;
-               break;
-
-       /* vertical motion */
-       case 5:
-               if(tp->t_flags & VTDELAY) /* tty 37 */
-                       c = 0177;
-               break;
-
-       /* carriage return */
-       case 6:
-               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)
-               (void) putc(c|0200, &tp->t_outq);
-}
-
-/*
- * Restart typewriter output following a delay
- * timeout.
- * The name of the routine is passed to the timeout
- * subroutine and it is called during a clock interrupt.
- */
-ttrstrt(tp)
-register struct tty *tp;
-{
-
-       tp->t_state &= ~TIMEOUT;
-       ttstart(tp);
-}
-
-/*
- * Start output on the typewriter. It is used from the top half
- * after some characters have been put on the output queue,
- * from the interrupt routine to transmit the next
- * character, and after a timeout has finished.
- */
-ttstart(tp)
-register struct tty *tp;
-{
-       register s;
-
-       s = spl5();
-       if((tp->t_state&(TIMEOUT|TTSTOP|BUSY)) == 0)
-               (*tp->t_oproc)(tp);
-       splx(s);
-}
-
-/*
- * Called from device's read routine after it has
- * calculated the tty-structure given as argument.
- */
-ttread(tp)
-register struct tty *tp;
-{
-register s;
-
-       if ((tp->t_state&CARR_ON)==0)
-               return(-1);
-       s = spl5();
-       if (tp->t_canq.c_cc==0)
-               while (canon(tp)<0)
-                       if (tp->t_chan==NULL) {
-                               sleep((caddr_t)&tp->t_rawq, TTIPRI); 
-                       } else {
-                               splx(s);
-                               return(0);
-                       }
-       splx(s);
-       while (tp->t_canq.c_cc && passc(getc(&tp->t_canq))>=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)
-register struct tty *tp;
-{
-       /*
-        * THE POSITIONING OF CP, CC, AND CE ARE CRITICAL
-        * AND MUST NOT BE CHANGED WITHOUT PATCHING
-        * THE 'ASM' INLINES BELOW.  WATCH OUT.
-        */
-       register char *cp;
-       register int cc, ce;
-       register i;
-       char obuf[OBUFSIZ];
-
-       if ((tp->t_state&CARR_ON)==0)
-               return(NULL);
-       while (u.u_count) {
-               cc = MIN(u.u_count, OBUFSIZ);
-               cp = obuf;
-               iomove(cp, (unsigned)cc, B_WRITE);
-               if (u.u_error)
-                       break;
-               (void) spl5();
-               while (tp->t_outq.c_cc > TTHIWAT) {
-                       ttstart(tp);
-                       tp->t_state |= ASLEEP;
-                       if (tp->t_chan) {
-                               u.u_base -= cc;
-                               u.u_offset -= cc;
-                               u.u_count += cc;
-                               (void) spl0();
-                               return((caddr_t)&tp->t_outq);
-                       }
-                       sleep((caddr_t)&tp->t_outq, TTOPRI);
-               }
-               (void) spl0();
-               if (tp->t_flags&LCASE) {
-                       while (cc--)
-                               ttyoutput(*cp++,tp);
-                       continue;
-               }
-               while (cc) {
-                       if (tp->t_flags&RAW)
-                               ce=cc;
-                       else {
-#ifdef VAX
-                               asm("   scanc   r9,(r10),_partab,$077");
-                               asm("   subl3   r0,r9,r8");
-#else
-                               ce=0;
-                               while(((partab[*(cp+ce)]&077)==0)&&(ce<cc))
-                                       ce++;
-#endif
-                               if (ce==0) {
-                                       ttyoutput(*cp++,tp);
-                                       cc--;
-                                       goto check;
-                               }
-                       }
-                       i=b_to_q(cp,ce,&tp->t_outq);
-                       ce-=i;
-                       tk_nout+=ce;
-                       tp->t_col+=ce;
-                       cp+=ce;
-                       cc-=ce;
-check:
-                       if (tp->t_outq.c_cc > TTHIWAT) {
-                               (void) spl5();
-                               while (tp->t_outq.c_cc > TTHIWAT) {
-                                       ttstart(tp);
-                                       tp->t_state |= ASLEEP;
-                                       sleep((caddr_t)&tp->t_outq, TTOPRI);
-                               }
-                               (void) spl0();
-                       }
-               }
-       }
-       ttstart(tp);
-       return(NULL);
-}