xref: /csrg-svn/sys/kern/tty.c (revision 25415)
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*25415Skarels  *	@(#)tty.c	6.24 (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 /*
65725404Skarels  * Default modem control routine (for other line disciplines).
65825404Skarels  * Return argument flag, to turn off device on carrier drop.
65925404Skarels  */
660*25415Skarels nullmodem(tp, flag)
661*25415Skarels 	register struct tty *tp;
66225404Skarels 	int flag;
66325404Skarels {
66425404Skarels 
66525404Skarels 	if (flag)
66625404Skarels 		tp->t_state |= TS_CARR_ON;
66725404Skarels 	else
66825404Skarels 		tp->t_state &= ~TS_CARR_ON;
66925404Skarels 	return (flag);
67025404Skarels }
67125404Skarels 
67225404Skarels /*
6737502Sroot  * reinput pending characters after state switch
67417545Skarels  * call at spltty().
6757502Sroot  */
6767502Sroot ttypend(tp)
6777625Ssam 	register struct tty *tp;
6787502Sroot {
6797502Sroot 	struct clist tq;
6807502Sroot 	register c;
6817502Sroot 
6829578Ssam 	tp->t_flags &= ~PENDIN;
6839578Ssam 	tp->t_state |= TS_TYPEN;
6847502Sroot 	tq = tp->t_rawq;
6857502Sroot 	tp->t_rawq.c_cc = 0;
6867502Sroot 	tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0;
6877502Sroot 	while ((c = getc(&tq)) >= 0)
6887502Sroot 		ttyinput(c, tp);
6899578Ssam 	tp->t_state &= ~TS_TYPEN;
6907502Sroot }
6917502Sroot 
6927502Sroot /*
6939578Ssam  * Place a character on raw TTY input queue,
6949578Ssam  * putting in delimiters and waking up top
6959578Ssam  * half as needed.  Also echo if required.
6969578Ssam  * The arguments are the character and the
6979578Ssam  * appropriate tty structure.
6987502Sroot  */
6997502Sroot ttyinput(c, tp)
7007625Ssam 	register c;
7017625Ssam 	register struct tty *tp;
7027502Sroot {
7039578Ssam 	register int t_flags = tp->t_flags;
7047502Sroot 	int i;
7057502Sroot 
7069578Ssam 	/*
7079578Ssam 	 * If input is pending take it first.
7089578Ssam 	 */
7099578Ssam 	if (t_flags&PENDIN)
7107502Sroot 		ttypend(tp);
7117502Sroot 	tk_nin++;
7127502Sroot 	c &= 0377;
7139578Ssam 
7149578Ssam 	/*
7159578Ssam 	 * In tandem mode, check high water mark.
7169578Ssam 	 */
7177502Sroot 	if (t_flags&TANDEM)
7187502Sroot 		ttyblock(tp);
7199578Ssam 
7209578Ssam 	if (t_flags&RAW) {
7219578Ssam 		/*
7229578Ssam 		 * Raw mode, just put character
7239578Ssam 		 * in input q w/o interpretation.
7249578Ssam 		 */
7259578Ssam 		if (tp->t_rawq.c_cc > TTYHOG)
72612752Ssam 			ttyflush(tp, FREAD|FWRITE);
7279578Ssam 		else {
7289578Ssam 			if (putc(c, &tp->t_rawq) >= 0)
7299578Ssam 				ttwakeup(tp);
7309578Ssam 			ttyecho(c, tp);
7317502Sroot 		}
7329578Ssam 		goto endcase;
7339578Ssam 	}
7349578Ssam 
7359578Ssam 	/*
7369578Ssam 	 * Ignore any high bit added during
7379578Ssam 	 * previous ttyinput processing.
7389578Ssam 	 */
73924273Slepreau 	if ((tp->t_state&TS_TYPEN) == 0 && (t_flags&PASS8) == 0)
7409578Ssam 		c &= 0177;
7419578Ssam 	/*
7429578Ssam 	 * Check for literal nexting very first
7439578Ssam 	 */
7449578Ssam 	if (tp->t_state&TS_LNCH) {
7459578Ssam 		c |= 0200;
7469578Ssam 		tp->t_state &= ~TS_LNCH;
7479578Ssam 	}
7489578Ssam 
7499578Ssam 	/*
7509578Ssam 	 * Scan for special characters.  This code
7519578Ssam 	 * is really just a big case statement with
7529578Ssam 	 * non-constant cases.  The bottom of the
7539578Ssam 	 * case statement is labeled ``endcase'', so goto
7549578Ssam 	 * it after a case match, or similar.
7559578Ssam 	 */
7569578Ssam 	if (tp->t_line == NTTYDISC) {
7579578Ssam 		if (c == tp->t_lnextc) {
75821776Sbloom 			if (t_flags&ECHO)
7597502Sroot 				ttyout("^\b", tp);
7609578Ssam 			tp->t_state |= TS_LNCH;
7619578Ssam 			goto endcase;
7629578Ssam 		}
7639578Ssam 		if (c == tp->t_flushc) {
76421776Sbloom 			if (t_flags&FLUSHO)
7659578Ssam 				tp->t_flags &= ~FLUSHO;
7667502Sroot 			else {
76712752Ssam 				ttyflush(tp, FWRITE);
7687502Sroot 				ttyecho(c, tp);
7699578Ssam 				if (tp->t_rawq.c_cc + tp->t_canq.c_cc)
7707502Sroot 					ttyretype(tp);
7719578Ssam 				tp->t_flags |= FLUSHO;
7727502Sroot 			}
7739578Ssam 			goto startoutput;
7749578Ssam 		}
7759578Ssam 		if (c == tp->t_suspc) {
77621776Sbloom 			if ((t_flags&NOFLSH) == 0)
77712752Ssam 				ttyflush(tp, FREAD);
7789578Ssam 			ttyecho(c, tp);
7799578Ssam 			gsignal(tp->t_pgrp, SIGTSTP);
7809578Ssam 			goto endcase;
7819578Ssam 		}
7829578Ssam 	}
7839578Ssam 
7849578Ssam 	/*
7859578Ssam 	 * Handle start/stop characters.
7869578Ssam 	 */
7879578Ssam 	if (c == tp->t_stopc) {
7889578Ssam 		if ((tp->t_state&TS_TTSTOP) == 0) {
7899578Ssam 			tp->t_state |= TS_TTSTOP;
7909578Ssam 			(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
7917502Sroot 			return;
7929578Ssam 		}
7939578Ssam 		if (c != tp->t_startc)
7949578Ssam 			return;
7959578Ssam 		goto endcase;
7969578Ssam 	}
7979578Ssam 	if (c == tp->t_startc)
7989578Ssam 		goto restartoutput;
7999578Ssam 
8009578Ssam 	/*
8019578Ssam 	 * Look for interrupt/quit chars.
8029578Ssam 	 */
8039578Ssam 	if (c == tp->t_intrc || c == tp->t_quitc) {
80421776Sbloom 		if ((t_flags&NOFLSH) == 0)
80512752Ssam 			ttyflush(tp, FREAD|FWRITE);
8069578Ssam 		ttyecho(c, tp);
8079578Ssam 		gsignal(tp->t_pgrp, c == tp->t_intrc ? SIGINT : SIGQUIT);
8089578Ssam 		goto endcase;
8099578Ssam 	}
8109578Ssam 
81123165Sbloom 	if (tp->t_flags & LCASE && c <= 0177) {
81223165Sbloom 		if (tp->t_state&TS_BKSL) {
81323165Sbloom 			ttyrub(unputc(&tp->t_rawq), tp);
81423165Sbloom 			if (maptab[c])
81523165Sbloom 				c = maptab[c];
81623165Sbloom 			c |= 0200;
81723165Sbloom 			tp->t_state &= ~(TS_BKSL|TS_QUOT);
81823165Sbloom 		} else if (c >= 'A' && c <= 'Z')
81923165Sbloom 			c += 'a' - 'A';
82023165Sbloom 		else if (c == '\\')
82123165Sbloom 			tp->t_state |= TS_BKSL;
82223165Sbloom 	}
82323165Sbloom 
8249578Ssam 	/*
8259578Ssam 	 * Cbreak mode, don't process line editing
8269578Ssam 	 * characters; check high water mark for wakeup.
8279578Ssam 	 */
8289578Ssam 	if (t_flags&CBREAK) {
8299578Ssam 		if (tp->t_rawq.c_cc > TTYHOG) {
8307502Sroot 			if (tp->t_outq.c_cc < TTHIWAT(tp) &&
8317502Sroot 			    tp->t_line == NTTYDISC)
8327502Sroot 				(void) ttyoutput(CTRL(g), tp);
8337502Sroot 		} else if (putc(c, &tp->t_rawq) >= 0) {
8347502Sroot 			ttwakeup(tp);
8357502Sroot 			ttyecho(c, tp);
8367502Sroot 		}
8379578Ssam 		goto endcase;
8389578Ssam 	}
8399578Ssam 
8409578Ssam 	/*
8419578Ssam 	 * From here on down cooked mode character
8429578Ssam 	 * processing takes place.
8439578Ssam 	 */
8449578Ssam 	if ((tp->t_state&TS_QUOT) &&
8459578Ssam 	    (c == tp->t_erase || c == tp->t_kill)) {
8469578Ssam 		ttyrub(unputc(&tp->t_rawq), tp);
8479578Ssam 		c |= 0200;
8489578Ssam 	}
8499578Ssam 	if (c == tp->t_erase) {
8509578Ssam 		if (tp->t_rawq.c_cc)
8519578Ssam 			ttyrub(unputc(&tp->t_rawq), tp);
8529578Ssam 		goto endcase;
8539578Ssam 	}
8549578Ssam 	if (c == tp->t_kill) {
85521776Sbloom 		if (t_flags&CRTKIL &&
8569578Ssam 		    tp->t_rawq.c_cc == tp->t_rocount) {
8579578Ssam 			while (tp->t_rawq.c_cc)
8589578Ssam 				ttyrub(unputc(&tp->t_rawq), tp);
8599578Ssam 		} else {
8609578Ssam 			ttyecho(c, tp);
8619578Ssam 			ttyecho('\n', tp);
8629578Ssam 			while (getc(&tp->t_rawq) > 0)
8639578Ssam 				;
8649578Ssam 			tp->t_rocount = 0;
8659578Ssam 		}
8669578Ssam 		tp->t_state &= ~TS_LOCAL;
8679578Ssam 		goto endcase;
8689578Ssam 	}
8699578Ssam 
8709578Ssam 	/*
8719578Ssam 	 * New line discipline,
8729578Ssam 	 * check word erase/reprint line.
8739578Ssam 	 */
8749578Ssam 	if (tp->t_line == NTTYDISC) {
8759578Ssam 		if (c == tp->t_werasc) {
8769578Ssam 			if (tp->t_rawq.c_cc == 0)
8779578Ssam 				goto endcase;
8789578Ssam 			do {
8799578Ssam 				c = unputc(&tp->t_rawq);
8809578Ssam 				if (c != ' ' && c != '\t')
8819578Ssam 					goto erasenb;
8829578Ssam 				ttyrub(c, tp);
8839578Ssam 			} while (tp->t_rawq.c_cc);
8849578Ssam 			goto endcase;
8859578Ssam 	erasenb:
8869578Ssam 			do {
8879578Ssam 				ttyrub(c, tp);
8889578Ssam 				if (tp->t_rawq.c_cc == 0)
8899578Ssam 					goto endcase;
8909578Ssam 				c = unputc(&tp->t_rawq);
8919578Ssam 			} while (c != ' ' && c != '\t');
8929578Ssam 			(void) putc(c, &tp->t_rawq);
8939578Ssam 			goto endcase;
8949578Ssam 		}
8959578Ssam 		if (c == tp->t_rprntc) {
8969578Ssam 			ttyretype(tp);
8979578Ssam 			goto endcase;
8989578Ssam 		}
8999578Ssam 	}
9009578Ssam 
9019578Ssam 	/*
9029578Ssam 	 * Check for input buffer overflow
9039578Ssam 	 */
90410391Ssam 	if (tp->t_rawq.c_cc+tp->t_canq.c_cc >= TTYHOG) {
90510391Ssam 		if (tp->t_line == NTTYDISC)
90610391Ssam 			(void) ttyoutput(CTRL(g), tp);
9079578Ssam 		goto endcase;
90810391Ssam 	}
9099578Ssam 
9109578Ssam 	/*
9119578Ssam 	 * Put data char in q for user and
9129578Ssam 	 * wakeup on seeing a line delimiter.
9139578Ssam 	 */
9149578Ssam 	if (putc(c, &tp->t_rawq) >= 0) {
9159578Ssam 		if (ttbreakc(c, tp)) {
9169578Ssam 			tp->t_rocount = 0;
9179578Ssam 			catq(&tp->t_rawq, &tp->t_canq);
9187502Sroot 			ttwakeup(tp);
9199578Ssam 		} else if (tp->t_rocount++ == 0)
9209578Ssam 			tp->t_rocol = tp->t_col;
9219578Ssam 		tp->t_state &= ~TS_QUOT;
9229578Ssam 		if (c == '\\')
9239578Ssam 			tp->t_state |= TS_QUOT;
9249578Ssam 		if (tp->t_state&TS_ERASE) {
9259578Ssam 			tp->t_state &= ~TS_ERASE;
9269578Ssam 			(void) ttyoutput('/', tp);
9279578Ssam 		}
9289578Ssam 		i = tp->t_col;
9297502Sroot 		ttyecho(c, tp);
93021776Sbloom 		if (c == tp->t_eofc && t_flags&ECHO) {
9319578Ssam 			i = MIN(2, tp->t_col - i);
9329578Ssam 			while (i > 0) {
9339578Ssam 				(void) ttyoutput('\b', tp);
9349578Ssam 				i--;
9359578Ssam 			}
9369578Ssam 		}
9377502Sroot 	}
9389578Ssam endcase:
9399578Ssam 	/*
9409578Ssam 	 * If DEC-style start/stop is enabled don't restart
9419578Ssam 	 * output until seeing the start character.
9429578Ssam 	 */
94321776Sbloom 	if (t_flags&DECCTQ && tp->t_state&TS_TTSTOP &&
9449578Ssam 	    tp->t_startc != tp->t_stopc)
9457502Sroot 		return;
9469578Ssam restartoutput:
9477502Sroot 	tp->t_state &= ~TS_TTSTOP;
9489578Ssam 	tp->t_flags &= ~FLUSHO;
9499578Ssam startoutput:
9507502Sroot 	ttstart(tp);
9517502Sroot }
9527502Sroot 
9537502Sroot /*
9549578Ssam  * Put character on TTY output queue, adding delays,
9557502Sroot  * expanding tabs, and handling the CR/NL bit.
9569578Ssam  * This is called both from the top half for output,
9579578Ssam  * and from interrupt level for echoing.
9587502Sroot  * The arguments are the character and the tty structure.
9597502Sroot  * Returns < 0 if putc succeeds, otherwise returns char to resend
9607502Sroot  * Must be recursive.
9617502Sroot  */
9627502Sroot ttyoutput(c, tp)
9637502Sroot 	register c;
9647502Sroot 	register struct tty *tp;
9657502Sroot {
9667502Sroot 	register char *colp;
9677502Sroot 	register ctype;
9687502Sroot 
9699578Ssam 	if (tp->t_flags & (RAW|LITOUT)) {
9709578Ssam 		if (tp->t_flags&FLUSHO)
9717502Sroot 			return (-1);
9727502Sroot 		if (putc(c, &tp->t_outq))
9737625Ssam 			return (c);
9747502Sroot 		tk_nout++;
9757502Sroot 		return (-1);
9767502Sroot 	}
9779578Ssam 
9787502Sroot 	/*
9799578Ssam 	 * Ignore EOT in normal mode to avoid
9809578Ssam 	 * hanging up certain terminals.
9817502Sroot 	 */
9827502Sroot 	c &= 0177;
9839578Ssam 	if (c == CEOT && (tp->t_flags&CBREAK) == 0)
9847502Sroot 		return (-1);
9857502Sroot 	/*
9867502Sroot 	 * Turn tabs to spaces as required
9877502Sroot 	 */
9889578Ssam 	if (c == '\t' && (tp->t_flags&TBDELAY) == XTABS) {
9897502Sroot 		register int s;
9907502Sroot 
9917502Sroot 		c = 8 - (tp->t_col&7);
9929578Ssam 		if ((tp->t_flags&FLUSHO) == 0) {
99317545Skarels 			s = spltty();		/* don't interrupt tabs */
9947502Sroot 			c -= b_to_q("        ", c, &tp->t_outq);
9957502Sroot 			tk_nout += c;
9967502Sroot 			splx(s);
9977502Sroot 		}
9987502Sroot 		tp->t_col += c;
9997502Sroot 		return (c ? -1 : '\t');
10007502Sroot 	}
10017502Sroot 	tk_nout++;
10027502Sroot 	/*
10037502Sroot 	 * for upper-case-only terminals,
10047502Sroot 	 * generate escapes.
10057502Sroot 	 */
10067502Sroot 	if (tp->t_flags&LCASE) {
10077502Sroot 		colp = "({)}!|^~'`";
10087625Ssam 		while (*colp++)
10097625Ssam 			if (c == *colp++) {
10107502Sroot 				if (ttyoutput('\\', tp) >= 0)
10117502Sroot 					return (c);
10127502Sroot 				c = colp[-2];
10137502Sroot 				break;
10147502Sroot 			}
10159578Ssam 		if ('A' <= c && c <= 'Z') {
10167502Sroot 			if (ttyoutput('\\', tp) >= 0)
10177502Sroot 				return (c);
10189578Ssam 		} else if ('a' <= c && c <= 'z')
10197502Sroot 			c += 'A' - 'a';
10207502Sroot 	}
10219578Ssam 
10227502Sroot 	/*
10237502Sroot 	 * turn <nl> to <cr><lf> if desired.
10247502Sroot 	 */
10259578Ssam 	if (c == '\n' && tp->t_flags&CRMOD)
10267502Sroot 		if (ttyoutput('\r', tp) >= 0)
10277502Sroot 			return (c);
10289578Ssam 	if (c == '~' && tp->t_flags&TILDE)
10297502Sroot 		c = '`';
10309578Ssam 	if ((tp->t_flags&FLUSHO) == 0 && putc(c, &tp->t_outq))
10317502Sroot 		return (c);
10327502Sroot 	/*
10337502Sroot 	 * Calculate delays.
10347502Sroot 	 * The numbers here represent clock ticks
10357502Sroot 	 * and are not necessarily optimal for all terminals.
10367502Sroot 	 * The delays are indicated by characters above 0200.
10377502Sroot 	 * In raw mode there are no delays and the
10387502Sroot 	 * transmission path is 8 bits wide.
10399578Ssam 	 *
10409578Ssam 	 * SHOULD JUST ALLOW USER TO SPECIFY DELAYS
10417502Sroot 	 */
10427502Sroot 	colp = &tp->t_col;
10437502Sroot 	ctype = partab[c];
10447502Sroot 	c = 0;
10457502Sroot 	switch (ctype&077) {
10467502Sroot 
10477502Sroot 	case ORDINARY:
10487502Sroot 		(*colp)++;
10497502Sroot 
10507502Sroot 	case CONTROL:
10517502Sroot 		break;
10527502Sroot 
10537502Sroot 	case BACKSPACE:
10547502Sroot 		if (*colp)
10557502Sroot 			(*colp)--;
10567502Sroot 		break;
10577502Sroot 
105813821Ssam 	/*
105913821Ssam 	 * This macro is close enough to the correct thing;
106013821Ssam 	 * it should be replaced by real user settable delays
106113821Ssam 	 * in any event...
106213821Ssam 	 */
106313821Ssam #define	mstohz(ms)	(((ms) * hz) >> 10)
10647502Sroot 	case NEWLINE:
10657502Sroot 		ctype = (tp->t_flags >> 8) & 03;
10667625Ssam 		if (ctype == 1) { /* tty 37 */
106712752Ssam 			if (*colp > 0)
106813863Ssam 				c = max((((unsigned)*colp) >> 4) + 3,
106913863Ssam 				    (unsigned)6);
10709578Ssam 		} else if (ctype == 2) /* vt05 */
107113821Ssam 			c = mstohz(100);
10727502Sroot 		*colp = 0;
10737502Sroot 		break;
10747502Sroot 
10757502Sroot 	case TAB:
10767502Sroot 		ctype = (tp->t_flags >> 10) & 03;
10777625Ssam 		if (ctype == 1) { /* tty 37 */
10787502Sroot 			c = 1 - (*colp | ~07);
10797625Ssam 			if (c < 5)
10807502Sroot 				c = 0;
10817502Sroot 		}
10827502Sroot 		*colp |= 07;
10837502Sroot 		(*colp)++;
10847502Sroot 		break;
10857502Sroot 
10867502Sroot 	case VTAB:
10879578Ssam 		if (tp->t_flags&VTDELAY) /* tty 37 */
10887502Sroot 			c = 0177;
10897502Sroot 		break;
10907502Sroot 
10917502Sroot 	case RETURN:
10927502Sroot 		ctype = (tp->t_flags >> 12) & 03;
10939578Ssam 		if (ctype == 1) /* tn 300 */
109413821Ssam 			c = mstohz(83);
10959578Ssam 		else if (ctype == 2) /* ti 700 */
109613821Ssam 			c = mstohz(166);
10979578Ssam 		else if (ctype == 3) { /* concept 100 */
10987502Sroot 			int i;
10999578Ssam 
11007502Sroot 			if ((i = *colp) >= 0)
11019578Ssam 				for (; i < 9; i++)
11027502Sroot 					(void) putc(0177, &tp->t_outq);
11037502Sroot 		}
11047502Sroot 		*colp = 0;
11057502Sroot 	}
11069578Ssam 	if (c && (tp->t_flags&FLUSHO) == 0)
11077502Sroot 		(void) putc(c|0200, &tp->t_outq);
11087502Sroot 	return (-1);
11097502Sroot }
111013821Ssam #undef mstohz
11117502Sroot 
11127502Sroot /*
11137502Sroot  * Called from device's read routine after it has
11147502Sroot  * calculated the tty-structure given as argument.
11157502Sroot  */
11167722Swnj ttread(tp, uio)
11177625Ssam 	register struct tty *tp;
11187722Swnj 	struct uio *uio;
11197502Sroot {
11207502Sroot 	register struct clist *qp;
11219578Ssam 	register c, t_flags;
11229859Ssam 	int s, first, error = 0;
11237502Sroot 
11247502Sroot loop:
11259578Ssam 	/*
11269578Ssam 	 * Take any pending input first.
11279578Ssam 	 */
112817545Skarels 	s = spltty();
11299578Ssam 	if (tp->t_flags&PENDIN)
11307502Sroot 		ttypend(tp);
11319859Ssam 	splx(s);
11329578Ssam 
113323165Sbloom 	if ((tp->t_state&TS_CARR_ON)==0)
113423165Sbloom 		return (EIO);
113523165Sbloom 
11369578Ssam 	/*
11379578Ssam 	 * Hang process if it's in the background.
11389578Ssam 	 */
113923165Sbloom 	if (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) {
114024392Skarels 		if ((u.u_procp->p_sigignore & sigmask(SIGTTIN)) ||
114124392Skarels 		   (u.u_procp->p_sigmask & sigmask(SIGTTIN)) ||
11427502Sroot 		    u.u_procp->p_flag&SVFORK)
11438520Sroot 			return (EIO);
11447502Sroot 		gsignal(u.u_procp->p_pgrp, SIGTTIN);
11457502Sroot 		sleep((caddr_t)&lbolt, TTIPRI);
114623165Sbloom 		goto loop;
11477502Sroot 	}
11489578Ssam 	t_flags = tp->t_flags;
11499578Ssam 
11509578Ssam 	/*
11519578Ssam 	 * In raw mode take characters directly from the
11529578Ssam 	 * raw queue w/o processing.  Interlock against
11539578Ssam 	 * device interrupts when interrogating rawq.
11549578Ssam 	 */
11559578Ssam 	if (t_flags&RAW) {
115617545Skarels 		s = spltty();
11577502Sroot 		if (tp->t_rawq.c_cc <= 0) {
11589578Ssam 			if ((tp->t_state&TS_CARR_ON) == 0 ||
11597502Sroot 			    (tp->t_state&TS_NBIO)) {
11609859Ssam 				splx(s);
116115094Skarels 				return (EWOULDBLOCK);
11627502Sroot 			}
11637502Sroot 			sleep((caddr_t)&tp->t_rawq, TTIPRI);
11649859Ssam 			splx(s);
11657502Sroot 			goto loop;
11667502Sroot 		}
11679859Ssam 		splx(s);
116814938Smckusick  		while (!error && tp->t_rawq.c_cc && uio->uio_resid)
116914938Smckusick  			error = ureadc(getc(&tp->t_rawq), uio);
11709859Ssam 		goto checktandem;
11719578Ssam 	}
11729578Ssam 
11739578Ssam 	/*
11749578Ssam 	 * In cbreak mode use the rawq, otherwise
11759578Ssam 	 * take characters from the canonicalized q.
11769578Ssam 	 */
11779578Ssam 	qp = t_flags&CBREAK ? &tp->t_rawq : &tp->t_canq;
11789578Ssam 
11799578Ssam 	/*
11809578Ssam 	 * No input, sleep on rawq awaiting hardware
11819578Ssam 	 * receipt and notification.
11829578Ssam 	 */
118317545Skarels 	s = spltty();
11849578Ssam 	if (qp->c_cc <= 0) {
11859578Ssam 		if ((tp->t_state&TS_CARR_ON) == 0 ||
11869578Ssam 		    (tp->t_state&TS_NBIO)) {
11879859Ssam 			splx(s);
11889578Ssam 			return (EWOULDBLOCK);
11897502Sroot 		}
11909578Ssam 		sleep((caddr_t)&tp->t_rawq, TTIPRI);
11919859Ssam 		splx(s);
11929578Ssam 		goto loop;
11939578Ssam 	}
11949859Ssam 	splx(s);
11959578Ssam 
11969578Ssam 	/*
11979578Ssam 	 * Input present, perform input mapping
11989578Ssam 	 * and processing (we're not in raw mode).
11999578Ssam 	 */
12009578Ssam 	first = 1;
12019578Ssam 	while ((c = getc(qp)) >= 0) {
12029578Ssam 		if (t_flags&CRMOD && c == '\r')
12039578Ssam 			c = '\n';
12049578Ssam 		/*
12059578Ssam 		 * Check for delayed suspend character.
12069578Ssam 		 */
12079578Ssam 		if (tp->t_line == NTTYDISC && c == tp->t_dsuspc) {
12089578Ssam 			gsignal(tp->t_pgrp, SIGTSTP);
12099578Ssam 			if (first) {
12109578Ssam 				sleep((caddr_t)&lbolt, TTIPRI);
12119578Ssam 				goto loop;
12129578Ssam 			}
12139578Ssam 			break;
12147502Sroot 		}
12159578Ssam 		/*
12169578Ssam 		 * Interpret EOF only in cooked mode.
12179578Ssam 		 */
12189578Ssam 		if (c == tp->t_eofc && (t_flags&CBREAK) == 0)
12199578Ssam 			break;
12209578Ssam 		/*
12219578Ssam 		 * Give user character.
12229578Ssam 		 */
122324273Slepreau  		error = ureadc(t_flags&PASS8 ? c : c & 0177, uio);
12249578Ssam 		if (error)
12259578Ssam 			break;
122614938Smckusick  		if (uio->uio_resid == 0)
12279578Ssam 			break;
12289578Ssam 		/*
12299578Ssam 		 * In cooked mode check for a "break character"
12309578Ssam 		 * marking the end of a "line of input".
12319578Ssam 		 */
12329578Ssam 		if ((t_flags&CBREAK) == 0 && ttbreakc(c, tp))
12339578Ssam 			break;
12349578Ssam 		first = 0;
12357502Sroot 	}
12369578Ssam 
12379859Ssam checktandem:
12389578Ssam 	/*
12399578Ssam 	 * Look to unblock output now that (presumably)
12409578Ssam 	 * the input queue has gone down.
12419578Ssam 	 */
12429859Ssam 	if (tp->t_state&TS_TBLOCK && tp->t_rawq.c_cc < TTYHOG/5)
12439578Ssam 		if (putc(tp->t_startc, &tp->t_outq) == 0) {
12447502Sroot 			tp->t_state &= ~TS_TBLOCK;
12457502Sroot 			ttstart(tp);
12467502Sroot 		}
12478520Sroot 	return (error);
12487502Sroot }
12497502Sroot 
12507502Sroot /*
125125391Skarels  * Check the output queue on tp for space for a kernel message
125225391Skarels  * (from uprintf/tprintf).  Allow some space over the normal
125325391Skarels  * hiwater mark so we don't lose messages due to normal flow
125425391Skarels  * control, but don't let the tty run amok.
125525391Skarels  */
125625391Skarels ttycheckoutq(tp, wait)
125725391Skarels 	register struct tty *tp;
125825391Skarels 	int wait;
125925391Skarels {
126025391Skarels 	int hiwat, s;
126125391Skarels 
126225391Skarels 	hiwat = TTHIWAT(tp);
126325391Skarels 	s = spltty();
126425391Skarels 	if (tp->t_outq.c_cc > hiwat + 200)
126525391Skarels 	    while (tp->t_outq.c_cc > hiwat) {
126625391Skarels 		ttstart(tp);
126725391Skarels 		if (wait == 0) {
126825391Skarels 			splx(s);
126925391Skarels 			return (0);
127025391Skarels 		}
127125391Skarels 		tp->t_state |= TS_ASLEEP;
127225391Skarels 		sleep((caddr_t)&tp->t_outq, TTOPRI);
127325391Skarels 	}
127425391Skarels 	splx(s);
127525391Skarels 	return (1);
127625391Skarels }
127725391Skarels 
127825391Skarels /*
12797502Sroot  * Called from the device's write routine after it has
12807502Sroot  * calculated the tty-structure given as argument.
12817502Sroot  */
12827822Sroot ttwrite(tp, uio)
12837625Ssam 	register struct tty *tp;
12849578Ssam 	register struct uio *uio;
12857502Sroot {
12867502Sroot 	register char *cp;
12879578Ssam 	register int cc, ce, c;
12889578Ssam 	int i, hiwat, cnt, error, s;
12897502Sroot 	char obuf[OBUFSIZ];
12907502Sroot 
12919578Ssam 	hiwat = TTHIWAT(tp);
12929578Ssam 	cnt = uio->uio_resid;
12939578Ssam 	error = 0;
12947502Sroot loop:
129521776Sbloom 	if ((tp->t_state&TS_CARR_ON) == 0)
129621776Sbloom 		return (EIO);
12979578Ssam 	/*
12989578Ssam 	 * Hang the process if it's in the background.
12999578Ssam 	 */
130021776Sbloom 	if (u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp &&
13019578Ssam 	    (tp->t_flags&TOSTOP) && (u.u_procp->p_flag&SVFORK)==0 &&
130224392Skarels 	    !(u.u_procp->p_sigignore & sigmask(SIGTTOU)) &&
130324392Skarels 	    !(u.u_procp->p_sigmask & sigmask(SIGTTOU))) {
13047502Sroot 		gsignal(u.u_procp->p_pgrp, SIGTTOU);
13057502Sroot 		sleep((caddr_t)&lbolt, TTIPRI);
130621776Sbloom 		goto loop;
13077502Sroot 	}
13089578Ssam 
13099578Ssam 	/*
13109578Ssam 	 * Process the user's data in at most OBUFSIZ
13119578Ssam 	 * chunks.  Perform lower case simulation and
13129578Ssam 	 * similar hacks.  Keep track of high water
13139578Ssam 	 * mark, sleep on overflow awaiting device aid
13149578Ssam 	 * in acquiring new space.
13159578Ssam 	 */
13167822Sroot 	while (uio->uio_resid > 0) {
13179578Ssam 		/*
13189578Ssam 		 * Grab a hunk of data from the user.
13199578Ssam 		 */
13207822Sroot 		cc = uio->uio_iov->iov_len;
13217822Sroot 		if (cc == 0) {
13227822Sroot 			uio->uio_iovcnt--;
13237822Sroot 			uio->uio_iov++;
132421776Sbloom 			if (uio->uio_iovcnt <= 0)
13257822Sroot 				panic("ttwrite");
13267822Sroot 			continue;
13277822Sroot 		}
13287822Sroot 		if (cc > OBUFSIZ)
13297822Sroot 			cc = OBUFSIZ;
13307502Sroot 		cp = obuf;
133112752Ssam 		error = uiomove(cp, cc, UIO_WRITE, uio);
13328520Sroot 		if (error)
13337502Sroot 			break;
13347502Sroot 		if (tp->t_outq.c_cc > hiwat)
13357502Sroot 			goto ovhiwat;
13369578Ssam 		if (tp->t_flags&FLUSHO)
13377502Sroot 			continue;
13389578Ssam 		/*
13399578Ssam 		 * If we're mapping lower case or kludging tildes,
13409578Ssam 		 * then we've got to look at each character, so
13419578Ssam 		 * just feed the stuff to ttyoutput...
13429578Ssam 		 */
13439578Ssam 		if (tp->t_flags & (LCASE|TILDE)) {
13449578Ssam 			while (cc > 0) {
13457502Sroot 				c = *cp++;
13467502Sroot 				tp->t_rocount = 0;
13477625Ssam 				while ((c = ttyoutput(c, tp)) >= 0) {
13487502Sroot 					/* out of clists, wait a bit */
13497502Sroot 					ttstart(tp);
13507502Sroot 					sleep((caddr_t)&lbolt, TTOPRI);
13517502Sroot 					tp->t_rocount = 0;
135221776Sbloom 					if (cc != 0) {
135321776Sbloom 						uio->uio_iov->iov_base -= cc;
135421776Sbloom 						uio->uio_iov->iov_len += cc;
135521776Sbloom 						uio->uio_resid += cc;
135621776Sbloom 						uio->uio_offset -= cc;
135721776Sbloom 					}
135821776Sbloom 					goto loop;
13597502Sroot 				}
13607502Sroot 				--cc;
13617502Sroot 				if (tp->t_outq.c_cc > hiwat)
13627502Sroot 					goto ovhiwat;
13637502Sroot 			}
13647502Sroot 			continue;
13657502Sroot 		}
13669578Ssam 		/*
13679578Ssam 		 * If nothing fancy need be done, grab those characters we
13689578Ssam 		 * can handle without any of ttyoutput's processing and
13699578Ssam 		 * just transfer them to the output q.  For those chars
13709578Ssam 		 * which require special processing (as indicated by the
13719578Ssam 		 * bits in partab), call ttyoutput.  After processing
13729578Ssam 		 * a hunk of data, look for FLUSHO so ^O's will take effect
13739578Ssam 		 * immediately.
13749578Ssam 		 */
13759578Ssam 		while (cc > 0) {
13769578Ssam 			if (tp->t_flags & (RAW|LITOUT))
13777502Sroot 				ce = cc;
13787502Sroot 			else {
137912752Ssam 				ce = cc - scanc((unsigned)cc, (caddr_t)cp,
138012752Ssam 				   (caddr_t)partab, 077);
13819578Ssam 				/*
13829578Ssam 				 * If ce is zero, then we're processing
13839578Ssam 				 * a special character through ttyoutput.
13849578Ssam 				 */
13859578Ssam 				if (ce == 0) {
13867502Sroot 					tp->t_rocount = 0;
13877502Sroot 					if (ttyoutput(*cp, tp) >= 0) {
138821776Sbloom 					    /* no c-lists, wait a bit */
138921776Sbloom 					    ttstart(tp);
139021776Sbloom 					    sleep((caddr_t)&lbolt, TTOPRI);
139121776Sbloom 					    if (cc != 0) {
139221776Sbloom 					        uio->uio_iov->iov_base -= cc;
139321776Sbloom 					        uio->uio_iov->iov_len += cc;
139421776Sbloom 					        uio->uio_resid += cc;
139521776Sbloom 						uio->uio_offset -= cc;
139621776Sbloom 					    }
139721776Sbloom 					    goto loop;
13987502Sroot 					}
13999578Ssam 					cp++, cc--;
14009578Ssam 					if (tp->t_flags&FLUSHO ||
14019578Ssam 					    tp->t_outq.c_cc > hiwat)
14027502Sroot 						goto ovhiwat;
14039578Ssam 					continue;
14047502Sroot 				}
14057502Sroot 			}
14069578Ssam 			/*
14079578Ssam 			 * A bunch of normal characters have been found,
14089578Ssam 			 * transfer them en masse to the output queue and
14099578Ssam 			 * continue processing at the top of the loop.
14109578Ssam 			 * If there are any further characters in this
14119578Ssam 			 * <= OBUFSIZ chunk, the first should be a character
14129578Ssam 			 * requiring special handling by ttyoutput.
14139578Ssam 			 */
14147502Sroot 			tp->t_rocount = 0;
14159578Ssam 			i = b_to_q(cp, ce, &tp->t_outq);
14169578Ssam 			ce -= i;
14179578Ssam 			tp->t_col += ce;
14189578Ssam 			cp += ce, cc -= ce, tk_nout += ce;
14199578Ssam 			if (i > 0) {
14209578Ssam 				/* out of c-lists, wait a bit */
14217502Sroot 				ttstart(tp);
14227502Sroot 				sleep((caddr_t)&lbolt, TTOPRI);
142321776Sbloom 				uio->uio_iov->iov_base -= cc;
142421776Sbloom 				uio->uio_iov->iov_len += cc;
142521776Sbloom 				uio->uio_resid += cc;
142621776Sbloom 				uio->uio_offset -= cc;
142721776Sbloom 				goto loop;
14287502Sroot 			}
14299578Ssam 			if (tp->t_flags&FLUSHO || tp->t_outq.c_cc > hiwat)
14307502Sroot 				goto ovhiwat;
14317502Sroot 		}
14327502Sroot 	}
14337502Sroot 	ttstart(tp);
14348520Sroot 	return (error);
14357502Sroot 
14367502Sroot ovhiwat:
143717545Skarels 	s = spltty();
14389578Ssam 	if (cc != 0) {
14399578Ssam 		uio->uio_iov->iov_base -= cc;
14409578Ssam 		uio->uio_iov->iov_len += cc;
14419578Ssam 		uio->uio_resid += cc;
14429578Ssam 		uio->uio_offset -= cc;
14439578Ssam 	}
14449578Ssam 	/*
14459578Ssam 	 * This can only occur if FLUSHO
14469578Ssam 	 * is also set in t_flags.
14479578Ssam 	 */
14487502Sroot 	if (tp->t_outq.c_cc <= hiwat) {
14499578Ssam 		splx(s);
14507502Sroot 		goto loop;
14517502Sroot 	}
14527502Sroot 	ttstart(tp);
14539578Ssam 	if (tp->t_state&TS_NBIO) {
145417545Skarels 		splx(s);
14557822Sroot 		if (uio->uio_resid == cnt)
14568520Sroot 			return (EWOULDBLOCK);
14578520Sroot 		return (0);
14587502Sroot 	}
14597502Sroot 	tp->t_state |= TS_ASLEEP;
14607502Sroot 	sleep((caddr_t)&tp->t_outq, TTOPRI);
14619578Ssam 	splx(s);
14627502Sroot 	goto loop;
14637502Sroot }
14647502Sroot 
14657502Sroot /*
14667502Sroot  * Rubout one character from the rawq of tp
14677502Sroot  * as cleanly as possible.
14687502Sroot  */
14697502Sroot ttyrub(c, tp)
14707625Ssam 	register c;
14717625Ssam 	register struct tty *tp;
14727502Sroot {
14737502Sroot 	register char *cp;
14747502Sroot 	register int savecol;
14757502Sroot 	int s;
14767502Sroot 	char *nextc();
14777502Sroot 
14789578Ssam 	if ((tp->t_flags&ECHO) == 0)
14797502Sroot 		return;
14809578Ssam 	tp->t_flags &= ~FLUSHO;
14817502Sroot 	c &= 0377;
14829578Ssam 	if (tp->t_flags&CRTBS) {
14837502Sroot 		if (tp->t_rocount == 0) {
14847502Sroot 			/*
14857502Sroot 			 * Screwed by ttwrite; retype
14867502Sroot 			 */
14877502Sroot 			ttyretype(tp);
14887502Sroot 			return;
14897502Sroot 		}
14909578Ssam 		if (c == ('\t'|0200) || c == ('\n'|0200))
14917502Sroot 			ttyrubo(tp, 2);
14929578Ssam 		else switch (partab[c&=0177]&0177) {
14937502Sroot 
14947502Sroot 		case ORDINARY:
14957502Sroot 			if (tp->t_flags&LCASE && c >= 'A' && c <= 'Z')
14967502Sroot 				ttyrubo(tp, 2);
14977502Sroot 			else
14987502Sroot 				ttyrubo(tp, 1);
14997502Sroot 			break;
15007502Sroot 
15017502Sroot 		case VTAB:
15027502Sroot 		case BACKSPACE:
15037502Sroot 		case CONTROL:
15047502Sroot 		case RETURN:
15059578Ssam 			if (tp->t_flags&CTLECH)
15067502Sroot 				ttyrubo(tp, 2);
15077502Sroot 			break;
15087502Sroot 
15097502Sroot 		case TAB:
15107502Sroot 			if (tp->t_rocount < tp->t_rawq.c_cc) {
15117502Sroot 				ttyretype(tp);
15127502Sroot 				return;
15137502Sroot 			}
151417545Skarels 			s = spltty();
15157502Sroot 			savecol = tp->t_col;
15169578Ssam 			tp->t_state |= TS_CNTTB;
15179578Ssam 			tp->t_flags |= FLUSHO;
15187502Sroot 			tp->t_col = tp->t_rocol;
15199578Ssam 			cp = tp->t_rawq.c_cf;
15209578Ssam 			for (; cp; cp = nextc(&tp->t_rawq, cp))
15217502Sroot 				ttyecho(*cp, tp);
15229578Ssam 			tp->t_flags &= ~FLUSHO;
15239578Ssam 			tp->t_state &= ~TS_CNTTB;
15247502Sroot 			splx(s);
15257502Sroot 			/*
15267502Sroot 			 * savecol will now be length of the tab
15277502Sroot 			 */
15287502Sroot 			savecol -= tp->t_col;
15297502Sroot 			tp->t_col += savecol;
15307502Sroot 			if (savecol > 8)
15317502Sroot 				savecol = 8;		/* overflow screw */
15327502Sroot 			while (--savecol >= 0)
15337502Sroot 				(void) ttyoutput('\b', tp);
15347502Sroot 			break;
15357502Sroot 
15367502Sroot 		default:
15377502Sroot 			panic("ttyrub");
15387502Sroot 		}
15399578Ssam 	} else if (tp->t_flags&PRTERA) {
15409578Ssam 		if ((tp->t_state&TS_ERASE) == 0) {
15417502Sroot 			(void) ttyoutput('\\', tp);
15429578Ssam 			tp->t_state |= TS_ERASE;
15437502Sroot 		}
15447502Sroot 		ttyecho(c, tp);
15457502Sroot 	} else
15467502Sroot 		ttyecho(tp->t_erase, tp);
15477502Sroot 	tp->t_rocount--;
15487502Sroot }
15497502Sroot 
15507502Sroot /*
15517502Sroot  * Crt back over cnt chars perhaps
15527502Sroot  * erasing them.
15537502Sroot  */
15547502Sroot ttyrubo(tp, cnt)
15557625Ssam 	register struct tty *tp;
15567625Ssam 	int cnt;
15577502Sroot {
15589578Ssam 	register char *rubostring = tp->t_flags&CRTERA ? "\b \b" : "\b";
15597502Sroot 
15607502Sroot 	while (--cnt >= 0)
15619578Ssam 		ttyout(rubostring, tp);
15627502Sroot }
15637502Sroot 
15647502Sroot /*
15657502Sroot  * Reprint the rawq line.
15667502Sroot  * We assume c_cc has already been checked.
15677502Sroot  */
15687502Sroot ttyretype(tp)
15697625Ssam 	register struct tty *tp;
15707502Sroot {
15717502Sroot 	register char *cp;
15727502Sroot 	char *nextc();
15737502Sroot 	int s;
15747502Sroot 
15759578Ssam 	if (tp->t_rprntc != 0377)
15769578Ssam 		ttyecho(tp->t_rprntc, tp);
15777502Sroot 	(void) ttyoutput('\n', tp);
157817545Skarels 	s = spltty();
15797502Sroot 	for (cp = tp->t_canq.c_cf; cp; cp = nextc(&tp->t_canq, cp))
15807502Sroot 		ttyecho(*cp, tp);
15817502Sroot 	for (cp = tp->t_rawq.c_cf; cp; cp = nextc(&tp->t_rawq, cp))
15827502Sroot 		ttyecho(*cp, tp);
15839578Ssam 	tp->t_state &= ~TS_ERASE;
15847502Sroot 	splx(s);
15857502Sroot 	tp->t_rocount = tp->t_rawq.c_cc;
15867502Sroot 	tp->t_rocol = 0;
15877502Sroot }
15887502Sroot 
15897502Sroot /*
15907502Sroot  * Echo a typed character to the terminal
15917502Sroot  */
15927502Sroot ttyecho(c, tp)
15937625Ssam 	register c;
15947625Ssam 	register struct tty *tp;
15957502Sroot {
15967502Sroot 
15979578Ssam 	if ((tp->t_state&TS_CNTTB) == 0)
15989578Ssam 		tp->t_flags &= ~FLUSHO;
15997502Sroot 	if ((tp->t_flags&ECHO) == 0)
16007502Sroot 		return;
16017502Sroot 	c &= 0377;
16027502Sroot 	if (tp->t_flags&RAW) {
16037502Sroot 		(void) ttyoutput(c, tp);
16047502Sroot 		return;
16057502Sroot 	}
16067502Sroot 	if (c == '\r' && tp->t_flags&CRMOD)
16077502Sroot 		c = '\n';
16089578Ssam 	if (tp->t_flags&CTLECH) {
16097502Sroot 		if ((c&0177) <= 037 && c!='\t' && c!='\n' || (c&0177)==0177) {
16107502Sroot 			(void) ttyoutput('^', tp);
16117502Sroot 			c &= 0177;
16127502Sroot 			if (c == 0177)
16137502Sroot 				c = '?';
16147502Sroot 			else if (tp->t_flags&LCASE)
16157502Sroot 				c += 'a' - 1;
16167502Sroot 			else
16177502Sroot 				c += 'A' - 1;
16187502Sroot 		}
16197502Sroot 	}
16209578Ssam 	(void) ttyoutput(c&0177, tp);
16217502Sroot }
16227502Sroot 
16237502Sroot /*
16247502Sroot  * Is c a break char for tp?
16257502Sroot  */
16267502Sroot ttbreakc(c, tp)
16277625Ssam 	register c;
16287625Ssam 	register struct tty *tp;
16297502Sroot {
16309578Ssam 	return (c == '\n' || c == tp->t_eofc || c == tp->t_brkc ||
16317502Sroot 		c == '\r' && (tp->t_flags&CRMOD));
16327502Sroot }
16337502Sroot 
16347502Sroot /*
16357502Sroot  * send string cp to tp
16367502Sroot  */
16377502Sroot ttyout(cp, tp)
16387625Ssam 	register char *cp;
16397625Ssam 	register struct tty *tp;
16407502Sroot {
16417502Sroot 	register char c;
16427502Sroot 
16437502Sroot 	while (c = *cp++)
16447502Sroot 		(void) ttyoutput(c, tp);
16457502Sroot }
16467502Sroot 
16477502Sroot ttwakeup(tp)
16487502Sroot 	struct tty *tp;
16497502Sroot {
16507502Sroot 
16517502Sroot 	if (tp->t_rsel) {
16527502Sroot 		selwakeup(tp->t_rsel, tp->t_state&TS_RCOLL);
16537502Sroot 		tp->t_state &= ~TS_RCOLL;
16547502Sroot 		tp->t_rsel = 0;
16557502Sroot 	}
165612752Ssam 	if (tp->t_state & TS_ASYNC)
165712752Ssam 		gsignal(tp->t_pgrp, SIGIO);
16587502Sroot 	wakeup((caddr_t)&tp->t_rawq);
16597502Sroot }
1660