xref: /csrg-svn/sys/kern/tty.c (revision 26357)
123387Smckusick /*
223387Smckusick  * Copyright (c) 1982 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*26357Skarels  *	@(#)tty.c	6.26 (Berkeley) 02/23/86
723387Smckusick  */
839Sbill 
99760Ssam #include "../machine/reg.h"
109760Ssam 
1117095Sbloom #include "param.h"
1217095Sbloom #include "systm.h"
1317095Sbloom #include "dir.h"
1417095Sbloom #include "user.h"
1517095Sbloom #include "ioctl.h"
1617095Sbloom #include "tty.h"
1717095Sbloom #include "proc.h"
1817095Sbloom #include "inode.h"
1917095Sbloom #include "file.h"
2017095Sbloom #include "conf.h"
2117095Sbloom #include "buf.h"
2217095Sbloom #include "dk.h"
2317095Sbloom #include "uio.h"
2417095Sbloom #include "kernel.h"
2539Sbill 
267436Skre /*
277436Skre  * Table giving parity for characters and indicating
287436Skre  * character classes to tty driver.  In particular,
297436Skre  * if the low 6 bits are 0, then the character needs
307436Skre  * no special processing on output.
317436Skre  */
3239Sbill 
337436Skre char partab[] = {
347436Skre 	0001,0201,0201,0001,0201,0001,0001,0201,
357436Skre 	0202,0004,0003,0201,0005,0206,0201,0001,
367436Skre 	0201,0001,0001,0201,0001,0201,0201,0001,
377436Skre 	0001,0201,0201,0001,0201,0001,0001,0201,
387436Skre 	0200,0000,0000,0200,0000,0200,0200,0000,
397436Skre 	0000,0200,0200,0000,0200,0000,0000,0200,
407436Skre 	0000,0200,0200,0000,0200,0000,0000,0200,
417436Skre 	0200,0000,0000,0200,0000,0200,0200,0000,
427436Skre 	0200,0000,0000,0200,0000,0200,0200,0000,
437436Skre 	0000,0200,0200,0000,0200,0000,0000,0200,
447436Skre 	0000,0200,0200,0000,0200,0000,0000,0200,
457436Skre 	0200,0000,0000,0200,0000,0200,0200,0000,
467436Skre 	0000,0200,0200,0000,0200,0000,0000,0200,
477436Skre 	0200,0000,0000,0200,0000,0200,0200,0000,
487436Skre 	0200,0000,0000,0200,0000,0200,0200,0000,
497436Skre 	0000,0200,0200,0000,0200,0000,0000,0201,
507436Skre 
517436Skre 	/*
527436Skre 	 * 7 bit ascii ends with the last character above,
537436Skre 	 * but we contine through all 256 codes for the sake
547436Skre 	 * of the tty output routines which use special vax
557436Skre 	 * instructions which need a 256 character trt table.
567436Skre 	 */
577436Skre 
587436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
597436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
607436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
617436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
627436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
637436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
647436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
657436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
667436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
677436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
687436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
697436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
707436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
717436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
727436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
737436Skre 	0007,0007,0007,0007,0007,0007,0007,0007
747436Skre };
757436Skre 
76146Sbill /*
7739Sbill  * Input mapping table-- if an entry is non-zero, when the
7839Sbill  * corresponding character is typed preceded by "\" the escape
7939Sbill  * sequence is replaced by the table value.  Mostly used for
8039Sbill  * upper-case only terminals.
8139Sbill  */
8239Sbill char	maptab[] ={
8339Sbill 	000,000,000,000,000,000,000,000,
8439Sbill 	000,000,000,000,000,000,000,000,
8539Sbill 	000,000,000,000,000,000,000,000,
8639Sbill 	000,000,000,000,000,000,000,000,
8739Sbill 	000,'|',000,000,000,000,000,'`',
8839Sbill 	'{','}',000,000,000,000,000,000,
8939Sbill 	000,000,000,000,000,000,000,000,
9039Sbill 	000,000,000,000,000,000,000,000,
9139Sbill 	000,000,000,000,000,000,000,000,
9239Sbill 	000,000,000,000,000,000,000,000,
9339Sbill 	000,000,000,000,000,000,000,000,
9439Sbill 	000,000,000,000,000,000,'~',000,
9539Sbill 	000,'A','B','C','D','E','F','G',
9639Sbill 	'H','I','J','K','L','M','N','O',
9739Sbill 	'P','Q','R','S','T','U','V','W',
9839Sbill 	'X','Y','Z',000,000,000,000,000,
9939Sbill };
10039Sbill 
101925Sbill short	tthiwat[16] =
1028954Sroot    { 100,100,100,100,100,100,100,200,200,400,400,400,650,650,1300,2000 };
103925Sbill short	ttlowat[16] =
104925Sbill    {  30, 30, 30, 30, 30, 30, 30, 50, 50,120,120,120,125,125,125,125 };
105925Sbill 
1069578Ssam struct	ttychars ttydefaults = {
1079578Ssam 	CERASE,	CKILL,	CINTR,	CQUIT,	CSTART,	CSTOP,	CEOF,
1089578Ssam 	CBRK,	CSUSP,	CDSUSP, CRPRNT, CFLUSH, CWERASE,CLNEXT
1099578Ssam };
11039Sbill 
11139Sbill ttychars(tp)
1129578Ssam 	struct tty *tp;
11339Sbill {
114174Sbill 
1159578Ssam 	tp->t_chars = ttydefaults;
11639Sbill }
11739Sbill 
11839Sbill /*
119903Sbill  * Wait for output to drain, then flush input waiting.
12039Sbill  */
12112752Ssam ttywflush(tp)
1225408Swnj 	register struct tty *tp;
12339Sbill {
12439Sbill 
12512752Ssam 	ttywait(tp);
12612752Ssam 	ttyflush(tp, FREAD);
12712752Ssam }
12812752Ssam 
12912752Ssam ttywait(tp)
13012752Ssam 	register struct tty *tp;
13112752Ssam {
13217545Skarels 	register int s = spltty();
13312752Ssam 
13413809Ssam 	while ((tp->t_outq.c_cc || tp->t_state&TS_BUSY) &&
13525391Skarels 	    tp->t_state&TS_CARR_ON) {
136903Sbill 		(*tp->t_oproc)(tp);
1375408Swnj 		tp->t_state |= TS_ASLEEP;
138903Sbill 		sleep((caddr_t)&tp->t_outq, TTOPRI);
139903Sbill 	}
1409859Ssam 	splx(s);
14139Sbill }
14239Sbill 
14339Sbill /*
1449578Ssam  * Flush all TTY queues
14539Sbill  */
14612752Ssam ttyflush(tp, rw)
1477625Ssam 	register struct tty *tp;
14839Sbill {
149903Sbill 	register s;
150903Sbill 
15117545Skarels 	s = spltty();
152903Sbill 	if (rw & FREAD) {
153903Sbill 		while (getc(&tp->t_canq) >= 0)
154903Sbill 			;
155903Sbill 		wakeup((caddr_t)&tp->t_rawq);
156903Sbill 	}
157903Sbill 	if (rw & FWRITE) {
158903Sbill 		wakeup((caddr_t)&tp->t_outq);
1595408Swnj 		tp->t_state &= ~TS_TTSTOP;
1605426Swnj 		(*cdevsw[major(tp->t_dev)].d_stop)(tp, rw);
161903Sbill 		while (getc(&tp->t_outq) >= 0)
162903Sbill 			;
163903Sbill 	}
164903Sbill 	if (rw & FREAD) {
165903Sbill 		while (getc(&tp->t_rawq) >= 0)
166903Sbill 			;
1679578Ssam 		tp->t_rocount = 0;
168903Sbill 		tp->t_rocol = 0;
1699578Ssam 		tp->t_state &= ~TS_LOCAL;
170903Sbill 	}
171903Sbill 	splx(s);
17239Sbill }
17339Sbill 
174903Sbill /*
175903Sbill  * Send stop character on input overflow.
176903Sbill  */
177903Sbill ttyblock(tp)
1787625Ssam 	register struct tty *tp;
17939Sbill {
180903Sbill 	register x;
1819578Ssam 
182903Sbill 	x = tp->t_rawq.c_cc + tp->t_canq.c_cc;
183903Sbill 	if (tp->t_rawq.c_cc > TTYHOG) {
18412752Ssam 		ttyflush(tp, FREAD|FWRITE);
1855408Swnj 		tp->t_state &= ~TS_TBLOCK;
186903Sbill 	}
18715118Skarels 	/*
18815118Skarels 	 * Block further input iff:
18915118Skarels 	 * Current input > threshold AND input is available to user program
19015118Skarels 	 */
19116055Skarels 	if (x >= TTYHOG/2 &&
19216055Skarels 	    ((tp->t_flags & (RAW|CBREAK)) || (tp->t_canq.c_cc > 0))) {
19315118Skarels 		if (putc(tp->t_stopc, &tp->t_outq)==0) {
19415118Skarels 			tp->t_state |= TS_TBLOCK;
19515118Skarels 			ttstart(tp);
19615118Skarels 		}
197903Sbill 	}
19839Sbill }
19939Sbill 
20039Sbill /*
201903Sbill  * Restart typewriter output following a delay
202903Sbill  * timeout.
203903Sbill  * The name of the routine is passed to the timeout
204903Sbill  * subroutine and it is called during a clock interrupt.
205121Sbill  */
206903Sbill ttrstrt(tp)
2077625Ssam 	register struct tty *tp;
208121Sbill {
209121Sbill 
2109578Ssam 	if (tp == 0)
2119578Ssam 		panic("ttrstrt");
2125408Swnj 	tp->t_state &= ~TS_TIMEOUT;
213903Sbill 	ttstart(tp);
214121Sbill }
215121Sbill 
216121Sbill /*
217903Sbill  * Start output on the typewriter. It is used from the top half
218903Sbill  * after some characters have been put on the output queue,
219903Sbill  * from the interrupt routine to transmit the next
220903Sbill  * character, and after a timeout has finished.
22139Sbill  */
222903Sbill ttstart(tp)
2237625Ssam 	register struct tty *tp;
22439Sbill {
225903Sbill 	register s;
22639Sbill 
22717545Skarels 	s = spltty();
2289578Ssam 	if ((tp->t_state & (TS_TIMEOUT|TS_TTSTOP|TS_BUSY)) == 0 &&
2295622Swnj 	    tp->t_oproc)		/* kludge for pty */
230903Sbill 		(*tp->t_oproc)(tp);
231903Sbill 	splx(s);
23239Sbill }
23339Sbill 
23439Sbill /*
235903Sbill  * Common code for tty ioctls.
23639Sbill  */
2371780Sbill /*ARGSUSED*/
2387625Ssam ttioctl(tp, com, data, flag)
2397625Ssam 	register struct tty *tp;
2407625Ssam 	caddr_t data;
24139Sbill {
2428520Sroot 	int dev = tp->t_dev;
24339Sbill 	extern int nldisp;
2448556Sroot 	int s;
24512752Ssam 	register int newflags;
24639Sbill 
247903Sbill 	/*
248903Sbill 	 * If the ioctl involves modification,
24917545Skarels 	 * hang if in the background.
250903Sbill 	 */
2517625Ssam 	switch (com) {
25239Sbill 
253915Sbill 	case TIOCSETD:
254915Sbill 	case TIOCSETP:
255915Sbill 	case TIOCSETN:
256903Sbill 	case TIOCFLUSH:
257903Sbill 	case TIOCSETC:
258903Sbill 	case TIOCSLTC:
259903Sbill 	case TIOCSPGRP:
260903Sbill 	case TIOCLBIS:
261903Sbill 	case TIOCLBIC:
262903Sbill 	case TIOCLSET:
2639325Ssam 	case TIOCSTI:
26417598Sbloom 	case TIOCSWINSZ:
265903Sbill 		while (tp->t_line == NTTYDISC &&
266903Sbill 		   u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp &&
267903Sbill 		   (u.u_procp->p_flag&SVFORK) == 0 &&
26824392Skarels 		   !(u.u_procp->p_sigignore & sigmask(SIGTTOU)) &&
26924392Skarels 		   !(u.u_procp->p_sigmask & sigmask(SIGTTOU))) {
270903Sbill 			gsignal(u.u_procp->p_pgrp, SIGTTOU);
271903Sbill 			sleep((caddr_t)&lbolt, TTOPRI);
272903Sbill 		}
273903Sbill 		break;
274903Sbill 	}
275903Sbill 
2769578Ssam 	/*
2779578Ssam 	 * Process the ioctl.
2789578Ssam 	 */
2797625Ssam 	switch (com) {
280903Sbill 
2818556Sroot 	/* get discipline number */
28239Sbill 	case TIOCGETD:
2837625Ssam 		*(int *)data = tp->t_line;
28439Sbill 		break;
28539Sbill 
2868556Sroot 	/* set line discipline */
2877625Ssam 	case TIOCSETD: {
2887625Ssam 		register int t = *(int *)data;
2899578Ssam 		int error = 0;
2907625Ssam 
29115078Skarels 		if ((unsigned) t >= nldisp)
29210851Ssam 			return (ENXIO);
29325584Skarels 		if (t != tp->t_line) {
29425584Skarels 			s = spltty();
29525584Skarels 			(*linesw[tp->t_line].l_close)(tp);
29625584Skarels 			error = (*linesw[t].l_open)(dev, tp);
29725584Skarels 			if (error) {
29825584Skarels 				(void) (*linesw[tp->t_line].l_open)(dev, tp);
29925584Skarels 				splx(s);
30025584Skarels 				return (error);
30125584Skarels 			}
30225584Skarels 			tp->t_line = t;
30310851Ssam 			splx(s);
30410851Ssam 		}
30539Sbill 		break;
3067625Ssam 	}
30739Sbill 
3088556Sroot 	/* prevent more opens on channel */
3095614Swnj 	case TIOCEXCL:
3105614Swnj 		tp->t_state |= TS_XCLUDE;
3115614Swnj 		break;
3125614Swnj 
3135614Swnj 	case TIOCNXCL:
3145614Swnj 		tp->t_state &= ~TS_XCLUDE;
3155614Swnj 		break;
3165614Swnj 
3178556Sroot 	/* hang up line on last close */
31839Sbill 	case TIOCHPCL:
3195408Swnj 		tp->t_state |= TS_HUPCLS;
32039Sbill 		break;
32139Sbill 
3223942Sbugs 	case TIOCFLUSH: {
3237625Ssam 		register int flags = *(int *)data;
3247625Ssam 
3257625Ssam 		if (flags == 0)
3263942Sbugs 			flags = FREAD|FWRITE;
3277625Ssam 		else
3287625Ssam 			flags &= FREAD|FWRITE;
32912752Ssam 		ttyflush(tp, flags);
33039Sbill 		break;
3313944Sbugs 	}
33239Sbill 
3338556Sroot 	/* return number of characters immediately available */
3347625Ssam 	case FIONREAD:
3357625Ssam 		*(off_t *)data = ttnread(tp);
336174Sbill 		break;
337174Sbill 
33813077Ssam 	case TIOCOUTQ:
33913077Ssam 		*(int *)data = tp->t_outq.c_cc;
34013077Ssam 		break;
34113077Ssam 
3428589Sroot 	case TIOCSTOP:
34317545Skarels 		s = spltty();
3449578Ssam 		if ((tp->t_state&TS_TTSTOP) == 0) {
3455573Swnj 			tp->t_state |= TS_TTSTOP;
3465573Swnj 			(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
3475573Swnj 		}
3487625Ssam 		splx(s);
3495573Swnj 		break;
3505573Swnj 
3518589Sroot 	case TIOCSTART:
35217545Skarels 		s = spltty();
3539578Ssam 		if ((tp->t_state&TS_TTSTOP) || (tp->t_flags&FLUSHO)) {
3545573Swnj 			tp->t_state &= ~TS_TTSTOP;
3559578Ssam 			tp->t_flags &= ~FLUSHO;
3565573Swnj 			ttstart(tp);
3575573Swnj 		}
3587625Ssam 		splx(s);
3595573Swnj 		break;
3605573Swnj 
3619325Ssam 	/*
3629325Ssam 	 * Simulate typing of a character at the terminal.
3639325Ssam 	 */
3649325Ssam 	case TIOCSTI:
36517183Smckusick 		if (u.u_uid && (flag & FREAD) == 0)
36617183Smckusick 			return (EPERM);
3679325Ssam 		if (u.u_uid && u.u_ttyp != tp)
3689325Ssam 			return (EACCES);
3699578Ssam 		(*linesw[tp->t_line].l_rint)(*(char *)data, tp);
3709325Ssam 		break;
3719325Ssam 
37212752Ssam 	case TIOCSETP:
37312752Ssam 	case TIOCSETN: {
37412752Ssam 		register struct sgttyb *sg = (struct sgttyb *)data;
37512752Ssam 
37612752Ssam 		tp->t_erase = sg->sg_erase;
37712752Ssam 		tp->t_kill = sg->sg_kill;
37812752Ssam 		tp->t_ispeed = sg->sg_ispeed;
37912752Ssam 		tp->t_ospeed = sg->sg_ospeed;
38012752Ssam 		newflags = (tp->t_flags&0xffff0000) | (sg->sg_flags&0xffff);
38117545Skarels 		s = spltty();
38212752Ssam 		if (tp->t_flags&RAW || newflags&RAW || com == TIOCSETP) {
38312752Ssam 			ttywait(tp);
38412752Ssam 			ttyflush(tp, FREAD);
38512752Ssam 		} else if ((tp->t_flags&CBREAK) != (newflags&CBREAK)) {
38612752Ssam 			if (newflags&CBREAK) {
38712752Ssam 				struct clist tq;
38812752Ssam 
38912752Ssam 				catq(&tp->t_rawq, &tp->t_canq);
39012752Ssam 				tq = tp->t_rawq;
39112752Ssam 				tp->t_rawq = tp->t_canq;
39212752Ssam 				tp->t_canq = tq;
39312752Ssam 			} else {
39412752Ssam 				tp->t_flags |= PENDIN;
39513801Ssam 				newflags |= PENDIN;
39612752Ssam 				ttwakeup(tp);
39712752Ssam 			}
39812752Ssam 		}
39912752Ssam 		tp->t_flags = newflags;
40012752Ssam 		if (tp->t_flags&RAW) {
40112752Ssam 			tp->t_state &= ~TS_TTSTOP;
40212752Ssam 			ttstart(tp);
40312752Ssam 		}
40412752Ssam 		splx(s);
40512752Ssam 		break;
40612752Ssam 	}
40712752Ssam 
40812752Ssam 	/* send current parameters to user */
40912752Ssam 	case TIOCGETP: {
41012752Ssam 		register struct sgttyb *sg = (struct sgttyb *)data;
41112752Ssam 
41212752Ssam 		sg->sg_ispeed = tp->t_ispeed;
41312752Ssam 		sg->sg_ospeed = tp->t_ospeed;
41412752Ssam 		sg->sg_erase = tp->t_erase;
41512752Ssam 		sg->sg_kill = tp->t_kill;
41612752Ssam 		sg->sg_flags = tp->t_flags;
41712752Ssam 		break;
41812752Ssam 	}
41912752Ssam 
42012752Ssam 	case FIONBIO:
42112752Ssam 		if (*(int *)data)
42212752Ssam 			tp->t_state |= TS_NBIO;
42312752Ssam 		else
42412752Ssam 			tp->t_state &= ~TS_NBIO;
42512752Ssam 		break;
42612752Ssam 
42712752Ssam 	case FIOASYNC:
42812752Ssam 		if (*(int *)data)
42912752Ssam 			tp->t_state |= TS_ASYNC;
43012752Ssam 		else
43112752Ssam 			tp->t_state &= ~TS_ASYNC;
43212752Ssam 		break;
43312752Ssam 
43413077Ssam 	case TIOCGETC:
43513077Ssam 		bcopy((caddr_t)&tp->t_intrc, data, sizeof (struct tchars));
43613077Ssam 		break;
43713077Ssam 
43813077Ssam 	case TIOCSETC:
43913077Ssam 		bcopy(data, (caddr_t)&tp->t_intrc, sizeof (struct tchars));
44013077Ssam 		break;
44113077Ssam 
44212752Ssam 	/* set/get local special characters */
44312752Ssam 	case TIOCSLTC:
44412752Ssam 		bcopy(data, (caddr_t)&tp->t_suspc, sizeof (struct ltchars));
44512752Ssam 		break;
44612752Ssam 
44712752Ssam 	case TIOCGLTC:
44812752Ssam 		bcopy((caddr_t)&tp->t_suspc, data, sizeof (struct ltchars));
44912752Ssam 		break;
45012752Ssam 
45112752Ssam 	/*
45212752Ssam 	 * Modify local mode word.
45312752Ssam 	 */
45412752Ssam 	case TIOCLBIS:
45512752Ssam 		tp->t_flags |= *(int *)data << 16;
45612752Ssam 		break;
45712752Ssam 
45812752Ssam 	case TIOCLBIC:
45912752Ssam 		tp->t_flags &= ~(*(int *)data << 16);
46012752Ssam 		break;
46112752Ssam 
46212752Ssam 	case TIOCLSET:
46312752Ssam 		tp->t_flags &= 0xffff;
46412752Ssam 		tp->t_flags |= *(int *)data << 16;
46512752Ssam 		break;
46612752Ssam 
46712752Ssam 	case TIOCLGET:
46815720Skarels 		*(int *)data = ((unsigned) tp->t_flags) >> 16;
46912752Ssam 		break;
47012752Ssam 
47117545Skarels 	/*
47217932Skarels 	 * Allow SPGRP only if tty is open for reading.
47317598Sbloom 	 * Quick check: if we can find a process in the new pgrp,
47417598Sbloom 	 * this user must own that process.
47517598Sbloom 	 * SHOULD VERIFY THAT PGRP IS IN USE AND IS THIS USER'S.
47617545Skarels 	 */
47718650Sbloom 	case TIOCSPGRP: {
47817545Skarels 		struct proc *p;
47917545Skarels 		int pgrp = *(int *)data;
48017545Skarels 
48117545Skarels 		if (u.u_uid && (flag & FREAD) == 0)
48217545Skarels 			return (EPERM);
48317598Sbloom 		p = pfind(pgrp);
48417598Sbloom 		if (p && p->p_pgrp == pgrp &&
48517598Sbloom 		    p->p_uid != u.u_uid && u.u_uid && !inferior(p))
48617598Sbloom 			return (EPERM);
48717545Skarels 		tp->t_pgrp = pgrp;
48812752Ssam 		break;
48918650Sbloom 	}
49012752Ssam 
49112752Ssam 	case TIOCGPGRP:
49212752Ssam 		*(int *)data = tp->t_pgrp;
49312752Ssam 		break;
49412752Ssam 
49517598Sbloom 	case TIOCSWINSZ:
49618650Sbloom 		if (bcmp((caddr_t)&tp->t_winsize, data,
49718650Sbloom 		    sizeof (struct winsize))) {
49817598Sbloom 			tp->t_winsize = *(struct winsize *)data;
49917598Sbloom 			gsignal(tp->t_pgrp, SIGWINCH);
50017598Sbloom 		}
50117598Sbloom 		break;
50217598Sbloom 
50317598Sbloom 	case TIOCGWINSZ:
50417598Sbloom 		*(struct winsize *)data = tp->t_winsize;
50517598Sbloom 		break;
50617598Sbloom 
50739Sbill 	default:
5088556Sroot 		return (-1);
50939Sbill 	}
5108556Sroot 	return (0);
51139Sbill }
5124484Swnj 
5134484Swnj ttnread(tp)
5144484Swnj 	struct tty *tp;
5154484Swnj {
5164484Swnj 	int nread = 0;
5174484Swnj 
5189578Ssam 	if (tp->t_flags & PENDIN)
5194484Swnj 		ttypend(tp);
5204484Swnj 	nread = tp->t_canq.c_cc;
5214484Swnj 	if (tp->t_flags & (RAW|CBREAK))
5224484Swnj 		nread += tp->t_rawq.c_cc;
5234484Swnj 	return (nread);
5244484Swnj }
5254484Swnj 
5265408Swnj ttselect(dev, rw)
5274484Swnj 	dev_t dev;
5285408Swnj 	int rw;
5294484Swnj {
5304484Swnj 	register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)];
5314484Swnj 	int nread;
53217545Skarels 	int s = spltty();
5334484Swnj 
5345408Swnj 	switch (rw) {
5354484Swnj 
5364484Swnj 	case FREAD:
5374484Swnj 		nread = ttnread(tp);
53821776Sbloom 		if ((nread > 0) || ((tp->t_state & TS_CARR_ON) == 0))
5395408Swnj 			goto win;
5404938Swnj 		if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait)
5415408Swnj 			tp->t_state |= TS_RCOLL;
5424484Swnj 		else
5434484Swnj 			tp->t_rsel = u.u_procp;
5445408Swnj 		break;
5454484Swnj 
5465408Swnj 	case FWRITE:
5475408Swnj 		if (tp->t_outq.c_cc <= TTLOWAT(tp))
5485408Swnj 			goto win;
5495408Swnj 		if (tp->t_wsel && tp->t_wsel->p_wchan == (caddr_t)&selwait)
5505408Swnj 			tp->t_state |= TS_WCOLL;
5515408Swnj 		else
5525408Swnj 			tp->t_wsel = u.u_procp;
5535408Swnj 		break;
5544484Swnj 	}
5555408Swnj 	splx(s);
5565408Swnj 	return (0);
5575408Swnj win:
5585408Swnj 	splx(s);
5595408Swnj 	return (1);
5604484Swnj }
5617436Skre 
5627502Sroot /*
56325391Skarels  * Initial open of tty, or (re)entry to line discipline.
5649578Ssam  * Establish a process group for distribution of
5657502Sroot  * quits and interrupts from the tty.
5667502Sroot  */
5677502Sroot ttyopen(dev, tp)
5687625Ssam 	dev_t dev;
5697625Ssam 	register struct tty *tp;
5707502Sroot {
5717502Sroot 	register struct proc *pp;
5727502Sroot 
5737502Sroot 	pp = u.u_procp;
5747502Sroot 	tp->t_dev = dev;
5757625Ssam 	if (pp->p_pgrp == 0) {
5767502Sroot 		u.u_ttyp = tp;
5777502Sroot 		u.u_ttyd = dev;
5787502Sroot 		if (tp->t_pgrp == 0)
5797502Sroot 			tp->t_pgrp = pp->p_pid;
5807502Sroot 		pp->p_pgrp = tp->t_pgrp;
5817502Sroot 	}
5827502Sroot 	tp->t_state &= ~TS_WOPEN;
58317545Skarels 	if ((tp->t_state & TS_ISOPEN) == 0) {
58417545Skarels 		tp->t_state |= TS_ISOPEN;
58517598Sbloom 		bzero((caddr_t)&tp->t_winsize, sizeof(tp->t_winsize));
58617545Skarels 		if (tp->t_line != NTTYDISC)
58717545Skarels 			ttywflush(tp);
58817545Skarels 	}
5898556Sroot 	return (0);
5907502Sroot }
5917502Sroot 
5927502Sroot /*
59325391Skarels  * "close" a line discipline
59425391Skarels  */
59525391Skarels ttylclose(tp)
59625391Skarels 	register struct tty *tp;
59725391Skarels {
59825391Skarels 
59925391Skarels 	ttywflush(tp);
60025391Skarels 	tp->t_line = 0;
60125391Skarels }
60225391Skarels 
60325391Skarels /*
6047502Sroot  * clean tp on last close
6057502Sroot  */
6067502Sroot ttyclose(tp)
6077625Ssam 	register struct tty *tp;
6087502Sroot {
6097502Sroot 
61025391Skarels 	ttyflush(tp, FREAD|FWRITE);
6117502Sroot 	tp->t_pgrp = 0;
6127502Sroot 	tp->t_state = 0;
6137502Sroot }
6147502Sroot 
6157502Sroot /*
61625391Skarels  * Handle modem control transition on a tty.
61725391Skarels  * Flag indicates new state of carrier.
61825391Skarels  * Returns 0 if the line should be turned off, otherwise 1.
61925391Skarels  */
62025391Skarels ttymodem(tp, flag)
62125391Skarels 	register struct tty *tp;
62225391Skarels {
62325391Skarels 
62425391Skarels 	if ((tp->t_state&TS_WOPEN) == 0 && (tp->t_flags & MDMBUF)) {
62525391Skarels 		/*
62625391Skarels 		 * MDMBUF: do flow control according to carrier flag
62725391Skarels 		 */
62825391Skarels 		if (flag) {
62925391Skarels 			tp->t_state &= ~TS_TTSTOP;
63025391Skarels 			ttstart(tp);
63125391Skarels 		} else if ((tp->t_state&TS_TTSTOP) == 0) {
63225391Skarels 			tp->t_state |= TS_TTSTOP;
63325391Skarels 			(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
63425391Skarels 		}
63525391Skarels 	} else if (flag == 0) {
63625391Skarels 		/*
63725391Skarels 		 * Lost carrier.
63825391Skarels 		 */
63925391Skarels 		tp->t_state &= ~TS_CARR_ON;
64025391Skarels 		if (tp->t_state & TS_ISOPEN) {
64125391Skarels 			if ((tp->t_flags & NOHANG) == 0) {
64225391Skarels 				gsignal(tp->t_pgrp, SIGHUP);
64325391Skarels 				gsignal(tp->t_pgrp, SIGCONT);
64425391Skarels 				ttyflush(tp, FREAD|FWRITE);
64525391Skarels 				return (0);
64625391Skarels 			}
64725391Skarels 		}
64825391Skarels 	} else {
64925391Skarels 		/*
65025391Skarels 		 * Carrier now on.
65125391Skarels 		 */
65225391Skarels 		tp->t_state |= TS_CARR_ON;
65325391Skarels 		wakeup((caddr_t)&tp->t_rawq);
65425391Skarels 	}
65525391Skarels 	return (1);
65625391Skarels }
65725391Skarels 
65825391Skarels /*
65925404Skarels  * Default modem control routine (for other line disciplines).
66025404Skarels  * Return argument flag, to turn off device on carrier drop.
66125404Skarels  */
66225415Skarels nullmodem(tp, flag)
66325415Skarels 	register struct tty *tp;
66425404Skarels 	int flag;
66525404Skarels {
66625404Skarels 
66725404Skarels 	if (flag)
66825404Skarels 		tp->t_state |= TS_CARR_ON;
66925404Skarels 	else
67025404Skarels 		tp->t_state &= ~TS_CARR_ON;
67125404Skarels 	return (flag);
67225404Skarels }
67325404Skarels 
67425404Skarels /*
6757502Sroot  * reinput pending characters after state switch
67617545Skarels  * call at spltty().
6777502Sroot  */
6787502Sroot ttypend(tp)
6797625Ssam 	register struct tty *tp;
6807502Sroot {
6817502Sroot 	struct clist tq;
6827502Sroot 	register c;
6837502Sroot 
6849578Ssam 	tp->t_flags &= ~PENDIN;
6859578Ssam 	tp->t_state |= TS_TYPEN;
6867502Sroot 	tq = tp->t_rawq;
6877502Sroot 	tp->t_rawq.c_cc = 0;
6887502Sroot 	tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0;
6897502Sroot 	while ((c = getc(&tq)) >= 0)
6907502Sroot 		ttyinput(c, tp);
6919578Ssam 	tp->t_state &= ~TS_TYPEN;
6927502Sroot }
6937502Sroot 
6947502Sroot /*
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 {
7059578Ssam 	register int t_flags = tp->t_flags;
7067502Sroot 	int i;
7077502Sroot 
7089578Ssam 	/*
7099578Ssam 	 * If input is pending take it first.
7109578Ssam 	 */
7119578Ssam 	if (t_flags&PENDIN)
7127502Sroot 		ttypend(tp);
7137502Sroot 	tk_nin++;
7147502Sroot 	c &= 0377;
7159578Ssam 
7169578Ssam 	/*
7179578Ssam 	 * In tandem mode, check high water mark.
7189578Ssam 	 */
7197502Sroot 	if (t_flags&TANDEM)
7207502Sroot 		ttyblock(tp);
7219578Ssam 
7229578Ssam 	if (t_flags&RAW) {
7239578Ssam 		/*
7249578Ssam 		 * Raw mode, just put character
7259578Ssam 		 * in input q w/o interpretation.
7269578Ssam 		 */
7279578Ssam 		if (tp->t_rawq.c_cc > TTYHOG)
72812752Ssam 			ttyflush(tp, FREAD|FWRITE);
7299578Ssam 		else {
7309578Ssam 			if (putc(c, &tp->t_rawq) >= 0)
7319578Ssam 				ttwakeup(tp);
7329578Ssam 			ttyecho(c, tp);
7337502Sroot 		}
7349578Ssam 		goto endcase;
7359578Ssam 	}
7369578Ssam 
7379578Ssam 	/*
7389578Ssam 	 * Ignore any high bit added during
7399578Ssam 	 * previous ttyinput processing.
7409578Ssam 	 */
74124273Slepreau 	if ((tp->t_state&TS_TYPEN) == 0 && (t_flags&PASS8) == 0)
7429578Ssam 		c &= 0177;
7439578Ssam 	/*
7449578Ssam 	 * Check for literal nexting very first
7459578Ssam 	 */
7469578Ssam 	if (tp->t_state&TS_LNCH) {
7479578Ssam 		c |= 0200;
7489578Ssam 		tp->t_state &= ~TS_LNCH;
7499578Ssam 	}
7509578Ssam 
7519578Ssam 	/*
7529578Ssam 	 * Scan for special characters.  This code
7539578Ssam 	 * is really just a big case statement with
7549578Ssam 	 * non-constant cases.  The bottom of the
7559578Ssam 	 * case statement is labeled ``endcase'', so goto
7569578Ssam 	 * it after a case match, or similar.
7579578Ssam 	 */
7589578Ssam 	if (tp->t_line == NTTYDISC) {
7599578Ssam 		if (c == tp->t_lnextc) {
76021776Sbloom 			if (t_flags&ECHO)
7617502Sroot 				ttyout("^\b", tp);
7629578Ssam 			tp->t_state |= TS_LNCH;
7639578Ssam 			goto endcase;
7649578Ssam 		}
7659578Ssam 		if (c == tp->t_flushc) {
76621776Sbloom 			if (t_flags&FLUSHO)
7679578Ssam 				tp->t_flags &= ~FLUSHO;
7687502Sroot 			else {
76912752Ssam 				ttyflush(tp, FWRITE);
7707502Sroot 				ttyecho(c, tp);
7719578Ssam 				if (tp->t_rawq.c_cc + tp->t_canq.c_cc)
7727502Sroot 					ttyretype(tp);
7739578Ssam 				tp->t_flags |= FLUSHO;
7747502Sroot 			}
7759578Ssam 			goto startoutput;
7769578Ssam 		}
7779578Ssam 		if (c == tp->t_suspc) {
77821776Sbloom 			if ((t_flags&NOFLSH) == 0)
77912752Ssam 				ttyflush(tp, FREAD);
7809578Ssam 			ttyecho(c, tp);
7819578Ssam 			gsignal(tp->t_pgrp, SIGTSTP);
7829578Ssam 			goto endcase;
7839578Ssam 		}
7849578Ssam 	}
7859578Ssam 
7869578Ssam 	/*
7879578Ssam 	 * Handle start/stop characters.
7889578Ssam 	 */
7899578Ssam 	if (c == tp->t_stopc) {
7909578Ssam 		if ((tp->t_state&TS_TTSTOP) == 0) {
7919578Ssam 			tp->t_state |= TS_TTSTOP;
7929578Ssam 			(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
7937502Sroot 			return;
7949578Ssam 		}
7959578Ssam 		if (c != tp->t_startc)
7969578Ssam 			return;
7979578Ssam 		goto endcase;
7989578Ssam 	}
7999578Ssam 	if (c == tp->t_startc)
8009578Ssam 		goto restartoutput;
8019578Ssam 
8029578Ssam 	/*
8039578Ssam 	 * Look for interrupt/quit chars.
8049578Ssam 	 */
8059578Ssam 	if (c == tp->t_intrc || c == tp->t_quitc) {
80621776Sbloom 		if ((t_flags&NOFLSH) == 0)
80712752Ssam 			ttyflush(tp, FREAD|FWRITE);
8089578Ssam 		ttyecho(c, tp);
8099578Ssam 		gsignal(tp->t_pgrp, c == tp->t_intrc ? SIGINT : SIGQUIT);
8109578Ssam 		goto endcase;
8119578Ssam 	}
8129578Ssam 
81323165Sbloom 	if (tp->t_flags & LCASE && c <= 0177) {
81423165Sbloom 		if (tp->t_state&TS_BKSL) {
81523165Sbloom 			ttyrub(unputc(&tp->t_rawq), tp);
81623165Sbloom 			if (maptab[c])
81723165Sbloom 				c = maptab[c];
81823165Sbloom 			c |= 0200;
81923165Sbloom 			tp->t_state &= ~(TS_BKSL|TS_QUOT);
82023165Sbloom 		} else if (c >= 'A' && c <= 'Z')
82123165Sbloom 			c += 'a' - 'A';
82223165Sbloom 		else if (c == '\\')
82323165Sbloom 			tp->t_state |= TS_BKSL;
82423165Sbloom 	}
82523165Sbloom 
8269578Ssam 	/*
8279578Ssam 	 * Cbreak mode, don't process line editing
8289578Ssam 	 * characters; check high water mark for wakeup.
8299578Ssam 	 */
8309578Ssam 	if (t_flags&CBREAK) {
8319578Ssam 		if (tp->t_rawq.c_cc > TTYHOG) {
8327502Sroot 			if (tp->t_outq.c_cc < TTHIWAT(tp) &&
8337502Sroot 			    tp->t_line == NTTYDISC)
8347502Sroot 				(void) ttyoutput(CTRL(g), tp);
8357502Sroot 		} else if (putc(c, &tp->t_rawq) >= 0) {
8367502Sroot 			ttwakeup(tp);
8377502Sroot 			ttyecho(c, tp);
8387502Sroot 		}
8399578Ssam 		goto endcase;
8409578Ssam 	}
8419578Ssam 
8429578Ssam 	/*
8439578Ssam 	 * From here on down cooked mode character
8449578Ssam 	 * processing takes place.
8459578Ssam 	 */
8469578Ssam 	if ((tp->t_state&TS_QUOT) &&
8479578Ssam 	    (c == tp->t_erase || c == tp->t_kill)) {
8489578Ssam 		ttyrub(unputc(&tp->t_rawq), tp);
8499578Ssam 		c |= 0200;
8509578Ssam 	}
8519578Ssam 	if (c == tp->t_erase) {
8529578Ssam 		if (tp->t_rawq.c_cc)
8539578Ssam 			ttyrub(unputc(&tp->t_rawq), tp);
8549578Ssam 		goto endcase;
8559578Ssam 	}
8569578Ssam 	if (c == tp->t_kill) {
85721776Sbloom 		if (t_flags&CRTKIL &&
8589578Ssam 		    tp->t_rawq.c_cc == tp->t_rocount) {
8599578Ssam 			while (tp->t_rawq.c_cc)
8609578Ssam 				ttyrub(unputc(&tp->t_rawq), tp);
8619578Ssam 		} else {
8629578Ssam 			ttyecho(c, tp);
8639578Ssam 			ttyecho('\n', tp);
8649578Ssam 			while (getc(&tp->t_rawq) > 0)
8659578Ssam 				;
8669578Ssam 			tp->t_rocount = 0;
8679578Ssam 		}
8689578Ssam 		tp->t_state &= ~TS_LOCAL;
8699578Ssam 		goto endcase;
8709578Ssam 	}
8719578Ssam 
8729578Ssam 	/*
8739578Ssam 	 * New line discipline,
8749578Ssam 	 * check word erase/reprint line.
8759578Ssam 	 */
8769578Ssam 	if (tp->t_line == NTTYDISC) {
8779578Ssam 		if (c == tp->t_werasc) {
8789578Ssam 			if (tp->t_rawq.c_cc == 0)
8799578Ssam 				goto endcase;
8809578Ssam 			do {
8819578Ssam 				c = unputc(&tp->t_rawq);
8829578Ssam 				if (c != ' ' && c != '\t')
8839578Ssam 					goto erasenb;
8849578Ssam 				ttyrub(c, tp);
8859578Ssam 			} while (tp->t_rawq.c_cc);
8869578Ssam 			goto endcase;
8879578Ssam 	erasenb:
8889578Ssam 			do {
8899578Ssam 				ttyrub(c, tp);
8909578Ssam 				if (tp->t_rawq.c_cc == 0)
8919578Ssam 					goto endcase;
8929578Ssam 				c = unputc(&tp->t_rawq);
8939578Ssam 			} while (c != ' ' && c != '\t');
8949578Ssam 			(void) putc(c, &tp->t_rawq);
8959578Ssam 			goto endcase;
8969578Ssam 		}
8979578Ssam 		if (c == tp->t_rprntc) {
8989578Ssam 			ttyretype(tp);
8999578Ssam 			goto endcase;
9009578Ssam 		}
9019578Ssam 	}
9029578Ssam 
9039578Ssam 	/*
9049578Ssam 	 * Check for input buffer overflow
9059578Ssam 	 */
90610391Ssam 	if (tp->t_rawq.c_cc+tp->t_canq.c_cc >= TTYHOG) {
90710391Ssam 		if (tp->t_line == NTTYDISC)
90810391Ssam 			(void) ttyoutput(CTRL(g), tp);
9099578Ssam 		goto endcase;
91010391Ssam 	}
9119578Ssam 
9129578Ssam 	/*
9139578Ssam 	 * Put data char in q for user and
9149578Ssam 	 * wakeup on seeing a line delimiter.
9159578Ssam 	 */
9169578Ssam 	if (putc(c, &tp->t_rawq) >= 0) {
9179578Ssam 		if (ttbreakc(c, tp)) {
9189578Ssam 			tp->t_rocount = 0;
9199578Ssam 			catq(&tp->t_rawq, &tp->t_canq);
9207502Sroot 			ttwakeup(tp);
9219578Ssam 		} else if (tp->t_rocount++ == 0)
9229578Ssam 			tp->t_rocol = tp->t_col;
9239578Ssam 		tp->t_state &= ~TS_QUOT;
9249578Ssam 		if (c == '\\')
9259578Ssam 			tp->t_state |= TS_QUOT;
9269578Ssam 		if (tp->t_state&TS_ERASE) {
9279578Ssam 			tp->t_state &= ~TS_ERASE;
9289578Ssam 			(void) ttyoutput('/', tp);
9299578Ssam 		}
9309578Ssam 		i = tp->t_col;
9317502Sroot 		ttyecho(c, tp);
93221776Sbloom 		if (c == tp->t_eofc && t_flags&ECHO) {
9339578Ssam 			i = MIN(2, tp->t_col - i);
9349578Ssam 			while (i > 0) {
9359578Ssam 				(void) ttyoutput('\b', tp);
9369578Ssam 				i--;
9379578Ssam 			}
9389578Ssam 		}
9397502Sroot 	}
9409578Ssam endcase:
9419578Ssam 	/*
9429578Ssam 	 * If DEC-style start/stop is enabled don't restart
9439578Ssam 	 * output until seeing the start character.
9449578Ssam 	 */
94521776Sbloom 	if (t_flags&DECCTQ && tp->t_state&TS_TTSTOP &&
9469578Ssam 	    tp->t_startc != tp->t_stopc)
9477502Sroot 		return;
9489578Ssam restartoutput:
9497502Sroot 	tp->t_state &= ~TS_TTSTOP;
9509578Ssam 	tp->t_flags &= ~FLUSHO;
9519578Ssam startoutput:
9527502Sroot 	ttstart(tp);
9537502Sroot }
9547502Sroot 
9557502Sroot /*
9569578Ssam  * Put character on TTY output queue, adding delays,
9577502Sroot  * expanding tabs, and handling the CR/NL bit.
9589578Ssam  * This is called both from the top half for output,
9599578Ssam  * and from interrupt level for echoing.
9607502Sroot  * The arguments are the character and the tty structure.
9617502Sroot  * Returns < 0 if putc succeeds, otherwise returns char to resend
9627502Sroot  * Must be recursive.
9637502Sroot  */
9647502Sroot ttyoutput(c, tp)
9657502Sroot 	register c;
9667502Sroot 	register struct tty *tp;
9677502Sroot {
9687502Sroot 	register char *colp;
9697502Sroot 	register ctype;
9707502Sroot 
9719578Ssam 	if (tp->t_flags & (RAW|LITOUT)) {
9729578Ssam 		if (tp->t_flags&FLUSHO)
9737502Sroot 			return (-1);
9747502Sroot 		if (putc(c, &tp->t_outq))
9757625Ssam 			return (c);
9767502Sroot 		tk_nout++;
9777502Sroot 		return (-1);
9787502Sroot 	}
9799578Ssam 
9807502Sroot 	/*
9819578Ssam 	 * Ignore EOT in normal mode to avoid
9829578Ssam 	 * hanging up certain terminals.
9837502Sroot 	 */
9847502Sroot 	c &= 0177;
9859578Ssam 	if (c == CEOT && (tp->t_flags&CBREAK) == 0)
9867502Sroot 		return (-1);
9877502Sroot 	/*
9887502Sroot 	 * Turn tabs to spaces as required
9897502Sroot 	 */
9909578Ssam 	if (c == '\t' && (tp->t_flags&TBDELAY) == XTABS) {
9917502Sroot 		register int s;
9927502Sroot 
9937502Sroot 		c = 8 - (tp->t_col&7);
9949578Ssam 		if ((tp->t_flags&FLUSHO) == 0) {
99517545Skarels 			s = spltty();		/* don't interrupt tabs */
9967502Sroot 			c -= b_to_q("        ", c, &tp->t_outq);
9977502Sroot 			tk_nout += c;
9987502Sroot 			splx(s);
9997502Sroot 		}
10007502Sroot 		tp->t_col += c;
10017502Sroot 		return (c ? -1 : '\t');
10027502Sroot 	}
10037502Sroot 	tk_nout++;
10047502Sroot 	/*
10057502Sroot 	 * for upper-case-only terminals,
10067502Sroot 	 * generate escapes.
10077502Sroot 	 */
10087502Sroot 	if (tp->t_flags&LCASE) {
10097502Sroot 		colp = "({)}!|^~'`";
10107625Ssam 		while (*colp++)
10117625Ssam 			if (c == *colp++) {
10127502Sroot 				if (ttyoutput('\\', tp) >= 0)
10137502Sroot 					return (c);
10147502Sroot 				c = colp[-2];
10157502Sroot 				break;
10167502Sroot 			}
10179578Ssam 		if ('A' <= c && c <= 'Z') {
10187502Sroot 			if (ttyoutput('\\', tp) >= 0)
10197502Sroot 				return (c);
10209578Ssam 		} else if ('a' <= c && c <= 'z')
10217502Sroot 			c += 'A' - 'a';
10227502Sroot 	}
10239578Ssam 
10247502Sroot 	/*
10257502Sroot 	 * turn <nl> to <cr><lf> if desired.
10267502Sroot 	 */
10279578Ssam 	if (c == '\n' && tp->t_flags&CRMOD)
10287502Sroot 		if (ttyoutput('\r', tp) >= 0)
10297502Sroot 			return (c);
10309578Ssam 	if (c == '~' && tp->t_flags&TILDE)
10317502Sroot 		c = '`';
10329578Ssam 	if ((tp->t_flags&FLUSHO) == 0 && putc(c, &tp->t_outq))
10337502Sroot 		return (c);
10347502Sroot 	/*
10357502Sroot 	 * Calculate delays.
10367502Sroot 	 * The numbers here represent clock ticks
10377502Sroot 	 * and are not necessarily optimal for all terminals.
10387502Sroot 	 * The delays are indicated by characters above 0200.
10397502Sroot 	 * In raw mode there are no delays and the
10407502Sroot 	 * transmission path is 8 bits wide.
10419578Ssam 	 *
10429578Ssam 	 * SHOULD JUST ALLOW USER TO SPECIFY DELAYS
10437502Sroot 	 */
10447502Sroot 	colp = &tp->t_col;
10457502Sroot 	ctype = partab[c];
10467502Sroot 	c = 0;
10477502Sroot 	switch (ctype&077) {
10487502Sroot 
10497502Sroot 	case ORDINARY:
10507502Sroot 		(*colp)++;
10517502Sroot 
10527502Sroot 	case CONTROL:
10537502Sroot 		break;
10547502Sroot 
10557502Sroot 	case BACKSPACE:
10567502Sroot 		if (*colp)
10577502Sroot 			(*colp)--;
10587502Sroot 		break;
10597502Sroot 
106013821Ssam 	/*
106113821Ssam 	 * This macro is close enough to the correct thing;
106213821Ssam 	 * it should be replaced by real user settable delays
106313821Ssam 	 * in any event...
106413821Ssam 	 */
106513821Ssam #define	mstohz(ms)	(((ms) * hz) >> 10)
10667502Sroot 	case NEWLINE:
10677502Sroot 		ctype = (tp->t_flags >> 8) & 03;
10687625Ssam 		if (ctype == 1) { /* tty 37 */
1069*26357Skarels 			if (*colp > 0) {
1070*26357Skarels 				c = (((unsigned)*colp) >> 4) + 3;
1071*26357Skarels 				if ((unsigned)c > 6)
1072*26357Skarels 					c = 6;
1073*26357Skarels 			}
10749578Ssam 		} else if (ctype == 2) /* vt05 */
107513821Ssam 			c = mstohz(100);
10767502Sroot 		*colp = 0;
10777502Sroot 		break;
10787502Sroot 
10797502Sroot 	case TAB:
10807502Sroot 		ctype = (tp->t_flags >> 10) & 03;
10817625Ssam 		if (ctype == 1) { /* tty 37 */
10827502Sroot 			c = 1 - (*colp | ~07);
10837625Ssam 			if (c < 5)
10847502Sroot 				c = 0;
10857502Sroot 		}
10867502Sroot 		*colp |= 07;
10877502Sroot 		(*colp)++;
10887502Sroot 		break;
10897502Sroot 
10907502Sroot 	case VTAB:
10919578Ssam 		if (tp->t_flags&VTDELAY) /* tty 37 */
10927502Sroot 			c = 0177;
10937502Sroot 		break;
10947502Sroot 
10957502Sroot 	case RETURN:
10967502Sroot 		ctype = (tp->t_flags >> 12) & 03;
10979578Ssam 		if (ctype == 1) /* tn 300 */
109813821Ssam 			c = mstohz(83);
10999578Ssam 		else if (ctype == 2) /* ti 700 */
110013821Ssam 			c = mstohz(166);
11019578Ssam 		else if (ctype == 3) { /* concept 100 */
11027502Sroot 			int i;
11039578Ssam 
11047502Sroot 			if ((i = *colp) >= 0)
11059578Ssam 				for (; i < 9; i++)
11067502Sroot 					(void) putc(0177, &tp->t_outq);
11077502Sroot 		}
11087502Sroot 		*colp = 0;
11097502Sroot 	}
11109578Ssam 	if (c && (tp->t_flags&FLUSHO) == 0)
11117502Sroot 		(void) putc(c|0200, &tp->t_outq);
11127502Sroot 	return (-1);
11137502Sroot }
111413821Ssam #undef mstohz
11157502Sroot 
11167502Sroot /*
11177502Sroot  * Called from device's read routine after it has
11187502Sroot  * calculated the tty-structure given as argument.
11197502Sroot  */
11207722Swnj ttread(tp, uio)
11217625Ssam 	register struct tty *tp;
11227722Swnj 	struct uio *uio;
11237502Sroot {
11247502Sroot 	register struct clist *qp;
11259578Ssam 	register c, t_flags;
11269859Ssam 	int s, first, error = 0;
11277502Sroot 
11287502Sroot loop:
11299578Ssam 	/*
11309578Ssam 	 * Take any pending input first.
11319578Ssam 	 */
113217545Skarels 	s = spltty();
11339578Ssam 	if (tp->t_flags&PENDIN)
11347502Sroot 		ttypend(tp);
11359859Ssam 	splx(s);
11369578Ssam 
113723165Sbloom 	if ((tp->t_state&TS_CARR_ON)==0)
113823165Sbloom 		return (EIO);
113923165Sbloom 
11409578Ssam 	/*
11419578Ssam 	 * Hang process if it's in the background.
11429578Ssam 	 */
114323165Sbloom 	if (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) {
114424392Skarels 		if ((u.u_procp->p_sigignore & sigmask(SIGTTIN)) ||
114524392Skarels 		   (u.u_procp->p_sigmask & sigmask(SIGTTIN)) ||
11467502Sroot 		    u.u_procp->p_flag&SVFORK)
11478520Sroot 			return (EIO);
11487502Sroot 		gsignal(u.u_procp->p_pgrp, SIGTTIN);
11497502Sroot 		sleep((caddr_t)&lbolt, TTIPRI);
115023165Sbloom 		goto loop;
11517502Sroot 	}
11529578Ssam 	t_flags = tp->t_flags;
11539578Ssam 
11549578Ssam 	/*
11559578Ssam 	 * In raw mode take characters directly from the
11569578Ssam 	 * raw queue w/o processing.  Interlock against
11579578Ssam 	 * device interrupts when interrogating rawq.
11589578Ssam 	 */
11599578Ssam 	if (t_flags&RAW) {
116017545Skarels 		s = spltty();
11617502Sroot 		if (tp->t_rawq.c_cc <= 0) {
11629578Ssam 			if ((tp->t_state&TS_CARR_ON) == 0 ||
11637502Sroot 			    (tp->t_state&TS_NBIO)) {
11649859Ssam 				splx(s);
116515094Skarels 				return (EWOULDBLOCK);
11667502Sroot 			}
11677502Sroot 			sleep((caddr_t)&tp->t_rawq, TTIPRI);
11689859Ssam 			splx(s);
11697502Sroot 			goto loop;
11707502Sroot 		}
11719859Ssam 		splx(s);
117214938Smckusick  		while (!error && tp->t_rawq.c_cc && uio->uio_resid)
117314938Smckusick  			error = ureadc(getc(&tp->t_rawq), uio);
11749859Ssam 		goto checktandem;
11759578Ssam 	}
11769578Ssam 
11779578Ssam 	/*
11789578Ssam 	 * In cbreak mode use the rawq, otherwise
11799578Ssam 	 * take characters from the canonicalized q.
11809578Ssam 	 */
11819578Ssam 	qp = t_flags&CBREAK ? &tp->t_rawq : &tp->t_canq;
11829578Ssam 
11839578Ssam 	/*
11849578Ssam 	 * No input, sleep on rawq awaiting hardware
11859578Ssam 	 * receipt and notification.
11869578Ssam 	 */
118717545Skarels 	s = spltty();
11889578Ssam 	if (qp->c_cc <= 0) {
11899578Ssam 		if ((tp->t_state&TS_CARR_ON) == 0 ||
11909578Ssam 		    (tp->t_state&TS_NBIO)) {
11919859Ssam 			splx(s);
11929578Ssam 			return (EWOULDBLOCK);
11937502Sroot 		}
11949578Ssam 		sleep((caddr_t)&tp->t_rawq, TTIPRI);
11959859Ssam 		splx(s);
11969578Ssam 		goto loop;
11979578Ssam 	}
11989859Ssam 	splx(s);
11999578Ssam 
12009578Ssam 	/*
12019578Ssam 	 * Input present, perform input mapping
12029578Ssam 	 * and processing (we're not in raw mode).
12039578Ssam 	 */
12049578Ssam 	first = 1;
12059578Ssam 	while ((c = getc(qp)) >= 0) {
12069578Ssam 		if (t_flags&CRMOD && c == '\r')
12079578Ssam 			c = '\n';
12089578Ssam 		/*
12099578Ssam 		 * Check for delayed suspend character.
12109578Ssam 		 */
12119578Ssam 		if (tp->t_line == NTTYDISC && c == tp->t_dsuspc) {
12129578Ssam 			gsignal(tp->t_pgrp, SIGTSTP);
12139578Ssam 			if (first) {
12149578Ssam 				sleep((caddr_t)&lbolt, TTIPRI);
12159578Ssam 				goto loop;
12169578Ssam 			}
12179578Ssam 			break;
12187502Sroot 		}
12199578Ssam 		/*
12209578Ssam 		 * Interpret EOF only in cooked mode.
12219578Ssam 		 */
12229578Ssam 		if (c == tp->t_eofc && (t_flags&CBREAK) == 0)
12239578Ssam 			break;
12249578Ssam 		/*
12259578Ssam 		 * Give user character.
12269578Ssam 		 */
122724273Slepreau  		error = ureadc(t_flags&PASS8 ? c : c & 0177, uio);
12289578Ssam 		if (error)
12299578Ssam 			break;
123014938Smckusick  		if (uio->uio_resid == 0)
12319578Ssam 			break;
12329578Ssam 		/*
12339578Ssam 		 * In cooked mode check for a "break character"
12349578Ssam 		 * marking the end of a "line of input".
12359578Ssam 		 */
12369578Ssam 		if ((t_flags&CBREAK) == 0 && ttbreakc(c, tp))
12379578Ssam 			break;
12389578Ssam 		first = 0;
12397502Sroot 	}
12409578Ssam 
12419859Ssam checktandem:
12429578Ssam 	/*
12439578Ssam 	 * Look to unblock output now that (presumably)
12449578Ssam 	 * the input queue has gone down.
12459578Ssam 	 */
12469859Ssam 	if (tp->t_state&TS_TBLOCK && tp->t_rawq.c_cc < TTYHOG/5)
12479578Ssam 		if (putc(tp->t_startc, &tp->t_outq) == 0) {
12487502Sroot 			tp->t_state &= ~TS_TBLOCK;
12497502Sroot 			ttstart(tp);
12507502Sroot 		}
12518520Sroot 	return (error);
12527502Sroot }
12537502Sroot 
12547502Sroot /*
125525391Skarels  * Check the output queue on tp for space for a kernel message
125625391Skarels  * (from uprintf/tprintf).  Allow some space over the normal
125725391Skarels  * hiwater mark so we don't lose messages due to normal flow
125825391Skarels  * control, but don't let the tty run amok.
125925391Skarels  */
126025391Skarels ttycheckoutq(tp, wait)
126125391Skarels 	register struct tty *tp;
126225391Skarels 	int wait;
126325391Skarels {
126425391Skarels 	int hiwat, s;
126525391Skarels 
126625391Skarels 	hiwat = TTHIWAT(tp);
126725391Skarels 	s = spltty();
126825391Skarels 	if (tp->t_outq.c_cc > hiwat + 200)
126925391Skarels 	    while (tp->t_outq.c_cc > hiwat) {
127025391Skarels 		ttstart(tp);
127125391Skarels 		if (wait == 0) {
127225391Skarels 			splx(s);
127325391Skarels 			return (0);
127425391Skarels 		}
127525391Skarels 		tp->t_state |= TS_ASLEEP;
127625391Skarels 		sleep((caddr_t)&tp->t_outq, TTOPRI);
127725391Skarels 	}
127825391Skarels 	splx(s);
127925391Skarels 	return (1);
128025391Skarels }
128125391Skarels 
128225391Skarels /*
12837502Sroot  * Called from the device's write routine after it has
12847502Sroot  * calculated the tty-structure given as argument.
12857502Sroot  */
12867822Sroot ttwrite(tp, uio)
12877625Ssam 	register struct tty *tp;
12889578Ssam 	register struct uio *uio;
12897502Sroot {
12907502Sroot 	register char *cp;
12919578Ssam 	register int cc, ce, c;
12929578Ssam 	int i, hiwat, cnt, error, s;
12937502Sroot 	char obuf[OBUFSIZ];
12947502Sroot 
12959578Ssam 	hiwat = TTHIWAT(tp);
12969578Ssam 	cnt = uio->uio_resid;
12979578Ssam 	error = 0;
12987502Sroot loop:
129921776Sbloom 	if ((tp->t_state&TS_CARR_ON) == 0)
130021776Sbloom 		return (EIO);
13019578Ssam 	/*
13029578Ssam 	 * Hang the process if it's in the background.
13039578Ssam 	 */
130421776Sbloom 	if (u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp &&
13059578Ssam 	    (tp->t_flags&TOSTOP) && (u.u_procp->p_flag&SVFORK)==0 &&
130624392Skarels 	    !(u.u_procp->p_sigignore & sigmask(SIGTTOU)) &&
130724392Skarels 	    !(u.u_procp->p_sigmask & sigmask(SIGTTOU))) {
13087502Sroot 		gsignal(u.u_procp->p_pgrp, SIGTTOU);
13097502Sroot 		sleep((caddr_t)&lbolt, TTIPRI);
131021776Sbloom 		goto loop;
13117502Sroot 	}
13129578Ssam 
13139578Ssam 	/*
13149578Ssam 	 * Process the user's data in at most OBUFSIZ
13159578Ssam 	 * chunks.  Perform lower case simulation and
13169578Ssam 	 * similar hacks.  Keep track of high water
13179578Ssam 	 * mark, sleep on overflow awaiting device aid
13189578Ssam 	 * in acquiring new space.
13199578Ssam 	 */
13207822Sroot 	while (uio->uio_resid > 0) {
13219578Ssam 		/*
13229578Ssam 		 * Grab a hunk of data from the user.
13239578Ssam 		 */
13247822Sroot 		cc = uio->uio_iov->iov_len;
13257822Sroot 		if (cc == 0) {
13267822Sroot 			uio->uio_iovcnt--;
13277822Sroot 			uio->uio_iov++;
132821776Sbloom 			if (uio->uio_iovcnt <= 0)
13297822Sroot 				panic("ttwrite");
13307822Sroot 			continue;
13317822Sroot 		}
13327822Sroot 		if (cc > OBUFSIZ)
13337822Sroot 			cc = OBUFSIZ;
13347502Sroot 		cp = obuf;
133512752Ssam 		error = uiomove(cp, cc, UIO_WRITE, uio);
13368520Sroot 		if (error)
13377502Sroot 			break;
13387502Sroot 		if (tp->t_outq.c_cc > hiwat)
13397502Sroot 			goto ovhiwat;
13409578Ssam 		if (tp->t_flags&FLUSHO)
13417502Sroot 			continue;
13429578Ssam 		/*
13439578Ssam 		 * If we're mapping lower case or kludging tildes,
13449578Ssam 		 * then we've got to look at each character, so
13459578Ssam 		 * just feed the stuff to ttyoutput...
13469578Ssam 		 */
13479578Ssam 		if (tp->t_flags & (LCASE|TILDE)) {
13489578Ssam 			while (cc > 0) {
13497502Sroot 				c = *cp++;
13507502Sroot 				tp->t_rocount = 0;
13517625Ssam 				while ((c = ttyoutput(c, tp)) >= 0) {
13527502Sroot 					/* out of clists, wait a bit */
13537502Sroot 					ttstart(tp);
13547502Sroot 					sleep((caddr_t)&lbolt, TTOPRI);
13557502Sroot 					tp->t_rocount = 0;
135621776Sbloom 					if (cc != 0) {
135721776Sbloom 						uio->uio_iov->iov_base -= cc;
135821776Sbloom 						uio->uio_iov->iov_len += cc;
135921776Sbloom 						uio->uio_resid += cc;
136021776Sbloom 						uio->uio_offset -= cc;
136121776Sbloom 					}
136221776Sbloom 					goto loop;
13637502Sroot 				}
13647502Sroot 				--cc;
13657502Sroot 				if (tp->t_outq.c_cc > hiwat)
13667502Sroot 					goto ovhiwat;
13677502Sroot 			}
13687502Sroot 			continue;
13697502Sroot 		}
13709578Ssam 		/*
13719578Ssam 		 * If nothing fancy need be done, grab those characters we
13729578Ssam 		 * can handle without any of ttyoutput's processing and
13739578Ssam 		 * just transfer them to the output q.  For those chars
13749578Ssam 		 * which require special processing (as indicated by the
13759578Ssam 		 * bits in partab), call ttyoutput.  After processing
13769578Ssam 		 * a hunk of data, look for FLUSHO so ^O's will take effect
13779578Ssam 		 * immediately.
13789578Ssam 		 */
13799578Ssam 		while (cc > 0) {
13809578Ssam 			if (tp->t_flags & (RAW|LITOUT))
13817502Sroot 				ce = cc;
13827502Sroot 			else {
138312752Ssam 				ce = cc - scanc((unsigned)cc, (caddr_t)cp,
138412752Ssam 				   (caddr_t)partab, 077);
13859578Ssam 				/*
13869578Ssam 				 * If ce is zero, then we're processing
13879578Ssam 				 * a special character through ttyoutput.
13889578Ssam 				 */
13899578Ssam 				if (ce == 0) {
13907502Sroot 					tp->t_rocount = 0;
13917502Sroot 					if (ttyoutput(*cp, tp) >= 0) {
139221776Sbloom 					    /* no c-lists, wait a bit */
139321776Sbloom 					    ttstart(tp);
139421776Sbloom 					    sleep((caddr_t)&lbolt, TTOPRI);
139521776Sbloom 					    if (cc != 0) {
139621776Sbloom 					        uio->uio_iov->iov_base -= cc;
139721776Sbloom 					        uio->uio_iov->iov_len += cc;
139821776Sbloom 					        uio->uio_resid += cc;
139921776Sbloom 						uio->uio_offset -= cc;
140021776Sbloom 					    }
140121776Sbloom 					    goto loop;
14027502Sroot 					}
14039578Ssam 					cp++, cc--;
14049578Ssam 					if (tp->t_flags&FLUSHO ||
14059578Ssam 					    tp->t_outq.c_cc > hiwat)
14067502Sroot 						goto ovhiwat;
14079578Ssam 					continue;
14087502Sroot 				}
14097502Sroot 			}
14109578Ssam 			/*
14119578Ssam 			 * A bunch of normal characters have been found,
14129578Ssam 			 * transfer them en masse to the output queue and
14139578Ssam 			 * continue processing at the top of the loop.
14149578Ssam 			 * If there are any further characters in this
14159578Ssam 			 * <= OBUFSIZ chunk, the first should be a character
14169578Ssam 			 * requiring special handling by ttyoutput.
14179578Ssam 			 */
14187502Sroot 			tp->t_rocount = 0;
14199578Ssam 			i = b_to_q(cp, ce, &tp->t_outq);
14209578Ssam 			ce -= i;
14219578Ssam 			tp->t_col += ce;
14229578Ssam 			cp += ce, cc -= ce, tk_nout += ce;
14239578Ssam 			if (i > 0) {
14249578Ssam 				/* out of c-lists, wait a bit */
14257502Sroot 				ttstart(tp);
14267502Sroot 				sleep((caddr_t)&lbolt, TTOPRI);
142721776Sbloom 				uio->uio_iov->iov_base -= cc;
142821776Sbloom 				uio->uio_iov->iov_len += cc;
142921776Sbloom 				uio->uio_resid += cc;
143021776Sbloom 				uio->uio_offset -= cc;
143121776Sbloom 				goto loop;
14327502Sroot 			}
14339578Ssam 			if (tp->t_flags&FLUSHO || tp->t_outq.c_cc > hiwat)
14347502Sroot 				goto ovhiwat;
14357502Sroot 		}
14367502Sroot 	}
14377502Sroot 	ttstart(tp);
14388520Sroot 	return (error);
14397502Sroot 
14407502Sroot ovhiwat:
144117545Skarels 	s = spltty();
14429578Ssam 	if (cc != 0) {
14439578Ssam 		uio->uio_iov->iov_base -= cc;
14449578Ssam 		uio->uio_iov->iov_len += cc;
14459578Ssam 		uio->uio_resid += cc;
14469578Ssam 		uio->uio_offset -= cc;
14479578Ssam 	}
14489578Ssam 	/*
14499578Ssam 	 * This can only occur if FLUSHO
14509578Ssam 	 * is also set in t_flags.
14519578Ssam 	 */
14527502Sroot 	if (tp->t_outq.c_cc <= hiwat) {
14539578Ssam 		splx(s);
14547502Sroot 		goto loop;
14557502Sroot 	}
14567502Sroot 	ttstart(tp);
14579578Ssam 	if (tp->t_state&TS_NBIO) {
145817545Skarels 		splx(s);
14597822Sroot 		if (uio->uio_resid == cnt)
14608520Sroot 			return (EWOULDBLOCK);
14618520Sroot 		return (0);
14627502Sroot 	}
14637502Sroot 	tp->t_state |= TS_ASLEEP;
14647502Sroot 	sleep((caddr_t)&tp->t_outq, TTOPRI);
14659578Ssam 	splx(s);
14667502Sroot 	goto loop;
14677502Sroot }
14687502Sroot 
14697502Sroot /*
14707502Sroot  * Rubout one character from the rawq of tp
14717502Sroot  * as cleanly as possible.
14727502Sroot  */
14737502Sroot ttyrub(c, tp)
14747625Ssam 	register c;
14757625Ssam 	register struct tty *tp;
14767502Sroot {
14777502Sroot 	register char *cp;
14787502Sroot 	register int savecol;
14797502Sroot 	int s;
14807502Sroot 	char *nextc();
14817502Sroot 
14829578Ssam 	if ((tp->t_flags&ECHO) == 0)
14837502Sroot 		return;
14849578Ssam 	tp->t_flags &= ~FLUSHO;
14857502Sroot 	c &= 0377;
14869578Ssam 	if (tp->t_flags&CRTBS) {
14877502Sroot 		if (tp->t_rocount == 0) {
14887502Sroot 			/*
14897502Sroot 			 * Screwed by ttwrite; retype
14907502Sroot 			 */
14917502Sroot 			ttyretype(tp);
14927502Sroot 			return;
14937502Sroot 		}
14949578Ssam 		if (c == ('\t'|0200) || c == ('\n'|0200))
14957502Sroot 			ttyrubo(tp, 2);
14969578Ssam 		else switch (partab[c&=0177]&0177) {
14977502Sroot 
14987502Sroot 		case ORDINARY:
14997502Sroot 			if (tp->t_flags&LCASE && c >= 'A' && c <= 'Z')
15007502Sroot 				ttyrubo(tp, 2);
15017502Sroot 			else
15027502Sroot 				ttyrubo(tp, 1);
15037502Sroot 			break;
15047502Sroot 
15057502Sroot 		case VTAB:
15067502Sroot 		case BACKSPACE:
15077502Sroot 		case CONTROL:
15087502Sroot 		case RETURN:
15099578Ssam 			if (tp->t_flags&CTLECH)
15107502Sroot 				ttyrubo(tp, 2);
15117502Sroot 			break;
15127502Sroot 
15137502Sroot 		case TAB:
15147502Sroot 			if (tp->t_rocount < tp->t_rawq.c_cc) {
15157502Sroot 				ttyretype(tp);
15167502Sroot 				return;
15177502Sroot 			}
151817545Skarels 			s = spltty();
15197502Sroot 			savecol = tp->t_col;
15209578Ssam 			tp->t_state |= TS_CNTTB;
15219578Ssam 			tp->t_flags |= FLUSHO;
15227502Sroot 			tp->t_col = tp->t_rocol;
15239578Ssam 			cp = tp->t_rawq.c_cf;
15249578Ssam 			for (; cp; cp = nextc(&tp->t_rawq, cp))
15257502Sroot 				ttyecho(*cp, tp);
15269578Ssam 			tp->t_flags &= ~FLUSHO;
15279578Ssam 			tp->t_state &= ~TS_CNTTB;
15287502Sroot 			splx(s);
15297502Sroot 			/*
15307502Sroot 			 * savecol will now be length of the tab
15317502Sroot 			 */
15327502Sroot 			savecol -= tp->t_col;
15337502Sroot 			tp->t_col += savecol;
15347502Sroot 			if (savecol > 8)
15357502Sroot 				savecol = 8;		/* overflow screw */
15367502Sroot 			while (--savecol >= 0)
15377502Sroot 				(void) ttyoutput('\b', tp);
15387502Sroot 			break;
15397502Sroot 
15407502Sroot 		default:
15417502Sroot 			panic("ttyrub");
15427502Sroot 		}
15439578Ssam 	} else if (tp->t_flags&PRTERA) {
15449578Ssam 		if ((tp->t_state&TS_ERASE) == 0) {
15457502Sroot 			(void) ttyoutput('\\', tp);
15469578Ssam 			tp->t_state |= TS_ERASE;
15477502Sroot 		}
15487502Sroot 		ttyecho(c, tp);
15497502Sroot 	} else
15507502Sroot 		ttyecho(tp->t_erase, tp);
15517502Sroot 	tp->t_rocount--;
15527502Sroot }
15537502Sroot 
15547502Sroot /*
15557502Sroot  * Crt back over cnt chars perhaps
15567502Sroot  * erasing them.
15577502Sroot  */
15587502Sroot ttyrubo(tp, cnt)
15597625Ssam 	register struct tty *tp;
15607625Ssam 	int cnt;
15617502Sroot {
15629578Ssam 	register char *rubostring = tp->t_flags&CRTERA ? "\b \b" : "\b";
15637502Sroot 
15647502Sroot 	while (--cnt >= 0)
15659578Ssam 		ttyout(rubostring, tp);
15667502Sroot }
15677502Sroot 
15687502Sroot /*
15697502Sroot  * Reprint the rawq line.
15707502Sroot  * We assume c_cc has already been checked.
15717502Sroot  */
15727502Sroot ttyretype(tp)
15737625Ssam 	register struct tty *tp;
15747502Sroot {
15757502Sroot 	register char *cp;
15767502Sroot 	char *nextc();
15777502Sroot 	int s;
15787502Sroot 
15799578Ssam 	if (tp->t_rprntc != 0377)
15809578Ssam 		ttyecho(tp->t_rprntc, tp);
15817502Sroot 	(void) ttyoutput('\n', tp);
158217545Skarels 	s = spltty();
15837502Sroot 	for (cp = tp->t_canq.c_cf; cp; cp = nextc(&tp->t_canq, cp))
15847502Sroot 		ttyecho(*cp, tp);
15857502Sroot 	for (cp = tp->t_rawq.c_cf; cp; cp = nextc(&tp->t_rawq, cp))
15867502Sroot 		ttyecho(*cp, tp);
15879578Ssam 	tp->t_state &= ~TS_ERASE;
15887502Sroot 	splx(s);
15897502Sroot 	tp->t_rocount = tp->t_rawq.c_cc;
15907502Sroot 	tp->t_rocol = 0;
15917502Sroot }
15927502Sroot 
15937502Sroot /*
15947502Sroot  * Echo a typed character to the terminal
15957502Sroot  */
15967502Sroot ttyecho(c, tp)
15977625Ssam 	register c;
15987625Ssam 	register struct tty *tp;
15997502Sroot {
16007502Sroot 
16019578Ssam 	if ((tp->t_state&TS_CNTTB) == 0)
16029578Ssam 		tp->t_flags &= ~FLUSHO;
16037502Sroot 	if ((tp->t_flags&ECHO) == 0)
16047502Sroot 		return;
16057502Sroot 	c &= 0377;
16067502Sroot 	if (tp->t_flags&RAW) {
16077502Sroot 		(void) ttyoutput(c, tp);
16087502Sroot 		return;
16097502Sroot 	}
16107502Sroot 	if (c == '\r' && tp->t_flags&CRMOD)
16117502Sroot 		c = '\n';
16129578Ssam 	if (tp->t_flags&CTLECH) {
16137502Sroot 		if ((c&0177) <= 037 && c!='\t' && c!='\n' || (c&0177)==0177) {
16147502Sroot 			(void) ttyoutput('^', tp);
16157502Sroot 			c &= 0177;
16167502Sroot 			if (c == 0177)
16177502Sroot 				c = '?';
16187502Sroot 			else if (tp->t_flags&LCASE)
16197502Sroot 				c += 'a' - 1;
16207502Sroot 			else
16217502Sroot 				c += 'A' - 1;
16227502Sroot 		}
16237502Sroot 	}
16249578Ssam 	(void) ttyoutput(c&0177, tp);
16257502Sroot }
16267502Sroot 
16277502Sroot /*
16287502Sroot  * Is c a break char for tp?
16297502Sroot  */
16307502Sroot ttbreakc(c, tp)
16317625Ssam 	register c;
16327625Ssam 	register struct tty *tp;
16337502Sroot {
16349578Ssam 	return (c == '\n' || c == tp->t_eofc || c == tp->t_brkc ||
16357502Sroot 		c == '\r' && (tp->t_flags&CRMOD));
16367502Sroot }
16377502Sroot 
16387502Sroot /*
16397502Sroot  * send string cp to tp
16407502Sroot  */
16417502Sroot ttyout(cp, tp)
16427625Ssam 	register char *cp;
16437625Ssam 	register struct tty *tp;
16447502Sroot {
16457502Sroot 	register char c;
16467502Sroot 
16477502Sroot 	while (c = *cp++)
16487502Sroot 		(void) ttyoutput(c, tp);
16497502Sroot }
16507502Sroot 
16517502Sroot ttwakeup(tp)
16527502Sroot 	struct tty *tp;
16537502Sroot {
16547502Sroot 
16557502Sroot 	if (tp->t_rsel) {
16567502Sroot 		selwakeup(tp->t_rsel, tp->t_state&TS_RCOLL);
16577502Sroot 		tp->t_state &= ~TS_RCOLL;
16587502Sroot 		tp->t_rsel = 0;
16597502Sroot 	}
166012752Ssam 	if (tp->t_state & TS_ASYNC)
166112752Ssam 		gsignal(tp->t_pgrp, SIGIO);
16627502Sroot 	wakeup((caddr_t)&tp->t_rawq);
16637502Sroot }
1664