xref: /csrg-svn/sys/kern/tty.c (revision 39555)
123387Smckusick /*
229107Smckusick  * Copyright (c) 1982, 1986 Regents of the University of California.
323387Smckusick  * All rights reserved.  The Berkeley software License Agreement
423387Smckusick  * specifies the terms and conditions for redistribution.
523387Smckusick  *
6*39555Smarc  *	@(#)tty.c	7.19 (Berkeley) 11/20/89
723387Smckusick  */
839Sbill 
917095Sbloom #include "param.h"
1017095Sbloom #include "systm.h"
1117095Sbloom #include "user.h"
1217095Sbloom #include "ioctl.h"
1339407Smarc #define TTYDEFCHARS
1417095Sbloom #include "tty.h"
1535811Smarc #undef TTYDEFCHARS
1617095Sbloom #include "proc.h"
1717095Sbloom #include "file.h"
1817095Sbloom #include "conf.h"
1929946Skarels #include "dkstat.h"
2017095Sbloom #include "uio.h"
2117095Sbloom #include "kernel.h"
2237728Smckusick #include "vnode.h"
2335811Smarc #include "syslog.h"
2439Sbill 
2537525Smckusick #include "machine/reg.h"
2637525Smckusick 
277436Skre /*
287436Skre  * Table giving parity for characters and indicating
2935811Smarc  * character classes to tty driver. The 8th bit
3035811Smarc  * indicates parity, the 7th bit indicates the character
3135811Smarc  * is an alphameric or underscore (for ALTWERASE), and the
3235811Smarc  * low 6 bits indicate delay type.  If the low 6 bits are 0
3335811Smarc  * then the character needs no special processing on output.
347436Skre  */
3539Sbill 
367436Skre char partab[] = {
3735811Smarc 	0001,0201,0201,0001,0201,0001,0001,0201,	/* nul - bel */
3835811Smarc 	0202,0004,0003,0201,0005,0206,0201,0001,	/* bs - si */
3935811Smarc 	0201,0001,0001,0201,0001,0201,0201,0001,	/* dle - etb */
4035811Smarc 	0001,0201,0201,0001,0201,0001,0001,0201,	/* can - us */
4135811Smarc 	0200,0000,0000,0200,0000,0200,0200,0000,	/* sp - ' */
4235811Smarc 	0000,0200,0200,0000,0200,0000,0000,0200,	/* ( - / */
4335811Smarc 	0100,0300,0300,0100,0300,0100,0100,0300,	/* 0 - 7 */
4435811Smarc 	0300,0100,0000,0200,0000,0200,0200,0000,	/* 8 - ? */
4535811Smarc 	0200,0100,0100,0300,0100,0300,0300,0100,	/* @ - G */
4635811Smarc 	0100,0300,0300,0100,0300,0100,0100,0300,	/* H - O */
4735811Smarc 	0100,0300,0300,0100,0300,0100,0100,0300,	/* P - W */
4835811Smarc 	0300,0100,0100,0200,0000,0200,0200,0300,	/* X - _ */
4935811Smarc 	0000,0300,0300,0100,0300,0100,0100,0300,	/* ` - g */
5035811Smarc 	0300,0100,0100,0300,0100,0300,0300,0100,	/* h - o */
5135811Smarc 	0300,0100,0100,0300,0100,0300,0300,0100,	/* p - w */
5235811Smarc 	0100,0300,0300,0000,0200,0000,0000,0201,	/* x - del */
537436Skre 	/*
5435811Smarc 	 * meta chars
557436Skre 	 */
5635811Smarc 	0001,0201,0201,0001,0201,0001,0001,0201,	/* nul - bel */
5735811Smarc 	0202,0004,0003,0201,0005,0206,0201,0001,	/* bs - si */
5835811Smarc 	0201,0001,0001,0201,0001,0201,0201,0001,	/* dle - etb */
5935811Smarc 	0001,0201,0201,0001,0201,0001,0001,0201,	/* can - us */
6035811Smarc 	0200,0000,0000,0200,0000,0200,0200,0000,	/* sp - ' */
6135811Smarc 	0000,0200,0200,0000,0200,0000,0000,0200,	/* ( - / */
6235811Smarc 	0100,0300,0300,0100,0300,0100,0100,0300,	/* 0 - 7 */
6335811Smarc 	0300,0100,0000,0200,0000,0200,0200,0000,	/* 8 - ? */
6435811Smarc 	0200,0100,0100,0300,0100,0300,0300,0100,	/* @ - G */
6535811Smarc 	0100,0300,0300,0100,0300,0100,0100,0300,	/* H - O */
6635811Smarc 	0100,0300,0300,0100,0300,0100,0100,0300,	/* P - W */
6735811Smarc 	0300,0100,0100,0200,0000,0200,0200,0300,	/* X - _ */
6835811Smarc 	0000,0300,0300,0100,0300,0100,0100,0300,	/* ` - g */
6935811Smarc 	0300,0100,0100,0300,0100,0300,0300,0100,	/* h - o */
7035811Smarc 	0300,0100,0100,0300,0100,0300,0300,0100,	/* p - w */
7135811Smarc 	0100,0300,0300,0000,0200,0000,0000,0201,	/* x - del */
727436Skre };
737436Skre 
7435811Smarc extern struct tty *constty;		/* temporary virtual console */
7535811Smarc extern char partab[], maptab[];
7635811Smarc 
77146Sbill /*
7835811Smarc  * Is 'c' a line delimiter ("break" character)?
7939Sbill  */
8035811Smarc #define ttbreakc(c) (c == '\n' || CCEQ(cc[VEOF], c) || \
8135811Smarc 		CCEQ(cc[VEOL], c) || CCEQ(cc[VEOL2], c))
8239Sbill 
8339Sbill ttychars(tp)
849578Ssam 	struct tty *tp;
8539Sbill {
8635811Smarc 	bcopy(ttydefchars, tp->t_cc, sizeof(ttydefchars));
8739Sbill }
8839Sbill 
8939Sbill /*
90903Sbill  * Wait for output to drain, then flush input waiting.
9139Sbill  */
9212752Ssam ttywflush(tp)
9337584Smarc 	struct tty *tp;
9439Sbill {
9539Sbill 
9612752Ssam 	ttywait(tp);
9712752Ssam 	ttyflush(tp, FREAD);
9812752Ssam }
9912752Ssam 
10035811Smarc /*
10135811Smarc  * Wait for output to drain.
10235811Smarc  */
10312752Ssam ttywait(tp)
10412752Ssam 	register struct tty *tp;
10512752Ssam {
10637584Smarc 	int s = spltty();
10712752Ssam 
10813809Ssam 	while ((tp->t_outq.c_cc || tp->t_state&TS_BUSY) &&
10937584Smarc 	    (tp->t_state&TS_CARR_ON || tp->t_cflag&CLOCAL) &&
11037584Smarc 	    tp->t_oproc) {
111903Sbill 		(*tp->t_oproc)(tp);
1125408Swnj 		tp->t_state |= TS_ASLEEP;
113903Sbill 		sleep((caddr_t)&tp->t_outq, TTOPRI);
114903Sbill 	}
1159859Ssam 	splx(s);
11639Sbill }
11739Sbill 
11839Sbill /*
1199578Ssam  * Flush all TTY queues
12039Sbill  */
12112752Ssam ttyflush(tp, rw)
1227625Ssam 	register struct tty *tp;
12339Sbill {
124903Sbill 	register s;
125903Sbill 
12617545Skarels 	s = spltty();
127903Sbill 	if (rw & FREAD) {
128903Sbill 		while (getc(&tp->t_canq) >= 0)
129903Sbill 			;
13037584Smarc 		ttwakeup(tp);
131903Sbill 	}
132903Sbill 	if (rw & FWRITE) {
13337584Smarc 		wakeup((caddr_t)&tp->t_outq); /* XXX? what about selwakeup? */
1345408Swnj 		tp->t_state &= ~TS_TTSTOP;
1355426Swnj 		(*cdevsw[major(tp->t_dev)].d_stop)(tp, rw);
136903Sbill 		while (getc(&tp->t_outq) >= 0)
137903Sbill 			;
138903Sbill 	}
139903Sbill 	if (rw & FREAD) {
140903Sbill 		while (getc(&tp->t_rawq) >= 0)
141903Sbill 			;
1429578Ssam 		tp->t_rocount = 0;
143903Sbill 		tp->t_rocol = 0;
1449578Ssam 		tp->t_state &= ~TS_LOCAL;
145903Sbill 	}
146903Sbill 	splx(s);
14739Sbill }
14839Sbill 
149903Sbill /*
150903Sbill  * Send stop character on input overflow.
151903Sbill  */
152903Sbill ttyblock(tp)
1537625Ssam 	register struct tty *tp;
15439Sbill {
155903Sbill 	register x;
1569578Ssam 
157903Sbill 	x = tp->t_rawq.c_cc + tp->t_canq.c_cc;
158903Sbill 	if (tp->t_rawq.c_cc > TTYHOG) {
15912752Ssam 		ttyflush(tp, FREAD|FWRITE);
1605408Swnj 		tp->t_state &= ~TS_TBLOCK;
161903Sbill 	}
16215118Skarels 	/*
16315118Skarels 	 * Block further input iff:
16415118Skarels 	 * Current input > threshold AND input is available to user program
16515118Skarels 	 */
16616055Skarels 	if (x >= TTYHOG/2 &&
16735811Smarc 	    (!(tp->t_lflag&ICANON)) || (tp->t_canq.c_cc > 0) &&
16835811Smarc 	    tp->t_cc[VSTOP] != _POSIX_VDISABLE) {
16935811Smarc 		if (putc(tp->t_cc[VSTOP], &tp->t_outq)==0) {
17015118Skarels 			tp->t_state |= TS_TBLOCK;
17115118Skarels 			ttstart(tp);
17215118Skarels 		}
173903Sbill 	}
17439Sbill }
17539Sbill 
17639Sbill /*
177903Sbill  * Restart typewriter output following a delay
178903Sbill  * timeout.
179903Sbill  * The name of the routine is passed to the timeout
180903Sbill  * subroutine and it is called during a clock interrupt.
181121Sbill  */
182903Sbill ttrstrt(tp)
18337584Smarc 	struct tty *tp;
184121Sbill {
185121Sbill 
1869578Ssam 	if (tp == 0)
1879578Ssam 		panic("ttrstrt");
1885408Swnj 	tp->t_state &= ~TS_TIMEOUT;
189903Sbill 	ttstart(tp);
190121Sbill }
191121Sbill 
192121Sbill /*
193903Sbill  * Start output on the typewriter. It is used from the top half
194903Sbill  * after some characters have been put on the output queue,
195903Sbill  * from the interrupt routine to transmit the next
196903Sbill  * character, and after a timeout has finished.
19739Sbill  */
198903Sbill ttstart(tp)
19937584Smarc 	struct tty *tp;
20039Sbill {
20139Sbill 
20232067Skarels 	if (tp->t_oproc)		/* kludge for pty */
203903Sbill 		(*tp->t_oproc)(tp);
20439Sbill }
20539Sbill 
20639Sbill /*
207903Sbill  * Common code for tty ioctls.
20839Sbill  */
2091780Sbill /*ARGSUSED*/
2107625Ssam ttioctl(tp, com, data, flag)
2117625Ssam 	register struct tty *tp;
2127625Ssam 	caddr_t data;
21339Sbill {
21439Sbill 	extern int nldisp;
21537554Smckusick 	int s, error;
21639Sbill 
217903Sbill 	/*
218903Sbill 	 * If the ioctl involves modification,
21917545Skarels 	 * hang if in the background.
220903Sbill 	 */
2217625Ssam 	switch (com) {
22239Sbill 
22335811Smarc 	case TIOCSETD:
224903Sbill 	case TIOCFLUSH:
22535811Smarc 	/*case TIOCSPGRP:*/
2269325Ssam 	case TIOCSTI:
22717598Sbloom 	case TIOCSWINSZ:
22835811Smarc 	case TIOCSETA:
22935811Smarc 	case TIOCSETAW:
23035811Smarc 	case TIOCSETAF:
23139407Smarc /**** these get removed ****
23235811Smarc 	case TIOCSETAS:
23335811Smarc 	case TIOCSETAWS:
23435811Smarc 	case TIOCSETAFS:
23539407Smarc /***************************/
236*39555Smarc 		while (isbackground(u.u_procp, tp) &&
23735811Smarc 		   u.u_procp->p_pgrp->pg_jobc &&
238903Sbill 		   (u.u_procp->p_flag&SVFORK) == 0 &&
23924392Skarels 		   !(u.u_procp->p_sigignore & sigmask(SIGTTOU)) &&
24024392Skarels 		   !(u.u_procp->p_sigmask & sigmask(SIGTTOU))) {
24135811Smarc 			pgsignal(u.u_procp->p_pgrp, SIGTTOU);
242903Sbill 			sleep((caddr_t)&lbolt, TTOPRI);
243903Sbill 		}
244903Sbill 		break;
245903Sbill 	}
246903Sbill 
2479578Ssam 	/*
2489578Ssam 	 * Process the ioctl.
2499578Ssam 	 */
2507625Ssam 	switch (com) {
251903Sbill 
2528556Sroot 	/* get discipline number */
25339Sbill 	case TIOCGETD:
2547625Ssam 		*(int *)data = tp->t_line;
25539Sbill 		break;
25639Sbill 
2578556Sroot 	/* set line discipline */
2587625Ssam 	case TIOCSETD: {
2597625Ssam 		register int t = *(int *)data;
26035811Smarc 		dev_t dev = tp->t_dev;
2619578Ssam 		int error = 0;
2627625Ssam 
26335811Smarc 		if ((unsigned)t >= nldisp)
26410851Ssam 			return (ENXIO);
26525584Skarels 		if (t != tp->t_line) {
26625584Skarels 			s = spltty();
26725584Skarels 			(*linesw[tp->t_line].l_close)(tp);
26825584Skarels 			error = (*linesw[t].l_open)(dev, tp);
26925584Skarels 			if (error) {
27035811Smarc 				(void)(*linesw[tp->t_line].l_open)(dev, tp);
27125584Skarels 				splx(s);
27225584Skarels 				return (error);
27325584Skarels 			}
27425584Skarels 			tp->t_line = t;
27510851Ssam 			splx(s);
27610851Ssam 		}
27739Sbill 		break;
2787625Ssam 	}
27939Sbill 
2808556Sroot 	/* prevent more opens on channel */
2815614Swnj 	case TIOCEXCL:
2825614Swnj 		tp->t_state |= TS_XCLUDE;
2835614Swnj 		break;
2845614Swnj 
2855614Swnj 	case TIOCNXCL:
2865614Swnj 		tp->t_state &= ~TS_XCLUDE;
2875614Swnj 		break;
2885614Swnj 
28939Sbill 	case TIOCHPCL:
29035811Smarc 		tp->t_cflag |= HUPCL;
29139Sbill 		break;
29239Sbill 
2933942Sbugs 	case TIOCFLUSH: {
2947625Ssam 		register int flags = *(int *)data;
2957625Ssam 
2967625Ssam 		if (flags == 0)
2973942Sbugs 			flags = FREAD|FWRITE;
2987625Ssam 		else
2997625Ssam 			flags &= FREAD|FWRITE;
30012752Ssam 		ttyflush(tp, flags);
30139Sbill 		break;
3023944Sbugs 	}
30339Sbill 
30437584Smarc 	case FIOASYNC:
30537584Smarc 		if (*(int *)data)
30637584Smarc 			tp->t_state |= TS_ASYNC;
30737584Smarc 		else
30837584Smarc 			tp->t_state &= ~TS_ASYNC;
30937584Smarc 		break;
31037584Smarc 
31137584Smarc 	case FIONBIO:
31237584Smarc 		break;	/* XXX remove */
31337584Smarc 
3148556Sroot 	/* return number of characters immediately available */
3157625Ssam 	case FIONREAD:
3167625Ssam 		*(off_t *)data = ttnread(tp);
317174Sbill 		break;
318174Sbill 
31913077Ssam 	case TIOCOUTQ:
32013077Ssam 		*(int *)data = tp->t_outq.c_cc;
32113077Ssam 		break;
32213077Ssam 
3238589Sroot 	case TIOCSTOP:
32417545Skarels 		s = spltty();
3259578Ssam 		if ((tp->t_state&TS_TTSTOP) == 0) {
3265573Swnj 			tp->t_state |= TS_TTSTOP;
3275573Swnj 			(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
3285573Swnj 		}
3297625Ssam 		splx(s);
3305573Swnj 		break;
3315573Swnj 
3328589Sroot 	case TIOCSTART:
33317545Skarels 		s = spltty();
33435811Smarc 		if ((tp->t_state&TS_TTSTOP) || (tp->t_lflag&FLUSHO)) {
3355573Swnj 			tp->t_state &= ~TS_TTSTOP;
33635811Smarc 			tp->t_lflag &= ~FLUSHO;
3375573Swnj 			ttstart(tp);
3385573Swnj 		}
3397625Ssam 		splx(s);
3405573Swnj 		break;
3415573Swnj 
3429325Ssam 	/*
3439325Ssam 	 * Simulate typing of a character at the terminal.
3449325Ssam 	 */
3459325Ssam 	case TIOCSTI:
34617183Smckusick 		if (u.u_uid && (flag & FREAD) == 0)
34717183Smckusick 			return (EPERM);
348*39555Smarc 		if (u.u_uid && !isctty(u.u_procp, tp))
3499325Ssam 			return (EACCES);
3509578Ssam 		(*linesw[tp->t_line].l_rint)(*(char *)data, tp);
3519325Ssam 		break;
3529325Ssam 
35335811Smarc 	case TIOCGETA: {
35435811Smarc 		struct termios *t = (struct termios *)data;
35512752Ssam 
35635811Smarc 		bcopy(&tp->t_termios, t, sizeof(struct termios));
35735811Smarc 		break;
35835811Smarc 	}
35935811Smarc 
36039407Smarc 	/*** THIS ALL GETS REMOVED ***/
36139407Smarc 	case JUNK_TIOCSETAS:
36239407Smarc 	case JUNK_TIOCSETAWS:
36339407Smarc 	case JUNK_TIOCSETAFS:
36439407Smarc 		((struct termios *)data)->c_cflag |= CIGNORE;
36539407Smarc 		switch(com) {
36639407Smarc 		case JUNK_TIOCSETAS:
36739407Smarc 			com = TIOCSETA;
36839407Smarc 			break;
36939407Smarc 		case JUNK_TIOCSETAWS:
37039407Smarc 			com = TIOCSETAW;
37139407Smarc 			break;
37239407Smarc 		case JUNK_TIOCSETAFS:
37339407Smarc 			com = TIOCSETAF;
37439407Smarc 			break;
37539407Smarc 		}
37639407Smarc 	/*******************************/
37739407Smarc 		/*FALLTHROGH*/
37835811Smarc 	case TIOCSETA:
37935811Smarc 	case TIOCSETAW:
38037584Smarc 	case TIOCSETAF: {
38135811Smarc 		register struct termios *t = (struct termios *)data;
38217545Skarels 		s = spltty();
38339407Smarc 		if (com == TIOCSETAW || com == TIOCSETAF) {
38439407Smarc 			ttywait(tp);
38539407Smarc 			if (com == TIOCSETAF);
38639407Smarc 				ttyflush(tp, FREAD);
38739407Smarc 		}
38839407Smarc 		if (!(t->c_cflag&CIGNORE)) {
38935811Smarc 			/*
39035811Smarc 			 * set device hardware
39135811Smarc 			 */
39237584Smarc 			if (tp->t_param && (error = (*tp->t_param)(tp, t))) {
39337584Smarc 				splx(s);
39435811Smarc 				return (error);
39537584Smarc 			} else {
39637584Smarc 				if (!(tp->t_state&TS_CARR_ON) &&
39737584Smarc 				    (tp->t_cflag&CLOCAL) &&
39837584Smarc 				    !(t->c_cflag&CLOCAL)) {
39937584Smarc 					tp->t_state &= ~TS_ISOPEN;
40037584Smarc 					tp->t_state |= TS_WOPEN;
40137584Smarc 					ttwakeup(tp);
40237584Smarc 				}
40335811Smarc 				tp->t_cflag = t->c_cflag;
40435811Smarc 				tp->t_ispeed = t->c_ispeed;
40535811Smarc 				tp->t_ospeed = t->c_ospeed;
40634492Skarels 			}
40735811Smarc 			ttsetwater(tp);
40812752Ssam 		}
40939407Smarc 		if (com != TIOCSETAF) {
41035811Smarc 			if ((t->c_lflag&ICANON) != (tp->t_lflag&ICANON))
41135811Smarc 				if (t->c_lflag&ICANON) {
41235811Smarc 					tp->t_lflag |= PENDIN;
41335811Smarc 					ttwakeup(tp);
41435811Smarc 				}
41535811Smarc 				else {
41635811Smarc 					struct clist tq;
41735811Smarc 
41835811Smarc 					catq(&tp->t_rawq, &tp->t_canq);
41935811Smarc 					tq = tp->t_rawq;
42035811Smarc 					tp->t_rawq = tp->t_canq;
42135811Smarc 					tp->t_canq = tq;
42235811Smarc 				}
42312752Ssam 		}
42435811Smarc 		tp->t_iflag = t->c_iflag;
42535811Smarc 		tp->t_oflag = t->c_oflag;
42635811Smarc 		tp->t_lflag = t->c_lflag;
42735811Smarc 		bcopy(t->c_cc, tp->t_cc, sizeof(t->c_cc));
42812752Ssam 		splx(s);
42912752Ssam 		break;
43012752Ssam 	}
43112752Ssam 
43212752Ssam 	/*
433*39555Smarc 	 * Set controlling terminal.
434*39555Smarc 	 * Session ctty vnode pointer set in vnode layer.
43534492Skarels 	 */
43635811Smarc 	case TIOCSCTTY: {
43735811Smarc 		register struct proc *p = u.u_procp;
43834492Skarels 
439*39555Smarc 		if (!SESS_LEADER(p) ||
440*39555Smarc 		   (p->p_session->s_ttyvp || tp->t_session) &&
441*39555Smarc 		   (tp->t_session != p->p_session))
44239407Smarc 			return (EPERM);
44335811Smarc 		tp->t_session = p->p_session;
444*39555Smarc 		tp->t_pgrp = p->p_pgrp;
445*39555Smarc 		p->p_session->s_ttyp = tp;
446*39555Smarc 		p->p_flag |= SCTTY;
44734492Skarels 		break;
44835811Smarc 	}
449*39555Smarc 
45034492Skarels 	/*
45135811Smarc 	 * Set terminal process group.
45217545Skarels 	 */
45318650Sbloom 	case TIOCSPGRP: {
45435811Smarc 		register struct proc *p = u.u_procp;
45535811Smarc 		register struct pgrp *pgrp = pgfind(*(int *)data);
45617545Skarels 
457*39555Smarc 		if (!isctty(p, tp))
458*39555Smarc 			return (ENOTTY);
459*39555Smarc 		else if (pgrp->pg_session != p->p_session)
460*39555Smarc 			return (EPERM);
461*39555Smarc 		tp->t_pgrp = pgrp;
46212752Ssam 		break;
46318650Sbloom 	}
46412752Ssam 
46512752Ssam 	case TIOCGPGRP:
466*39555Smarc 		if (!isctty(u.u_procp, tp))
467*39555Smarc 			return (ENOTTY);
468*39555Smarc 		*(int *)data = tp->t_pgrp ? tp->t_pgrp->pg_id : 0;
46912752Ssam 		break;
47012752Ssam 
47117598Sbloom 	case TIOCSWINSZ:
47218650Sbloom 		if (bcmp((caddr_t)&tp->t_winsize, data,
47318650Sbloom 		    sizeof (struct winsize))) {
47417598Sbloom 			tp->t_winsize = *(struct winsize *)data;
475*39555Smarc 			pgsignal(tp->t_pgrp, SIGWINCH);
47617598Sbloom 		}
47717598Sbloom 		break;
47817598Sbloom 
47917598Sbloom 	case TIOCGWINSZ:
48017598Sbloom 		*(struct winsize *)data = tp->t_winsize;
48117598Sbloom 		break;
48217598Sbloom 
48330534Skarels 	case TIOCCONS:
48430534Skarels 		if (*(int *)data) {
48530534Skarels 			if (constty != NULL)
48630534Skarels 				return (EBUSY);
48730534Skarels #ifndef	UCONSOLE
48837554Smckusick 			if (error = suser(u.u_cred, &u.u_acflag))
48937554Smckusick 				return (error);
49030534Skarels #endif
49130534Skarels 			constty = tp;
49230534Skarels 		} else if (tp == constty)
49333404Skarels 			constty = NULL;
49430534Skarels 		break;
49530534Skarels 
49635811Smarc #ifdef COMPAT_43
49735811Smarc 	case TIOCGETP:
49835811Smarc 	case TIOCSETP:
49935811Smarc 	case TIOCSETN:
50035811Smarc 	case TIOCGETC:
50135811Smarc 	case TIOCSETC:
50235811Smarc 	case TIOCSLTC:
50335811Smarc 	case TIOCGLTC:
50435811Smarc 	case TIOCLBIS:
50535811Smarc 	case TIOCLBIC:
50635811Smarc 	case TIOCLSET:
50735811Smarc 	case TIOCLGET:
50839407Smarc 	case OTIOCGETD:
50939407Smarc 	case OTIOCSETD:
51035811Smarc 		return(ttcompat(tp, com, data, flag));
51135811Smarc #endif
51235811Smarc 
51339Sbill 	default:
5148556Sroot 		return (-1);
51539Sbill 	}
5168556Sroot 	return (0);
51739Sbill }
5184484Swnj 
5194484Swnj ttnread(tp)
5204484Swnj 	struct tty *tp;
5214484Swnj {
5224484Swnj 	int nread = 0;
5234484Swnj 
52435811Smarc 	if (tp->t_lflag & PENDIN)
5254484Swnj 		ttypend(tp);
5264484Swnj 	nread = tp->t_canq.c_cc;
52735811Smarc 	if ((tp->t_lflag & ICANON) == 0)
5284484Swnj 		nread += tp->t_rawq.c_cc;
5294484Swnj 	return (nread);
5304484Swnj }
5314484Swnj 
5325408Swnj ttselect(dev, rw)
5334484Swnj 	dev_t dev;
5345408Swnj 	int rw;
5354484Swnj {
5364484Swnj 	register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)];
5374484Swnj 	int nread;
53817545Skarels 	int s = spltty();
5394484Swnj 
5405408Swnj 	switch (rw) {
5414484Swnj 
5424484Swnj 	case FREAD:
5434484Swnj 		nread = ttnread(tp);
54437584Smarc 		if (nread > 0 ||
54537584Smarc 		   (!(tp->t_cflag&CLOCAL) && !(tp->t_state&TS_CARR_ON)))
5465408Swnj 			goto win;
5474938Swnj 		if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait)
5485408Swnj 			tp->t_state |= TS_RCOLL;
5494484Swnj 		else
5504484Swnj 			tp->t_rsel = u.u_procp;
5515408Swnj 		break;
5524484Swnj 
5535408Swnj 	case FWRITE:
55435811Smarc 		if (tp->t_outq.c_cc <= tp->t_lowat)
5555408Swnj 			goto win;
5565408Swnj 		if (tp->t_wsel && tp->t_wsel->p_wchan == (caddr_t)&selwait)
5575408Swnj 			tp->t_state |= TS_WCOLL;
5585408Swnj 		else
5595408Swnj 			tp->t_wsel = u.u_procp;
5605408Swnj 		break;
5614484Swnj 	}
5625408Swnj 	splx(s);
5635408Swnj 	return (0);
5645408Swnj win:
5655408Swnj 	splx(s);
5665408Swnj 	return (1);
5674484Swnj }
5687436Skre 
5697502Sroot /*
57025391Skarels  * Initial open of tty, or (re)entry to line discipline.
5717502Sroot  */
5727502Sroot ttyopen(dev, tp)
5737625Ssam 	dev_t dev;
5747625Ssam 	register struct tty *tp;
5757502Sroot {
5767502Sroot 
5777502Sroot 	tp->t_dev = dev;
57835811Smarc 
5797502Sroot 	tp->t_state &= ~TS_WOPEN;
58017545Skarels 	if ((tp->t_state & TS_ISOPEN) == 0) {
58117545Skarels 		tp->t_state |= TS_ISOPEN;
58217598Sbloom 		bzero((caddr_t)&tp->t_winsize, sizeof(tp->t_winsize));
58317545Skarels 	}
5848556Sroot 	return (0);
5857502Sroot }
5867502Sroot 
5877502Sroot /*
58825391Skarels  * "close" a line discipline
58925391Skarels  */
59025391Skarels ttylclose(tp)
59125391Skarels 	register struct tty *tp;
59225391Skarels {
59325391Skarels 
59425391Skarels 	ttywflush(tp);
59525391Skarels }
59625391Skarels 
59725391Skarels /*
5987502Sroot  * clean tp on last close
5997502Sroot  */
6007502Sroot ttyclose(tp)
6017625Ssam 	register struct tty *tp;
6027502Sroot {
60330534Skarels 	if (constty == tp)
60430534Skarels 		constty = NULL;
60525391Skarels 	ttyflush(tp, FREAD|FWRITE);
606*39555Smarc 	tp->t_session = NULL;
607*39555Smarc 	tp->t_pgrp = NULL;
6087502Sroot 	tp->t_state = 0;
6097502Sroot }
6107502Sroot 
6117502Sroot /*
61225391Skarels  * Handle modem control transition on a tty.
61325391Skarels  * Flag indicates new state of carrier.
61425391Skarels  * Returns 0 if the line should be turned off, otherwise 1.
61525391Skarels  */
61625391Skarels ttymodem(tp, flag)
61725391Skarels 	register struct tty *tp;
61825391Skarels {
61925391Skarels 
62035811Smarc 	if ((tp->t_state&TS_WOPEN) == 0 && (tp->t_lflag & MDMBUF)) {
62125391Skarels 		/*
62225391Skarels 		 * MDMBUF: do flow control according to carrier flag
62325391Skarels 		 */
62425391Skarels 		if (flag) {
62525391Skarels 			tp->t_state &= ~TS_TTSTOP;
62625391Skarels 			ttstart(tp);
62725391Skarels 		} else if ((tp->t_state&TS_TTSTOP) == 0) {
62825391Skarels 			tp->t_state |= TS_TTSTOP;
62925391Skarels 			(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
63025391Skarels 		}
63125391Skarels 	} else if (flag == 0) {
63225391Skarels 		/*
63325391Skarels 		 * Lost carrier.
63425391Skarels 		 */
63525391Skarels 		tp->t_state &= ~TS_CARR_ON;
63625391Skarels 		if (tp->t_state & TS_ISOPEN) {
63735811Smarc 			if ((tp->t_lflag & NOHANG) == 0) {
638*39555Smarc 				pgsignal(tp->t_pgrp, SIGHUP);
639*39555Smarc 				pgsignal(tp->t_pgrp, SIGCONT);
64025391Skarels 				ttyflush(tp, FREAD|FWRITE);
64125391Skarels 				return (0);
64225391Skarels 			}
64325391Skarels 		}
64425391Skarels 	} else {
64525391Skarels 		/*
64625391Skarels 		 * Carrier now on.
64725391Skarels 		 */
64825391Skarels 		tp->t_state |= TS_CARR_ON;
64937584Smarc 		ttwakeup(tp);
65025391Skarels 	}
65125391Skarels 	return (1);
65225391Skarels }
65325391Skarels 
65425391Skarels /*
65525404Skarels  * Default modem control routine (for other line disciplines).
65625404Skarels  * Return argument flag, to turn off device on carrier drop.
65725404Skarels  */
65825415Skarels nullmodem(tp, flag)
65925415Skarels 	register struct tty *tp;
66025404Skarels 	int flag;
66125404Skarels {
66225404Skarels 
66325404Skarels 	if (flag)
66425404Skarels 		tp->t_state |= TS_CARR_ON;
66539407Smarc 	else {
66625404Skarels 		tp->t_state &= ~TS_CARR_ON;
66739407Smarc 		if ((tp->t_lflag & NOHANG) == 0)
668*39555Smarc 			pgsignal(tp->t_pgrp, SIGHUP);
66939407Smarc 	}
67025404Skarels 	return (flag);
67125404Skarels }
67225404Skarels 
67325404Skarels /*
6747502Sroot  * reinput pending characters after state switch
67517545Skarels  * call at spltty().
6767502Sroot  */
6777502Sroot ttypend(tp)
6787625Ssam 	register struct tty *tp;
6797502Sroot {
6807502Sroot 	struct clist tq;
6817502Sroot 	register c;
6827502Sroot 
68335811Smarc 	tp->t_lflag &= ~PENDIN;
6849578Ssam 	tp->t_state |= TS_TYPEN;
6857502Sroot 	tq = tp->t_rawq;
6867502Sroot 	tp->t_rawq.c_cc = 0;
6877502Sroot 	tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0;
6887502Sroot 	while ((c = getc(&tq)) >= 0)
6897502Sroot 		ttyinput(c, tp);
6909578Ssam 	tp->t_state &= ~TS_TYPEN;
6917502Sroot }
6927502Sroot 
6937502Sroot /*
69435811Smarc  *
6959578Ssam  * Place a character on raw TTY input queue,
6969578Ssam  * putting in delimiters and waking up top
6979578Ssam  * half as needed.  Also echo if required.
6989578Ssam  * The arguments are the character and the
6999578Ssam  * appropriate tty structure.
7007502Sroot  */
7017502Sroot ttyinput(c, tp)
7027625Ssam 	register c;
7037625Ssam 	register struct tty *tp;
7047502Sroot {
70535811Smarc 	register int iflag = tp->t_iflag;
70635811Smarc 	register int lflag = tp->t_lflag;
70735811Smarc 	register u_char *cc = tp->t_cc;
70835811Smarc 	int i, err;
7097502Sroot 
7109578Ssam 	/*
7119578Ssam 	 * If input is pending take it first.
7129578Ssam 	 */
71335811Smarc 	if (lflag&PENDIN)
7147502Sroot 		ttypend(tp);
71535811Smarc 	/*
71635811Smarc 	 * Gather stats.
71735811Smarc 	 */
7187502Sroot 	tk_nin++;
71935811Smarc 	if (lflag&ICANON) {
72035811Smarc 		tk_cancc++;
72135811Smarc 		tp->t_cancc++;
72235811Smarc 	} else {
72335811Smarc 		tk_rawcc++;
72435811Smarc 		tp->t_rawcc++;
72535811Smarc 	}
7269578Ssam 	/*
72735811Smarc 	 * Handle exceptional conditions (break, parity, framing).
7289578Ssam 	 */
72935811Smarc 	if (err = (c&TTY_ERRORMASK)) {
73035811Smarc 		c &= ~TTY_ERRORMASK;
73135811Smarc 		if (err&TTY_FE && !c) {		/* break */
73235811Smarc 			if (iflag&IGNBRK)
73335811Smarc 				goto endcase;
73435811Smarc 			else if (iflag&BRKINT && lflag&ISIG &&
73535811Smarc 				(cc[VINTR] != _POSIX_VDISABLE))
73635811Smarc 				c = cc[VINTR];
73735811Smarc 			else {
73835811Smarc 				c = 0;
73935811Smarc 				if (iflag&PARMRK)
74035811Smarc 					goto parmrk;
74135811Smarc 			}
74235811Smarc 		} else if ((err&TTY_PE && iflag&INPCK) || err&TTY_FE) {
74335811Smarc 			if (iflag&IGNPAR)
74435811Smarc 				goto endcase;
74535811Smarc 			else if (iflag&PARMRK) {
74635811Smarc parmrk:
74735811Smarc 				putc(0377|TTY_QUOTE, &tp->t_rawq);
74835811Smarc 				putc(0|TTY_QUOTE, &tp->t_rawq);
74935811Smarc 				putc(c|TTY_QUOTE, &tp->t_rawq);
75035811Smarc 				goto endcase;
75135811Smarc 			} else
75235811Smarc 				c = 0;
7537502Sroot 		}
7549578Ssam 	}
7559578Ssam 	/*
75635811Smarc 	 * In tandem mode, check high water mark.
7579578Ssam 	 */
75835811Smarc 	if (iflag&IXOFF)
75935811Smarc 		ttyblock(tp);
76035811Smarc 	if ((tp->t_state&TS_TYPEN) == 0 && (iflag&ISTRIP))
7619578Ssam 		c &= 0177;
7629578Ssam 	/*
7639578Ssam 	 * Check for literal nexting very first
7649578Ssam 	 */
7659578Ssam 	if (tp->t_state&TS_LNCH) {
76635811Smarc 		c |= TTY_QUOTE;
7679578Ssam 		tp->t_state &= ~TS_LNCH;
7689578Ssam 	}
7699578Ssam 	/*
7709578Ssam 	 * Scan for special characters.  This code
7719578Ssam 	 * is really just a big case statement with
7729578Ssam 	 * non-constant cases.  The bottom of the
7739578Ssam 	 * case statement is labeled ``endcase'', so goto
7749578Ssam 	 * it after a case match, or similar.
7759578Ssam 	 */
77635811Smarc 	/*
77735811Smarc 	 * Control chars which aren't controlled
77835811Smarc 	 * by ICANON, ISIG, or IXON.
77935811Smarc 	 */
78039407Smarc 	if (lflag&IEXTEN) {
78135811Smarc 		if (CCEQ(cc[VLNEXT],c)) {
78235811Smarc 			if (lflag&ECHO) {
78335811Smarc 				if (lflag&ECHOE)
78435811Smarc 					ttyout("^\b", tp);
78535811Smarc 				else
78635811Smarc 					ttyecho(c, tp);
78735811Smarc 			}
7889578Ssam 			tp->t_state |= TS_LNCH;
7899578Ssam 			goto endcase;
7909578Ssam 		}
79135811Smarc 		if (CCEQ(cc[VFLUSHO],c)) {
79235811Smarc 			if (lflag&FLUSHO)
79335811Smarc 				tp->t_lflag &= ~FLUSHO;
7947502Sroot 			else {
79512752Ssam 				ttyflush(tp, FWRITE);
7967502Sroot 				ttyecho(c, tp);
7979578Ssam 				if (tp->t_rawq.c_cc + tp->t_canq.c_cc)
7987502Sroot 					ttyretype(tp);
79935811Smarc 				tp->t_lflag |= FLUSHO;
8007502Sroot 			}
8019578Ssam 			goto startoutput;
8029578Ssam 		}
80335811Smarc 	}
80435811Smarc 	/*
80535811Smarc 	 * Signals.
80635811Smarc 	 */
80735811Smarc 	if (lflag&ISIG) {
80835811Smarc 		if (CCEQ(cc[VINTR], c) || CCEQ(cc[VQUIT], c)) {
80935811Smarc 			if ((lflag&NOFLSH) == 0)
81035811Smarc 				ttyflush(tp, FREAD|FWRITE);
81135811Smarc 			ttyecho(c, tp);
812*39555Smarc 			pgsignal(tp->t_pgrp,
813*39555Smarc 					CCEQ(cc[VINTR],c) ? SIGINT : SIGQUIT);
81435811Smarc 			goto endcase;
81535811Smarc 		}
81635811Smarc 		if (CCEQ(cc[VSUSP],c)) {
81735811Smarc 			if ((lflag&NOFLSH) == 0)
81812752Ssam 				ttyflush(tp, FREAD);
8199578Ssam 			ttyecho(c, tp);
820*39555Smarc 			pgsignal(tp->t_pgrp, SIGTSTP);
8219578Ssam 			goto endcase;
8229578Ssam 		}
82339407Smarc 		if (CCEQ(cc[VINFO],c)) {
82439407Smarc 			ttyinfo(tp);
82539407Smarc 			goto endcase;
82639407Smarc 		}
8279578Ssam 	}
8289578Ssam 	/*
8299578Ssam 	 * Handle start/stop characters.
8309578Ssam 	 */
83135811Smarc 	if (iflag&IXON) {
83235811Smarc 		if (CCEQ(cc[VSTOP],c)) {
83335811Smarc 			if ((tp->t_state&TS_TTSTOP) == 0) {
83435811Smarc 				tp->t_state |= TS_TTSTOP;
83535811Smarc 				(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
83635811Smarc 				return;
83735811Smarc 			}
83835811Smarc 			if (!CCEQ(cc[VSTART], c))
83935811Smarc 				return;
84035811Smarc 			/*
84135811Smarc 			 * if VSTART == VSTOP then toggle
84235811Smarc 			 */
84335811Smarc 			goto endcase;
8449578Ssam 		}
84535811Smarc 		if (CCEQ(cc[VSTART], c))
84635811Smarc 			goto restartoutput;
8479578Ssam 	}
8489578Ssam 	/*
84935811Smarc 	 * IGNCR, ICRNL, & INLCR
8509578Ssam 	 */
85135811Smarc 	if (c == '\r') {
85235811Smarc 		if (iflag&IGNCR)
85335811Smarc 			goto endcase;
85435811Smarc 		else if (iflag&ICRNL)
85535811Smarc 			c = '\n';
8569578Ssam 	}
85735811Smarc 	else if (c == '\n' && iflag&INLCR)
85835811Smarc 		c = '\r';
8599578Ssam 	/*
86035811Smarc 	 * Non canonical mode; don't process line editing
8619578Ssam 	 * characters; check high water mark for wakeup.
86235811Smarc 	 *
8639578Ssam 	 */
86435811Smarc 	if (!(lflag&ICANON)) {
8659578Ssam 		if (tp->t_rawq.c_cc > TTYHOG) {
86635811Smarc 			if (iflag&IMAXBEL) {
86735811Smarc 				if (tp->t_outq.c_cc < tp->t_hiwat)
86835811Smarc 					(void) ttyoutput(CTRL('g'), tp);
86935811Smarc 			} else
87035811Smarc 				ttyflush(tp, FREAD | FWRITE);
87135811Smarc 		} else {
87235811Smarc 			if (putc(c, &tp->t_rawq) >= 0) {
87335811Smarc 				ttwakeup(tp);
87435811Smarc 				ttyecho(c, tp);
87535811Smarc 			}
8767502Sroot 		}
8779578Ssam 		goto endcase;
8789578Ssam 	}
8799578Ssam 	/*
88035811Smarc 	 * From here on down canonical mode character
8819578Ssam 	 * processing takes place.
8829578Ssam 	 */
88335811Smarc 	/*
88435811Smarc 	 * erase (^H / ^?)
88535811Smarc 	 */
88639407Smarc 	if (CCEQ(cc[VERASE], c)) {
8879578Ssam 		if (tp->t_rawq.c_cc)
8889578Ssam 			ttyrub(unputc(&tp->t_rawq), tp);
8899578Ssam 		goto endcase;
8909578Ssam 	}
89135811Smarc 	/*
89235811Smarc 	 * kill (^U)
89335811Smarc 	 */
89435811Smarc 	if (CCEQ(cc[VKILL], c)) {
89537584Smarc 		if (lflag&ECHOKE && tp->t_rawq.c_cc == tp->t_rocount &&
89637584Smarc 		    !(lflag&ECHOPRT)) {
8979578Ssam 			while (tp->t_rawq.c_cc)
8989578Ssam 				ttyrub(unputc(&tp->t_rawq), tp);
8999578Ssam 		} else {
9009578Ssam 			ttyecho(c, tp);
90135811Smarc 			if (lflag&ECHOK || lflag&ECHOKE)
90235811Smarc 				ttyecho('\n', tp);
9039578Ssam 			while (getc(&tp->t_rawq) > 0)
9049578Ssam 				;
9059578Ssam 			tp->t_rocount = 0;
9069578Ssam 		}
9079578Ssam 		tp->t_state &= ~TS_LOCAL;
9089578Ssam 		goto endcase;
9099578Ssam 	}
9109578Ssam 	/*
91135811Smarc 	 * word erase (^W)
9129578Ssam 	 */
91335811Smarc 	if (CCEQ(cc[VWERASE], c)) {
91435811Smarc 		int ctype;
91535811Smarc 
91635811Smarc #define CTYPE(c) ((lflag&ALTWERASE) ? (partab[(c)&TTY_CHARMASK]&0100) : 0)
91735811Smarc 		/*
91835811Smarc 		 * erase whitespace
91935811Smarc 		 */
92035811Smarc 		while ((c = unputc(&tp->t_rawq)) == ' ' || c == '\t')
92135811Smarc 			ttyrub(c, tp);
92235811Smarc 		if (c == -1)
92334492Skarels 			goto endcase;
92435811Smarc 		/*
92535811Smarc 		 * special case last char of token
92635811Smarc 		 */
92735811Smarc 		ttyrub(c, tp);
92835811Smarc 		c = unputc(&tp->t_rawq);
92935811Smarc 		if (c == -1 || c == ' ' || c == '\t') {
93035811Smarc 			if (c != -1)
93135811Smarc 				(void) putc(c, &tp->t_rawq);
93234492Skarels 			goto endcase;
93334492Skarels 		}
93435811Smarc 		/*
93535811Smarc 		 * erase rest of token
93635811Smarc 		 */
93735811Smarc 		ctype = CTYPE(c);
93835811Smarc 		do {
93935811Smarc 			ttyrub(c, tp);
94035811Smarc 			c = unputc(&tp->t_rawq);
94135811Smarc 			if (c == -1)
94235811Smarc 				goto endcase;
94335811Smarc 		} while (c != ' ' && c != '\t' && CTYPE(c) == ctype);
94435811Smarc 		(void) putc(c, &tp->t_rawq);
94535811Smarc 		goto endcase;
94635811Smarc #undef CTYPE
9479578Ssam 	}
9489578Ssam 	/*
94935811Smarc 	 * reprint line (^R)
95035811Smarc 	 */
95135811Smarc 	if (CCEQ(cc[VREPRINT], c)) {
95235811Smarc 		ttyretype(tp);
95335811Smarc 		goto endcase;
95435811Smarc 	}
95535811Smarc 	/*
9569578Ssam 	 * Check for input buffer overflow
9579578Ssam 	 */
95810391Ssam 	if (tp->t_rawq.c_cc+tp->t_canq.c_cc >= TTYHOG) {
95935811Smarc 		if (iflag&IMAXBEL) {
96035811Smarc 			if (tp->t_outq.c_cc < tp->t_hiwat)
96135811Smarc 				(void) ttyoutput(CTRL('g'), tp);
96235811Smarc 		} else
96335811Smarc 			ttyflush(tp, FREAD | FWRITE);
9649578Ssam 		goto endcase;
96510391Ssam 	}
9669578Ssam 	/*
9679578Ssam 	 * Put data char in q for user and
9689578Ssam 	 * wakeup on seeing a line delimiter.
9699578Ssam 	 */
9709578Ssam 	if (putc(c, &tp->t_rawq) >= 0) {
97135811Smarc 		if (ttbreakc(c)) {
9729578Ssam 			tp->t_rocount = 0;
9739578Ssam 			catq(&tp->t_rawq, &tp->t_canq);
9747502Sroot 			ttwakeup(tp);
9759578Ssam 		} else if (tp->t_rocount++ == 0)
9769578Ssam 			tp->t_rocol = tp->t_col;
9779578Ssam 		if (tp->t_state&TS_ERASE) {
97835811Smarc 			/*
97935811Smarc 			 * end of prterase \.../
98035811Smarc 			 */
9819578Ssam 			tp->t_state &= ~TS_ERASE;
9829578Ssam 			(void) ttyoutput('/', tp);
9839578Ssam 		}
9849578Ssam 		i = tp->t_col;
9857502Sroot 		ttyecho(c, tp);
98635811Smarc 		if (CCEQ(cc[VEOF], c) && lflag&ECHO) {
98735811Smarc 			/*
98835811Smarc 			 * Place the cursor over the '^' of the ^D.
98935811Smarc 			 */
9909578Ssam 			i = MIN(2, tp->t_col - i);
9919578Ssam 			while (i > 0) {
9929578Ssam 				(void) ttyoutput('\b', tp);
9939578Ssam 				i--;
9949578Ssam 			}
9959578Ssam 		}
9967502Sroot 	}
9979578Ssam endcase:
9989578Ssam 	/*
99935811Smarc 	 * IXANY means allow any character to restart output.
10009578Ssam 	 */
100135811Smarc 	if ((tp->t_state&TS_TTSTOP) && !(iflag&IXANY)
100235811Smarc 	    && cc[VSTART] != cc[VSTOP])
10037502Sroot 		return;
10049578Ssam restartoutput:
10057502Sroot 	tp->t_state &= ~TS_TTSTOP;
100635811Smarc 	tp->t_lflag &= ~FLUSHO;
10079578Ssam startoutput:
10087502Sroot 	ttstart(tp);
10097502Sroot }
10107502Sroot 
10117502Sroot /*
10129578Ssam  * Put character on TTY output queue, adding delays,
10137502Sroot  * expanding tabs, and handling the CR/NL bit.
10149578Ssam  * This is called both from the top half for output,
10159578Ssam  * and from interrupt level for echoing.
10167502Sroot  * The arguments are the character and the tty structure.
10177502Sroot  * Returns < 0 if putc succeeds, otherwise returns char to resend
10187502Sroot  * Must be recursive.
10197502Sroot  */
10207502Sroot ttyoutput(c, tp)
10217502Sroot 	register c;
10227502Sroot 	register struct tty *tp;
10237502Sroot {
10247502Sroot 	register char *colp;
10257502Sroot 	register ctype;
102635811Smarc 	register long oflag = tp->t_oflag;
102735811Smarc 
102835811Smarc 	if (!(oflag&OPOST)) {
102935811Smarc 		if (tp->t_lflag&FLUSHO)
10307502Sroot 			return (-1);
10317502Sroot 		if (putc(c, &tp->t_outq))
10327625Ssam 			return (c);
10337502Sroot 		tk_nout++;
103435811Smarc 		tp->t_outcc++;
10357502Sroot 		return (-1);
10367502Sroot 	}
103735811Smarc 	c &= TTY_CHARMASK;
10387502Sroot 	/*
10397502Sroot 	 * Turn tabs to spaces as required
10407502Sroot 	 */
104135811Smarc 	if (c == '\t' && oflag&OXTABS ) {
10427502Sroot 		register int s;
10437502Sroot 
10447502Sroot 		c = 8 - (tp->t_col&7);
104535811Smarc 		if ((tp->t_lflag&FLUSHO) == 0) {
104617545Skarels 			s = spltty();		/* don't interrupt tabs */
10477502Sroot 			c -= b_to_q("        ", c, &tp->t_outq);
10487502Sroot 			tk_nout += c;
104935811Smarc 			tp->t_outcc += c;
10507502Sroot 			splx(s);
10517502Sroot 		}
10527502Sroot 		tp->t_col += c;
10537502Sroot 		return (c ? -1 : '\t');
10547502Sroot 	}
105535811Smarc 	if (c == CEOT && oflag&ONOEOT)
105635811Smarc 		return(-1);
10577502Sroot 	tk_nout++;
105835811Smarc 	tp->t_outcc++;
10597502Sroot 	/*
10607502Sroot 	 * turn <nl> to <cr><lf> if desired.
10617502Sroot 	 */
106235811Smarc 	if (c == '\n' && (tp->t_oflag&ONLCR) && ttyoutput('\r', tp) >= 0)
10637502Sroot 		return (c);
106435811Smarc 	if ((tp->t_lflag&FLUSHO) == 0 && putc(c, &tp->t_outq))
106535811Smarc 		return (c);
10667502Sroot 	/*
10677502Sroot 	 * Calculate delays.
10687502Sroot 	 * The numbers here represent clock ticks
10697502Sroot 	 * and are not necessarily optimal for all terminals.
10709578Ssam 	 *
10719578Ssam 	 * SHOULD JUST ALLOW USER TO SPECIFY DELAYS
107235811Smarc 	 *
107335811Smarc 	 * (actually, should THROW AWAY terminals which need delays)
10747502Sroot 	 */
10757502Sroot 	colp = &tp->t_col;
10767502Sroot 	ctype = partab[c];
10777502Sroot 	c = 0;
10787502Sroot 	switch (ctype&077) {
10797502Sroot 
10807502Sroot 	case ORDINARY:
10817502Sroot 		(*colp)++;
10827502Sroot 
10837502Sroot 	case CONTROL:
10847502Sroot 		break;
10857502Sroot 
10867502Sroot 	case BACKSPACE:
10877502Sroot 		if (*colp)
10887502Sroot 			(*colp)--;
10897502Sroot 		break;
10907502Sroot 
109113821Ssam 	/*
109213821Ssam 	 * This macro is close enough to the correct thing;
109313821Ssam 	 * it should be replaced by real user settable delays
109413821Ssam 	 * in any event...
109513821Ssam 	 */
109613821Ssam #define	mstohz(ms)	(((ms) * hz) >> 10)
10977502Sroot 	case NEWLINE:
10987502Sroot 		ctype = (tp->t_flags >> 8) & 03;
10997625Ssam 		if (ctype == 1) { /* tty 37 */
110026357Skarels 			if (*colp > 0) {
110126357Skarels 				c = (((unsigned)*colp) >> 4) + 3;
110226357Skarels 				if ((unsigned)c > 6)
110326357Skarels 					c = 6;
110426357Skarels 			}
11059578Ssam 		} else if (ctype == 2) /* vt05 */
110613821Ssam 			c = mstohz(100);
11077502Sroot 		*colp = 0;
11087502Sroot 		break;
11097502Sroot 
11107502Sroot 	case TAB:
11117502Sroot 		ctype = (tp->t_flags >> 10) & 03;
11127625Ssam 		if (ctype == 1) { /* tty 37 */
11137502Sroot 			c = 1 - (*colp | ~07);
11147625Ssam 			if (c < 5)
11157502Sroot 				c = 0;
11167502Sroot 		}
11177502Sroot 		*colp |= 07;
11187502Sroot 		(*colp)++;
11197502Sroot 		break;
11207502Sroot 
11217502Sroot 	case VTAB:
11229578Ssam 		if (tp->t_flags&VTDELAY) /* tty 37 */
11237502Sroot 			c = 0177;
11247502Sroot 		break;
11257502Sroot 
11267502Sroot 	case RETURN:
11277502Sroot 		ctype = (tp->t_flags >> 12) & 03;
11289578Ssam 		if (ctype == 1) /* tn 300 */
112913821Ssam 			c = mstohz(83);
11309578Ssam 		else if (ctype == 2) /* ti 700 */
113113821Ssam 			c = mstohz(166);
11329578Ssam 		else if (ctype == 3) { /* concept 100 */
11337502Sroot 			int i;
11349578Ssam 
11357502Sroot 			if ((i = *colp) >= 0)
11369578Ssam 				for (; i < 9; i++)
11377502Sroot 					(void) putc(0177, &tp->t_outq);
11387502Sroot 		}
11397502Sroot 		*colp = 0;
11407502Sroot 	}
114135811Smarc 	if (c && (tp->t_lflag&FLUSHO) == 0)
114235811Smarc 		(void) putc(c|TTY_QUOTE, &tp->t_outq);
11437502Sroot 	return (-1);
11447502Sroot }
114513821Ssam #undef mstohz
11467502Sroot 
11477502Sroot /*
11487502Sroot  * Called from device's read routine after it has
11497502Sroot  * calculated the tty-structure given as argument.
11507502Sroot  */
115137584Smarc ttread(tp, uio, flag)
11527625Ssam 	register struct tty *tp;
11537722Swnj 	struct uio *uio;
11547502Sroot {
11557502Sroot 	register struct clist *qp;
115635811Smarc 	register int c;
115735811Smarc 	register long lflag = tp->t_lflag;
115835811Smarc 	register u_char *cc = tp->t_cc;
11599859Ssam 	int s, first, error = 0;
11607502Sroot 
11617502Sroot loop:
116237584Smarc 	s = spltty();
11639578Ssam 	/*
116437584Smarc 	 * take pending input first
11659578Ssam 	 */
116635811Smarc 	if (lflag&PENDIN)
11677502Sroot 		ttypend(tp);
116837584Smarc 	/*
116937584Smarc 	 * Handle carrier.
117037584Smarc 	 */
117137584Smarc 	if (!(tp->t_state&TS_CARR_ON) && !(tp->t_cflag&CLOCAL)) {
117237584Smarc 		if (tp->t_state&TS_ISOPEN) {
117337584Smarc 			splx(s);
117437584Smarc 			return (0);	/* EOF */
117537728Smckusick 		} else if (flag & IO_NDELAY) {
117637584Smarc 			splx(s);
117737584Smarc 			return (EWOULDBLOCK);
117837584Smarc 		} else {
117937584Smarc 			/*
118037584Smarc 			 * sleep awaiting carrier
118137584Smarc 			 */
118237584Smarc 			sleep((caddr_t)&tp->t_rawq, TTIPRI);
118337584Smarc 			splx(s);
118437584Smarc 			goto loop;
118537584Smarc 		}
118637584Smarc 	}
11879859Ssam 	splx(s);
11889578Ssam 	/*
11899578Ssam 	 * Hang process if it's in the background.
11909578Ssam 	 */
1191*39555Smarc 	if (isbackground(u.u_procp, tp)) {
119224392Skarels 		if ((u.u_procp->p_sigignore & sigmask(SIGTTIN)) ||
119324392Skarels 		   (u.u_procp->p_sigmask & sigmask(SIGTTIN)) ||
119435811Smarc 		    u.u_procp->p_flag&SVFORK || u.u_procp->p_pgrp->pg_jobc == 0)
11958520Sroot 			return (EIO);
119635811Smarc 		pgsignal(u.u_procp->p_pgrp, SIGTTIN);
11977502Sroot 		sleep((caddr_t)&lbolt, TTIPRI);
119823165Sbloom 		goto loop;
11997502Sroot 	}
12009578Ssam 	/*
120135811Smarc 	 * If canonical, use the canonical queue,
120235811Smarc 	 * else use the raw queue.
120337584Smarc 	 *
120437584Smarc 	 * XXX - should get rid of canonical queue.
120537584Smarc 	 * (actually, should get rid of clists...)
12069578Ssam 	 */
120735811Smarc 	qp = lflag&ICANON ? &tp->t_canq : &tp->t_rawq;
12089578Ssam 	/*
12099578Ssam 	 * No input, sleep on rawq awaiting hardware
12109578Ssam 	 * receipt and notification.
12119578Ssam 	 */
121217545Skarels 	s = spltty();
12139578Ssam 	if (qp->c_cc <= 0) {
121437584Smarc 		/** XXX ??? ask mike why TS_CARR_ON was (once) necessary here
12159578Ssam 		if ((tp->t_state&TS_CARR_ON) == 0 ||
12169578Ssam 		    (tp->t_state&TS_NBIO)) {
12179859Ssam 			splx(s);
12189578Ssam 			return (EWOULDBLOCK);
12197502Sroot 		}
122037584Smarc 		**/
122137728Smckusick 		if (flag & IO_NDELAY) {
122237584Smarc 			splx(s);
122337584Smarc 			return (EWOULDBLOCK);
122437584Smarc 		}
12259578Ssam 		sleep((caddr_t)&tp->t_rawq, TTIPRI);
12269859Ssam 		splx(s);
12279578Ssam 		goto loop;
12289578Ssam 	}
12299859Ssam 	splx(s);
12309578Ssam 	/*
123135811Smarc 	 * Input present, check for input mapping and processing.
12329578Ssam 	 */
12339578Ssam 	first = 1;
12349578Ssam 	while ((c = getc(qp)) >= 0) {
12359578Ssam 		/*
123635811Smarc 		 * delayed suspend (^Y)
12379578Ssam 		 */
123835811Smarc 		if (CCEQ(cc[VDSUSP], c) && lflag&ISIG) {
1239*39555Smarc 			pgsignal(tp->t_pgrp, SIGTSTP);
12409578Ssam 			if (first) {
12419578Ssam 				sleep((caddr_t)&lbolt, TTIPRI);
12429578Ssam 				goto loop;
12439578Ssam 			}
12449578Ssam 			break;
12457502Sroot 		}
12469578Ssam 		/*
124735811Smarc 		 * Interpret EOF only in canonical mode.
12489578Ssam 		 */
124935811Smarc 		if (CCEQ(cc[VEOF], c) && lflag&ICANON)
12509578Ssam 			break;
12519578Ssam 		/*
12529578Ssam 		 * Give user character.
12539578Ssam 		 */
125435811Smarc  		error = ureadc(c , uio);
12559578Ssam 		if (error)
12569578Ssam 			break;
125714938Smckusick  		if (uio->uio_resid == 0)
12589578Ssam 			break;
12599578Ssam 		/*
126035811Smarc 		 * In canonical mode check for a "break character"
12619578Ssam 		 * marking the end of a "line of input".
12629578Ssam 		 */
126335811Smarc 		if (lflag&ICANON && ttbreakc(c)) {
12649578Ssam 			break;
126535811Smarc 		}
12669578Ssam 		first = 0;
12677502Sroot 	}
12689578Ssam 	/*
12699578Ssam 	 * Look to unblock output now that (presumably)
12709578Ssam 	 * the input queue has gone down.
12719578Ssam 	 */
127235811Smarc 	if (tp->t_state&TS_TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) {
127335811Smarc 		if (cc[VSTART] != _POSIX_VDISABLE
127435811Smarc 		   && putc(cc[VSTART], &tp->t_outq) == 0) {
12757502Sroot 			tp->t_state &= ~TS_TBLOCK;
12767502Sroot 			ttstart(tp);
12777502Sroot 		}
127835811Smarc 	}
12798520Sroot 	return (error);
12807502Sroot }
12817502Sroot 
12827502Sroot /*
128325391Skarels  * Check the output queue on tp for space for a kernel message
128425391Skarels  * (from uprintf/tprintf).  Allow some space over the normal
128525391Skarels  * hiwater mark so we don't lose messages due to normal flow
128625391Skarels  * control, but don't let the tty run amok.
128730695Skarels  * Sleeps here are not interruptible, but we return prematurely
128830695Skarels  * if new signals come in.
128925391Skarels  */
129025391Skarels ttycheckoutq(tp, wait)
129125391Skarels 	register struct tty *tp;
129225391Skarels 	int wait;
129325391Skarels {
129430695Skarels 	int hiwat, s, oldsig;
129525391Skarels 
129635811Smarc 	hiwat = tp->t_hiwat;
129725391Skarels 	s = spltty();
129830695Skarels 	oldsig = u.u_procp->p_sig;
129925391Skarels 	if (tp->t_outq.c_cc > hiwat + 200)
130029946Skarels 		while (tp->t_outq.c_cc > hiwat) {
130129946Skarels 			ttstart(tp);
130230695Skarels 			if (wait == 0 || u.u_procp->p_sig != oldsig) {
130329946Skarels 				splx(s);
130429946Skarels 				return (0);
130529946Skarels 			}
130630695Skarels 			timeout(wakeup, (caddr_t)&tp->t_outq, hz);
130729946Skarels 			tp->t_state |= TS_ASLEEP;
130830695Skarels 			sleep((caddr_t)&tp->t_outq, PZERO - 1);
130925391Skarels 		}
131025391Skarels 	splx(s);
131125391Skarels 	return (1);
131225391Skarels }
131325391Skarels 
131425391Skarels /*
13157502Sroot  * Called from the device's write routine after it has
13167502Sroot  * calculated the tty-structure given as argument.
13177502Sroot  */
131837584Smarc ttwrite(tp, uio, flag)
13197625Ssam 	register struct tty *tp;
13209578Ssam 	register struct uio *uio;
13217502Sroot {
13227502Sroot 	register char *cp;
132337728Smckusick 	register int cc, ce;
13249578Ssam 	int i, hiwat, cnt, error, s;
13257502Sroot 	char obuf[OBUFSIZ];
13267502Sroot 
132735811Smarc 	hiwat = tp->t_hiwat;
13289578Ssam 	cnt = uio->uio_resid;
13299578Ssam 	error = 0;
13307502Sroot loop:
133137584Smarc 	s = spltty();
133237584Smarc 	if (!(tp->t_state&TS_CARR_ON) && !(tp->t_cflag&CLOCAL)) {
133337584Smarc 		if (tp->t_state&TS_ISOPEN) {
133437584Smarc 			splx(s);
133537584Smarc 			return (EIO);
133637728Smckusick 		} else if (flag & IO_NDELAY) {
133737584Smarc 			splx(s);
133837584Smarc 			return (EWOULDBLOCK);
133937584Smarc 		} else {
134037584Smarc 			/*
134137584Smarc 			 * sleep awaiting carrier
134237584Smarc 			 */
134337584Smarc 			sleep((caddr_t)&tp->t_rawq, TTIPRI);
134437584Smarc 			splx(s);
134537584Smarc 			goto loop;
134637584Smarc 		}
134737584Smarc 	}
134837584Smarc 	splx(s);
13499578Ssam 	/*
13509578Ssam 	 * Hang the process if it's in the background.
13519578Ssam 	 */
1352*39555Smarc 	if (isbackground(u.u_procp, tp) &&
135335811Smarc 	    (tp->t_lflag&TOSTOP) && (u.u_procp->p_flag&SVFORK)==0 &&
135424392Skarels 	    !(u.u_procp->p_sigignore & sigmask(SIGTTOU)) &&
135535811Smarc 	    !(u.u_procp->p_sigmask & sigmask(SIGTTOU)) &&
135635811Smarc 	     u.u_procp->p_pgrp->pg_jobc) {
135735811Smarc 		pgsignal(u.u_procp->p_pgrp, SIGTTOU);
13587502Sroot 		sleep((caddr_t)&lbolt, TTIPRI);
135921776Sbloom 		goto loop;
13607502Sroot 	}
13619578Ssam 	/*
13629578Ssam 	 * Process the user's data in at most OBUFSIZ
13639578Ssam 	 * chunks.  Perform lower case simulation and
13649578Ssam 	 * similar hacks.  Keep track of high water
13659578Ssam 	 * mark, sleep on overflow awaiting device aid
13669578Ssam 	 * in acquiring new space.
13679578Ssam 	 */
13687822Sroot 	while (uio->uio_resid > 0) {
136932067Skarels 		if (tp->t_outq.c_cc > hiwat) {
137032067Skarels 			cc = 0;
137132067Skarels 			goto ovhiwat;
137232067Skarels 		}
13739578Ssam 		/*
13749578Ssam 		 * Grab a hunk of data from the user.
13759578Ssam 		 */
13767822Sroot 		cc = uio->uio_iov->iov_len;
13777822Sroot 		if (cc == 0) {
13787822Sroot 			uio->uio_iovcnt--;
13797822Sroot 			uio->uio_iov++;
138021776Sbloom 			if (uio->uio_iovcnt <= 0)
13817822Sroot 				panic("ttwrite");
13827822Sroot 			continue;
13837822Sroot 		}
13847822Sroot 		if (cc > OBUFSIZ)
13857822Sroot 			cc = OBUFSIZ;
13867502Sroot 		cp = obuf;
138737728Smckusick 		error = uiomove(cp, cc, uio);
13888520Sroot 		if (error)
13897502Sroot 			break;
139035811Smarc 		if (tp->t_lflag&FLUSHO)
13917502Sroot 			continue;
13929578Ssam 		/*
13939578Ssam 		 * If nothing fancy need be done, grab those characters we
13949578Ssam 		 * can handle without any of ttyoutput's processing and
13959578Ssam 		 * just transfer them to the output q.  For those chars
13969578Ssam 		 * which require special processing (as indicated by the
13979578Ssam 		 * bits in partab), call ttyoutput.  After processing
13989578Ssam 		 * a hunk of data, look for FLUSHO so ^O's will take effect
13999578Ssam 		 * immediately.
14009578Ssam 		 */
14019578Ssam 		while (cc > 0) {
140235811Smarc 			if (!(tp->t_oflag&OPOST))
14037502Sroot 				ce = cc;
14047502Sroot 			else {
140534492Skarels 				ce = cc - scanc((unsigned)cc, (u_char *)cp,
140634492Skarels 				   (u_char *)partab, 077);
14079578Ssam 				/*
14089578Ssam 				 * If ce is zero, then we're processing
14099578Ssam 				 * a special character through ttyoutput.
14109578Ssam 				 */
14119578Ssam 				if (ce == 0) {
14127502Sroot 					tp->t_rocount = 0;
14137502Sroot 					if (ttyoutput(*cp, tp) >= 0) {
141421776Sbloom 					    /* no c-lists, wait a bit */
141521776Sbloom 					    ttstart(tp);
141621776Sbloom 					    sleep((caddr_t)&lbolt, TTOPRI);
141721776Sbloom 					    if (cc != 0) {
141821776Sbloom 					        uio->uio_iov->iov_base -= cc;
141921776Sbloom 					        uio->uio_iov->iov_len += cc;
142021776Sbloom 					        uio->uio_resid += cc;
142121776Sbloom 						uio->uio_offset -= cc;
142221776Sbloom 					    }
142321776Sbloom 					    goto loop;
14247502Sroot 					}
14259578Ssam 					cp++, cc--;
142635811Smarc 					if ((tp->t_lflag&FLUSHO) ||
14279578Ssam 					    tp->t_outq.c_cc > hiwat)
14287502Sroot 						goto ovhiwat;
14299578Ssam 					continue;
14307502Sroot 				}
14317502Sroot 			}
14329578Ssam 			/*
14339578Ssam 			 * A bunch of normal characters have been found,
14349578Ssam 			 * transfer them en masse to the output queue and
14359578Ssam 			 * continue processing at the top of the loop.
14369578Ssam 			 * If there are any further characters in this
14379578Ssam 			 * <= OBUFSIZ chunk, the first should be a character
14389578Ssam 			 * requiring special handling by ttyoutput.
14399578Ssam 			 */
14407502Sroot 			tp->t_rocount = 0;
14419578Ssam 			i = b_to_q(cp, ce, &tp->t_outq);
14429578Ssam 			ce -= i;
14439578Ssam 			tp->t_col += ce;
14449578Ssam 			cp += ce, cc -= ce, tk_nout += ce;
144535811Smarc 			tp->t_outcc += ce;
14469578Ssam 			if (i > 0) {
14479578Ssam 				/* out of c-lists, wait a bit */
14487502Sroot 				ttstart(tp);
14497502Sroot 				sleep((caddr_t)&lbolt, TTOPRI);
145021776Sbloom 				uio->uio_iov->iov_base -= cc;
145121776Sbloom 				uio->uio_iov->iov_len += cc;
145221776Sbloom 				uio->uio_resid += cc;
145321776Sbloom 				uio->uio_offset -= cc;
145421776Sbloom 				goto loop;
14557502Sroot 			}
145635811Smarc 			if (tp->t_lflag&FLUSHO || tp->t_outq.c_cc > hiwat)
14577502Sroot 				goto ovhiwat;
14587502Sroot 		}
145935811Smarc 		ttstart(tp);
14607502Sroot 	}
14618520Sroot 	return (error);
14627502Sroot ovhiwat:
14639578Ssam 	if (cc != 0) {
14649578Ssam 		uio->uio_iov->iov_base -= cc;
14659578Ssam 		uio->uio_iov->iov_len += cc;
14669578Ssam 		uio->uio_resid += cc;
14679578Ssam 		uio->uio_offset -= cc;
14689578Ssam 	}
146932067Skarels 	ttstart(tp);
147032067Skarels 	s = spltty();
14719578Ssam 	/*
147235811Smarc 	 * This can only occur if FLUSHO is set in t_lflag,
147332067Skarels 	 * or if ttstart/oproc is synchronous (or very fast).
14749578Ssam 	 */
14757502Sroot 	if (tp->t_outq.c_cc <= hiwat) {
14769578Ssam 		splx(s);
14777502Sroot 		goto loop;
14787502Sroot 	}
147937728Smckusick 	if (flag & IO_NDELAY) {
148017545Skarels 		splx(s);
14817822Sroot 		if (uio->uio_resid == cnt)
14828520Sroot 			return (EWOULDBLOCK);
14838520Sroot 		return (0);
14847502Sroot 	}
14857502Sroot 	tp->t_state |= TS_ASLEEP;
14867502Sroot 	sleep((caddr_t)&tp->t_outq, TTOPRI);
14879578Ssam 	splx(s);
14887502Sroot 	goto loop;
14897502Sroot }
14907502Sroot 
14917502Sroot /*
14927502Sroot  * Rubout one character from the rawq of tp
14937502Sroot  * as cleanly as possible.
14947502Sroot  */
14957502Sroot ttyrub(c, tp)
14967625Ssam 	register c;
14977625Ssam 	register struct tty *tp;
14987502Sroot {
14997502Sroot 	register char *cp;
15007502Sroot 	register int savecol;
15017502Sroot 	int s;
15027502Sroot 	char *nextc();
15037502Sroot 
150435811Smarc 	if ((tp->t_lflag&ECHO) == 0)
15057502Sroot 		return;
150635811Smarc 	tp->t_lflag &= ~FLUSHO;
150735811Smarc 	if (tp->t_lflag&ECHOE) {
15087502Sroot 		if (tp->t_rocount == 0) {
15097502Sroot 			/*
15107502Sroot 			 * Screwed by ttwrite; retype
15117502Sroot 			 */
15127502Sroot 			ttyretype(tp);
15137502Sroot 			return;
15147502Sroot 		}
151535811Smarc 		if (c == ('\t'|TTY_QUOTE) || c == ('\n'|TTY_QUOTE))
15167502Sroot 			ttyrubo(tp, 2);
151735811Smarc 		else switch (partab[c&=0377]&077) {
15187502Sroot 
15197502Sroot 		case ORDINARY:
152035811Smarc 			ttyrubo(tp, 1);
15217502Sroot 			break;
15227502Sroot 
15237502Sroot 		case VTAB:
15247502Sroot 		case BACKSPACE:
15257502Sroot 		case CONTROL:
15267502Sroot 		case RETURN:
152735811Smarc 			if (tp->t_lflag&ECHOCTL)
15287502Sroot 				ttyrubo(tp, 2);
15297502Sroot 			break;
15307502Sroot 
153135811Smarc 		case TAB: {
153235811Smarc 			int c;
153335811Smarc 
15347502Sroot 			if (tp->t_rocount < tp->t_rawq.c_cc) {
15357502Sroot 				ttyretype(tp);
15367502Sroot 				return;
15377502Sroot 			}
153817545Skarels 			s = spltty();
15397502Sroot 			savecol = tp->t_col;
15409578Ssam 			tp->t_state |= TS_CNTTB;
154135811Smarc 			tp->t_lflag |= FLUSHO;
15427502Sroot 			tp->t_col = tp->t_rocol;
15439578Ssam 			cp = tp->t_rawq.c_cf;
154439407Smarc 			if (cp)
154539407Smarc 				c = *cp;	/* XXX FIX NEXTC */
154635811Smarc 			for (; cp; cp = nextc(&tp->t_rawq, cp, &c))
154735811Smarc 				ttyecho(c, tp);
154835811Smarc 			tp->t_lflag &= ~FLUSHO;
15499578Ssam 			tp->t_state &= ~TS_CNTTB;
15507502Sroot 			splx(s);
15517502Sroot 			/*
15527502Sroot 			 * savecol will now be length of the tab
15537502Sroot 			 */
15547502Sroot 			savecol -= tp->t_col;
15557502Sroot 			tp->t_col += savecol;
15567502Sroot 			if (savecol > 8)
15577502Sroot 				savecol = 8;		/* overflow screw */
15587502Sroot 			while (--savecol >= 0)
15597502Sroot 				(void) ttyoutput('\b', tp);
15607502Sroot 			break;
156135811Smarc 		}
15627502Sroot 
15637502Sroot 		default:
156437584Smarc 			/* XXX */
156535811Smarc 			printf("ttyrub: would panic c = %d, val = %d\n",
156635811Smarc 				c, partab[c&=0377]&077);
156735811Smarc 			/*panic("ttyrub");*/
15687502Sroot 		}
156935811Smarc 	} else if (tp->t_lflag&ECHOPRT) {
15709578Ssam 		if ((tp->t_state&TS_ERASE) == 0) {
15717502Sroot 			(void) ttyoutput('\\', tp);
15729578Ssam 			tp->t_state |= TS_ERASE;
15737502Sroot 		}
15747502Sroot 		ttyecho(c, tp);
15757502Sroot 	} else
157635811Smarc 		ttyecho(tp->t_cc[VERASE], tp);
15777502Sroot 	tp->t_rocount--;
15787502Sroot }
15797502Sroot 
15807502Sroot /*
15817502Sroot  * Crt back over cnt chars perhaps
15827502Sroot  * erasing them.
15837502Sroot  */
15847502Sroot ttyrubo(tp, cnt)
15857625Ssam 	register struct tty *tp;
15867625Ssam 	int cnt;
15877502Sroot {
15887502Sroot 
15897502Sroot 	while (--cnt >= 0)
159035811Smarc 		ttyout("\b \b", tp);
15917502Sroot }
15927502Sroot 
15937502Sroot /*
15947502Sroot  * Reprint the rawq line.
15957502Sroot  * We assume c_cc has already been checked.
15967502Sroot  */
15977502Sroot ttyretype(tp)
15987625Ssam 	register struct tty *tp;
15997502Sroot {
16007502Sroot 	register char *cp;
16017502Sroot 	char *nextc();
160235811Smarc 	int s, c;
16037502Sroot 
160435811Smarc 	if (tp->t_cc[VREPRINT] != _POSIX_VDISABLE)
160535811Smarc 		ttyecho(tp->t_cc[VREPRINT], tp);
16067502Sroot 	(void) ttyoutput('\n', tp);
160717545Skarels 	s = spltty();
160835811Smarc 	/*** XXX *** FIX *** NEXTC IS BROKEN - DOESN'T CHECK QUOTE
160935811Smarc 	  BIT OF FIRST CHAR ****/
161035811Smarc 	for (cp = tp->t_canq.c_cf, c=(cp?*cp:0); cp; cp = nextc(&tp->t_canq, cp, &c)) {
161135811Smarc 		ttyecho(c, tp);
161235811Smarc 	}
161335811Smarc 	for (cp = tp->t_rawq.c_cf, c=(cp?*cp:0); cp; cp = nextc(&tp->t_rawq, cp, &c)) {
161435811Smarc 		ttyecho(c, tp);
161535811Smarc 	}
16169578Ssam 	tp->t_state &= ~TS_ERASE;
16177502Sroot 	splx(s);
16187502Sroot 	tp->t_rocount = tp->t_rawq.c_cc;
16197502Sroot 	tp->t_rocol = 0;
16207502Sroot }
16217502Sroot 
16227502Sroot /*
162335811Smarc  * Echo a typed character to the terminal.
16247502Sroot  */
16257502Sroot ttyecho(c, tp)
16267625Ssam 	register c;
16277625Ssam 	register struct tty *tp;
16287502Sroot {
16299578Ssam 	if ((tp->t_state&TS_CNTTB) == 0)
163035811Smarc 		tp->t_lflag &= ~FLUSHO;
163135811Smarc 	if ((tp->t_lflag&ECHO) == 0 && !(tp->t_lflag&ECHONL && c == '\n'))
16327502Sroot 		return;
163335811Smarc 	if (tp->t_lflag&ECHOCTL) {
163435811Smarc 		if ((c&TTY_CHARMASK)<=037 && c!='\t' && c!='\n' || c==0177) {
16357502Sroot 			(void) ttyoutput('^', tp);
163635811Smarc 			c &= TTY_CHARMASK;
16377502Sroot 			if (c == 0177)
16387502Sroot 				c = '?';
16397502Sroot 			else
16407502Sroot 				c += 'A' - 1;
16417502Sroot 		}
16427502Sroot 	}
164335811Smarc 	(void) ttyoutput(c, tp);
16447502Sroot }
16457502Sroot 
16467502Sroot /*
16477502Sroot  * send string cp to tp
16487502Sroot  */
16497502Sroot ttyout(cp, tp)
16507625Ssam 	register char *cp;
16517625Ssam 	register struct tty *tp;
16527502Sroot {
16537502Sroot 	register char c;
16547502Sroot 
16557502Sroot 	while (c = *cp++)
16567502Sroot 		(void) ttyoutput(c, tp);
16577502Sroot }
16587502Sroot 
16597502Sroot ttwakeup(tp)
16607502Sroot 	struct tty *tp;
16617502Sroot {
16627502Sroot 
16637502Sroot 	if (tp->t_rsel) {
16647502Sroot 		selwakeup(tp->t_rsel, tp->t_state&TS_RCOLL);
16657502Sroot 		tp->t_state &= ~TS_RCOLL;
16667502Sroot 		tp->t_rsel = 0;
16677502Sroot 	}
166812752Ssam 	if (tp->t_state & TS_ASYNC)
1669*39555Smarc 		pgsignal(tp->t_pgrp, SIGIO);
16707502Sroot 	wakeup((caddr_t)&tp->t_rawq);
16717502Sroot }
167235811Smarc 
167335811Smarc /*
167435811Smarc  * set tty hi and low water marks
167535811Smarc  *
167635811Smarc  * Try to arrange the dynamics so there's about one second
167735811Smarc  * from hi to low water.
167835811Smarc  *
167935811Smarc  */
168035811Smarc ttsetwater(tp)
168135811Smarc 	struct tty *tp;
168235811Smarc {
168335811Smarc 	register cps = tp->t_ospeed / 10;
168435811Smarc 	register x;
168535811Smarc 
168635811Smarc #define clamp(x, h, l) ((x)>h ? h : ((x)<l) ? l : (x))
168735811Smarc 	tp->t_lowat = x = clamp(cps/2, TTMAXLOWAT, TTMINLOWAT);
168835811Smarc 	x += cps;
168935811Smarc 	x = clamp(x, TTMAXHIWAT, TTMINHIWAT);
169035811Smarc 	tp->t_hiwat = roundup(x, CBSIZE);
169135811Smarc #undef clamp
169235811Smarc }
169335811Smarc 
169435811Smarc ttspeedtab(speed, table)
169535811Smarc 	struct speedtab table[];
169635811Smarc {
169735811Smarc 	register int i;
169835811Smarc 
169935811Smarc 	for (i = 0; table[i].sp_speed != -1; i++)
170035811Smarc 		if (table[i].sp_speed == speed)
170135811Smarc 			return(table[i].sp_code);
170235811Smarc 	return(-1);
170335811Smarc }
170439407Smarc 
170539407Smarc /*
170639407Smarc  * (^T)
170739407Smarc  * Report on state of foreground process group.
170839407Smarc  */
170939407Smarc ttyinfo(tp)
171039407Smarc 	struct tty *tp;
171139407Smarc {
171239407Smarc 	register struct proc *p;
171339407Smarc 
171439407Smarc 	if (ttycheckoutq(tp,0) == 0)
171539407Smarc 		return;
1716*39555Smarc 	if (tp->t_session == NULL)
1717*39555Smarc 		ttyprintf(tp, "kernel: not a controlling terminal\n");
1718*39555Smarc 	else if (tp->t_pgrp == NULL ||
1719*39555Smarc 		(p = tp->t_pgrp->pg_mem) == NULL)
172039407Smarc 		ttyprintf(tp, "kernel: no foreground process group\n");
172139407Smarc 	else {
172239407Smarc 		int i = 0;
1723*39555Smarc 
172439407Smarc 		for (; p != NULL; p = p->p_pgrpnxt) {
172539407Smarc 			ttyprintf(tp,
172639407Smarc 			 "kernel: pid: %d state: %x wchan: %x ticks: %d\n",
172739407Smarc 				p->p_pid, p->p_stat, p->p_wchan, p->p_cpticks);
172839407Smarc 			if (++i > 6) {
172939407Smarc 				ttyprintf(tp, "kernel: more...\n");
173039407Smarc 				break;
173139407Smarc 			}
173239407Smarc 		}
173339407Smarc 	}
173439407Smarc }
173539407Smarc 
173639407Smarc #define TOTTY	0x2	/* XXX should be in header */
173739407Smarc /*VARARGS2*/
173839407Smarc ttyprintf(tp, fmt, x1)
1739*39555Smarc 	struct tty *tp;
174039407Smarc 	char *fmt;
174139407Smarc 	unsigned x1;
174239407Smarc {
1743*39555Smarc 	prf(fmt, &x1, TOTTY, (caddr_t)tp);
174439407Smarc }
1745*39555Smarc 
1746*39555Smarc /*
1747*39555Smarc  * Output char to tty; console putchar style.
1748*39555Smarc  */
1749*39555Smarc tputchar(c, tp)
1750*39555Smarc 	int c;
1751*39555Smarc 	struct tty *tp;
1752*39555Smarc {
1753*39555Smarc 	register s = spltty();
1754*39555Smarc 
1755*39555Smarc 	if ((tp->t_state & (TS_CARR_ON | TS_ISOPEN))
1756*39555Smarc 	    == (TS_CARR_ON | TS_ISOPEN)) {
1757*39555Smarc 		if (c == '\n')
1758*39555Smarc 			(void) ttyoutput('\r', tp);
1759*39555Smarc 		(void) ttyoutput(c, tp);
1760*39555Smarc 		ttstart(tp);
1761*39555Smarc 		splx(s);
1762*39555Smarc 		return (0);
1763*39555Smarc 	}
1764*39555Smarc 	splx(s);
1765*39555Smarc 	return (-1);
1766*39555Smarc }
1767