-/* tty.c 4.25 82/08/01 */
-
/*
- * TTY subroutines common to more than one line discipline
+ * Copyright (c) 1982 Regents of the University of California.
+ * All rights reserved. The Berkeley software License Agreement
+ * specifies the terms and conditions for redistribution.
+ *
+ * @(#)tty.c 6.22 (Berkeley) %G%
*/
-#include "../h/param.h"
-#include "../h/systm.h"
-#include "../h/dir.h"
-#include "../h/user.h"
-#include "../h/tty.h"
-#include "../h/proc.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 "../machine/reg.h"
+
+#include "param.h"
+#include "systm.h"
+#include "dir.h"
+#include "user.h"
+#include "ioctl.h"
+#include "tty.h"
+#include "proc.h"
+#include "inode.h"
+#include "file.h"
+#include "conf.h"
+#include "buf.h"
+#include "dk.h"
+#include "uio.h"
+#include "kernel.h"
/*
* Table giving parity for characters and indicating
* 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,
};
short tthiwat[16] =
- { 100,100,100,100,100,100,100,200,200,400,400,400,650,650,650,650 };
+ { 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 };
-#define OBUFSIZ 100
+struct ttychars ttydefaults = {
+ CERASE, CKILL, CINTR, CQUIT, CSTART, CSTOP, CEOF,
+ CBRK, CSUSP, CDSUSP, CRPRNT, CFLUSH, CWERASE,CLNEXT
+};
-/*
- * set default control characters.
- */
ttychars(tp)
- register struct tty *tp;
+ 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;
-/* begin local */
- tlun.t_suspc = CTRL(z);
- tlun.t_dsuspc = CTRL(y);
- tlun.t_rprntc = CTRL(r);
- tlun.t_flushc = CTRL(o);
- tlun.t_werasc = CTRL(w);
- tlun.t_lnextc = CTRL(v);
- tp->t_local = 0;
- tp->t_lstate = 0;
-/* end local */
+ tp->t_chars = ttydefaults;
}
/*
* Wait for output to drain, then flush input waiting.
*/
-wflushtty(tp)
+ttywflush(tp)
+ register struct tty *tp;
+{
+
+ ttywait(tp);
+ ttyflush(tp, FREAD);
+}
+
+ttywait(tp)
register struct tty *tp;
{
+ register int s = spltty();
- (void) spl5();
- while (tp->t_outq.c_cc && tp->t_state&TS_CARR_ON
- && tp->t_oproc) { /* kludge for pty */
+ while ((tp->t_outq.c_cc || tp->t_state&TS_BUSY) &&
+ tp->t_state&TS_CARR_ON) {
(*tp->t_oproc)(tp);
tp->t_state |= TS_ASLEEP;
sleep((caddr_t)&tp->t_outq, TTOPRI);
}
- flushtty(tp, FREAD);
- (void) spl0();
+ splx(s);
}
/*
- * flush all TTY queues
+ * Flush all TTY queues
*/
-flushtty(tp, rw)
+ttyflush(tp, rw)
register struct tty *tp;
{
register s;
- s = spl6();
+ s = spltty();
if (rw & FREAD) {
while (getc(&tp->t_canq) >= 0)
;
if (rw & FREAD) {
while (getc(&tp->t_rawq) >= 0)
;
- tp->t_delct = 0;
- tp->t_rocount = 0; /* local */
+ tp->t_rocount = 0;
tp->t_rocol = 0;
- tp->t_lstate = 0;
+ tp->t_state &= ~TS_LOCAL;
}
splx(s);
}
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);
+ ttyflush(tp, FREAD|FWRITE);
tp->t_state &= ~TS_TBLOCK;
}
- if (x >= TTYHOG/2) {
- if (putc(tun.t_stopc, &tp->t_outq)==0) {
+ /*
+ * Block further input iff:
+ * Current input > threshold AND input is available to user program
+ */
+ if (x >= TTYHOG/2 &&
+ ((tp->t_flags & (RAW|CBREAK)) || (tp->t_canq.c_cc > 0))) {
+ if (putc(tp->t_stopc, &tp->t_outq)==0) {
tp->t_state |= TS_TBLOCK;
- tp->t_char++;
ttstart(tp);
}
}
register struct tty *tp;
{
- if (tp == 0) {
- printf("ttrstrt: arg was 0!\n");
- return;
- }
+ if (tp == 0)
+ panic("ttrstrt");
tp->t_state &= ~TS_TIMEOUT;
ttstart(tp);
}
{
register s;
- s = spl5();
- if ((tp->t_state&(TS_TIMEOUT|TS_TTSTOP|TS_BUSY)) == 0 &&
+ s = spltty();
+ if ((tp->t_state & (TS_TIMEOUT|TS_TTSTOP|TS_BUSY)) == 0 &&
tp->t_oproc) /* kludge for pty */
(*tp->t_oproc)(tp);
splx(s);
register struct tty *tp;
caddr_t data;
{
- int dev;
+ int dev = tp->t_dev;
extern int nldisp;
+ int s;
+ register int newflags;
- /*
- * This is especially so that isatty() will
- * fail when carrier is gone.
- */
- if ((tp->t_state&TS_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.
+ * hang if in the background.
*/
switch (com) {
case TIOCLBIS:
case TIOCLBIC:
case TIOCLSET:
-/* this is reasonable, but impractical...
- if ((flag & FWRITE) == 0) {
- u.u_error = EBADF;
- return (1);
- }
- */
+ case TIOCSTI:
+ case TIOCSWINSZ:
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) {
-*/
- ) {
+ !(u.u_procp->p_sigignore & sigmask(SIGTTOU)) &&
+ !(u.u_procp->p_sigmask & sigmask(SIGTTOU))) {
gsignal(u.u_procp->p_pgrp, SIGTTOU);
sleep((caddr_t)&lbolt, TTOPRI);
}
*/
switch (com) {
- /*
- * Get discipline number
- */
+ /* get discipline number */
case TIOCGETD:
*(int *)data = tp->t_line;
break;
- /*
- * Set line discipline
- */
+ /* set line discipline */
case TIOCSETD: {
register int t = *(int *)data;
-
- if (t >= nldisp) {
- u.u_error = ENXIO;
- break;
+ int error = 0;
+
+ if ((unsigned) t >= nldisp)
+ return (ENXIO);
+ s = spltty();
+ (*linesw[tp->t_line].l_close)(tp);
+ error = (*linesw[t].l_open)(dev, tp);
+ if (error) {
+ (void) (*linesw[tp->t_line].l_open)(dev, tp);
+ splx(s);
+ return (error);
}
- (void) spl5();
- if (tp->t_line)
- (*linesw[tp->t_line].l_close)(tp);
- if (t)
- (*linesw[t].l_open)(dev, tp);
- if (u.u_error==0)
- tp->t_line = t;
- (void) spl0();
+ tp->t_line = t;
+ splx(s);
break;
}
- /*
- * Prevent more opens on channel
- */
+ /* prevent more opens on channel */
case TIOCEXCL:
tp->t_state |= TS_XCLUDE;
break;
tp->t_state &= ~TS_XCLUDE;
break;
+ /* hang up line on last close */
+ case TIOCHPCL:
+ tp->t_state |= TS_HUPCLS;
+ break;
+
+ case TIOCFLUSH: {
+ register int flags = *(int *)data;
+
+ if (flags == 0)
+ flags = FREAD|FWRITE;
+ else
+ flags &= FREAD|FWRITE;
+ ttyflush(tp, flags);
+ break;
+ }
+
+ /* return number of characters immediately available */
+ case FIONREAD:
+ *(off_t *)data = ttnread(tp);
+ break;
+
+ case TIOCOUTQ:
+ *(int *)data = tp->t_outq.c_cc;
+ break;
+
+ case TIOCSTOP:
+ s = spltty();
+ 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 = spltty();
+ if ((tp->t_state&TS_TTSTOP) || (tp->t_flags&FLUSHO)) {
+ tp->t_state &= ~TS_TTSTOP;
+ tp->t_flags &= ~FLUSHO;
+ ttstart(tp);
+ }
+ splx(s);
+ break;
+
/*
- * Set new parameters
+ * Simulate typing of a character at the terminal.
*/
+ case TIOCSTI:
+ if (u.u_uid && (flag & FREAD) == 0)
+ return (EPERM);
+ if (u.u_uid && u.u_ttyp != tp)
+ return (EACCES);
+ (*linesw[tp->t_line].l_rint)(*(char *)data, tp);
+ break;
+
case TIOCSETP:
case TIOCSETN: {
register struct sgttyb *sg = (struct sgttyb *)data;
- struct clist tq;
- (void) spl5();
- if (tp->t_flags&RAW || sg->sg_flags&RAW || com == TIOCSETP)
- wflushtty(tp);
- else if ((tp->t_flags&CBREAK) != (sg->sg_flags&CBREAK)) {
- if (sg->sg_flags & CBREAK) {
+ tp->t_erase = sg->sg_erase;
+ tp->t_kill = sg->sg_kill;
+ tp->t_ispeed = sg->sg_ispeed;
+ tp->t_ospeed = sg->sg_ospeed;
+ newflags = (tp->t_flags&0xffff0000) | (sg->sg_flags&0xffff);
+ s = spltty();
+ if (tp->t_flags&RAW || newflags&RAW || com == TIOCSETP) {
+ ttywait(tp);
+ ttyflush(tp, FREAD);
+ } 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_local |= LPENDIN;
+ tp->t_flags |= PENDIN;
+ newflags |= PENDIN;
ttwakeup(tp);
}
}
- 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) {
+ tp->t_flags = newflags;
+ if (tp->t_flags&RAW) {
tp->t_state &= ~TS_TTSTOP;
ttstart(tp);
}
- (void) spl0();
+ splx(s);
break;
}
- /*
- * Send current parameters to user
- */
+ /* send current parameters to user */
case TIOCGETP: {
register struct sgttyb *sg = (struct sgttyb *)data;
break;
}
- /*
- * Hang up line on last close
- */
- case TIOCHPCL:
- tp->t_state |= TS_HUPCLS;
- break;
-
- case TIOCFLUSH: {
- register int flags = *(int *)data;
-
- if (flags == 0)
- flags = FREAD|FWRITE;
- else
- flags &= FREAD|FWRITE;
- flushtty(tp, flags);
- break;
- }
-
case FIONBIO:
if (*(int *)data)
tp->t_state |= TS_NBIO;
tp->t_state &= ~TS_ASYNC;
break;
- /*
- * Set and fetch special characters
- */
- case TIOCSETC:
- bcopy(data, (caddr_t)&tun, sizeof (struct tchars));
+ case TIOCGETC:
+ bcopy((caddr_t)&tp->t_intrc, data, sizeof (struct tchars));
break;
- case TIOCGETC:
- bcopy((caddr_t)&tun, data, sizeof (struct tchars));
+ case TIOCSETC:
+ bcopy(data, (caddr_t)&tp->t_intrc, sizeof (struct tchars));
break;
-/* local ioctls */
- /*
- * Set/get local special characters.
- */
+ /* set/get local special characters */
case TIOCSLTC:
- bcopy(data, (caddr_t)&tlun, sizeof (struct ltchars));
+ bcopy(data, (caddr_t)&tp->t_suspc, sizeof (struct ltchars));
break;
case TIOCGLTC:
- bcopy((caddr_t)&tlun, data, sizeof (struct ltchars));
- break;
-
- /*
- * Return number of characters immediately available.
- */
- case FIONREAD:
- *(off_t *)data = ttnread(tp);
- break;
-
- /*
- * Should allow SPGRP and GPGRP only if tty open for reading.
- */
- case TIOCSPGRP:
- tp->t_pgrp = *(int *)data;
- break;
-
- case TIOCGPGRP:
- *(int *)data = tp->t_pgrp;
+ bcopy((caddr_t)&tp->t_suspc, data, sizeof (struct ltchars));
break;
/*
* Modify local mode word.
*/
case TIOCLBIS:
- tp->t_local |= *(int *)data;
+ tp->t_flags |= *(int *)data << 16;
break;
case TIOCLBIC:
- tp->t_local &= ~(*(int *)data);
+ tp->t_flags &= ~(*(int *)data << 16);
break;
case TIOCLSET:
- tp->t_local = *(int *)data;
+ tp->t_flags &= 0xffff;
+ tp->t_flags |= *(int *)data << 16;
break;
case TIOCLGET:
- *(int *)data = tp->t_local;
+ *(int *)data = ((unsigned) tp->t_flags) >> 16;
break;
- 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);
+ /*
+ * Allow SPGRP only if tty is open for reading.
+ * Quick check: if we can find a process in the new pgrp,
+ * this user must own that process.
+ * SHOULD VERIFY THAT PGRP IS IN USE AND IS THIS USER'S.
+ */
+ case TIOCSPGRP: {
+ struct proc *p;
+ int pgrp = *(int *)data;
+
+ if (u.u_uid && (flag & FREAD) == 0)
+ return (EPERM);
+ p = pfind(pgrp);
+ if (p && p->p_pgrp == pgrp &&
+ p->p_uid != u.u_uid && u.u_uid && !inferior(p))
+ return (EPERM);
+ tp->t_pgrp = pgrp;
break;
}
- case TIOCSTART: {
- int s = spl5();
+ case TIOCGPGRP:
+ *(int *)data = tp->t_pgrp;
+ break;
- if ((tp->t_state & TS_TTSTOP) || (tp->t_local & LFLUSHO)) {
- tp->t_state &= ~TS_TTSTOP;
- tp->t_local &= ~LFLUSHO;
- ttstart(tp);
+ case TIOCSWINSZ:
+ if (bcmp((caddr_t)&tp->t_winsize, data,
+ sizeof (struct winsize))) {
+ tp->t_winsize = *(struct winsize *)data;
+ gsignal(tp->t_pgrp, SIGWINCH);
}
- splx(s);
break;
- }
-/* end of locals */
+ case TIOCGWINSZ:
+ *(struct winsize *)data = tp->t_winsize;
+ break;
default:
- return (0);
+ return (-1);
}
- return (1);
+ return (0);
}
ttnread(tp)
{
int nread = 0;
- if (tp->t_local & LPENDIN)
+ if (tp->t_flags & PENDIN)
ttypend(tp);
nread = tp->t_canq.c_cc;
if (tp->t_flags & (RAW|CBREAK))
{
register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)];
int nread;
- int s = spl5();
+ int s = spltty();
switch (rw) {
case FREAD:
nread = ttnread(tp);
- if (nread > 0)
+ if ((nread > 0) || ((tp->t_state & TS_CARR_ON) == 0))
goto win;
if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait)
tp->t_state |= TS_RCOLL;
return (1);
}
-#define OBUFSIZ 100
-
/*
- * routine called on opens while tp->t_line == NTTYDISC
- * establishes a process group for distribution of
+ * Initial open of tty, or (re)entry to line discipline.
+ * Establish 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;
pp->p_pgrp = tp->t_pgrp;
}
tp->t_state &= ~TS_WOPEN;
- tp->t_state |= TS_ISOPEN;
- if (tp->t_line != NTTYDISC)
- wflushtty(tp);
+ if ((tp->t_state & TS_ISOPEN) == 0) {
+ tp->t_state |= TS_ISOPEN;
+ bzero((caddr_t)&tp->t_winsize, sizeof(tp->t_winsize));
+ if (tp->t_line != NTTYDISC)
+ ttywflush(tp);
+ }
+ return (0);
+}
+
+/*
+ * "close" a line discipline
+ */
+ttylclose(tp)
+ register struct tty *tp;
+{
+
+ ttywflush(tp);
+ tp->t_line = 0;
}
/*
register struct tty *tp;
{
- if (tp->t_line) {
- wflushtty(tp);
- tp->t_line = 0;
- return;
- }
+ ttyflush(tp, FREAD|FWRITE);
tp->t_pgrp = 0;
- wflushtty(tp);
tp->t_state = 0;
}
+/*
+ * Handle modem control transition on a tty.
+ * Flag indicates new state of carrier.
+ * Returns 0 if the line should be turned off, otherwise 1.
+ */
+ttymodem(tp, flag)
+ register struct tty *tp;
+{
+
+ if ((tp->t_state&TS_WOPEN) == 0 && (tp->t_flags & MDMBUF)) {
+ /*
+ * MDMBUF: do flow control according to carrier flag
+ */
+ if (flag) {
+ tp->t_state &= ~TS_TTSTOP;
+ ttstart(tp);
+ } else if ((tp->t_state&TS_TTSTOP) == 0) {
+ tp->t_state |= TS_TTSTOP;
+ (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
+ }
+ } else if (flag == 0) {
+ /*
+ * Lost carrier.
+ */
+ tp->t_state &= ~TS_CARR_ON;
+ if (tp->t_state & TS_ISOPEN) {
+ if ((tp->t_flags & NOHANG) == 0) {
+ gsignal(tp->t_pgrp, SIGHUP);
+ gsignal(tp->t_pgrp, SIGCONT);
+ ttyflush(tp, FREAD|FWRITE);
+ return (0);
+ }
+ }
+ } else {
+ /*
+ * Carrier now on.
+ */
+ tp->t_state |= TS_CARR_ON;
+ wakeup((caddr_t)&tp->t_rawq);
+ }
+ return (1);
+}
+
/*
* reinput pending characters after state switch
- * call at spl5().
+ * call at spltty().
*/
ttypend(tp)
register struct tty *tp;
struct clist tq;
register c;
- tp->t_local &= ~LPENDIN;
- tp->t_lstate |= LSTYPEN;
+ 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_lstate &= ~LSTYPEN;
+ 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 int t_flags;
+ register int t_flags = tp->t_flags;
int i;
- if (tp->t_local&LPENDIN)
+ /*
+ * 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 ((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 (t_flags&RAW) {
+ /*
+ * Raw mode, just put character
+ * in input q w/o interpretation.
+ */
+ if (tp->t_rawq.c_cc > TTYHOG)
+ ttyflush(tp, FREAD|FWRITE);
+ else {
+ if (putc(c, &tp->t_rawq) >= 0)
+ ttwakeup(tp);
+ ttyecho(c, tp);
}
- if (tp->t_line == NTTYDISC && c==tlun.t_lnextc) {
- if (tp->t_flags&ECHO)
+ goto endcase;
+ }
+
+ /*
+ * Ignore any high bit added during
+ * previous ttyinput processing.
+ */
+ if ((tp->t_state&TS_TYPEN) == 0 && (t_flags&PASS8) == 0)
+ c &= 0177;
+ /*
+ * 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 (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;
+ tp->t_state |= TS_LNCH;
+ goto endcase;
+ }
+ if (c == tp->t_flushc) {
+ if (t_flags&FLUSHO)
+ tp->t_flags &= ~FLUSHO;
else {
- flushtty(tp, FWRITE);
+ ttyflush(tp, FWRITE);
ttyecho(c, tp);
- if (tp->t_rawq.c_cc+tp->t_canq.c_cc)
+ if (tp->t_rawq.c_cc + tp->t_canq.c_cc)
ttyretype(tp);
- tp->t_local |= LFLUSHO;
+ tp->t_flags |= FLUSHO;
}
- 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);
+ goto startoutput;
+ }
+ if (c == tp->t_suspc) {
+ if ((t_flags&NOFLSH) == 0)
+ ttyflush(tp, FREAD);
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) {
+ 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 != tp->t_startc)
+ return;
+ goto endcase;
+ }
+ if (c == tp->t_startc)
+ goto restartoutput;
+
+ /*
+ * Look for interrupt/quit chars.
+ */
+ if (c == tp->t_intrc || c == tp->t_quitc) {
+ if ((t_flags&NOFLSH) == 0)
+ ttyflush(tp, FREAD|FWRITE);
+ ttyecho(c, tp);
+ gsignal(tp->t_pgrp, c == tp->t_intrc ? SIGINT : SIGQUIT);
+ goto endcase;
+ }
+
+ if (tp->t_flags & LCASE && c <= 0177) {
+ if (tp->t_state&TS_BKSL) {
+ ttyrub(unputc(&tp->t_rawq), tp);
+ if (maptab[c])
+ c = maptab[c];
+ c |= 0200;
+ tp->t_state &= ~(TS_BKSL|TS_QUOT);
+ } else if (c >= 'A' && c <= 'Z')
+ c += 'a' - 'A';
+ else if (c == '\\')
+ tp->t_state |= TS_BKSL;
+ }
+
+ /*
+ * 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);
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)
+ 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 (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;
+ }
+
+ /*
+ * 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) {
+ if (tp->t_line == NTTYDISC)
+ (void) ttyoutput(CTRL(g), tp);
+ goto endcase;
+ }
+
+ /*
+ * Put data char in q for user and
+ * wakeup on seeing a line delimiter.
+ */
+ if (putc(c, &tp->t_rawq) >= 0) {
+ 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 && t_flags&ECHO) {
+ i = MIN(2, tp->t_col - i);
+ while (i > 0) {
+ (void) ttyoutput('\b', tp);
+ i--;
+ }
+ }
}
-out:
- if (tp->t_local & LDECCTQ && tp->t_state & TS_TTSTOP &&
- tun.t_startc != tun.t_stopc)
+endcase:
+ /*
+ * If DEC-style start/stop is enabled don't restart
+ * output until seeing the start character.
+ */
+ if (t_flags&DECCTQ && tp->t_state&TS_TTSTOP &&
+ tp->t_startc != tp->t_stopc)
return;
+restartoutput:
tp->t_state &= ~TS_TTSTOP;
- tp->t_local &= ~LFLUSHO;
+ 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.
register char *colp;
register ctype;
- if (tp->t_flags&RAW || tp->t_local&LLITOUT) {
- if (tp->t_local&LFLUSHO)
+ 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.
+ * Ignore EOT in normal mode to avoid
+ * hanging up certain terminals.
*/
c &= 0177;
- if (c==CEOT && (tp->t_flags&CBREAK)==0)
+ if (c == CEOT && (tp->t_flags&CBREAK) == 0)
return (-1);
/*
* Turn tabs to spaces as required
*/
- if (c=='\t' && (tp->t_flags&TBDELAY)==XTABS) {
+ 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 */
+ if ((tp->t_flags&FLUSHO) == 0) {
+ s = spltty(); /* don't interrupt tabs */
c -= b_to_q(" ", c, &tp->t_outq);
tk_nout += c;
splx(s);
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')
+ } else if ('a' <= c && c <= 'z')
c += 'A' - 'a';
}
+
/*
* turn <nl> to <cr><lf> if desired.
*/
- if (c=='\n' && tp->t_flags&CRMOD)
+ if (c == '\n' && tp->t_flags&CRMOD)
if (ttyoutput('\r', tp) >= 0)
return (c);
- if (c=='~' && tp->t_local<ILDE)
+ if (c == '~' && tp->t_flags&TILDE)
c = '`';
- if ((tp->t_local&LFLUSHO) == 0 && putc(c, &tp->t_outq))
+ if ((tp->t_flags&FLUSHO) == 0 && putc(c, &tp->t_outq))
return (c);
/*
* Calculate delays.
* 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];
(*colp)--;
break;
+ /*
+ * This macro is close enough to the correct thing;
+ * it should be replaced by real user settable delays
+ * in any event...
+ */
+#define mstohz(ms) (((ms) * hz) >> 10)
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;
- }
+ if (*colp > 0)
+ c = max((((unsigned)*colp) >> 4) + 3,
+ (unsigned)6);
+ } else if (ctype == 2) /* vt05 */
+ c = mstohz(100);
*colp = 0;
break;
break;
case VTAB:
- if (tp->t_flags & VTDELAY) /* tty 37 */
+ 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 */
+ if (ctype == 1) /* tn 300 */
+ c = mstohz(83);
+ else if (ctype == 2) /* ti 700 */
+ c = mstohz(166);
+ else if (ctype == 3) { /* concept 100 */
int i;
+
if ((i = *colp) >= 0)
- for (; i<9; i++)
+ for (; i < 9; i++)
(void) putc(0177, &tp->t_outq);
}
*colp = 0;
}
- if (c && (tp->t_local&LFLUSHO) == 0)
+ if (c && (tp->t_flags&FLUSHO) == 0)
(void) putc(c|0200, &tp->t_outq);
return (-1);
}
+#undef mstohz
/*
* Called from device's read routine after it has
* calculated the tty-structure given as argument.
*/
-ttread(tp)
+ttread(tp, uio)
register struct tty *tp;
+ struct uio *uio;
{
register struct clist *qp;
- register c, first;
+ register c, t_flags;
+ int s, first, error = 0;
- if ((tp->t_state&TS_CARR_ON)==0)
- return (0);
loop:
- (void) spl5();
- if (tp->t_local&LPENDIN)
+ /*
+ * Take any pending input first.
+ */
+ s = spltty();
+ if (tp->t_flags&PENDIN)
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) ||
-*/
+ splx(s);
+
+ if ((tp->t_state&TS_CARR_ON)==0)
+ return (EIO);
+
+ /*
+ * Hang process if it's in the background.
+ */
+ if (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) {
+ if ((u.u_procp->p_sigignore & sigmask(SIGTTIN)) ||
+ (u.u_procp->p_sigmask & sigmask(SIGTTIN)) ||
u.u_procp->p_flag&SVFORK)
- return (0);
+ return (EIO);
gsignal(u.u_procp->p_pgrp, SIGTTIN);
sleep((caddr_t)&lbolt, TTIPRI);
+ goto loop;
}
- if (tp->t_flags&RAW) {
- (void) spl5();
+ t_flags = tp->t_flags;
+
+ /*
+ * In raw mode take characters directly from the
+ * raw queue w/o processing. Interlock against
+ * device interrupts when interrogating rawq.
+ */
+ if (t_flags&RAW) {
+ s = spltty();
if (tp->t_rawq.c_cc <= 0) {
- if ((tp->t_state&TS_CARR_ON)==0 ||
+ if ((tp->t_state&TS_CARR_ON) == 0 ||
(tp->t_state&TS_NBIO)) {
- (void) spl0();
- return (0);
+ splx(s);
+ return (EWOULDBLOCK);
}
sleep((caddr_t)&tp->t_rawq, TTIPRI);
- (void) spl0();
+ splx(s);
goto loop;
}
- (void) spl0();
- while (tp->t_rawq.c_cc && passc(getc(&tp->t_rawq))>=0)
- ;
- 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;
+ splx(s);
+ while (!error && tp->t_rawq.c_cc && uio->uio_resid)
+ error = ureadc(getc(&tp->t_rawq), uio);
+ goto checktandem;
+ }
+
+ /*
+ * In cbreak mode use the rawq, otherwise
+ * take characters from the canonicalized q.
+ */
+ qp = t_flags&CBREAK ? &tp->t_rawq : &tp->t_canq;
+
+ /*
+ * No input, sleep on rawq awaiting hardware
+ * receipt and notification.
+ */
+ s = spltty();
+ if (qp->c_cc <= 0) {
+ if ((tp->t_state&TS_CARR_ON) == 0 ||
+ (tp->t_state&TS_NBIO)) {
+ splx(s);
+ return (EWOULDBLOCK);
}
- (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 (c == tlun.t_dsuspc) {
- ttsignal(tp, SIGTSTP);
- if (first) {
- sleep((caddr_t)&lbolt, TTIPRI);
- goto loop;
- }
- break;
+ sleep((caddr_t)&tp->t_rawq, TTIPRI);
+ splx(s);
+ goto loop;
+ }
+ splx(s);
+
+ /*
+ * 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';
+ /*
+ * 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;
}
- if (c == tun.t_eofc && (tp->t_flags&CBREAK)==0)
- break;
- if (passc(c & 0177) < 0)
- break;
- if ((tp->t_flags&CBREAK)==0 && ttbreakc(c, tp))
- break;
- first = 0;
+ break;
}
- tp->t_lstate &= ~LSBKSL;
+ /*
+ * Interpret EOF only in cooked mode.
+ */
+ if (c == tp->t_eofc && (t_flags&CBREAK) == 0)
+ break;
+ /*
+ * Give user character.
+ */
+ error = ureadc(t_flags&PASS8 ? c : c & 0177, uio);
+ if (error)
+ break;
+ if (uio->uio_resid == 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;
}
- if (tp->t_state&TS_TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) {
- if (putc(tun.t_startc, &tp->t_outq)==0) {
+checktandem:
+ /*
+ * 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);
+}
- return (tp->t_rawq.c_cc + tp->t_canq.c_cc);
+/*
+ * Check the output queue on tp for space for a kernel message
+ * (from uprintf/tprintf). Allow some space over the normal
+ * hiwater mark so we don't lose messages due to normal flow
+ * control, but don't let the tty run amok.
+ */
+ttycheckoutq(tp, wait)
+ register struct tty *tp;
+ int wait;
+{
+ int hiwat, s;
+
+ hiwat = TTHIWAT(tp);
+ s = spltty();
+ if (tp->t_outq.c_cc > hiwat + 200)
+ while (tp->t_outq.c_cc > hiwat) {
+ ttstart(tp);
+ if (wait == 0) {
+ splx(s);
+ return (0);
+ }
+ tp->t_state |= TS_ASLEEP;
+ sleep((caddr_t)&tp->t_outq, TTOPRI);
+ }
+ splx(s);
+ return (1);
}
/*
* Called from the device's write routine after it has
* calculated the tty-structure given as argument.
*/
-caddr_t
-ttwrite(tp)
+ttwrite(tp, uio)
register struct tty *tp;
+ register 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;
+ register int cc, ce, c;
+ int i, hiwat, cnt, error, s;
char obuf[OBUFSIZ];
- register c;
- int hiwat = TTHIWAT(tp);
- int cnt = u.u_count;
- if ((tp->t_state&TS_CARR_ON)==0)
- return (NULL);
+ hiwat = TTHIWAT(tp);
+ cnt = uio->uio_resid;
+ error = 0;
loop:
- while (u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp &&
- (tp->t_local<OSTOP) && (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) {
-*/
- ) {
+ if ((tp->t_state&TS_CARR_ON) == 0)
+ return (EIO);
+ /*
+ * Hang the process if it's in the background.
+ */
+ if (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_procp->p_sigignore & sigmask(SIGTTOU)) &&
+ !(u.u_procp->p_sigmask & sigmask(SIGTTOU))) {
gsignal(u.u_procp->p_pgrp, SIGTTOU);
sleep((caddr_t)&lbolt, TTIPRI);
+ goto loop;
}
- while (u.u_count) {
- cc = MIN(u.u_count, OBUFSIZ);
+
+ /*
+ * 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, cc, UIO_WRITE, uio);
+ if (error)
break;
if (tp->t_outq.c_cc > hiwat)
goto ovhiwat;
- if (tp->t_local&LFLUSHO)
+ if (tp->t_flags&FLUSHO)
continue;
- if (tp->t_flags&LCASE || tp->t_local<ILDE) {
- while (cc) {
+ /*
+ * 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) {
ttstart(tp);
sleep((caddr_t)&lbolt, TTOPRI);
tp->t_rocount = 0;
+ if (cc != 0) {
+ uio->uio_iov->iov_base -= cc;
+ uio->uio_iov->iov_len += cc;
+ uio->uio_resid += cc;
+ uio->uio_offset -= cc;
+ }
+ goto loop;
}
--cc;
if (tp->t_outq.c_cc > hiwat)
}
continue;
}
- while (cc) {
- if (tp->t_flags&RAW || tp->t_local&LLITOUT)
+ /*
+ * 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[*(unsigned char *)(cp+ce)]&077)==0)&&(ce<cc))
- ce++;
-#endif
- if (ce==0) {
+ ce = cc - scanc((unsigned)cc, (caddr_t)cp,
+ (caddr_t)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) {
- ttstart(tp);
- sleep((caddr_t)&lbolt, TTOPRI);
- continue;
+ /* no c-lists, wait a bit */
+ ttstart(tp);
+ sleep((caddr_t)&lbolt, TTOPRI);
+ if (cc != 0) {
+ uio->uio_iov->iov_base -= cc;
+ uio->uio_iov->iov_len += cc;
+ uio->uio_resid += cc;
+ uio->uio_offset -= cc;
+ }
+ goto loop;
}
- cp++;
- cc--;
- if (tp->t_outq.c_cc > hiwat)
+ cp++, cc--;
+ if (tp->t_flags&FLUSHO ||
+ tp->t_outq.c_cc > hiwat)
goto ovhiwat;
+ continue;
}
}
+ /*
+ * 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;
- tk_nout+=ce;
- tp->t_col+=ce;
- cp+=ce;
- cc-=ce;
- if (i) {
+ 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);
+ uio->uio_iov->iov_base -= cc;
+ uio->uio_iov->iov_len += cc;
+ uio->uio_resid += cc;
+ uio->uio_offset -= cc;
+ goto loop;
}
- if (ce || tp->t_outq.c_cc > hiwat)
+ if (tp->t_flags&FLUSHO || tp->t_outq.c_cc > hiwat)
goto ovhiwat;
}
}
ttstart(tp);
- return (NULL);
+ return (error);
ovhiwat:
- (void) spl5();
- u.u_base -= cc;
- u.u_offset -= cc;
- u.u_count += cc;
+ s = spltty();
+ 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) {
- (void) spl0();
+ splx(s);
goto loop;
}
ttstart(tp);
- if (tp->t_state & TS_NBIO) {
- if (u.u_count == cnt)
- u.u_error = EWOULDBLOCK;
- return (NULL);
+ if (tp->t_state&TS_NBIO) {
+ splx(s);
+ if (uio->uio_resid == cnt)
+ return (EWOULDBLOCK);
+ return (0);
}
tp->t_state |= TS_ASLEEP;
sleep((caddr_t)&tp->t_outq, TTOPRI);
- (void) spl0();
+ splx(s);
goto loop;
}
int s;
char *nextc();
- if ((tp->t_flags&ECHO)==0)
+ if ((tp->t_flags&ECHO) == 0)
return;
- tp->t_local &= ~LFLUSHO;
+ tp->t_flags &= ~FLUSHO;
c &= 0377;
- if (tp->t_local&LCRTBS) {
+ if (tp->t_flags&CRTBS) {
if (tp->t_rocount == 0) {
/*
* Screwed by ttwrite; retype
ttyretype(tp);
return;
}
- if (c==('\t'|0200) || c==('\n'|0200))
+ if (c == ('\t'|0200) || c == ('\n'|0200))
ttyrubo(tp, 2);
- else switch (partab[c&=0177] & 0177) {
+ else switch (partab[c&=0177]&0177) {
case ORDINARY:
if (tp->t_flags&LCASE && c >= 'A' && c <= 'Z')
case BACKSPACE:
case CONTROL:
case RETURN:
- if (tp->t_local & LCTLECH)
+ if (tp->t_flags&CTLECH)
ttyrubo(tp, 2);
break;
ttyretype(tp);
return;
}
- s = spl5();
+ s = spltty();
savecol = tp->t_col;
- tp->t_lstate |= LSCNTTB;
- tp->t_local |= LFLUSHO;
+ tp->t_state |= TS_CNTTB;
+ tp->t_flags |= FLUSHO;
tp->t_col = tp->t_rocol;
- for (cp = tp->t_rawq.c_cf; cp; cp = nextc(&tp->t_rawq, cp))
+ cp = tp->t_rawq.c_cf;
+ for (; cp; cp = nextc(&tp->t_rawq, cp))
ttyecho(*cp, tp);
- tp->t_local &= ~LFLUSHO;
- tp->t_lstate &= ~LSCNTTB;
+ tp->t_flags &= ~FLUSHO;
+ tp->t_state &= ~TS_CNTTB;
splx(s);
/*
* savecol will now be length of the tab
default:
panic("ttyrub");
}
- } else if (tp->t_local&LPRTERA) {
- if ((tp->t_lstate&LSERASE) == 0) {
+ } else if (tp->t_flags&PRTERA) {
+ if ((tp->t_state&TS_ERASE) == 0) {
(void) ttyoutput('\\', tp);
- tp->t_lstate |= LSERASE;
+ tp->t_state |= TS_ERASE;
}
ttyecho(c, tp);
} else
register struct tty *tp;
int cnt;
{
+ register char *rubostring = tp->t_flags&CRTERA ? "\b \b" : "\b";
while (--cnt >= 0)
- ttyout(tp->t_local&LCRTERA ? "\b \b" : "\b", tp);
+ ttyout(rubostring, tp);
}
/*
char *nextc();
int s;
- if (tlun.t_rprntc != 0377)
- ttyecho(tlun.t_rprntc, tp);
+ if (tp->t_rprntc != 0377)
+ ttyecho(tp->t_rprntc, tp);
(void) ttyoutput('\n', tp);
- s = spl5();
+ s = spltty();
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;
+ tp->t_state &= ~TS_ERASE;
splx(s);
tp->t_rocount = tp->t_rawq.c_cc;
tp->t_rocol = 0;
register struct tty *tp;
{
- if ((tp->t_lstate & LSCNTTB) == 0)
- tp->t_local &= ~LFLUSHO;
+ if ((tp->t_state&TS_CNTTB) == 0)
+ tp->t_flags &= ~FLUSHO;
if ((tp->t_flags&ECHO) == 0)
return;
c &= 0377;
}
if (c == '\r' && tp->t_flags&CRMOD)
c = '\n';
- if (tp->t_local&LCTLECH) {
+ if (tp->t_flags&CTLECH) {
if ((c&0177) <= 037 && c!='\t' && c!='\n' || (c&0177)==0177) {
(void) ttyoutput('^', tp);
c &= 0177;
c += 'A' - 1;
}
}
- if ((tp->t_flags&LCASE) && (c >= 'A' && c <= 'Z'))
- c += 'a' - 'A';
- (void) ttyoutput(c & 0177, tp);
+ (void) ttyoutput(c&0177, tp);
}
/*
register c;
register struct tty *tp;
{
- return (c == '\n' || c == tun.t_eofc || c == tun.t_brkc ||
+ return (c == '\n' || c == tp->t_eofc || c == tp->t_brkc ||
c == '\r' && (tp->t_flags&CRMOD));
}
tp->t_state &= ~TS_RCOLL;
tp->t_rsel = 0;
}
+ if (tp->t_state & TS_ASYNC)
+ gsignal(tp->t_pgrp, SIGIO);
wakeup((caddr_t)&tp->t_rawq);
}
-
-ttsignal(tp, signo)
- struct tty *tp;
- int signo;
-{
-
- gsignal(tp->t_pgrp, signo);
-}