-/* tty.c 3.1 %H% */
+/* tty.c 4.37 82/12/17 */
+
+#include "../machine/reg.h"
-/*
- * general TTY subroutines
- */
#include "../h/param.h"
#include "../h/systm.h"
#include "../h/dir.h"
#include "../h/user.h"
+#include "../h/ioctl.h"
#include "../h/tty.h"
#include "../h/proc.h"
-#include "../h/mx.h"
#include "../h/inode.h"
#include "../h/file.h"
-#include "../h/reg.h"
#include "../h/conf.h"
#include "../h/buf.h"
+#include "../h/dk.h"
+#include "../h/uio.h"
+#include "../h/kernel.h"
+
+/*
+ * 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[];
+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
* sequence is replaced by the table value. Mostly used for
* upper-case only terminals.
*/
-
char maptab[] ={
000,000,000,000,000,000,000,000,
000,000,000,000,000,000,000,000,
'X','Y','Z',000,000,000,000,000,
};
+short tthiwat[16] =
+ { 100,100,100,100,100,100,100,200,200,400,400,400,650,650,1300,2000 };
+short ttlowat[16] =
+ { 30, 30, 30, 30, 30, 30, 30, 50, 50,120,120,120,125,125,125,125 };
-/*
- * shorthand
- */
-#define q1 tp->t_rawq
-#define q2 tp->t_canq
-#define q3 tp->t_outq
-#define q4 tp->t_un.t_ctlq
+struct ttychars ttydefaults = {
+ CERASE, CKILL, CINTR, CQUIT, CSTART, CSTOP, CEOF,
+ CBRK, CSUSP, CDSUSP, CRPRNT, CFLUSH, CWERASE,CLNEXT
+};
+
+ttychars(tp)
+ struct tty *tp;
+{
-#define OBUFSIZ 100
+ tp->t_chars = ttydefaults;
+}
/*
- * routine called on first teletype open.
- * establishes a process group for distribution
- * of quits and interrupts from the tty.
+ * Wait for output to drain, then flush input waiting.
*/
-ttyopen(dev, tp)
-dev_t dev;
-register struct tty *tp;
+wflushtty(tp)
+ 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;
+ (void) spl5();
+ while (tp->t_outq.c_cc && tp->t_state&TS_CARR_ON
+ && tp->t_oproc) { /* kludge for pty */
+ (*tp->t_oproc)(tp);
+ tp->t_state |= TS_ASLEEP;
+ sleep((caddr_t)&tp->t_outq, TTOPRI);
}
- tp->t_state &= ~WOPEN;
- tp->t_state |= ISOPEN;
+ flushtty(tp, FREAD);
+ (void) spl0();
}
-
/*
- * set default control characters.
+ * Flush all TTY queues
*/
-ttychars(tp)
-register struct tty *tp;
+flushtty(tp, rw)
+ register struct tty *tp;
{
- tun.t_intrc = CINTR;
- tun.t_quitc = CQUIT;
- tun.t_startc = CSTART;
- tun.t_stopc = CSTOP;
- tun.t_eofc = CEOT;
- tun.t_brkc = CBRK;
- tp->t_erase = CERASE;
- tp->t_kill = CKILL;
+ register s;
+
+ 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 &= ~TS_TTSTOP;
+ (*cdevsw[major(tp->t_dev)].d_stop)(tp, rw);
+ while (getc(&tp->t_outq) >= 0)
+ ;
+ }
+ if (rw & FREAD) {
+ while (getc(&tp->t_rawq) >= 0)
+ ;
+ tp->t_delct = 0;
+ tp->t_rocount = 0;
+ tp->t_rocol = 0;
+ tp->t_state &= ~TS_LOCAL;
+ }
+ splx(s);
}
/*
- * clean tp on last close
+ * Send stop character on input overflow.
*/
-ttyclose(tp)
-register struct tty *tp;
+ttyblock(tp)
+ register struct tty *tp;
{
+ register x;
- tp->t_pgrp = 0;
- wflushtty(tp);
- tp->t_state = 0;
+ 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 &= ~TS_TBLOCK;
+ }
+ if (x >= TTYHOG/2 && putc(tp->t_stopc, &tp->t_outq) == 0) {
+ tp->t_state |= TS_TBLOCK;
+ tp->t_char++;
+ ttstart(tp);
+ }
}
/*
- * stty/gtty writearound
+ * 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.
*/
-stty()
+ttrstrt(tp)
+ register struct tty *tp;
{
- u.u_arg[2] = u.u_arg[1];
- u.u_arg[1] = TIOCSETP;
- ioctl();
-}
-gtty()
-{
- u.u_arg[2] = u.u_arg[1];
- u.u_arg[1] = TIOCGETP;
- ioctl();
+ if (tp == 0)
+ panic("ttrstrt");
+ tp->t_state &= ~TS_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 (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) {
- 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);
+ register s;
+
+ s = spl5();
+ if ((tp->t_state & (TS_TIMEOUT|TS_TTSTOP|TS_BUSY)) == 0 &&
+ tp->t_oproc) /* kludge for pty */
+ (*tp->t_oproc)(tp);
+ splx(s);
}
/*
- * Common code for several tty ioctl commands
+ * Common code for tty ioctls.
*/
-ttioccomm(com, tp, addr, dev)
-register struct tty *tp;
-caddr_t addr;
+/*ARGSUSED*/
+ttioctl(tp, com, data, flag)
+ register struct tty *tp;
+ caddr_t data;
{
- unsigned t;
- struct ttiocb iocb;
+ int dev = tp->t_dev;
extern int nldisp;
-
- switch(com) {
+ int s;
/*
- * get discipline number
+ * If the ioctl involves modification,
+ * insist on being able to write the device,
+ * and hang if in the background.
*/
- case TIOCGETD:
- t = tp->t_line;
- if (copyout((caddr_t)&t, addr, sizeof(t)))
- u.u_error = EFAULT;
+ switch (com) {
+
+ case TIOCSETD:
+ case TIOCSETP:
+ case TIOCSETN:
+ case TIOCFLUSH:
+ case TIOCSETC:
+ case TIOCSLTC:
+ case TIOCSPGRP:
+ case TIOCLBIS:
+ case TIOCLBIC:
+ case TIOCLSET:
+ case TIOCBIS:
+ case TIOCBIC:
+ case TIOCSET:
+ case TIOCSTI:
+ 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) {
+ gsignal(u.u_procp->p_pgrp, SIGTTOU);
+ sleep((caddr_t)&lbolt, TTOPRI);
+ }
break;
+ }
/*
- * set line discipline
+ * Process the ioctl.
*/
- case TIOCSETD:
- if (copyin(addr, (caddr_t)&t, sizeof(t))) {
- u.u_error = EFAULT;
- break;
- }
+ switch (com) {
+
+ /* get discipline number */
+ case TIOCGETD:
+ *(int *)data = tp->t_line;
+ break;
+
+ /* set line discipline */
+ case TIOCSETD: {
+ register int t = *(int *)data;
+ int error = 0;
+
if (t >= nldisp) {
u.u_error = ENXIO;
break;
}
+ s = spl5();
if (tp->t_line)
(*linesw[tp->t_line].l_close)(tp);
if (t)
- (*linesw[t].l_open)(dev, tp, addr);
- if (u.u_error==0)
- tp->t_line = t;
+ error = (*linesw[t].l_open)(dev, tp);
+ splx(s);
+ if (error)
+ return (error);
+ tp->t_line = t;
break;
+ }
- /*
- * prevent more opens on channel
- */
+ /* prevent more opens on channel */
case TIOCEXCL:
- tp->t_state |= XCLUDE;
+ tp->t_state |= TS_XCLUDE;
break;
case TIOCNXCL:
- tp->t_state &= ~XCLUDE;
+ tp->t_state &= ~TS_XCLUDE;
break;
- /*
- * Set new parameters
- */
- case TIOCSETP:
- wflushtty(tp);
- case TIOCSETN:
- if (copyin(addr, (caddr_t)&iocb, sizeof(iocb))) {
- u.u_error = EFAULT;
- return(1);
+ case TIOCSET:
+ case TIOCBIS: {
+ u_long newflags = *(u_long *)data;
+
+ s = spl5();
+ if (tp->t_flags&RAW || newflags&RAW)
+ wflushtty(tp);
+ else if ((tp->t_flags&CBREAK) != (newflags&CBREAK))
+ if (newflags&CBREAK) {
+ struct clist tq;
+
+ catq(&tp->t_rawq, &tp->t_canq);
+ tq = tp->t_rawq;
+ tp->t_rawq = tp->t_canq;
+ tp->t_canq = tq;
+ } else {
+ tp->t_flags |= PENDIN;
+ ttwakeup(tp);
+ }
+ if (com == TIOCSET)
+ tp->t_flags = newflags;
+ else
+ tp->t_flags |= newflags;
+ if (tp->t_flags&RAW) {
+ tp->t_state &= ~TS_TTSTOP;
+ ttstart(tp);
}
- VOID spl5();
- while (canon(tp)>=0)
- ;
- if ((tp->t_state&SPEEDS)==0) {
- tp->t_ispeed = iocb.ioc_ispeed;
- tp->t_ospeed = iocb.ioc_ospeed;
- }
- tp->t_erase = iocb.ioc_erase;
- tp->t_kill = iocb.ioc_kill;
- tp->t_flags = iocb.ioc_flags;
- VOID spl0();
+ splx(s);
break;
+ }
- /*
- * send current parameters to user
- */
- case TIOCGETP:
- iocb.ioc_ispeed = tp->t_ispeed;
- iocb.ioc_ospeed = tp->t_ospeed;
- iocb.ioc_erase = tp->t_erase;
- iocb.ioc_kill = tp->t_kill;
- iocb.ioc_flags = tp->t_flags;
- if (copyout((caddr_t)&iocb, addr, sizeof(iocb)))
- u.u_error = EFAULT;
+ case TIOCBIC: {
+ u_long newflags = *(long *)data;
+
+ if (tp->t_flags&RAW)
+ wflushtty(tp);
+ else if ((tp->t_flags&CBREAK) != (CBREAK&~newflags))
+ if (newflags&CBREAK) {
+ tp->t_flags |= PENDIN;
+ ttwakeup(tp);
+ } else {
+ struct clist tq;
+
+ catq(&tp->t_rawq, &tp->t_canq);
+ tq = tp->t_rawq;
+ tp->t_rawq = tp->t_canq;
+ tp->t_canq = tq;
+ }
+ if (tp->t_flags&RAW) {
+ tp->t_state &= ~TS_TTSTOP;
+ ttstart(tp);
+ }
+ splx(s);
+ break;
+ }
+
+ case TIOCGET:
+ *(long *)data = tp->t_flags;
break;
- /*
- * Hang up line on last close
- */
+ case TIOCCGET:
+ bcopy((caddr_t)&tp->t_chars, data, sizeof (struct ttychars));
+ break;
+
+ case TIOCCSET:
+ bcopy(data, (caddr_t)&tp->t_chars, sizeof (struct ttychars));
+ break;
+ /* hang up line on last close */
case TIOCHPCL:
- tp->t_state |= HUPCLS;
+ tp->t_state |= TS_HUPCLS;
break;
- case TIOCFLUSH:
- flushtty(tp);
+ case TIOCFLUSH: {
+ register int flags = *(int *)data;
+
+ if (flags == 0)
+ flags = FREAD|FWRITE;
+ else
+ flags &= FREAD|FWRITE;
+ flushtty(tp, flags);
break;
+ }
- /*
- * ioctl entries to line discipline
- */
- case DIOCSETP:
- case DIOCGETP:
- (*linesw[tp->t_line].l_ioctl)(com, tp, addr);
+ /* return number of characters immediately available */
+ case FIONREAD:
+ *(off_t *)data = ttnread(tp);
break;
- /*
- * set and fetch special characters
- */
- case TIOCSETC:
- if (copyin(addr, (caddr_t)&tun, sizeof(struct tc)))
- u.u_error = EFAULT;
+ case TIOCSTOP:
+ 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;
+
+ case TIOCSTART:
+ s = spl5();
+ if ((tp->t_state&TS_TTSTOP) || (tp->t_flags&FLUSHO)) {
+ tp->t_state &= ~TS_TTSTOP;
+ tp->t_flags &= ~FLUSHO;
+ ttstart(tp);
+ }
+ splx(s);
break;
- case TIOCGETC:
- if (copyout((caddr_t)&tun, addr, sizeof(struct tc)))
- u.u_error = EFAULT;
+ /*
+ * Simulate typing of a character at the terminal.
+ */
+ case TIOCSTI:
+ if (u.u_uid && u.u_ttyp != tp)
+ return (EACCES);
+ (*linesw[tp->t_line].l_rint)(*(char *)data, tp);
break;
default:
- return(0);
+#ifndef NOCOMPAT
+ return (ottioctl(tp, com, data, flag));
+#else
+ return (-1);
+#endif
}
- return(1);
+ return (0);
}
-/*
- * Wait for output to drain, then flush input waiting.
- */
-wflushtty(tp)
-register struct tty *tp;
+ttnread(tp)
+ struct tty *tp;
{
+ int nread = 0;
+
+ if (tp->t_flags & PENDIN)
+ ttypend(tp);
+ nread = tp->t_canq.c_cc;
+ if (tp->t_flags & (RAW|CBREAK))
+ nread += tp->t_rawq.c_cc;
+ return (nread);
+}
- 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);
+ttselect(dev, rw)
+ dev_t dev;
+ int rw;
+{
+ register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)];
+ int nread;
+ int s = spl5();
+
+ switch (rw) {
+
+ case FREAD:
+ nread = ttnread(tp);
+ if (nread > 0)
+ goto win;
+ if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait)
+ tp->t_state |= TS_RCOLL;
+ 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;
}
- flushtty(tp);
- VOID spl0();
+ splx(s);
+ return (0);
+win:
+ splx(s);
+ return (1);
}
/*
- * flush all TTY queues
+ * Establish a process group for distribution of
+ * quits and interrupts from the tty.
*/
-flushtty(tp)
-register struct tty *tp;
+ttyopen(dev, tp)
+ dev_t dev;
+ register struct tty *tp;
{
- register s;
+ register struct proc *pp;
- while (getc(&tp->t_canq) >= 0)
- ;
- wakeup((caddr_t)&tp->t_rawq);
- wakeup((caddr_t)&tp->t_outq);
- s = spl6();
- tp->t_state &= ~TTSTOP;
- (*cdevsw[major(tp->t_dev)].d_stop)(tp);
- while (getc(&tp->t_outq) >= 0)
- ;
- while (getc(&tp->t_rawq) >= 0)
- ;
- tp->t_delct = 0;
- splx(s);
+ 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);
+ return (0);
}
-
-
/*
- * 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.
+ * clean tp on last close
*/
-canon(tp)
-register struct tty *tp;
+ttyclose(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;
+ if (tp->t_line) {
+ wflushtty(tp);
+ tp->t_line = 0;
+ return;
}
-
- splx(s);
- return(0);
+ tp->t_pgrp = 0;
+ wflushtty(tp);
+ tp->t_state = 0;
}
-
/*
- * block transfer input handler.
+ * reinput pending characters after state switch
+ * call at spl5().
*/
-ttyrend(tp, pb, pe)
-register struct tty *tp;
-register char *pb, *pe;
+ttypend(tp)
+ register struct tty *tp;
{
- 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);
+ struct clist tq;
+ register c;
+
+ tp->t_flags &= ~PENDIN;
+ tp->t_state |= TS_TYPEN;
+ 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_state &= ~TS_TYPEN;
}
/*
- * 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.
+ * 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 c;
+ register struct tty *tp;
{
- register int t_flags;
- register struct chan *cp;
+ register int t_flags = tp->t_flags;
+ int i;
- tk_nin += 1;
+ /*
+ * If input is pending take it first.
+ */
+ if (t_flags&PENDIN)
+ ttypend(tp);
+ tk_nin++;
c &= 0377;
- t_flags = tp->t_flags;
+
+ /*
+ * In tandem mode, check high water mark.
+ */
if (t_flags&TANDEM)
ttyblock(tp);
- if ((t_flags&RAW)==0) {
+
+ if (t_flags&RAW) {
+ /*
+ * Raw mode, just put character
+ * in input q w/o interpretation.
+ */
+ if (tp->t_rawq.c_cc > TTYHOG)
+ flushtty(tp, FREAD|FWRITE);
+ else {
+ if (putc(c, &tp->t_rawq) >= 0)
+ ttwakeup(tp);
+ ttyecho(c, tp);
+ }
+ goto endcase;
+ }
+
+ /*
+ * Ignore any high bit added during
+ * previous ttyinput processing.
+ */
+ if ((tp->t_state&TS_TYPEN) == 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;
+ /*
+ * Check for literal nexting very first
+ */
+ if (tp->t_state&TS_LNCH) {
+ c |= 0200;
+ tp->t_state &= ~TS_LNCH;
+ }
+
+ /*
+ * Scan for special characters. This code
+ * is really just a big case statement with
+ * non-constant cases. The bottom of the
+ * case statement is labeled ``endcase'', so goto
+ * it after a case match, or similar.
+ */
+ if (tp->t_line == NTTYDISC) {
+ if (c == tp->t_lnextc) {
+ if (tp->t_flags&ECHO)
+ ttyout("^\b", tp);
+ tp->t_state |= TS_LNCH;
+ goto endcase;
+ }
+ if (c == tp->t_flushc) {
+ if (tp->t_flags&FLUSHO)
+ tp->t_flags &= ~FLUSHO;
+ else {
+ flushtty(tp, FWRITE);
+ ttyecho(c, tp);
+ if (tp->t_rawq.c_cc + tp->t_canq.c_cc)
+ ttyretype(tp);
+ tp->t_flags |= FLUSHO;
}
- if (c==tun.t_startc)
- return;
+ goto startoutput;
}
- if (c==tun.t_quitc || c==tun.t_intrc) {
- flushtty(tp);
- c = (c==tun.t_intrc) ? SIGINT:SIGQUIT;
- if (tp->t_chan)
- scontrol(tp->t_chan, M_SIG, c);
- else
- signal(tp->t_pgrp, c);
+ if (c == tp->t_suspc) {
+ if ((tp->t_flags&NOFLSH) == 0)
+ flushtty(tp, FREAD);
+ ttyecho(c, tp);
+ gsignal(tp->t_pgrp, SIGTSTP);
+ goto endcase;
+ }
+ }
+
+ /*
+ * Handle start/stop characters.
+ */
+ if (c == tp->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=='\r' && t_flags&CRMOD)
- c = '\n';
+ if (c != tp->t_startc)
+ return;
+ goto endcase;
}
- if (tp->t_rawq.c_cc>TTYHOG) {
- flushtty(tp);
- return;
+ if (c == tp->t_startc)
+ goto restartoutput;
+
+ /*
+ * Look for interrupt/quit chars.
+ */
+ if (c == tp->t_intrc || c == tp->t_quitc) {
+ if ((tp->t_flags&NOFLSH) == 0)
+ flushtty(tp, FREAD|FWRITE);
+ ttyecho(c, tp);
+ gsignal(tp->t_pgrp, c == tp->t_intrc ? SIGINT : SIGQUIT);
+ goto endcase;
}
- 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);
+
+ /*
+ * Cbreak mode, don't process line editing
+ * characters; check high water mark for wakeup.
+ */
+ if (t_flags&CBREAK) {
+ 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);
+ }
+ goto endcase;
}
-}
+ /*
+ * From here on down cooked mode character
+ * processing takes place.
+ */
+ if ((tp->t_state&TS_QUOT) &&
+ (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);
+ goto endcase;
+ }
+ if (c == tp->t_kill) {
+ if (tp->t_flags&CRTKIL &&
+ 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_state &= ~TS_LOCAL;
+ goto endcase;
+ }
-/*
- * 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);
- 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);
+ /*
+ * New line discipline,
+ * check word erase/reprint line.
+ */
+ if (tp->t_line == NTTYDISC) {
+ if (c == tp->t_werasc) {
+ if (tp->t_rawq.c_cc == 0)
+ goto endcase;
+ do {
+ c = unputc(&tp->t_rawq);
+ if (c != ' ' && c != '\t')
+ goto erasenb;
+ ttyrub(c, tp);
+ } while (tp->t_rawq.c_cc);
+ goto endcase;
+ erasenb:
+ do {
+ ttyrub(c, tp);
+ if (tp->t_rawq.c_cc == 0)
+ goto endcase;
+ c = unputc(&tp->t_rawq);
+ } while (c != ' ' && c != '\t');
+ (void) putc(c, &tp->t_rawq);
+ goto endcase;
+ }
+ if (c == tp->t_rprntc) {
+ ttyretype(tp);
+ goto endcase;
+ }
+ }
+
+ /*
+ * Check for input buffer overflow
+ */
+ if (tp->t_rawq.c_cc+tp->t_canq.c_cc >= TTYHOG)
+ goto endcase;
+
+ /*
+ * Put data char in q for user and
+ * wakeup on seeing a line delimiter.
+ */
+ 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)) {
+ tp->t_rocount = 0;
+ catq(&tp->t_rawq, &tp->t_canq);
+ ttwakeup(tp);
+ } else if (tp->t_rocount++ == 0)
+ tp->t_rocol = tp->t_col;
+ tp->t_state &= ~TS_QUOT;
+ if (c == '\\')
+ tp->t_state |= TS_QUOT;
+ if (tp->t_state&TS_ERASE) {
+ tp->t_state &= ~TS_ERASE;
+ (void) ttyoutput('/', tp);
+ }
+ i = tp->t_col;
+ ttyecho(c, tp);
+ if (c == tp->t_eofc && tp->t_flags&ECHO) {
+ i = MIN(2, tp->t_col - i);
+ while (i > 0) {
+ (void) ttyoutput('\b', tp);
+ i--;
+ }
}
}
+
+endcase:
+ /*
+ * If DEC-style start/stop is enabled don't restart
+ * output until seeing the start character.
+ */
+ if (tp->t_flags&DECCTQ && tp->t_state&TS_TTSTOP &&
+ tp->t_startc != tp->t_stopc)
+ return;
+
+restartoutput:
+ tp->t_state &= ~TS_TTSTOP;
+ tp->t_flags &= ~FLUSHO;
+
+startoutput:
+ ttstart(tp);
}
/*
- * put character on TTY output queue, adding delays,
+ * 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.
+ * This 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 c;
+ register struct tty *tp;
{
register char *colp;
register ctype;
- tk_nout++;
- /*
- * 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 {
- VOID putc(c, &tp->t_outq);
- return;
+ if (tp->t_flags & (RAW|LITOUT)) {
+ if (tp->t_flags&FLUSHO)
+ 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) {
- c = 8;
- do
- ttyoutput(' ', tp);
- while (--c >= 0 && tp->t_col&07);
- return;
+ if (c == '\t' && (tp->t_flags&TBDELAY) == XTABS) {
+ register int s;
+
+ c = 8 - (tp->t_col&7);
+ if ((tp->t_flags&FLUSHO) == 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++) {
- ttyoutput('\\', tp);
+ while (*colp++)
+ if (c == *colp++) {
+ if (ttyoutput('\\', tp) >= 0)
+ return (c);
c = colp[-2];
break;
}
- if ('a'<=c && c<='z')
+ 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)
- ttyoutput('\r', tp);
- VOID putc(c, &tp->t_outq);
+ if (c == '\n' && tp->t_flags&CRMOD)
+ if (ttyoutput('\r', tp) >= 0)
+ return (c);
+ if (c == '~' && tp->t_flags&TILDE)
+ c = '`';
+ if ((tp->t_flags&FLUSHO) == 0 && putc(c, &tp->t_outq))
+ return (c);
/*
* Calculate delays.
* The numbers here represent clock ticks
* The delays are indicated by characters above 0200.
* In raw mode there are no delays and the
* transmission path is 8 bits wide.
+ *
+ * SHOULD JUST ALLOW USER TO SPECIFY DELAYS
*/
colp = &tp->t_col;
ctype = partab[c];
c = 0;
switch (ctype&077) {
- /* ordinary */
- case 0:
+ case ORDINARY:
(*colp)++;
- /* non-printing */
- case 1:
+ case CONTROL:
break;
- /* backspace */
- case 2:
+ case BACKSPACE:
if (*colp)
(*colp)--;
break;
- /* newline */
- case 3:
+ case NEWLINE:
ctype = (tp->t_flags >> 8) & 03;
- if(ctype == 1) { /* tty 37 */
+ if (ctype == 1) { /* tty 37 */
if (*colp)
c = max(((unsigned)*colp>>4) + 3, (unsigned)6);
- } else
- if(ctype == 2) { /* vt05 */
+ } else if (ctype == 2) /* vt05 */
c = 6;
- }
*colp = 0;
break;
- /* tab */
- case 4:
+ case TAB:
ctype = (tp->t_flags >> 10) & 03;
- if(ctype == 1) { /* tty 37 */
+ if (ctype == 1) { /* tty 37 */
c = 1 - (*colp | ~07);
- if(c < 5)
+ if (c < 5)
c = 0;
}
*colp |= 07;
(*colp)++;
break;
- /* vertical motion */
- case 5:
- if(tp->t_flags & VTDELAY) /* tty 37 */
+ case VTAB:
+ if (tp->t_flags&VTDELAY) /* tty 37 */
c = 0177;
break;
- /* carriage return */
- case 6:
+ case RETURN:
ctype = (tp->t_flags >> 12) & 03;
- if(ctype == 1) { /* tn 300 */
+ if (ctype == 1) /* tn 300 */
c = 5;
- } else if(ctype == 2) { /* ti 700 */
+ else if (ctype == 2) /* ti 700 */
c = 10;
- } else if(ctype == 3) { /* concept 100 */
+ else if (ctype == 3) { /* concept 100 */
int i;
- for (i= *colp; i<9; i++)
- VOID putc(0177, &tp->t_outq);
+
+ 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);
+ if (c && (tp->t_flags&FLUSHO) == 0)
+ (void) putc(c|0200, &tp->t_outq);
+ return (-1);
}
/*
- * 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.
+ * Called from device's read routine after it has
+ * calculated the tty-structure given as argument.
*/
-ttrstrt(tp)
-register struct tty *tp;
+ttread(tp, uio)
+ register struct tty *tp;
+ struct uio *uio;
{
+ register struct clist *qp;
+ register c, t_flags;
+ int first, error = 0;
- tp->t_state &= ~TIMEOUT;
- ttstart(tp);
-}
+ if ((tp->t_state&TS_CARR_ON)==0)
+ return (EIO);
+loop:
+ /*
+ * Take any pending input first.
+ */
+ (void) spl5();
+ if (tp->t_flags&PENDIN)
+ ttypend(tp);
+ (void) spl0();
+ /*
+ * Hang process if it's in the background.
+ */
+ 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 ||
/*
- * 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;
+ (u.u_procp->p_flag&SDETACH) ||
+*/
+ u.u_procp->p_flag&SVFORK)
+ return (EIO);
+ gsignal(u.u_procp->p_pgrp, SIGTTIN);
+ sleep((caddr_t)&lbolt, TTIPRI);
+ }
+ t_flags = tp->t_flags;
- s = spl5();
- if((tp->t_state&(TIMEOUT|TTSTOP|BUSY)) == 0)
- (*tp->t_oproc)(tp);
- splx(s);
-}
+ /*
+ * In raw mode take characters directly from the
+ * raw queue w/o processing. Interlock against
+ * device interrupts when interrogating rawq.
+ */
+ if (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) {
+ error = passuc(getc(&tp->t_rawq), uio);
+ if (error)
+ break;
+ }
+ return (error);
+ }
-/*
- * Called from device's read routine after it has
- * calculated the tty-structure given as argument.
- */
-ttread(tp)
-register struct tty *tp;
-{
-register s;
+ /*
+ * In cbreak mode use the rawq, otherwise
+ * take characters from the canonicalized q.
+ */
+ qp = t_flags&CBREAK ? &tp->t_rawq : &tp->t_canq;
- 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);
+ /*
+ * No input, sleep on rawq awaiting hardware
+ * receipt and notification.
+ */
+ (void) spl5();
+ if (qp->c_cc <= 0) {
+ if ((tp->t_state&TS_CARR_ON) == 0 ||
+ (tp->t_state&TS_NBIO)) {
+ (void) spl0();
+ return (EWOULDBLOCK);
+ }
+ sleep((caddr_t)&tp->t_rawq, TTIPRI);
+ (void) spl0();
+ goto loop;
+ }
+ (void) spl0();
+
+ /*
+ * Input present, perform input mapping
+ * and processing (we're not in raw mode).
+ */
+ first = 1;
+ while ((c = getc(qp)) >= 0) {
+ if (t_flags&CRMOD && c == '\r')
+ c = '\n';
+ /*
+ * Hack lower case simulation on
+ * upper case only terminals.
+ */
+ if (t_flags&LCASE && c <= 0177)
+ if (tp->t_state&TS_BKSL) {
+ if (maptab[c])
+ c = maptab[c];
+ tp->t_state &= ~TS_BKSL;
+ } else if (c >= 'A' && c <= 'Z')
+ c += 'a' - 'A';
+ else if (c == '\\') {
+ tp->t_state |= TS_BKSL;
+ continue;
}
- 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);
+ /*
+ * Check for delayed suspend character.
+ */
+ if (tp->t_line == NTTYDISC && c == tp->t_dsuspc) {
+ gsignal(tp->t_pgrp, SIGTSTP);
+ if (first) {
+ sleep((caddr_t)&lbolt, TTIPRI);
+ goto loop;
+ }
+ break;
+ }
+ /*
+ * Interpret EOF only in cooked mode.
+ */
+ if (c == tp->t_eofc && (t_flags&CBREAK) == 0)
+ break;
+ /*
+ * Give user character.
+ */
+ error = passuc(c & 0177, uio);
+ if (error)
+ break;
+ if (uio->uio_iovcnt == 0)
+ break;
+ /*
+ * In cooked mode check for a "break character"
+ * marking the end of a "line of input".
+ */
+ if ((t_flags&CBREAK) == 0 && ttbreakc(c, tp))
+ break;
+ first = 0;
+ }
+ tp->t_state &= ~TS_BKSL;
+
+ /*
+ * Look to unblock output now that (presumably)
+ * the input queue has gone down.
+ */
+ if (tp->t_state&TS_TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) {
+ if (putc(tp->t_startc, &tp->t_outq) == 0) {
+ tp->t_state &= ~TS_TBLOCK;
+ ttstart(tp);
+ }
+ tp->t_char = 0;
+ }
+ return (error);
}
/*
* 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;
+ttwrite(tp, uio)
+ register struct tty *tp;
+ register struct uio *uio;
{
- /*
- * 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;
+ register int cc, ce, c;
+ int i, hiwat, cnt, error, s;
char obuf[OBUFSIZ];
- if ((tp->t_state&CARR_ON)==0)
- return(NULL);
- while (u.u_count) {
- cc = MIN(u.u_count, OBUFSIZ);
+ if ((tp->t_state&TS_CARR_ON) == 0)
+ return (EIO);
+ hiwat = TTHIWAT(tp);
+ cnt = uio->uio_resid;
+ error = 0;
+loop:
+ /*
+ * Hang the process if it's in the background.
+ */
+ while (u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp &&
+ (tp->t_flags&TOSTOP) && (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);
+ }
+
+ /*
+ * Process the user's data in at most OBUFSIZ
+ * chunks. Perform lower case simulation and
+ * similar hacks. Keep track of high water
+ * mark, sleep on overflow awaiting device aid
+ * in acquiring new space.
+ */
+ while (uio->uio_resid > 0) {
+ /*
+ * Grab a hunk of data from the user.
+ */
+ 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;
- iomove(cp, (unsigned)cc, B_WRITE);
- if (u.u_error)
+ error = uiomove(cp, (unsigned)cc, UIO_WRITE, uio);
+ if (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);
+ if (tp->t_outq.c_cc > hiwat)
+ goto ovhiwat;
+ if (tp->t_flags&FLUSHO)
+ continue;
+ /*
+ * If we're mapping lower case or kludging tildes,
+ * then we've got to look at each character, so
+ * just feed the stuff to ttyoutput...
+ */
+ if (tp->t_flags & (LCASE|TILDE)) {
+ while (cc > 0) {
+ 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;
}
- 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;
+ /*
+ * If nothing fancy need be done, grab those characters we
+ * can handle without any of ttyoutput's processing and
+ * just transfer them to the output q. For those chars
+ * which require special processing (as indicated by the
+ * bits in partab), call ttyoutput. After processing
+ * a hunk of data, look for FLUSHO so ^O's will take effect
+ * immediately.
+ */
+ while (cc > 0) {
+ if (tp->t_flags & (RAW|LITOUT))
+ 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--;
+ ce = cc - scanc(cc, cp, partab, 077);
+ /*
+ * If ce is zero, then we're processing
+ * a special character through ttyoutput.
+ */
+ if (ce == 0) {
+ tp->t_rocount = 0;
+ if (ttyoutput(*cp, tp) >= 0) {
+ /* no c-lists, wait a bit */
+ ttstart(tp);
+ sleep((caddr_t)&lbolt, TTOPRI);
+ continue;
+ }
+ cp++, cc--;
+ if (tp->t_flags&FLUSHO ||
+ tp->t_outq.c_cc > hiwat)
+ goto ovhiwat;
continue;
}
}
- i=b_to_q(cp,ce,&tp->t_outq);
- ce-=i;
- tk_nout+=ce;
- tp->t_col+=ce;
- cp+=ce;
- cc-=ce;
- if (i) {
- VOID spl5();
- while (tp->t_outq.c_cc > TTHIWAT) {
- ttstart(tp);
- tp->t_state |= ASLEEP;
- sleep((caddr_t)&tp->t_outq, TTOPRI);
- }
- VOID spl0();
+ /*
+ * A bunch of normal characters have been found,
+ * transfer them en masse to the output queue and
+ * continue processing at the top of the loop.
+ * If there are any further characters in this
+ * <= OBUFSIZ chunk, the first should be a character
+ * requiring special handling by ttyoutput.
+ */
+ tp->t_rocount = 0;
+ i = b_to_q(cp, ce, &tp->t_outq);
+ ce -= i;
+ tp->t_col += ce;
+ cp += ce, cc -= ce, tk_nout += ce;
+ if (i > 0) {
+ /* out of c-lists, wait a bit */
+ ttstart(tp);
+ sleep((caddr_t)&lbolt, TTOPRI);
}
+ if (tp->t_flags&FLUSHO || tp->t_outq.c_cc > hiwat)
+ goto ovhiwat;
}
}
ttstart(tp);
- return(NULL);
+ return (error);
+
+ovhiwat:
+ s = spl5();
+ if (cc != 0) {
+ uio->uio_iov->iov_base -= cc;
+ uio->uio_iov->iov_len += cc;
+ uio->uio_resid += cc;
+ uio->uio_offset -= cc;
+ }
+ /*
+ * This can only occur if FLUSHO
+ * is also set in t_flags.
+ */
+ if (tp->t_outq.c_cc <= hiwat) {
+ splx(s);
+ goto loop;
+ }
+ ttstart(tp);
+ if (tp->t_state&TS_NBIO) {
+ if (uio->uio_resid == cnt)
+ return (EWOULDBLOCK);
+ return (0);
+ }
+ tp->t_state |= TS_ASLEEP;
+ sleep((caddr_t)&tp->t_outq, TTOPRI);
+ splx(s);
+ 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_flags &= ~FLUSHO;
+ c &= 0377;
+ if (tp->t_flags&CRTBS) {
+ 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_flags&CTLECH)
+ 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_state |= TS_CNTTB;
+ tp->t_flags |= FLUSHO;
+ tp->t_col = tp->t_rocol;
+ cp = tp->t_rawq.c_cf;
+ for (; cp; cp = nextc(&tp->t_rawq, cp))
+ ttyecho(*cp, tp);
+ tp->t_flags &= ~FLUSHO;
+ tp->t_state &= ~TS_CNTTB;
+ 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_flags&PRTERA) {
+ if ((tp->t_state&TS_ERASE) == 0) {
+ (void) ttyoutput('\\', tp);
+ tp->t_state |= TS_ERASE;
+ }
+ 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;
+{
+ register char *rubostring = tp->t_flags&CRTERA ? "\b \b" : "\b";
+
+ while (--cnt >= 0)
+ ttyout(rubostring, 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 (tp->t_rprntc != 0377)
+ ttyecho(tp->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_state &= ~TS_ERASE;
+ 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_state&TS_CNTTB) == 0)
+ tp->t_flags &= ~FLUSHO;
+ 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_flags&CTLECH) {
+ 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 == tp->t_eofc || c == tp->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);
+}
+
+#ifndef vax
+scanc(size, cp, table, mask)
+ register int size;
+ register char *cp, table[];
+ register int mask;
+{
+ register int i = 0;
+
+ while ((table[*(u_char *)(cp + i)]&mask) == 0 && i < size)
+ i++;
+ return (i);
+}
+#endif