xref: /csrg-svn/sys/kern/tty.c (revision 25404)
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*25404Skarels  *	@(#)tty.c	6.23 (Berkeley) 11/06/85
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);
29317545Skarels 		s = spltty();
29425391Skarels 		(*linesw[tp->t_line].l_close)(tp);
29525391Skarels 		error = (*linesw[t].l_open)(dev, tp);
29610851Ssam 		if (error) {
29725391Skarels 			(void) (*linesw[tp->t_line].l_open)(dev, tp);
29810851Ssam 			splx(s);
2998556Sroot 			return (error);
30010851Ssam 		}
3018556Sroot 		tp->t_line = t;
30218650Sbloom 		splx(s);
30339Sbill 		break;
3047625Ssam 	}
30539Sbill 
3068556Sroot 	/* prevent more opens on channel */
3075614Swnj 	case TIOCEXCL:
3085614Swnj 		tp->t_state |= TS_XCLUDE;
3095614Swnj 		break;
3105614Swnj 
3115614Swnj 	case TIOCNXCL:
3125614Swnj 		tp->t_state &= ~TS_XCLUDE;
3135614Swnj 		break;
3145614Swnj 
3158556Sroot 	/* hang up line on last close */
31639Sbill 	case TIOCHPCL:
3175408Swnj 		tp->t_state |= TS_HUPCLS;
31839Sbill 		break;
31939Sbill 
3203942Sbugs 	case TIOCFLUSH: {
3217625Ssam 		register int flags = *(int *)data;
3227625Ssam 
3237625Ssam 		if (flags == 0)
3243942Sbugs 			flags = FREAD|FWRITE;
3257625Ssam 		else
3267625Ssam 			flags &= FREAD|FWRITE;
32712752Ssam 		ttyflush(tp, flags);
32839Sbill 		break;
3293944Sbugs 	}
33039Sbill 
3318556Sroot 	/* return number of characters immediately available */
3327625Ssam 	case FIONREAD:
3337625Ssam 		*(off_t *)data = ttnread(tp);
334174Sbill 		break;
335174Sbill 
33613077Ssam 	case TIOCOUTQ:
33713077Ssam 		*(int *)data = tp->t_outq.c_cc;
33813077Ssam 		break;
33913077Ssam 
3408589Sroot 	case TIOCSTOP:
34117545Skarels 		s = spltty();
3429578Ssam 		if ((tp->t_state&TS_TTSTOP) == 0) {
3435573Swnj 			tp->t_state |= TS_TTSTOP;
3445573Swnj 			(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
3455573Swnj 		}
3467625Ssam 		splx(s);
3475573Swnj 		break;
3485573Swnj 
3498589Sroot 	case TIOCSTART:
35017545Skarels 		s = spltty();
3519578Ssam 		if ((tp->t_state&TS_TTSTOP) || (tp->t_flags&FLUSHO)) {
3525573Swnj 			tp->t_state &= ~TS_TTSTOP;
3539578Ssam 			tp->t_flags &= ~FLUSHO;
3545573Swnj 			ttstart(tp);
3555573Swnj 		}
3567625Ssam 		splx(s);
3575573Swnj 		break;
3585573Swnj 
3599325Ssam 	/*
3609325Ssam 	 * Simulate typing of a character at the terminal.
3619325Ssam 	 */
3629325Ssam 	case TIOCSTI:
36317183Smckusick 		if (u.u_uid && (flag & FREAD) == 0)
36417183Smckusick 			return (EPERM);
3659325Ssam 		if (u.u_uid && u.u_ttyp != tp)
3669325Ssam 			return (EACCES);
3679578Ssam 		(*linesw[tp->t_line].l_rint)(*(char *)data, tp);
3689325Ssam 		break;
3699325Ssam 
37012752Ssam 	case TIOCSETP:
37112752Ssam 	case TIOCSETN: {
37212752Ssam 		register struct sgttyb *sg = (struct sgttyb *)data;
37312752Ssam 
37412752Ssam 		tp->t_erase = sg->sg_erase;
37512752Ssam 		tp->t_kill = sg->sg_kill;
37612752Ssam 		tp->t_ispeed = sg->sg_ispeed;
37712752Ssam 		tp->t_ospeed = sg->sg_ospeed;
37812752Ssam 		newflags = (tp->t_flags&0xffff0000) | (sg->sg_flags&0xffff);
37917545Skarels 		s = spltty();
38012752Ssam 		if (tp->t_flags&RAW || newflags&RAW || com == TIOCSETP) {
38112752Ssam 			ttywait(tp);
38212752Ssam 			ttyflush(tp, FREAD);
38312752Ssam 		} else if ((tp->t_flags&CBREAK) != (newflags&CBREAK)) {
38412752Ssam 			if (newflags&CBREAK) {
38512752Ssam 				struct clist tq;
38612752Ssam 
38712752Ssam 				catq(&tp->t_rawq, &tp->t_canq);
38812752Ssam 				tq = tp->t_rawq;
38912752Ssam 				tp->t_rawq = tp->t_canq;
39012752Ssam 				tp->t_canq = tq;
39112752Ssam 			} else {
39212752Ssam 				tp->t_flags |= PENDIN;
39313801Ssam 				newflags |= PENDIN;
39412752Ssam 				ttwakeup(tp);
39512752Ssam 			}
39612752Ssam 		}
39712752Ssam 		tp->t_flags = newflags;
39812752Ssam 		if (tp->t_flags&RAW) {
39912752Ssam 			tp->t_state &= ~TS_TTSTOP;
40012752Ssam 			ttstart(tp);
40112752Ssam 		}
40212752Ssam 		splx(s);
40312752Ssam 		break;
40412752Ssam 	}
40512752Ssam 
40612752Ssam 	/* send current parameters to user */
40712752Ssam 	case TIOCGETP: {
40812752Ssam 		register struct sgttyb *sg = (struct sgttyb *)data;
40912752Ssam 
41012752Ssam 		sg->sg_ispeed = tp->t_ispeed;
41112752Ssam 		sg->sg_ospeed = tp->t_ospeed;
41212752Ssam 		sg->sg_erase = tp->t_erase;
41312752Ssam 		sg->sg_kill = tp->t_kill;
41412752Ssam 		sg->sg_flags = tp->t_flags;
41512752Ssam 		break;
41612752Ssam 	}
41712752Ssam 
41812752Ssam 	case FIONBIO:
41912752Ssam 		if (*(int *)data)
42012752Ssam 			tp->t_state |= TS_NBIO;
42112752Ssam 		else
42212752Ssam 			tp->t_state &= ~TS_NBIO;
42312752Ssam 		break;
42412752Ssam 
42512752Ssam 	case FIOASYNC:
42612752Ssam 		if (*(int *)data)
42712752Ssam 			tp->t_state |= TS_ASYNC;
42812752Ssam 		else
42912752Ssam 			tp->t_state &= ~TS_ASYNC;
43012752Ssam 		break;
43112752Ssam 
43213077Ssam 	case TIOCGETC:
43313077Ssam 		bcopy((caddr_t)&tp->t_intrc, data, sizeof (struct tchars));
43413077Ssam 		break;
43513077Ssam 
43613077Ssam 	case TIOCSETC:
43713077Ssam 		bcopy(data, (caddr_t)&tp->t_intrc, sizeof (struct tchars));
43813077Ssam 		break;
43913077Ssam 
44012752Ssam 	/* set/get local special characters */
44112752Ssam 	case TIOCSLTC:
44212752Ssam 		bcopy(data, (caddr_t)&tp->t_suspc, sizeof (struct ltchars));
44312752Ssam 		break;
44412752Ssam 
44512752Ssam 	case TIOCGLTC:
44612752Ssam 		bcopy((caddr_t)&tp->t_suspc, data, sizeof (struct ltchars));
44712752Ssam 		break;
44812752Ssam 
44912752Ssam 	/*
45012752Ssam 	 * Modify local mode word.
45112752Ssam 	 */
45212752Ssam 	case TIOCLBIS:
45312752Ssam 		tp->t_flags |= *(int *)data << 16;
45412752Ssam 		break;
45512752Ssam 
45612752Ssam 	case TIOCLBIC:
45712752Ssam 		tp->t_flags &= ~(*(int *)data << 16);
45812752Ssam 		break;
45912752Ssam 
46012752Ssam 	case TIOCLSET:
46112752Ssam 		tp->t_flags &= 0xffff;
46212752Ssam 		tp->t_flags |= *(int *)data << 16;
46312752Ssam 		break;
46412752Ssam 
46512752Ssam 	case TIOCLGET:
46615720Skarels 		*(int *)data = ((unsigned) tp->t_flags) >> 16;
46712752Ssam 		break;
46812752Ssam 
46917545Skarels 	/*
47017932Skarels 	 * Allow SPGRP only if tty is open for reading.
47117598Sbloom 	 * Quick check: if we can find a process in the new pgrp,
47217598Sbloom 	 * this user must own that process.
47317598Sbloom 	 * SHOULD VERIFY THAT PGRP IS IN USE AND IS THIS USER'S.
47417545Skarels 	 */
47518650Sbloom 	case TIOCSPGRP: {
47617545Skarels 		struct proc *p;
47717545Skarels 		int pgrp = *(int *)data;
47817545Skarels 
47917545Skarels 		if (u.u_uid && (flag & FREAD) == 0)
48017545Skarels 			return (EPERM);
48117598Sbloom 		p = pfind(pgrp);
48217598Sbloom 		if (p && p->p_pgrp == pgrp &&
48317598Sbloom 		    p->p_uid != u.u_uid && u.u_uid && !inferior(p))
48417598Sbloom 			return (EPERM);
48517545Skarels 		tp->t_pgrp = pgrp;
48612752Ssam 		break;
48718650Sbloom 	}
48812752Ssam 
48912752Ssam 	case TIOCGPGRP:
49012752Ssam 		*(int *)data = tp->t_pgrp;
49112752Ssam 		break;
49212752Ssam 
49317598Sbloom 	case TIOCSWINSZ:
49418650Sbloom 		if (bcmp((caddr_t)&tp->t_winsize, data,
49518650Sbloom 		    sizeof (struct winsize))) {
49617598Sbloom 			tp->t_winsize = *(struct winsize *)data;
49717598Sbloom 			gsignal(tp->t_pgrp, SIGWINCH);
49817598Sbloom 		}
49917598Sbloom 		break;
50017598Sbloom 
50117598Sbloom 	case TIOCGWINSZ:
50217598Sbloom 		*(struct winsize *)data = tp->t_winsize;
50317598Sbloom 		break;
50417598Sbloom 
50539Sbill 	default:
5068556Sroot 		return (-1);
50739Sbill 	}
5088556Sroot 	return (0);
50939Sbill }
5104484Swnj 
5114484Swnj ttnread(tp)
5124484Swnj 	struct tty *tp;
5134484Swnj {
5144484Swnj 	int nread = 0;
5154484Swnj 
5169578Ssam 	if (tp->t_flags & PENDIN)
5174484Swnj 		ttypend(tp);
5184484Swnj 	nread = tp->t_canq.c_cc;
5194484Swnj 	if (tp->t_flags & (RAW|CBREAK))
5204484Swnj 		nread += tp->t_rawq.c_cc;
5214484Swnj 	return (nread);
5224484Swnj }
5234484Swnj 
5245408Swnj ttselect(dev, rw)
5254484Swnj 	dev_t dev;
5265408Swnj 	int rw;
5274484Swnj {
5284484Swnj 	register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)];
5294484Swnj 	int nread;
53017545Skarels 	int s = spltty();
5314484Swnj 
5325408Swnj 	switch (rw) {
5334484Swnj 
5344484Swnj 	case FREAD:
5354484Swnj 		nread = ttnread(tp);
53621776Sbloom 		if ((nread > 0) || ((tp->t_state & TS_CARR_ON) == 0))
5375408Swnj 			goto win;
5384938Swnj 		if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait)
5395408Swnj 			tp->t_state |= TS_RCOLL;
5404484Swnj 		else
5414484Swnj 			tp->t_rsel = u.u_procp;
5425408Swnj 		break;
5434484Swnj 
5445408Swnj 	case FWRITE:
5455408Swnj 		if (tp->t_outq.c_cc <= TTLOWAT(tp))
5465408Swnj 			goto win;
5475408Swnj 		if (tp->t_wsel && tp->t_wsel->p_wchan == (caddr_t)&selwait)
5485408Swnj 			tp->t_state |= TS_WCOLL;
5495408Swnj 		else
5505408Swnj 			tp->t_wsel = u.u_procp;
5515408Swnj 		break;
5524484Swnj 	}
5535408Swnj 	splx(s);
5545408Swnj 	return (0);
5555408Swnj win:
5565408Swnj 	splx(s);
5575408Swnj 	return (1);
5584484Swnj }
5597436Skre 
5607502Sroot /*
56125391Skarels  * Initial open of tty, or (re)entry to line discipline.
5629578Ssam  * Establish a process group for distribution of
5637502Sroot  * quits and interrupts from the tty.
5647502Sroot  */
5657502Sroot ttyopen(dev, tp)
5667625Ssam 	dev_t dev;
5677625Ssam 	register struct tty *tp;
5687502Sroot {
5697502Sroot 	register struct proc *pp;
5707502Sroot 
5717502Sroot 	pp = u.u_procp;
5727502Sroot 	tp->t_dev = dev;
5737625Ssam 	if (pp->p_pgrp == 0) {
5747502Sroot 		u.u_ttyp = tp;
5757502Sroot 		u.u_ttyd = dev;
5767502Sroot 		if (tp->t_pgrp == 0)
5777502Sroot 			tp->t_pgrp = pp->p_pid;
5787502Sroot 		pp->p_pgrp = tp->t_pgrp;
5797502Sroot 	}
5807502Sroot 	tp->t_state &= ~TS_WOPEN;
58117545Skarels 	if ((tp->t_state & TS_ISOPEN) == 0) {
58217545Skarels 		tp->t_state |= TS_ISOPEN;
58317598Sbloom 		bzero((caddr_t)&tp->t_winsize, sizeof(tp->t_winsize));
58417545Skarels 		if (tp->t_line != NTTYDISC)
58517545Skarels 			ttywflush(tp);
58617545Skarels 	}
5878556Sroot 	return (0);
5887502Sroot }
5897502Sroot 
5907502Sroot /*
59125391Skarels  * "close" a line discipline
59225391Skarels  */
59325391Skarels ttylclose(tp)
59425391Skarels 	register struct tty *tp;
59525391Skarels {
59625391Skarels 
59725391Skarels 	ttywflush(tp);
59825391Skarels 	tp->t_line = 0;
59925391Skarels }
60025391Skarels 
60125391Skarels /*
6027502Sroot  * clean tp on last close
6037502Sroot  */
6047502Sroot ttyclose(tp)
6057625Ssam 	register struct tty *tp;
6067502Sroot {
6077502Sroot 
60825391Skarels 	ttyflush(tp, FREAD|FWRITE);
6097502Sroot 	tp->t_pgrp = 0;
6107502Sroot 	tp->t_state = 0;
6117502Sroot }
6127502Sroot 
6137502Sroot /*
61425391Skarels  * Handle modem control transition on a tty.
61525391Skarels  * Flag indicates new state of carrier.
61625391Skarels  * Returns 0 if the line should be turned off, otherwise 1.
61725391Skarels  */
61825391Skarels ttymodem(tp, flag)
61925391Skarels 	register struct tty *tp;
62025391Skarels {
62125391Skarels 
62225391Skarels 	if ((tp->t_state&TS_WOPEN) == 0 && (tp->t_flags & MDMBUF)) {
62325391Skarels 		/*
62425391Skarels 		 * MDMBUF: do flow control according to carrier flag
62525391Skarels 		 */
62625391Skarels 		if (flag) {
62725391Skarels 			tp->t_state &= ~TS_TTSTOP;
62825391Skarels 			ttstart(tp);
62925391Skarels 		} else if ((tp->t_state&TS_TTSTOP) == 0) {
63025391Skarels 			tp->t_state |= TS_TTSTOP;
63125391Skarels 			(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
63225391Skarels 		}
63325391Skarels 	} else if (flag == 0) {
63425391Skarels 		/*
63525391Skarels 		 * Lost carrier.
63625391Skarels 		 */
63725391Skarels 		tp->t_state &= ~TS_CARR_ON;
63825391Skarels 		if (tp->t_state & TS_ISOPEN) {
63925391Skarels 			if ((tp->t_flags & NOHANG) == 0) {
64025391Skarels 				gsignal(tp->t_pgrp, SIGHUP);
64125391Skarels 				gsignal(tp->t_pgrp, SIGCONT);
64225391Skarels 				ttyflush(tp, FREAD|FWRITE);
64325391Skarels 				return (0);
64425391Skarels 			}
64525391Skarels 		}
64625391Skarels 	} else {
64725391Skarels 		/*
64825391Skarels 		 * Carrier now on.
64925391Skarels 		 */
65025391Skarels 		tp->t_state |= TS_CARR_ON;
65125391Skarels 		wakeup((caddr_t)&tp->t_rawq);
65225391Skarels 	}
65325391Skarels 	return (1);
65425391Skarels }
65525391Skarels 
65625391Skarels /*
657*25404Skarels  * Default modem control routine (for other line disciplines).
658*25404Skarels  * Return argument flag, to turn off device on carrier drop.
659*25404Skarels  */
660*25404Skarels nullmodem(flag)
661*25404Skarels 	int flag;
662*25404Skarels {
663*25404Skarels 
664*25404Skarels 	if (flag)
665*25404Skarels 		tp->t_state |= TS_CARR_ON;
666*25404Skarels 	else
667*25404Skarels 		tp->t_state &= ~TS_CARR_ON;
668*25404Skarels 	return (flag);
669*25404Skarels }
670*25404Skarels 
671*25404Skarels /*
6727502Sroot  * reinput pending characters after state switch
67317545Skarels  * call at spltty().
6747502Sroot  */
6757502Sroot ttypend(tp)
6767625Ssam 	register struct tty *tp;
6777502Sroot {
6787502Sroot 	struct clist tq;
6797502Sroot 	register c;
6807502Sroot 
6819578Ssam 	tp->t_flags &= ~PENDIN;
6829578Ssam 	tp->t_state |= TS_TYPEN;
6837502Sroot 	tq = tp->t_rawq;
6847502Sroot 	tp->t_rawq.c_cc = 0;
6857502Sroot 	tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0;
6867502Sroot 	while ((c = getc(&tq)) >= 0)
6877502Sroot 		ttyinput(c, tp);
6889578Ssam 	tp->t_state &= ~TS_TYPEN;
6897502Sroot }
6907502Sroot 
6917502Sroot /*
6929578Ssam  * Place a character on raw TTY input queue,
6939578Ssam  * putting in delimiters and waking up top
6949578Ssam  * half as needed.  Also echo if required.
6959578Ssam  * The arguments are the character and the
6969578Ssam  * appropriate tty structure.
6977502Sroot  */
6987502Sroot ttyinput(c, tp)
6997625Ssam 	register c;
7007625Ssam 	register struct tty *tp;
7017502Sroot {
7029578Ssam 	register int t_flags = tp->t_flags;
7037502Sroot 	int i;
7047502Sroot 
7059578Ssam 	/*
7069578Ssam 	 * If input is pending take it first.
7079578Ssam 	 */
7089578Ssam 	if (t_flags&PENDIN)
7097502Sroot 		ttypend(tp);
7107502Sroot 	tk_nin++;
7117502Sroot 	c &= 0377;
7129578Ssam 
7139578Ssam 	/*
7149578Ssam 	 * In tandem mode, check high water mark.
7159578Ssam 	 */
7167502Sroot 	if (t_flags&TANDEM)
7177502Sroot 		ttyblock(tp);
7189578Ssam 
7199578Ssam 	if (t_flags&RAW) {
7209578Ssam 		/*
7219578Ssam 		 * Raw mode, just put character
7229578Ssam 		 * in input q w/o interpretation.
7239578Ssam 		 */
7249578Ssam 		if (tp->t_rawq.c_cc > TTYHOG)
72512752Ssam 			ttyflush(tp, FREAD|FWRITE);
7269578Ssam 		else {
7279578Ssam 			if (putc(c, &tp->t_rawq) >= 0)
7289578Ssam 				ttwakeup(tp);
7299578Ssam 			ttyecho(c, tp);
7307502Sroot 		}
7319578Ssam 		goto endcase;
7329578Ssam 	}
7339578Ssam 
7349578Ssam 	/*
7359578Ssam 	 * Ignore any high bit added during
7369578Ssam 	 * previous ttyinput processing.
7379578Ssam 	 */
73824273Slepreau 	if ((tp->t_state&TS_TYPEN) == 0 && (t_flags&PASS8) == 0)
7399578Ssam 		c &= 0177;
7409578Ssam 	/*
7419578Ssam 	 * Check for literal nexting very first
7429578Ssam 	 */
7439578Ssam 	if (tp->t_state&TS_LNCH) {
7449578Ssam 		c |= 0200;
7459578Ssam 		tp->t_state &= ~TS_LNCH;
7469578Ssam 	}
7479578Ssam 
7489578Ssam 	/*
7499578Ssam 	 * Scan for special characters.  This code
7509578Ssam 	 * is really just a big case statement with
7519578Ssam 	 * non-constant cases.  The bottom of the
7529578Ssam 	 * case statement is labeled ``endcase'', so goto
7539578Ssam 	 * it after a case match, or similar.
7549578Ssam 	 */
7559578Ssam 	if (tp->t_line == NTTYDISC) {
7569578Ssam 		if (c == tp->t_lnextc) {
75721776Sbloom 			if (t_flags&ECHO)
7587502Sroot 				ttyout("^\b", tp);
7599578Ssam 			tp->t_state |= TS_LNCH;
7609578Ssam 			goto endcase;
7619578Ssam 		}
7629578Ssam 		if (c == tp->t_flushc) {
76321776Sbloom 			if (t_flags&FLUSHO)
7649578Ssam 				tp->t_flags &= ~FLUSHO;
7657502Sroot 			else {
76612752Ssam 				ttyflush(tp, FWRITE);
7677502Sroot 				ttyecho(c, tp);
7689578Ssam 				if (tp->t_rawq.c_cc + tp->t_canq.c_cc)
7697502Sroot 					ttyretype(tp);
7709578Ssam 				tp->t_flags |= FLUSHO;
7717502Sroot 			}
7729578Ssam 			goto startoutput;
7739578Ssam 		}
7749578Ssam 		if (c == tp->t_suspc) {
77521776Sbloom 			if ((t_flags&NOFLSH) == 0)
77612752Ssam 				ttyflush(tp, FREAD);
7779578Ssam 			ttyecho(c, tp);
7789578Ssam 			gsignal(tp->t_pgrp, SIGTSTP);
7799578Ssam 			goto endcase;
7809578Ssam 		}
7819578Ssam 	}
7829578Ssam 
7839578Ssam 	/*
7849578Ssam 	 * Handle start/stop characters.
7859578Ssam 	 */
7869578Ssam 	if (c == tp->t_stopc) {
7879578Ssam 		if ((tp->t_state&TS_TTSTOP) == 0) {
7889578Ssam 			tp->t_state |= TS_TTSTOP;
7899578Ssam 			(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
7907502Sroot 			return;
7919578Ssam 		}
7929578Ssam 		if (c != tp->t_startc)
7939578Ssam 			return;
7949578Ssam 		goto endcase;
7959578Ssam 	}
7969578Ssam 	if (c == tp->t_startc)
7979578Ssam 		goto restartoutput;
7989578Ssam 
7999578Ssam 	/*
8009578Ssam 	 * Look for interrupt/quit chars.
8019578Ssam 	 */
8029578Ssam 	if (c == tp->t_intrc || c == tp->t_quitc) {
80321776Sbloom 		if ((t_flags&NOFLSH) == 0)
80412752Ssam 			ttyflush(tp, FREAD|FWRITE);
8059578Ssam 		ttyecho(c, tp);
8069578Ssam 		gsignal(tp->t_pgrp, c == tp->t_intrc ? SIGINT : SIGQUIT);
8079578Ssam 		goto endcase;
8089578Ssam 	}
8099578Ssam 
81023165Sbloom 	if (tp->t_flags & LCASE && c <= 0177) {
81123165Sbloom 		if (tp->t_state&TS_BKSL) {
81223165Sbloom 			ttyrub(unputc(&tp->t_rawq), tp);
81323165Sbloom 			if (maptab[c])
81423165Sbloom 				c = maptab[c];
81523165Sbloom 			c |= 0200;
81623165Sbloom 			tp->t_state &= ~(TS_BKSL|TS_QUOT);
81723165Sbloom 		} else if (c >= 'A' && c <= 'Z')
81823165Sbloom 			c += 'a' - 'A';
81923165Sbloom 		else if (c == '\\')
82023165Sbloom 			tp->t_state |= TS_BKSL;
82123165Sbloom 	}
82223165Sbloom 
8239578Ssam 	/*
8249578Ssam 	 * Cbreak mode, don't process line editing
8259578Ssam 	 * characters; check high water mark for wakeup.
8269578Ssam 	 */
8279578Ssam 	if (t_flags&CBREAK) {
8289578Ssam 		if (tp->t_rawq.c_cc > TTYHOG) {
8297502Sroot 			if (tp->t_outq.c_cc < TTHIWAT(tp) &&
8307502Sroot 			    tp->t_line == NTTYDISC)
8317502Sroot 				(void) ttyoutput(CTRL(g), tp);
8327502Sroot 		} else if (putc(c, &tp->t_rawq) >= 0) {
8337502Sroot 			ttwakeup(tp);
8347502Sroot 			ttyecho(c, tp);
8357502Sroot 		}
8369578Ssam 		goto endcase;
8379578Ssam 	}
8389578Ssam 
8399578Ssam 	/*
8409578Ssam 	 * From here on down cooked mode character
8419578Ssam 	 * processing takes place.
8429578Ssam 	 */
8439578Ssam 	if ((tp->t_state&TS_QUOT) &&
8449578Ssam 	    (c == tp->t_erase || c == tp->t_kill)) {
8459578Ssam 		ttyrub(unputc(&tp->t_rawq), tp);
8469578Ssam 		c |= 0200;
8479578Ssam 	}
8489578Ssam 	if (c == tp->t_erase) {
8499578Ssam 		if (tp->t_rawq.c_cc)
8509578Ssam 			ttyrub(unputc(&tp->t_rawq), tp);
8519578Ssam 		goto endcase;
8529578Ssam 	}
8539578Ssam 	if (c == tp->t_kill) {
85421776Sbloom 		if (t_flags&CRTKIL &&
8559578Ssam 		    tp->t_rawq.c_cc == tp->t_rocount) {
8569578Ssam 			while (tp->t_rawq.c_cc)
8579578Ssam 				ttyrub(unputc(&tp->t_rawq), tp);
8589578Ssam 		} else {
8599578Ssam 			ttyecho(c, tp);
8609578Ssam 			ttyecho('\n', tp);
8619578Ssam 			while (getc(&tp->t_rawq) > 0)
8629578Ssam 				;
8639578Ssam 			tp->t_rocount = 0;
8649578Ssam 		}
8659578Ssam 		tp->t_state &= ~TS_LOCAL;
8669578Ssam 		goto endcase;
8679578Ssam 	}
8689578Ssam 
8699578Ssam 	/*
8709578Ssam 	 * New line discipline,
8719578Ssam 	 * check word erase/reprint line.
8729578Ssam 	 */
8739578Ssam 	if (tp->t_line == NTTYDISC) {
8749578Ssam 		if (c == tp->t_werasc) {
8759578Ssam 			if (tp->t_rawq.c_cc == 0)
8769578Ssam 				goto endcase;
8779578Ssam 			do {
8789578Ssam 				c = unputc(&tp->t_rawq);
8799578Ssam 				if (c != ' ' && c != '\t')
8809578Ssam 					goto erasenb;
8819578Ssam 				ttyrub(c, tp);
8829578Ssam 			} while (tp->t_rawq.c_cc);
8839578Ssam 			goto endcase;
8849578Ssam 	erasenb:
8859578Ssam 			do {
8869578Ssam 				ttyrub(c, tp);
8879578Ssam 				if (tp->t_rawq.c_cc == 0)
8889578Ssam 					goto endcase;
8899578Ssam 				c = unputc(&tp->t_rawq);
8909578Ssam 			} while (c != ' ' && c != '\t');
8919578Ssam 			(void) putc(c, &tp->t_rawq);
8929578Ssam 			goto endcase;
8939578Ssam 		}
8949578Ssam 		if (c == tp->t_rprntc) {
8959578Ssam 			ttyretype(tp);
8969578Ssam 			goto endcase;
8979578Ssam 		}
8989578Ssam 	}
8999578Ssam 
9009578Ssam 	/*
9019578Ssam 	 * Check for input buffer overflow
9029578Ssam 	 */
90310391Ssam 	if (tp->t_rawq.c_cc+tp->t_canq.c_cc >= TTYHOG) {
90410391Ssam 		if (tp->t_line == NTTYDISC)
90510391Ssam 			(void) ttyoutput(CTRL(g), tp);
9069578Ssam 		goto endcase;
90710391Ssam 	}
9089578Ssam 
9099578Ssam 	/*
9109578Ssam 	 * Put data char in q for user and
9119578Ssam 	 * wakeup on seeing a line delimiter.
9129578Ssam 	 */
9139578Ssam 	if (putc(c, &tp->t_rawq) >= 0) {
9149578Ssam 		if (ttbreakc(c, tp)) {
9159578Ssam 			tp->t_rocount = 0;
9169578Ssam 			catq(&tp->t_rawq, &tp->t_canq);
9177502Sroot 			ttwakeup(tp);
9189578Ssam 		} else if (tp->t_rocount++ == 0)
9199578Ssam 			tp->t_rocol = tp->t_col;
9209578Ssam 		tp->t_state &= ~TS_QUOT;
9219578Ssam 		if (c == '\\')
9229578Ssam 			tp->t_state |= TS_QUOT;
9239578Ssam 		if (tp->t_state&TS_ERASE) {
9249578Ssam 			tp->t_state &= ~TS_ERASE;
9259578Ssam 			(void) ttyoutput('/', tp);
9269578Ssam 		}
9279578Ssam 		i = tp->t_col;
9287502Sroot 		ttyecho(c, tp);
92921776Sbloom 		if (c == tp->t_eofc && t_flags&ECHO) {
9309578Ssam 			i = MIN(2, tp->t_col - i);
9319578Ssam 			while (i > 0) {
9329578Ssam 				(void) ttyoutput('\b', tp);
9339578Ssam 				i--;
9349578Ssam 			}
9359578Ssam 		}
9367502Sroot 	}
9379578Ssam endcase:
9389578Ssam 	/*
9399578Ssam 	 * If DEC-style start/stop is enabled don't restart
9409578Ssam 	 * output until seeing the start character.
9419578Ssam 	 */
94221776Sbloom 	if (t_flags&DECCTQ && tp->t_state&TS_TTSTOP &&
9439578Ssam 	    tp->t_startc != tp->t_stopc)
9447502Sroot 		return;
9459578Ssam restartoutput:
9467502Sroot 	tp->t_state &= ~TS_TTSTOP;
9479578Ssam 	tp->t_flags &= ~FLUSHO;
9489578Ssam startoutput:
9497502Sroot 	ttstart(tp);
9507502Sroot }
9517502Sroot 
9527502Sroot /*
9539578Ssam  * Put character on TTY output queue, adding delays,
9547502Sroot  * expanding tabs, and handling the CR/NL bit.
9559578Ssam  * This is called both from the top half for output,
9569578Ssam  * and from interrupt level for echoing.
9577502Sroot  * The arguments are the character and the tty structure.
9587502Sroot  * Returns < 0 if putc succeeds, otherwise returns char to resend
9597502Sroot  * Must be recursive.
9607502Sroot  */
9617502Sroot ttyoutput(c, tp)
9627502Sroot 	register c;
9637502Sroot 	register struct tty *tp;
9647502Sroot {
9657502Sroot 	register char *colp;
9667502Sroot 	register ctype;
9677502Sroot 
9689578Ssam 	if (tp->t_flags & (RAW|LITOUT)) {
9699578Ssam 		if (tp->t_flags&FLUSHO)
9707502Sroot 			return (-1);
9717502Sroot 		if (putc(c, &tp->t_outq))
9727625Ssam 			return (c);
9737502Sroot 		tk_nout++;
9747502Sroot 		return (-1);
9757502Sroot 	}
9769578Ssam 
9777502Sroot 	/*
9789578Ssam 	 * Ignore EOT in normal mode to avoid
9799578Ssam 	 * hanging up certain terminals.
9807502Sroot 	 */
9817502Sroot 	c &= 0177;
9829578Ssam 	if (c == CEOT && (tp->t_flags&CBREAK) == 0)
9837502Sroot 		return (-1);
9847502Sroot 	/*
9857502Sroot 	 * Turn tabs to spaces as required
9867502Sroot 	 */
9879578Ssam 	if (c == '\t' && (tp->t_flags&TBDELAY) == XTABS) {
9887502Sroot 		register int s;
9897502Sroot 
9907502Sroot 		c = 8 - (tp->t_col&7);
9919578Ssam 		if ((tp->t_flags&FLUSHO) == 0) {
99217545Skarels 			s = spltty();		/* don't interrupt tabs */
9937502Sroot 			c -= b_to_q("        ", c, &tp->t_outq);
9947502Sroot 			tk_nout += c;
9957502Sroot 			splx(s);
9967502Sroot 		}
9977502Sroot 		tp->t_col += c;
9987502Sroot 		return (c ? -1 : '\t');
9997502Sroot 	}
10007502Sroot 	tk_nout++;
10017502Sroot 	/*
10027502Sroot 	 * for upper-case-only terminals,
10037502Sroot 	 * generate escapes.
10047502Sroot 	 */
10057502Sroot 	if (tp->t_flags&LCASE) {
10067502Sroot 		colp = "({)}!|^~'`";
10077625Ssam 		while (*colp++)
10087625Ssam 			if (c == *colp++) {
10097502Sroot 				if (ttyoutput('\\', tp) >= 0)
10107502Sroot 					return (c);
10117502Sroot 				c = colp[-2];
10127502Sroot 				break;
10137502Sroot 			}
10149578Ssam 		if ('A' <= c && c <= 'Z') {
10157502Sroot 			if (ttyoutput('\\', tp) >= 0)
10167502Sroot 				return (c);
10179578Ssam 		} else if ('a' <= c && c <= 'z')
10187502Sroot 			c += 'A' - 'a';
10197502Sroot 	}
10209578Ssam 
10217502Sroot 	/*
10227502Sroot 	 * turn <nl> to <cr><lf> if desired.
10237502Sroot 	 */
10249578Ssam 	if (c == '\n' && tp->t_flags&CRMOD)
10257502Sroot 		if (ttyoutput('\r', tp) >= 0)
10267502Sroot 			return (c);
10279578Ssam 	if (c == '~' && tp->t_flags&TILDE)
10287502Sroot 		c = '`';
10299578Ssam 	if ((tp->t_flags&FLUSHO) == 0 && putc(c, &tp->t_outq))
10307502Sroot 		return (c);
10317502Sroot 	/*
10327502Sroot 	 * Calculate delays.
10337502Sroot 	 * The numbers here represent clock ticks
10347502Sroot 	 * and are not necessarily optimal for all terminals.
10357502Sroot 	 * The delays are indicated by characters above 0200.
10367502Sroot 	 * In raw mode there are no delays and the
10377502Sroot 	 * transmission path is 8 bits wide.
10389578Ssam 	 *
10399578Ssam 	 * SHOULD JUST ALLOW USER TO SPECIFY DELAYS
10407502Sroot 	 */
10417502Sroot 	colp = &tp->t_col;
10427502Sroot 	ctype = partab[c];
10437502Sroot 	c = 0;
10447502Sroot 	switch (ctype&077) {
10457502Sroot 
10467502Sroot 	case ORDINARY:
10477502Sroot 		(*colp)++;
10487502Sroot 
10497502Sroot 	case CONTROL:
10507502Sroot 		break;
10517502Sroot 
10527502Sroot 	case BACKSPACE:
10537502Sroot 		if (*colp)
10547502Sroot 			(*colp)--;
10557502Sroot 		break;
10567502Sroot 
105713821Ssam 	/*
105813821Ssam 	 * This macro is close enough to the correct thing;
105913821Ssam 	 * it should be replaced by real user settable delays
106013821Ssam 	 * in any event...
106113821Ssam 	 */
106213821Ssam #define	mstohz(ms)	(((ms) * hz) >> 10)
10637502Sroot 	case NEWLINE:
10647502Sroot 		ctype = (tp->t_flags >> 8) & 03;
10657625Ssam 		if (ctype == 1) { /* tty 37 */
106612752Ssam 			if (*colp > 0)
106713863Ssam 				c = max((((unsigned)*colp) >> 4) + 3,
106813863Ssam 				    (unsigned)6);
10699578Ssam 		} else if (ctype == 2) /* vt05 */
107013821Ssam 			c = mstohz(100);
10717502Sroot 		*colp = 0;
10727502Sroot 		break;
10737502Sroot 
10747502Sroot 	case TAB:
10757502Sroot 		ctype = (tp->t_flags >> 10) & 03;
10767625Ssam 		if (ctype == 1) { /* tty 37 */
10777502Sroot 			c = 1 - (*colp | ~07);
10787625Ssam 			if (c < 5)
10797502Sroot 				c = 0;
10807502Sroot 		}
10817502Sroot 		*colp |= 07;
10827502Sroot 		(*colp)++;
10837502Sroot 		break;
10847502Sroot 
10857502Sroot 	case VTAB:
10869578Ssam 		if (tp->t_flags&VTDELAY) /* tty 37 */
10877502Sroot 			c = 0177;
10887502Sroot 		break;
10897502Sroot 
10907502Sroot 	case RETURN:
10917502Sroot 		ctype = (tp->t_flags >> 12) & 03;
10929578Ssam 		if (ctype == 1) /* tn 300 */
109313821Ssam 			c = mstohz(83);
10949578Ssam 		else if (ctype == 2) /* ti 700 */
109513821Ssam 			c = mstohz(166);
10969578Ssam 		else if (ctype == 3) { /* concept 100 */
10977502Sroot 			int i;
10989578Ssam 
10997502Sroot 			if ((i = *colp) >= 0)
11009578Ssam 				for (; i < 9; i++)
11017502Sroot 					(void) putc(0177, &tp->t_outq);
11027502Sroot 		}
11037502Sroot 		*colp = 0;
11047502Sroot 	}
11059578Ssam 	if (c && (tp->t_flags&FLUSHO) == 0)
11067502Sroot 		(void) putc(c|0200, &tp->t_outq);
11077502Sroot 	return (-1);
11087502Sroot }
110913821Ssam #undef mstohz
11107502Sroot 
11117502Sroot /*
11127502Sroot  * Called from device's read routine after it has
11137502Sroot  * calculated the tty-structure given as argument.
11147502Sroot  */
11157722Swnj ttread(tp, uio)
11167625Ssam 	register struct tty *tp;
11177722Swnj 	struct uio *uio;
11187502Sroot {
11197502Sroot 	register struct clist *qp;
11209578Ssam 	register c, t_flags;
11219859Ssam 	int s, first, error = 0;
11227502Sroot 
11237502Sroot loop:
11249578Ssam 	/*
11259578Ssam 	 * Take any pending input first.
11269578Ssam 	 */
112717545Skarels 	s = spltty();
11289578Ssam 	if (tp->t_flags&PENDIN)
11297502Sroot 		ttypend(tp);
11309859Ssam 	splx(s);
11319578Ssam 
113223165Sbloom 	if ((tp->t_state&TS_CARR_ON)==0)
113323165Sbloom 		return (EIO);
113423165Sbloom 
11359578Ssam 	/*
11369578Ssam 	 * Hang process if it's in the background.
11379578Ssam 	 */
113823165Sbloom 	if (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) {
113924392Skarels 		if ((u.u_procp->p_sigignore & sigmask(SIGTTIN)) ||
114024392Skarels 		   (u.u_procp->p_sigmask & sigmask(SIGTTIN)) ||
11417502Sroot 		    u.u_procp->p_flag&SVFORK)
11428520Sroot 			return (EIO);
11437502Sroot 		gsignal(u.u_procp->p_pgrp, SIGTTIN);
11447502Sroot 		sleep((caddr_t)&lbolt, TTIPRI);
114523165Sbloom 		goto loop;
11467502Sroot 	}
11479578Ssam 	t_flags = tp->t_flags;
11489578Ssam 
11499578Ssam 	/*
11509578Ssam 	 * In raw mode take characters directly from the
11519578Ssam 	 * raw queue w/o processing.  Interlock against
11529578Ssam 	 * device interrupts when interrogating rawq.
11539578Ssam 	 */
11549578Ssam 	if (t_flags&RAW) {
115517545Skarels 		s = spltty();
11567502Sroot 		if (tp->t_rawq.c_cc <= 0) {
11579578Ssam 			if ((tp->t_state&TS_CARR_ON) == 0 ||
11587502Sroot 			    (tp->t_state&TS_NBIO)) {
11599859Ssam 				splx(s);
116015094Skarels 				return (EWOULDBLOCK);
11617502Sroot 			}
11627502Sroot 			sleep((caddr_t)&tp->t_rawq, TTIPRI);
11639859Ssam 			splx(s);
11647502Sroot 			goto loop;
11657502Sroot 		}
11669859Ssam 		splx(s);
116714938Smckusick  		while (!error && tp->t_rawq.c_cc && uio->uio_resid)
116814938Smckusick  			error = ureadc(getc(&tp->t_rawq), uio);
11699859Ssam 		goto checktandem;
11709578Ssam 	}
11719578Ssam 
11729578Ssam 	/*
11739578Ssam 	 * In cbreak mode use the rawq, otherwise
11749578Ssam 	 * take characters from the canonicalized q.
11759578Ssam 	 */
11769578Ssam 	qp = t_flags&CBREAK ? &tp->t_rawq : &tp->t_canq;
11779578Ssam 
11789578Ssam 	/*
11799578Ssam 	 * No input, sleep on rawq awaiting hardware
11809578Ssam 	 * receipt and notification.
11819578Ssam 	 */
118217545Skarels 	s = spltty();
11839578Ssam 	if (qp->c_cc <= 0) {
11849578Ssam 		if ((tp->t_state&TS_CARR_ON) == 0 ||
11859578Ssam 		    (tp->t_state&TS_NBIO)) {
11869859Ssam 			splx(s);
11879578Ssam 			return (EWOULDBLOCK);
11887502Sroot 		}
11899578Ssam 		sleep((caddr_t)&tp->t_rawq, TTIPRI);
11909859Ssam 		splx(s);
11919578Ssam 		goto loop;
11929578Ssam 	}
11939859Ssam 	splx(s);
11949578Ssam 
11959578Ssam 	/*
11969578Ssam 	 * Input present, perform input mapping
11979578Ssam 	 * and processing (we're not in raw mode).
11989578Ssam 	 */
11999578Ssam 	first = 1;
12009578Ssam 	while ((c = getc(qp)) >= 0) {
12019578Ssam 		if (t_flags&CRMOD && c == '\r')
12029578Ssam 			c = '\n';
12039578Ssam 		/*
12049578Ssam 		 * Check for delayed suspend character.
12059578Ssam 		 */
12069578Ssam 		if (tp->t_line == NTTYDISC && c == tp->t_dsuspc) {
12079578Ssam 			gsignal(tp->t_pgrp, SIGTSTP);
12089578Ssam 			if (first) {
12099578Ssam 				sleep((caddr_t)&lbolt, TTIPRI);
12109578Ssam 				goto loop;
12119578Ssam 			}
12129578Ssam 			break;
12137502Sroot 		}
12149578Ssam 		/*
12159578Ssam 		 * Interpret EOF only in cooked mode.
12169578Ssam 		 */
12179578Ssam 		if (c == tp->t_eofc && (t_flags&CBREAK) == 0)
12189578Ssam 			break;
12199578Ssam 		/*
12209578Ssam 		 * Give user character.
12219578Ssam 		 */
122224273Slepreau  		error = ureadc(t_flags&PASS8 ? c : c & 0177, uio);
12239578Ssam 		if (error)
12249578Ssam 			break;
122514938Smckusick  		if (uio->uio_resid == 0)
12269578Ssam 			break;
12279578Ssam 		/*
12289578Ssam 		 * In cooked mode check for a "break character"
12299578Ssam 		 * marking the end of a "line of input".
12309578Ssam 		 */
12319578Ssam 		if ((t_flags&CBREAK) == 0 && ttbreakc(c, tp))
12329578Ssam 			break;
12339578Ssam 		first = 0;
12347502Sroot 	}
12359578Ssam 
12369859Ssam checktandem:
12379578Ssam 	/*
12389578Ssam 	 * Look to unblock output now that (presumably)
12399578Ssam 	 * the input queue has gone down.
12409578Ssam 	 */
12419859Ssam 	if (tp->t_state&TS_TBLOCK && tp->t_rawq.c_cc < TTYHOG/5)
12429578Ssam 		if (putc(tp->t_startc, &tp->t_outq) == 0) {
12437502Sroot 			tp->t_state &= ~TS_TBLOCK;
12447502Sroot 			ttstart(tp);
12457502Sroot 		}
12468520Sroot 	return (error);
12477502Sroot }
12487502Sroot 
12497502Sroot /*
125025391Skarels  * Check the output queue on tp for space for a kernel message
125125391Skarels  * (from uprintf/tprintf).  Allow some space over the normal
125225391Skarels  * hiwater mark so we don't lose messages due to normal flow
125325391Skarels  * control, but don't let the tty run amok.
125425391Skarels  */
125525391Skarels ttycheckoutq(tp, wait)
125625391Skarels 	register struct tty *tp;
125725391Skarels 	int wait;
125825391Skarels {
125925391Skarels 	int hiwat, s;
126025391Skarels 
126125391Skarels 	hiwat = TTHIWAT(tp);
126225391Skarels 	s = spltty();
126325391Skarels 	if (tp->t_outq.c_cc > hiwat + 200)
126425391Skarels 	    while (tp->t_outq.c_cc > hiwat) {
126525391Skarels 		ttstart(tp);
126625391Skarels 		if (wait == 0) {
126725391Skarels 			splx(s);
126825391Skarels 			return (0);
126925391Skarels 		}
127025391Skarels 		tp->t_state |= TS_ASLEEP;
127125391Skarels 		sleep((caddr_t)&tp->t_outq, TTOPRI);
127225391Skarels 	}
127325391Skarels 	splx(s);
127425391Skarels 	return (1);
127525391Skarels }
127625391Skarels 
127725391Skarels /*
12787502Sroot  * Called from the device's write routine after it has
12797502Sroot  * calculated the tty-structure given as argument.
12807502Sroot  */
12817822Sroot ttwrite(tp, uio)
12827625Ssam 	register struct tty *tp;
12839578Ssam 	register struct uio *uio;
12847502Sroot {
12857502Sroot 	register char *cp;
12869578Ssam 	register int cc, ce, c;
12879578Ssam 	int i, hiwat, cnt, error, s;
12887502Sroot 	char obuf[OBUFSIZ];
12897502Sroot 
12909578Ssam 	hiwat = TTHIWAT(tp);
12919578Ssam 	cnt = uio->uio_resid;
12929578Ssam 	error = 0;
12937502Sroot loop:
129421776Sbloom 	if ((tp->t_state&TS_CARR_ON) == 0)
129521776Sbloom 		return (EIO);
12969578Ssam 	/*
12979578Ssam 	 * Hang the process if it's in the background.
12989578Ssam 	 */
129921776Sbloom 	if (u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp &&
13009578Ssam 	    (tp->t_flags&TOSTOP) && (u.u_procp->p_flag&SVFORK)==0 &&
130124392Skarels 	    !(u.u_procp->p_sigignore & sigmask(SIGTTOU)) &&
130224392Skarels 	    !(u.u_procp->p_sigmask & sigmask(SIGTTOU))) {
13037502Sroot 		gsignal(u.u_procp->p_pgrp, SIGTTOU);
13047502Sroot 		sleep((caddr_t)&lbolt, TTIPRI);
130521776Sbloom 		goto loop;
13067502Sroot 	}
13079578Ssam 
13089578Ssam 	/*
13099578Ssam 	 * Process the user's data in at most OBUFSIZ
13109578Ssam 	 * chunks.  Perform lower case simulation and
13119578Ssam 	 * similar hacks.  Keep track of high water
13129578Ssam 	 * mark, sleep on overflow awaiting device aid
13139578Ssam 	 * in acquiring new space.
13149578Ssam 	 */
13157822Sroot 	while (uio->uio_resid > 0) {
13169578Ssam 		/*
13179578Ssam 		 * Grab a hunk of data from the user.
13189578Ssam 		 */
13197822Sroot 		cc = uio->uio_iov->iov_len;
13207822Sroot 		if (cc == 0) {
13217822Sroot 			uio->uio_iovcnt--;
13227822Sroot 			uio->uio_iov++;
132321776Sbloom 			if (uio->uio_iovcnt <= 0)
13247822Sroot 				panic("ttwrite");
13257822Sroot 			continue;
13267822Sroot 		}
13277822Sroot 		if (cc > OBUFSIZ)
13287822Sroot 			cc = OBUFSIZ;
13297502Sroot 		cp = obuf;
133012752Ssam 		error = uiomove(cp, cc, UIO_WRITE, uio);
13318520Sroot 		if (error)
13327502Sroot 			break;
13337502Sroot 		if (tp->t_outq.c_cc > hiwat)
13347502Sroot 			goto ovhiwat;
13359578Ssam 		if (tp->t_flags&FLUSHO)
13367502Sroot 			continue;
13379578Ssam 		/*
13389578Ssam 		 * If we're mapping lower case or kludging tildes,
13399578Ssam 		 * then we've got to look at each character, so
13409578Ssam 		 * just feed the stuff to ttyoutput...
13419578Ssam 		 */
13429578Ssam 		if (tp->t_flags & (LCASE|TILDE)) {
13439578Ssam 			while (cc > 0) {
13447502Sroot 				c = *cp++;
13457502Sroot 				tp->t_rocount = 0;
13467625Ssam 				while ((c = ttyoutput(c, tp)) >= 0) {
13477502Sroot 					/* out of clists, wait a bit */
13487502Sroot 					ttstart(tp);
13497502Sroot 					sleep((caddr_t)&lbolt, TTOPRI);
13507502Sroot 					tp->t_rocount = 0;
135121776Sbloom 					if (cc != 0) {
135221776Sbloom 						uio->uio_iov->iov_base -= cc;
135321776Sbloom 						uio->uio_iov->iov_len += cc;
135421776Sbloom 						uio->uio_resid += cc;
135521776Sbloom 						uio->uio_offset -= cc;
135621776Sbloom 					}
135721776Sbloom 					goto loop;
13587502Sroot 				}
13597502Sroot 				--cc;
13607502Sroot 				if (tp->t_outq.c_cc > hiwat)
13617502Sroot 					goto ovhiwat;
13627502Sroot 			}
13637502Sroot 			continue;
13647502Sroot 		}
13659578Ssam 		/*
13669578Ssam 		 * If nothing fancy need be done, grab those characters we
13679578Ssam 		 * can handle without any of ttyoutput's processing and
13689578Ssam 		 * just transfer them to the output q.  For those chars
13699578Ssam 		 * which require special processing (as indicated by the
13709578Ssam 		 * bits in partab), call ttyoutput.  After processing
13719578Ssam 		 * a hunk of data, look for FLUSHO so ^O's will take effect
13729578Ssam 		 * immediately.
13739578Ssam 		 */
13749578Ssam 		while (cc > 0) {
13759578Ssam 			if (tp->t_flags & (RAW|LITOUT))
13767502Sroot 				ce = cc;
13777502Sroot 			else {
137812752Ssam 				ce = cc - scanc((unsigned)cc, (caddr_t)cp,
137912752Ssam 				   (caddr_t)partab, 077);
13809578Ssam 				/*
13819578Ssam 				 * If ce is zero, then we're processing
13829578Ssam 				 * a special character through ttyoutput.
13839578Ssam 				 */
13849578Ssam 				if (ce == 0) {
13857502Sroot 					tp->t_rocount = 0;
13867502Sroot 					if (ttyoutput(*cp, tp) >= 0) {
138721776Sbloom 					    /* no c-lists, wait a bit */
138821776Sbloom 					    ttstart(tp);
138921776Sbloom 					    sleep((caddr_t)&lbolt, TTOPRI);
139021776Sbloom 					    if (cc != 0) {
139121776Sbloom 					        uio->uio_iov->iov_base -= cc;
139221776Sbloom 					        uio->uio_iov->iov_len += cc;
139321776Sbloom 					        uio->uio_resid += cc;
139421776Sbloom 						uio->uio_offset -= cc;
139521776Sbloom 					    }
139621776Sbloom 					    goto loop;
13977502Sroot 					}
13989578Ssam 					cp++, cc--;
13999578Ssam 					if (tp->t_flags&FLUSHO ||
14009578Ssam 					    tp->t_outq.c_cc > hiwat)
14017502Sroot 						goto ovhiwat;
14029578Ssam 					continue;
14037502Sroot 				}
14047502Sroot 			}
14059578Ssam 			/*
14069578Ssam 			 * A bunch of normal characters have been found,
14079578Ssam 			 * transfer them en masse to the output queue and
14089578Ssam 			 * continue processing at the top of the loop.
14099578Ssam 			 * If there are any further characters in this
14109578Ssam 			 * <= OBUFSIZ chunk, the first should be a character
14119578Ssam 			 * requiring special handling by ttyoutput.
14129578Ssam 			 */
14137502Sroot 			tp->t_rocount = 0;
14149578Ssam 			i = b_to_q(cp, ce, &tp->t_outq);
14159578Ssam 			ce -= i;
14169578Ssam 			tp->t_col += ce;
14179578Ssam 			cp += ce, cc -= ce, tk_nout += ce;
14189578Ssam 			if (i > 0) {
14199578Ssam 				/* out of c-lists, wait a bit */
14207502Sroot 				ttstart(tp);
14217502Sroot 				sleep((caddr_t)&lbolt, TTOPRI);
142221776Sbloom 				uio->uio_iov->iov_base -= cc;
142321776Sbloom 				uio->uio_iov->iov_len += cc;
142421776Sbloom 				uio->uio_resid += cc;
142521776Sbloom 				uio->uio_offset -= cc;
142621776Sbloom 				goto loop;
14277502Sroot 			}
14289578Ssam 			if (tp->t_flags&FLUSHO || tp->t_outq.c_cc > hiwat)
14297502Sroot 				goto ovhiwat;
14307502Sroot 		}
14317502Sroot 	}
14327502Sroot 	ttstart(tp);
14338520Sroot 	return (error);
14347502Sroot 
14357502Sroot ovhiwat:
143617545Skarels 	s = spltty();
14379578Ssam 	if (cc != 0) {
14389578Ssam 		uio->uio_iov->iov_base -= cc;
14399578Ssam 		uio->uio_iov->iov_len += cc;
14409578Ssam 		uio->uio_resid += cc;
14419578Ssam 		uio->uio_offset -= cc;
14429578Ssam 	}
14439578Ssam 	/*
14449578Ssam 	 * This can only occur if FLUSHO
14459578Ssam 	 * is also set in t_flags.
14469578Ssam 	 */
14477502Sroot 	if (tp->t_outq.c_cc <= hiwat) {
14489578Ssam 		splx(s);
14497502Sroot 		goto loop;
14507502Sroot 	}
14517502Sroot 	ttstart(tp);
14529578Ssam 	if (tp->t_state&TS_NBIO) {
145317545Skarels 		splx(s);
14547822Sroot 		if (uio->uio_resid == cnt)
14558520Sroot 			return (EWOULDBLOCK);
14568520Sroot 		return (0);
14577502Sroot 	}
14587502Sroot 	tp->t_state |= TS_ASLEEP;
14597502Sroot 	sleep((caddr_t)&tp->t_outq, TTOPRI);
14609578Ssam 	splx(s);
14617502Sroot 	goto loop;
14627502Sroot }
14637502Sroot 
14647502Sroot /*
14657502Sroot  * Rubout one character from the rawq of tp
14667502Sroot  * as cleanly as possible.
14677502Sroot  */
14687502Sroot ttyrub(c, tp)
14697625Ssam 	register c;
14707625Ssam 	register struct tty *tp;
14717502Sroot {
14727502Sroot 	register char *cp;
14737502Sroot 	register int savecol;
14747502Sroot 	int s;
14757502Sroot 	char *nextc();
14767502Sroot 
14779578Ssam 	if ((tp->t_flags&ECHO) == 0)
14787502Sroot 		return;
14799578Ssam 	tp->t_flags &= ~FLUSHO;
14807502Sroot 	c &= 0377;
14819578Ssam 	if (tp->t_flags&CRTBS) {
14827502Sroot 		if (tp->t_rocount == 0) {
14837502Sroot 			/*
14847502Sroot 			 * Screwed by ttwrite; retype
14857502Sroot 			 */
14867502Sroot 			ttyretype(tp);
14877502Sroot 			return;
14887502Sroot 		}
14899578Ssam 		if (c == ('\t'|0200) || c == ('\n'|0200))
14907502Sroot 			ttyrubo(tp, 2);
14919578Ssam 		else switch (partab[c&=0177]&0177) {
14927502Sroot 
14937502Sroot 		case ORDINARY:
14947502Sroot 			if (tp->t_flags&LCASE && c >= 'A' && c <= 'Z')
14957502Sroot 				ttyrubo(tp, 2);
14967502Sroot 			else
14977502Sroot 				ttyrubo(tp, 1);
14987502Sroot 			break;
14997502Sroot 
15007502Sroot 		case VTAB:
15017502Sroot 		case BACKSPACE:
15027502Sroot 		case CONTROL:
15037502Sroot 		case RETURN:
15049578Ssam 			if (tp->t_flags&CTLECH)
15057502Sroot 				ttyrubo(tp, 2);
15067502Sroot 			break;
15077502Sroot 
15087502Sroot 		case TAB:
15097502Sroot 			if (tp->t_rocount < tp->t_rawq.c_cc) {
15107502Sroot 				ttyretype(tp);
15117502Sroot 				return;
15127502Sroot 			}
151317545Skarels 			s = spltty();
15147502Sroot 			savecol = tp->t_col;
15159578Ssam 			tp->t_state |= TS_CNTTB;
15169578Ssam 			tp->t_flags |= FLUSHO;
15177502Sroot 			tp->t_col = tp->t_rocol;
15189578Ssam 			cp = tp->t_rawq.c_cf;
15199578Ssam 			for (; cp; cp = nextc(&tp->t_rawq, cp))
15207502Sroot 				ttyecho(*cp, tp);
15219578Ssam 			tp->t_flags &= ~FLUSHO;
15229578Ssam 			tp->t_state &= ~TS_CNTTB;
15237502Sroot 			splx(s);
15247502Sroot 			/*
15257502Sroot 			 * savecol will now be length of the tab
15267502Sroot 			 */
15277502Sroot 			savecol -= tp->t_col;
15287502Sroot 			tp->t_col += savecol;
15297502Sroot 			if (savecol > 8)
15307502Sroot 				savecol = 8;		/* overflow screw */
15317502Sroot 			while (--savecol >= 0)
15327502Sroot 				(void) ttyoutput('\b', tp);
15337502Sroot 			break;
15347502Sroot 
15357502Sroot 		default:
15367502Sroot 			panic("ttyrub");
15377502Sroot 		}
15389578Ssam 	} else if (tp->t_flags&PRTERA) {
15399578Ssam 		if ((tp->t_state&TS_ERASE) == 0) {
15407502Sroot 			(void) ttyoutput('\\', tp);
15419578Ssam 			tp->t_state |= TS_ERASE;
15427502Sroot 		}
15437502Sroot 		ttyecho(c, tp);
15447502Sroot 	} else
15457502Sroot 		ttyecho(tp->t_erase, tp);
15467502Sroot 	tp->t_rocount--;
15477502Sroot }
15487502Sroot 
15497502Sroot /*
15507502Sroot  * Crt back over cnt chars perhaps
15517502Sroot  * erasing them.
15527502Sroot  */
15537502Sroot ttyrubo(tp, cnt)
15547625Ssam 	register struct tty *tp;
15557625Ssam 	int cnt;
15567502Sroot {
15579578Ssam 	register char *rubostring = tp->t_flags&CRTERA ? "\b \b" : "\b";
15587502Sroot 
15597502Sroot 	while (--cnt >= 0)
15609578Ssam 		ttyout(rubostring, tp);
15617502Sroot }
15627502Sroot 
15637502Sroot /*
15647502Sroot  * Reprint the rawq line.
15657502Sroot  * We assume c_cc has already been checked.
15667502Sroot  */
15677502Sroot ttyretype(tp)
15687625Ssam 	register struct tty *tp;
15697502Sroot {
15707502Sroot 	register char *cp;
15717502Sroot 	char *nextc();
15727502Sroot 	int s;
15737502Sroot 
15749578Ssam 	if (tp->t_rprntc != 0377)
15759578Ssam 		ttyecho(tp->t_rprntc, tp);
15767502Sroot 	(void) ttyoutput('\n', tp);
157717545Skarels 	s = spltty();
15787502Sroot 	for (cp = tp->t_canq.c_cf; cp; cp = nextc(&tp->t_canq, cp))
15797502Sroot 		ttyecho(*cp, tp);
15807502Sroot 	for (cp = tp->t_rawq.c_cf; cp; cp = nextc(&tp->t_rawq, cp))
15817502Sroot 		ttyecho(*cp, tp);
15829578Ssam 	tp->t_state &= ~TS_ERASE;
15837502Sroot 	splx(s);
15847502Sroot 	tp->t_rocount = tp->t_rawq.c_cc;
15857502Sroot 	tp->t_rocol = 0;
15867502Sroot }
15877502Sroot 
15887502Sroot /*
15897502Sroot  * Echo a typed character to the terminal
15907502Sroot  */
15917502Sroot ttyecho(c, tp)
15927625Ssam 	register c;
15937625Ssam 	register struct tty *tp;
15947502Sroot {
15957502Sroot 
15969578Ssam 	if ((tp->t_state&TS_CNTTB) == 0)
15979578Ssam 		tp->t_flags &= ~FLUSHO;
15987502Sroot 	if ((tp->t_flags&ECHO) == 0)
15997502Sroot 		return;
16007502Sroot 	c &= 0377;
16017502Sroot 	if (tp->t_flags&RAW) {
16027502Sroot 		(void) ttyoutput(c, tp);
16037502Sroot 		return;
16047502Sroot 	}
16057502Sroot 	if (c == '\r' && tp->t_flags&CRMOD)
16067502Sroot 		c = '\n';
16079578Ssam 	if (tp->t_flags&CTLECH) {
16087502Sroot 		if ((c&0177) <= 037 && c!='\t' && c!='\n' || (c&0177)==0177) {
16097502Sroot 			(void) ttyoutput('^', tp);
16107502Sroot 			c &= 0177;
16117502Sroot 			if (c == 0177)
16127502Sroot 				c = '?';
16137502Sroot 			else if (tp->t_flags&LCASE)
16147502Sroot 				c += 'a' - 1;
16157502Sroot 			else
16167502Sroot 				c += 'A' - 1;
16177502Sroot 		}
16187502Sroot 	}
16199578Ssam 	(void) ttyoutput(c&0177, tp);
16207502Sroot }
16217502Sroot 
16227502Sroot /*
16237502Sroot  * Is c a break char for tp?
16247502Sroot  */
16257502Sroot ttbreakc(c, tp)
16267625Ssam 	register c;
16277625Ssam 	register struct tty *tp;
16287502Sroot {
16299578Ssam 	return (c == '\n' || c == tp->t_eofc || c == tp->t_brkc ||
16307502Sroot 		c == '\r' && (tp->t_flags&CRMOD));
16317502Sroot }
16327502Sroot 
16337502Sroot /*
16347502Sroot  * send string cp to tp
16357502Sroot  */
16367502Sroot ttyout(cp, tp)
16377625Ssam 	register char *cp;
16387625Ssam 	register struct tty *tp;
16397502Sroot {
16407502Sroot 	register char c;
16417502Sroot 
16427502Sroot 	while (c = *cp++)
16437502Sroot 		(void) ttyoutput(c, tp);
16447502Sroot }
16457502Sroot 
16467502Sroot ttwakeup(tp)
16477502Sroot 	struct tty *tp;
16487502Sroot {
16497502Sroot 
16507502Sroot 	if (tp->t_rsel) {
16517502Sroot 		selwakeup(tp->t_rsel, tp->t_state&TS_RCOLL);
16527502Sroot 		tp->t_state &= ~TS_RCOLL;
16537502Sroot 		tp->t_rsel = 0;
16547502Sroot 	}
165512752Ssam 	if (tp->t_state & TS_ASYNC)
165612752Ssam 		gsignal(tp->t_pgrp, SIGIO);
16577502Sroot 	wakeup((caddr_t)&tp->t_rawq);
16587502Sroot }
1659