xref: /csrg-svn/sys/kern/tty.c (revision 25391)
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*25391Skarels  *	@(#)tty.c	6.22 (Berkeley) 11/04/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) &&
135*25391Skarels 	    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();
294*25391Skarels 		(*linesw[tp->t_line].l_close)(tp);
295*25391Skarels 		error = (*linesw[t].l_open)(dev, tp);
29610851Ssam 		if (error) {
297*25391Skarels 			(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 /*
561*25391Skarels  * 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 /*
591*25391Skarels  * "close" a line discipline
592*25391Skarels  */
593*25391Skarels ttylclose(tp)
594*25391Skarels 	register struct tty *tp;
595*25391Skarels {
596*25391Skarels 
597*25391Skarels 	ttywflush(tp);
598*25391Skarels 	tp->t_line = 0;
599*25391Skarels }
600*25391Skarels 
601*25391Skarels /*
6027502Sroot  * clean tp on last close
6037502Sroot  */
6047502Sroot ttyclose(tp)
6057625Ssam 	register struct tty *tp;
6067502Sroot {
6077502Sroot 
608*25391Skarels 	ttyflush(tp, FREAD|FWRITE);
6097502Sroot 	tp->t_pgrp = 0;
6107502Sroot 	tp->t_state = 0;
6117502Sroot }
6127502Sroot 
6137502Sroot /*
614*25391Skarels  * Handle modem control transition on a tty.
615*25391Skarels  * Flag indicates new state of carrier.
616*25391Skarels  * Returns 0 if the line should be turned off, otherwise 1.
617*25391Skarels  */
618*25391Skarels ttymodem(tp, flag)
619*25391Skarels 	register struct tty *tp;
620*25391Skarels {
621*25391Skarels 
622*25391Skarels 	if ((tp->t_state&TS_WOPEN) == 0 && (tp->t_flags & MDMBUF)) {
623*25391Skarels 		/*
624*25391Skarels 		 * MDMBUF: do flow control according to carrier flag
625*25391Skarels 		 */
626*25391Skarels 		if (flag) {
627*25391Skarels 			tp->t_state &= ~TS_TTSTOP;
628*25391Skarels 			ttstart(tp);
629*25391Skarels 		} else if ((tp->t_state&TS_TTSTOP) == 0) {
630*25391Skarels 			tp->t_state |= TS_TTSTOP;
631*25391Skarels 			(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
632*25391Skarels 		}
633*25391Skarels 	} else if (flag == 0) {
634*25391Skarels 		/*
635*25391Skarels 		 * Lost carrier.
636*25391Skarels 		 */
637*25391Skarels 		tp->t_state &= ~TS_CARR_ON;
638*25391Skarels 		if (tp->t_state & TS_ISOPEN) {
639*25391Skarels 			if ((tp->t_flags & NOHANG) == 0) {
640*25391Skarels 				gsignal(tp->t_pgrp, SIGHUP);
641*25391Skarels 				gsignal(tp->t_pgrp, SIGCONT);
642*25391Skarels 				ttyflush(tp, FREAD|FWRITE);
643*25391Skarels 				return (0);
644*25391Skarels 			}
645*25391Skarels 		}
646*25391Skarels 	} else {
647*25391Skarels 		/*
648*25391Skarels 		 * Carrier now on.
649*25391Skarels 		 */
650*25391Skarels 		tp->t_state |= TS_CARR_ON;
651*25391Skarels 		wakeup((caddr_t)&tp->t_rawq);
652*25391Skarels 	}
653*25391Skarels 	return (1);
654*25391Skarels }
655*25391Skarels 
656*25391Skarels /*
6577502Sroot  * reinput pending characters after state switch
65817545Skarels  * call at spltty().
6597502Sroot  */
6607502Sroot ttypend(tp)
6617625Ssam 	register struct tty *tp;
6627502Sroot {
6637502Sroot 	struct clist tq;
6647502Sroot 	register c;
6657502Sroot 
6669578Ssam 	tp->t_flags &= ~PENDIN;
6679578Ssam 	tp->t_state |= TS_TYPEN;
6687502Sroot 	tq = tp->t_rawq;
6697502Sroot 	tp->t_rawq.c_cc = 0;
6707502Sroot 	tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0;
6717502Sroot 	while ((c = getc(&tq)) >= 0)
6727502Sroot 		ttyinput(c, tp);
6739578Ssam 	tp->t_state &= ~TS_TYPEN;
6747502Sroot }
6757502Sroot 
6767502Sroot /*
6779578Ssam  * Place a character on raw TTY input queue,
6789578Ssam  * putting in delimiters and waking up top
6799578Ssam  * half as needed.  Also echo if required.
6809578Ssam  * The arguments are the character and the
6819578Ssam  * appropriate tty structure.
6827502Sroot  */
6837502Sroot ttyinput(c, tp)
6847625Ssam 	register c;
6857625Ssam 	register struct tty *tp;
6867502Sroot {
6879578Ssam 	register int t_flags = tp->t_flags;
6887502Sroot 	int i;
6897502Sroot 
6909578Ssam 	/*
6919578Ssam 	 * If input is pending take it first.
6929578Ssam 	 */
6939578Ssam 	if (t_flags&PENDIN)
6947502Sroot 		ttypend(tp);
6957502Sroot 	tk_nin++;
6967502Sroot 	c &= 0377;
6979578Ssam 
6989578Ssam 	/*
6999578Ssam 	 * In tandem mode, check high water mark.
7009578Ssam 	 */
7017502Sroot 	if (t_flags&TANDEM)
7027502Sroot 		ttyblock(tp);
7039578Ssam 
7049578Ssam 	if (t_flags&RAW) {
7059578Ssam 		/*
7069578Ssam 		 * Raw mode, just put character
7079578Ssam 		 * in input q w/o interpretation.
7089578Ssam 		 */
7099578Ssam 		if (tp->t_rawq.c_cc > TTYHOG)
71012752Ssam 			ttyflush(tp, FREAD|FWRITE);
7119578Ssam 		else {
7129578Ssam 			if (putc(c, &tp->t_rawq) >= 0)
7139578Ssam 				ttwakeup(tp);
7149578Ssam 			ttyecho(c, tp);
7157502Sroot 		}
7169578Ssam 		goto endcase;
7179578Ssam 	}
7189578Ssam 
7199578Ssam 	/*
7209578Ssam 	 * Ignore any high bit added during
7219578Ssam 	 * previous ttyinput processing.
7229578Ssam 	 */
72324273Slepreau 	if ((tp->t_state&TS_TYPEN) == 0 && (t_flags&PASS8) == 0)
7249578Ssam 		c &= 0177;
7259578Ssam 	/*
7269578Ssam 	 * Check for literal nexting very first
7279578Ssam 	 */
7289578Ssam 	if (tp->t_state&TS_LNCH) {
7299578Ssam 		c |= 0200;
7309578Ssam 		tp->t_state &= ~TS_LNCH;
7319578Ssam 	}
7329578Ssam 
7339578Ssam 	/*
7349578Ssam 	 * Scan for special characters.  This code
7359578Ssam 	 * is really just a big case statement with
7369578Ssam 	 * non-constant cases.  The bottom of the
7379578Ssam 	 * case statement is labeled ``endcase'', so goto
7389578Ssam 	 * it after a case match, or similar.
7399578Ssam 	 */
7409578Ssam 	if (tp->t_line == NTTYDISC) {
7419578Ssam 		if (c == tp->t_lnextc) {
74221776Sbloom 			if (t_flags&ECHO)
7437502Sroot 				ttyout("^\b", tp);
7449578Ssam 			tp->t_state |= TS_LNCH;
7459578Ssam 			goto endcase;
7469578Ssam 		}
7479578Ssam 		if (c == tp->t_flushc) {
74821776Sbloom 			if (t_flags&FLUSHO)
7499578Ssam 				tp->t_flags &= ~FLUSHO;
7507502Sroot 			else {
75112752Ssam 				ttyflush(tp, FWRITE);
7527502Sroot 				ttyecho(c, tp);
7539578Ssam 				if (tp->t_rawq.c_cc + tp->t_canq.c_cc)
7547502Sroot 					ttyretype(tp);
7559578Ssam 				tp->t_flags |= FLUSHO;
7567502Sroot 			}
7579578Ssam 			goto startoutput;
7589578Ssam 		}
7599578Ssam 		if (c == tp->t_suspc) {
76021776Sbloom 			if ((t_flags&NOFLSH) == 0)
76112752Ssam 				ttyflush(tp, FREAD);
7629578Ssam 			ttyecho(c, tp);
7639578Ssam 			gsignal(tp->t_pgrp, SIGTSTP);
7649578Ssam 			goto endcase;
7659578Ssam 		}
7669578Ssam 	}
7679578Ssam 
7689578Ssam 	/*
7699578Ssam 	 * Handle start/stop characters.
7709578Ssam 	 */
7719578Ssam 	if (c == tp->t_stopc) {
7729578Ssam 		if ((tp->t_state&TS_TTSTOP) == 0) {
7739578Ssam 			tp->t_state |= TS_TTSTOP;
7749578Ssam 			(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
7757502Sroot 			return;
7769578Ssam 		}
7779578Ssam 		if (c != tp->t_startc)
7789578Ssam 			return;
7799578Ssam 		goto endcase;
7809578Ssam 	}
7819578Ssam 	if (c == tp->t_startc)
7829578Ssam 		goto restartoutput;
7839578Ssam 
7849578Ssam 	/*
7859578Ssam 	 * Look for interrupt/quit chars.
7869578Ssam 	 */
7879578Ssam 	if (c == tp->t_intrc || c == tp->t_quitc) {
78821776Sbloom 		if ((t_flags&NOFLSH) == 0)
78912752Ssam 			ttyflush(tp, FREAD|FWRITE);
7909578Ssam 		ttyecho(c, tp);
7919578Ssam 		gsignal(tp->t_pgrp, c == tp->t_intrc ? SIGINT : SIGQUIT);
7929578Ssam 		goto endcase;
7939578Ssam 	}
7949578Ssam 
79523165Sbloom 	if (tp->t_flags & LCASE && c <= 0177) {
79623165Sbloom 		if (tp->t_state&TS_BKSL) {
79723165Sbloom 			ttyrub(unputc(&tp->t_rawq), tp);
79823165Sbloom 			if (maptab[c])
79923165Sbloom 				c = maptab[c];
80023165Sbloom 			c |= 0200;
80123165Sbloom 			tp->t_state &= ~(TS_BKSL|TS_QUOT);
80223165Sbloom 		} else if (c >= 'A' && c <= 'Z')
80323165Sbloom 			c += 'a' - 'A';
80423165Sbloom 		else if (c == '\\')
80523165Sbloom 			tp->t_state |= TS_BKSL;
80623165Sbloom 	}
80723165Sbloom 
8089578Ssam 	/*
8099578Ssam 	 * Cbreak mode, don't process line editing
8109578Ssam 	 * characters; check high water mark for wakeup.
8119578Ssam 	 */
8129578Ssam 	if (t_flags&CBREAK) {
8139578Ssam 		if (tp->t_rawq.c_cc > TTYHOG) {
8147502Sroot 			if (tp->t_outq.c_cc < TTHIWAT(tp) &&
8157502Sroot 			    tp->t_line == NTTYDISC)
8167502Sroot 				(void) ttyoutput(CTRL(g), tp);
8177502Sroot 		} else if (putc(c, &tp->t_rawq) >= 0) {
8187502Sroot 			ttwakeup(tp);
8197502Sroot 			ttyecho(c, tp);
8207502Sroot 		}
8219578Ssam 		goto endcase;
8229578Ssam 	}
8239578Ssam 
8249578Ssam 	/*
8259578Ssam 	 * From here on down cooked mode character
8269578Ssam 	 * processing takes place.
8279578Ssam 	 */
8289578Ssam 	if ((tp->t_state&TS_QUOT) &&
8299578Ssam 	    (c == tp->t_erase || c == tp->t_kill)) {
8309578Ssam 		ttyrub(unputc(&tp->t_rawq), tp);
8319578Ssam 		c |= 0200;
8329578Ssam 	}
8339578Ssam 	if (c == tp->t_erase) {
8349578Ssam 		if (tp->t_rawq.c_cc)
8359578Ssam 			ttyrub(unputc(&tp->t_rawq), tp);
8369578Ssam 		goto endcase;
8379578Ssam 	}
8389578Ssam 	if (c == tp->t_kill) {
83921776Sbloom 		if (t_flags&CRTKIL &&
8409578Ssam 		    tp->t_rawq.c_cc == tp->t_rocount) {
8419578Ssam 			while (tp->t_rawq.c_cc)
8429578Ssam 				ttyrub(unputc(&tp->t_rawq), tp);
8439578Ssam 		} else {
8449578Ssam 			ttyecho(c, tp);
8459578Ssam 			ttyecho('\n', tp);
8469578Ssam 			while (getc(&tp->t_rawq) > 0)
8479578Ssam 				;
8489578Ssam 			tp->t_rocount = 0;
8499578Ssam 		}
8509578Ssam 		tp->t_state &= ~TS_LOCAL;
8519578Ssam 		goto endcase;
8529578Ssam 	}
8539578Ssam 
8549578Ssam 	/*
8559578Ssam 	 * New line discipline,
8569578Ssam 	 * check word erase/reprint line.
8579578Ssam 	 */
8589578Ssam 	if (tp->t_line == NTTYDISC) {
8599578Ssam 		if (c == tp->t_werasc) {
8609578Ssam 			if (tp->t_rawq.c_cc == 0)
8619578Ssam 				goto endcase;
8629578Ssam 			do {
8639578Ssam 				c = unputc(&tp->t_rawq);
8649578Ssam 				if (c != ' ' && c != '\t')
8659578Ssam 					goto erasenb;
8669578Ssam 				ttyrub(c, tp);
8679578Ssam 			} while (tp->t_rawq.c_cc);
8689578Ssam 			goto endcase;
8699578Ssam 	erasenb:
8709578Ssam 			do {
8719578Ssam 				ttyrub(c, tp);
8729578Ssam 				if (tp->t_rawq.c_cc == 0)
8739578Ssam 					goto endcase;
8749578Ssam 				c = unputc(&tp->t_rawq);
8759578Ssam 			} while (c != ' ' && c != '\t');
8769578Ssam 			(void) putc(c, &tp->t_rawq);
8779578Ssam 			goto endcase;
8789578Ssam 		}
8799578Ssam 		if (c == tp->t_rprntc) {
8809578Ssam 			ttyretype(tp);
8819578Ssam 			goto endcase;
8829578Ssam 		}
8839578Ssam 	}
8849578Ssam 
8859578Ssam 	/*
8869578Ssam 	 * Check for input buffer overflow
8879578Ssam 	 */
88810391Ssam 	if (tp->t_rawq.c_cc+tp->t_canq.c_cc >= TTYHOG) {
88910391Ssam 		if (tp->t_line == NTTYDISC)
89010391Ssam 			(void) ttyoutput(CTRL(g), tp);
8919578Ssam 		goto endcase;
89210391Ssam 	}
8939578Ssam 
8949578Ssam 	/*
8959578Ssam 	 * Put data char in q for user and
8969578Ssam 	 * wakeup on seeing a line delimiter.
8979578Ssam 	 */
8989578Ssam 	if (putc(c, &tp->t_rawq) >= 0) {
8999578Ssam 		if (ttbreakc(c, tp)) {
9009578Ssam 			tp->t_rocount = 0;
9019578Ssam 			catq(&tp->t_rawq, &tp->t_canq);
9027502Sroot 			ttwakeup(tp);
9039578Ssam 		} else if (tp->t_rocount++ == 0)
9049578Ssam 			tp->t_rocol = tp->t_col;
9059578Ssam 		tp->t_state &= ~TS_QUOT;
9069578Ssam 		if (c == '\\')
9079578Ssam 			tp->t_state |= TS_QUOT;
9089578Ssam 		if (tp->t_state&TS_ERASE) {
9099578Ssam 			tp->t_state &= ~TS_ERASE;
9109578Ssam 			(void) ttyoutput('/', tp);
9119578Ssam 		}
9129578Ssam 		i = tp->t_col;
9137502Sroot 		ttyecho(c, tp);
91421776Sbloom 		if (c == tp->t_eofc && t_flags&ECHO) {
9159578Ssam 			i = MIN(2, tp->t_col - i);
9169578Ssam 			while (i > 0) {
9179578Ssam 				(void) ttyoutput('\b', tp);
9189578Ssam 				i--;
9199578Ssam 			}
9209578Ssam 		}
9217502Sroot 	}
9229578Ssam endcase:
9239578Ssam 	/*
9249578Ssam 	 * If DEC-style start/stop is enabled don't restart
9259578Ssam 	 * output until seeing the start character.
9269578Ssam 	 */
92721776Sbloom 	if (t_flags&DECCTQ && tp->t_state&TS_TTSTOP &&
9289578Ssam 	    tp->t_startc != tp->t_stopc)
9297502Sroot 		return;
9309578Ssam restartoutput:
9317502Sroot 	tp->t_state &= ~TS_TTSTOP;
9329578Ssam 	tp->t_flags &= ~FLUSHO;
9339578Ssam startoutput:
9347502Sroot 	ttstart(tp);
9357502Sroot }
9367502Sroot 
9377502Sroot /*
9389578Ssam  * Put character on TTY output queue, adding delays,
9397502Sroot  * expanding tabs, and handling the CR/NL bit.
9409578Ssam  * This is called both from the top half for output,
9419578Ssam  * and from interrupt level for echoing.
9427502Sroot  * The arguments are the character and the tty structure.
9437502Sroot  * Returns < 0 if putc succeeds, otherwise returns char to resend
9447502Sroot  * Must be recursive.
9457502Sroot  */
9467502Sroot ttyoutput(c, tp)
9477502Sroot 	register c;
9487502Sroot 	register struct tty *tp;
9497502Sroot {
9507502Sroot 	register char *colp;
9517502Sroot 	register ctype;
9527502Sroot 
9539578Ssam 	if (tp->t_flags & (RAW|LITOUT)) {
9549578Ssam 		if (tp->t_flags&FLUSHO)
9557502Sroot 			return (-1);
9567502Sroot 		if (putc(c, &tp->t_outq))
9577625Ssam 			return (c);
9587502Sroot 		tk_nout++;
9597502Sroot 		return (-1);
9607502Sroot 	}
9619578Ssam 
9627502Sroot 	/*
9639578Ssam 	 * Ignore EOT in normal mode to avoid
9649578Ssam 	 * hanging up certain terminals.
9657502Sroot 	 */
9667502Sroot 	c &= 0177;
9679578Ssam 	if (c == CEOT && (tp->t_flags&CBREAK) == 0)
9687502Sroot 		return (-1);
9697502Sroot 	/*
9707502Sroot 	 * Turn tabs to spaces as required
9717502Sroot 	 */
9729578Ssam 	if (c == '\t' && (tp->t_flags&TBDELAY) == XTABS) {
9737502Sroot 		register int s;
9747502Sroot 
9757502Sroot 		c = 8 - (tp->t_col&7);
9769578Ssam 		if ((tp->t_flags&FLUSHO) == 0) {
97717545Skarels 			s = spltty();		/* don't interrupt tabs */
9787502Sroot 			c -= b_to_q("        ", c, &tp->t_outq);
9797502Sroot 			tk_nout += c;
9807502Sroot 			splx(s);
9817502Sroot 		}
9827502Sroot 		tp->t_col += c;
9837502Sroot 		return (c ? -1 : '\t');
9847502Sroot 	}
9857502Sroot 	tk_nout++;
9867502Sroot 	/*
9877502Sroot 	 * for upper-case-only terminals,
9887502Sroot 	 * generate escapes.
9897502Sroot 	 */
9907502Sroot 	if (tp->t_flags&LCASE) {
9917502Sroot 		colp = "({)}!|^~'`";
9927625Ssam 		while (*colp++)
9937625Ssam 			if (c == *colp++) {
9947502Sroot 				if (ttyoutput('\\', tp) >= 0)
9957502Sroot 					return (c);
9967502Sroot 				c = colp[-2];
9977502Sroot 				break;
9987502Sroot 			}
9999578Ssam 		if ('A' <= c && c <= 'Z') {
10007502Sroot 			if (ttyoutput('\\', tp) >= 0)
10017502Sroot 				return (c);
10029578Ssam 		} else if ('a' <= c && c <= 'z')
10037502Sroot 			c += 'A' - 'a';
10047502Sroot 	}
10059578Ssam 
10067502Sroot 	/*
10077502Sroot 	 * turn <nl> to <cr><lf> if desired.
10087502Sroot 	 */
10099578Ssam 	if (c == '\n' && tp->t_flags&CRMOD)
10107502Sroot 		if (ttyoutput('\r', tp) >= 0)
10117502Sroot 			return (c);
10129578Ssam 	if (c == '~' && tp->t_flags&TILDE)
10137502Sroot 		c = '`';
10149578Ssam 	if ((tp->t_flags&FLUSHO) == 0 && putc(c, &tp->t_outq))
10157502Sroot 		return (c);
10167502Sroot 	/*
10177502Sroot 	 * Calculate delays.
10187502Sroot 	 * The numbers here represent clock ticks
10197502Sroot 	 * and are not necessarily optimal for all terminals.
10207502Sroot 	 * The delays are indicated by characters above 0200.
10217502Sroot 	 * In raw mode there are no delays and the
10227502Sroot 	 * transmission path is 8 bits wide.
10239578Ssam 	 *
10249578Ssam 	 * SHOULD JUST ALLOW USER TO SPECIFY DELAYS
10257502Sroot 	 */
10267502Sroot 	colp = &tp->t_col;
10277502Sroot 	ctype = partab[c];
10287502Sroot 	c = 0;
10297502Sroot 	switch (ctype&077) {
10307502Sroot 
10317502Sroot 	case ORDINARY:
10327502Sroot 		(*colp)++;
10337502Sroot 
10347502Sroot 	case CONTROL:
10357502Sroot 		break;
10367502Sroot 
10377502Sroot 	case BACKSPACE:
10387502Sroot 		if (*colp)
10397502Sroot 			(*colp)--;
10407502Sroot 		break;
10417502Sroot 
104213821Ssam 	/*
104313821Ssam 	 * This macro is close enough to the correct thing;
104413821Ssam 	 * it should be replaced by real user settable delays
104513821Ssam 	 * in any event...
104613821Ssam 	 */
104713821Ssam #define	mstohz(ms)	(((ms) * hz) >> 10)
10487502Sroot 	case NEWLINE:
10497502Sroot 		ctype = (tp->t_flags >> 8) & 03;
10507625Ssam 		if (ctype == 1) { /* tty 37 */
105112752Ssam 			if (*colp > 0)
105213863Ssam 				c = max((((unsigned)*colp) >> 4) + 3,
105313863Ssam 				    (unsigned)6);
10549578Ssam 		} else if (ctype == 2) /* vt05 */
105513821Ssam 			c = mstohz(100);
10567502Sroot 		*colp = 0;
10577502Sroot 		break;
10587502Sroot 
10597502Sroot 	case TAB:
10607502Sroot 		ctype = (tp->t_flags >> 10) & 03;
10617625Ssam 		if (ctype == 1) { /* tty 37 */
10627502Sroot 			c = 1 - (*colp | ~07);
10637625Ssam 			if (c < 5)
10647502Sroot 				c = 0;
10657502Sroot 		}
10667502Sroot 		*colp |= 07;
10677502Sroot 		(*colp)++;
10687502Sroot 		break;
10697502Sroot 
10707502Sroot 	case VTAB:
10719578Ssam 		if (tp->t_flags&VTDELAY) /* tty 37 */
10727502Sroot 			c = 0177;
10737502Sroot 		break;
10747502Sroot 
10757502Sroot 	case RETURN:
10767502Sroot 		ctype = (tp->t_flags >> 12) & 03;
10779578Ssam 		if (ctype == 1) /* tn 300 */
107813821Ssam 			c = mstohz(83);
10799578Ssam 		else if (ctype == 2) /* ti 700 */
108013821Ssam 			c = mstohz(166);
10819578Ssam 		else if (ctype == 3) { /* concept 100 */
10827502Sroot 			int i;
10839578Ssam 
10847502Sroot 			if ((i = *colp) >= 0)
10859578Ssam 				for (; i < 9; i++)
10867502Sroot 					(void) putc(0177, &tp->t_outq);
10877502Sroot 		}
10887502Sroot 		*colp = 0;
10897502Sroot 	}
10909578Ssam 	if (c && (tp->t_flags&FLUSHO) == 0)
10917502Sroot 		(void) putc(c|0200, &tp->t_outq);
10927502Sroot 	return (-1);
10937502Sroot }
109413821Ssam #undef mstohz
10957502Sroot 
10967502Sroot /*
10977502Sroot  * Called from device's read routine after it has
10987502Sroot  * calculated the tty-structure given as argument.
10997502Sroot  */
11007722Swnj ttread(tp, uio)
11017625Ssam 	register struct tty *tp;
11027722Swnj 	struct uio *uio;
11037502Sroot {
11047502Sroot 	register struct clist *qp;
11059578Ssam 	register c, t_flags;
11069859Ssam 	int s, first, error = 0;
11077502Sroot 
11087502Sroot loop:
11099578Ssam 	/*
11109578Ssam 	 * Take any pending input first.
11119578Ssam 	 */
111217545Skarels 	s = spltty();
11139578Ssam 	if (tp->t_flags&PENDIN)
11147502Sroot 		ttypend(tp);
11159859Ssam 	splx(s);
11169578Ssam 
111723165Sbloom 	if ((tp->t_state&TS_CARR_ON)==0)
111823165Sbloom 		return (EIO);
111923165Sbloom 
11209578Ssam 	/*
11219578Ssam 	 * Hang process if it's in the background.
11229578Ssam 	 */
112323165Sbloom 	if (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) {
112424392Skarels 		if ((u.u_procp->p_sigignore & sigmask(SIGTTIN)) ||
112524392Skarels 		   (u.u_procp->p_sigmask & sigmask(SIGTTIN)) ||
11267502Sroot 		    u.u_procp->p_flag&SVFORK)
11278520Sroot 			return (EIO);
11287502Sroot 		gsignal(u.u_procp->p_pgrp, SIGTTIN);
11297502Sroot 		sleep((caddr_t)&lbolt, TTIPRI);
113023165Sbloom 		goto loop;
11317502Sroot 	}
11329578Ssam 	t_flags = tp->t_flags;
11339578Ssam 
11349578Ssam 	/*
11359578Ssam 	 * In raw mode take characters directly from the
11369578Ssam 	 * raw queue w/o processing.  Interlock against
11379578Ssam 	 * device interrupts when interrogating rawq.
11389578Ssam 	 */
11399578Ssam 	if (t_flags&RAW) {
114017545Skarels 		s = spltty();
11417502Sroot 		if (tp->t_rawq.c_cc <= 0) {
11429578Ssam 			if ((tp->t_state&TS_CARR_ON) == 0 ||
11437502Sroot 			    (tp->t_state&TS_NBIO)) {
11449859Ssam 				splx(s);
114515094Skarels 				return (EWOULDBLOCK);
11467502Sroot 			}
11477502Sroot 			sleep((caddr_t)&tp->t_rawq, TTIPRI);
11489859Ssam 			splx(s);
11497502Sroot 			goto loop;
11507502Sroot 		}
11519859Ssam 		splx(s);
115214938Smckusick  		while (!error && tp->t_rawq.c_cc && uio->uio_resid)
115314938Smckusick  			error = ureadc(getc(&tp->t_rawq), uio);
11549859Ssam 		goto checktandem;
11559578Ssam 	}
11569578Ssam 
11579578Ssam 	/*
11589578Ssam 	 * In cbreak mode use the rawq, otherwise
11599578Ssam 	 * take characters from the canonicalized q.
11609578Ssam 	 */
11619578Ssam 	qp = t_flags&CBREAK ? &tp->t_rawq : &tp->t_canq;
11629578Ssam 
11639578Ssam 	/*
11649578Ssam 	 * No input, sleep on rawq awaiting hardware
11659578Ssam 	 * receipt and notification.
11669578Ssam 	 */
116717545Skarels 	s = spltty();
11689578Ssam 	if (qp->c_cc <= 0) {
11699578Ssam 		if ((tp->t_state&TS_CARR_ON) == 0 ||
11709578Ssam 		    (tp->t_state&TS_NBIO)) {
11719859Ssam 			splx(s);
11729578Ssam 			return (EWOULDBLOCK);
11737502Sroot 		}
11749578Ssam 		sleep((caddr_t)&tp->t_rawq, TTIPRI);
11759859Ssam 		splx(s);
11769578Ssam 		goto loop;
11779578Ssam 	}
11789859Ssam 	splx(s);
11799578Ssam 
11809578Ssam 	/*
11819578Ssam 	 * Input present, perform input mapping
11829578Ssam 	 * and processing (we're not in raw mode).
11839578Ssam 	 */
11849578Ssam 	first = 1;
11859578Ssam 	while ((c = getc(qp)) >= 0) {
11869578Ssam 		if (t_flags&CRMOD && c == '\r')
11879578Ssam 			c = '\n';
11889578Ssam 		/*
11899578Ssam 		 * Check for delayed suspend character.
11909578Ssam 		 */
11919578Ssam 		if (tp->t_line == NTTYDISC && c == tp->t_dsuspc) {
11929578Ssam 			gsignal(tp->t_pgrp, SIGTSTP);
11939578Ssam 			if (first) {
11949578Ssam 				sleep((caddr_t)&lbolt, TTIPRI);
11959578Ssam 				goto loop;
11969578Ssam 			}
11979578Ssam 			break;
11987502Sroot 		}
11999578Ssam 		/*
12009578Ssam 		 * Interpret EOF only in cooked mode.
12019578Ssam 		 */
12029578Ssam 		if (c == tp->t_eofc && (t_flags&CBREAK) == 0)
12039578Ssam 			break;
12049578Ssam 		/*
12059578Ssam 		 * Give user character.
12069578Ssam 		 */
120724273Slepreau  		error = ureadc(t_flags&PASS8 ? c : c & 0177, uio);
12089578Ssam 		if (error)
12099578Ssam 			break;
121014938Smckusick  		if (uio->uio_resid == 0)
12119578Ssam 			break;
12129578Ssam 		/*
12139578Ssam 		 * In cooked mode check for a "break character"
12149578Ssam 		 * marking the end of a "line of input".
12159578Ssam 		 */
12169578Ssam 		if ((t_flags&CBREAK) == 0 && ttbreakc(c, tp))
12179578Ssam 			break;
12189578Ssam 		first = 0;
12197502Sroot 	}
12209578Ssam 
12219859Ssam checktandem:
12229578Ssam 	/*
12239578Ssam 	 * Look to unblock output now that (presumably)
12249578Ssam 	 * the input queue has gone down.
12259578Ssam 	 */
12269859Ssam 	if (tp->t_state&TS_TBLOCK && tp->t_rawq.c_cc < TTYHOG/5)
12279578Ssam 		if (putc(tp->t_startc, &tp->t_outq) == 0) {
12287502Sroot 			tp->t_state &= ~TS_TBLOCK;
12297502Sroot 			ttstart(tp);
12307502Sroot 		}
12318520Sroot 	return (error);
12327502Sroot }
12337502Sroot 
12347502Sroot /*
1235*25391Skarels  * Check the output queue on tp for space for a kernel message
1236*25391Skarels  * (from uprintf/tprintf).  Allow some space over the normal
1237*25391Skarels  * hiwater mark so we don't lose messages due to normal flow
1238*25391Skarels  * control, but don't let the tty run amok.
1239*25391Skarels  */
1240*25391Skarels ttycheckoutq(tp, wait)
1241*25391Skarels 	register struct tty *tp;
1242*25391Skarels 	int wait;
1243*25391Skarels {
1244*25391Skarels 	int hiwat, s;
1245*25391Skarels 
1246*25391Skarels 	hiwat = TTHIWAT(tp);
1247*25391Skarels 	s = spltty();
1248*25391Skarels 	if (tp->t_outq.c_cc > hiwat + 200)
1249*25391Skarels 	    while (tp->t_outq.c_cc > hiwat) {
1250*25391Skarels 		ttstart(tp);
1251*25391Skarels 		if (wait == 0) {
1252*25391Skarels 			splx(s);
1253*25391Skarels 			return (0);
1254*25391Skarels 		}
1255*25391Skarels 		tp->t_state |= TS_ASLEEP;
1256*25391Skarels 		sleep((caddr_t)&tp->t_outq, TTOPRI);
1257*25391Skarels 	}
1258*25391Skarels 	splx(s);
1259*25391Skarels 	return (1);
1260*25391Skarels }
1261*25391Skarels 
1262*25391Skarels /*
12637502Sroot  * Called from the device's write routine after it has
12647502Sroot  * calculated the tty-structure given as argument.
12657502Sroot  */
12667822Sroot ttwrite(tp, uio)
12677625Ssam 	register struct tty *tp;
12689578Ssam 	register struct uio *uio;
12697502Sroot {
12707502Sroot 	register char *cp;
12719578Ssam 	register int cc, ce, c;
12729578Ssam 	int i, hiwat, cnt, error, s;
12737502Sroot 	char obuf[OBUFSIZ];
12747502Sroot 
12759578Ssam 	hiwat = TTHIWAT(tp);
12769578Ssam 	cnt = uio->uio_resid;
12779578Ssam 	error = 0;
12787502Sroot loop:
127921776Sbloom 	if ((tp->t_state&TS_CARR_ON) == 0)
128021776Sbloom 		return (EIO);
12819578Ssam 	/*
12829578Ssam 	 * Hang the process if it's in the background.
12839578Ssam 	 */
128421776Sbloom 	if (u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp &&
12859578Ssam 	    (tp->t_flags&TOSTOP) && (u.u_procp->p_flag&SVFORK)==0 &&
128624392Skarels 	    !(u.u_procp->p_sigignore & sigmask(SIGTTOU)) &&
128724392Skarels 	    !(u.u_procp->p_sigmask & sigmask(SIGTTOU))) {
12887502Sroot 		gsignal(u.u_procp->p_pgrp, SIGTTOU);
12897502Sroot 		sleep((caddr_t)&lbolt, TTIPRI);
129021776Sbloom 		goto loop;
12917502Sroot 	}
12929578Ssam 
12939578Ssam 	/*
12949578Ssam 	 * Process the user's data in at most OBUFSIZ
12959578Ssam 	 * chunks.  Perform lower case simulation and
12969578Ssam 	 * similar hacks.  Keep track of high water
12979578Ssam 	 * mark, sleep on overflow awaiting device aid
12989578Ssam 	 * in acquiring new space.
12999578Ssam 	 */
13007822Sroot 	while (uio->uio_resid > 0) {
13019578Ssam 		/*
13029578Ssam 		 * Grab a hunk of data from the user.
13039578Ssam 		 */
13047822Sroot 		cc = uio->uio_iov->iov_len;
13057822Sroot 		if (cc == 0) {
13067822Sroot 			uio->uio_iovcnt--;
13077822Sroot 			uio->uio_iov++;
130821776Sbloom 			if (uio->uio_iovcnt <= 0)
13097822Sroot 				panic("ttwrite");
13107822Sroot 			continue;
13117822Sroot 		}
13127822Sroot 		if (cc > OBUFSIZ)
13137822Sroot 			cc = OBUFSIZ;
13147502Sroot 		cp = obuf;
131512752Ssam 		error = uiomove(cp, cc, UIO_WRITE, uio);
13168520Sroot 		if (error)
13177502Sroot 			break;
13187502Sroot 		if (tp->t_outq.c_cc > hiwat)
13197502Sroot 			goto ovhiwat;
13209578Ssam 		if (tp->t_flags&FLUSHO)
13217502Sroot 			continue;
13229578Ssam 		/*
13239578Ssam 		 * If we're mapping lower case or kludging tildes,
13249578Ssam 		 * then we've got to look at each character, so
13259578Ssam 		 * just feed the stuff to ttyoutput...
13269578Ssam 		 */
13279578Ssam 		if (tp->t_flags & (LCASE|TILDE)) {
13289578Ssam 			while (cc > 0) {
13297502Sroot 				c = *cp++;
13307502Sroot 				tp->t_rocount = 0;
13317625Ssam 				while ((c = ttyoutput(c, tp)) >= 0) {
13327502Sroot 					/* out of clists, wait a bit */
13337502Sroot 					ttstart(tp);
13347502Sroot 					sleep((caddr_t)&lbolt, TTOPRI);
13357502Sroot 					tp->t_rocount = 0;
133621776Sbloom 					if (cc != 0) {
133721776Sbloom 						uio->uio_iov->iov_base -= cc;
133821776Sbloom 						uio->uio_iov->iov_len += cc;
133921776Sbloom 						uio->uio_resid += cc;
134021776Sbloom 						uio->uio_offset -= cc;
134121776Sbloom 					}
134221776Sbloom 					goto loop;
13437502Sroot 				}
13447502Sroot 				--cc;
13457502Sroot 				if (tp->t_outq.c_cc > hiwat)
13467502Sroot 					goto ovhiwat;
13477502Sroot 			}
13487502Sroot 			continue;
13497502Sroot 		}
13509578Ssam 		/*
13519578Ssam 		 * If nothing fancy need be done, grab those characters we
13529578Ssam 		 * can handle without any of ttyoutput's processing and
13539578Ssam 		 * just transfer them to the output q.  For those chars
13549578Ssam 		 * which require special processing (as indicated by the
13559578Ssam 		 * bits in partab), call ttyoutput.  After processing
13569578Ssam 		 * a hunk of data, look for FLUSHO so ^O's will take effect
13579578Ssam 		 * immediately.
13589578Ssam 		 */
13599578Ssam 		while (cc > 0) {
13609578Ssam 			if (tp->t_flags & (RAW|LITOUT))
13617502Sroot 				ce = cc;
13627502Sroot 			else {
136312752Ssam 				ce = cc - scanc((unsigned)cc, (caddr_t)cp,
136412752Ssam 				   (caddr_t)partab, 077);
13659578Ssam 				/*
13669578Ssam 				 * If ce is zero, then we're processing
13679578Ssam 				 * a special character through ttyoutput.
13689578Ssam 				 */
13699578Ssam 				if (ce == 0) {
13707502Sroot 					tp->t_rocount = 0;
13717502Sroot 					if (ttyoutput(*cp, tp) >= 0) {
137221776Sbloom 					    /* no c-lists, wait a bit */
137321776Sbloom 					    ttstart(tp);
137421776Sbloom 					    sleep((caddr_t)&lbolt, TTOPRI);
137521776Sbloom 					    if (cc != 0) {
137621776Sbloom 					        uio->uio_iov->iov_base -= cc;
137721776Sbloom 					        uio->uio_iov->iov_len += cc;
137821776Sbloom 					        uio->uio_resid += cc;
137921776Sbloom 						uio->uio_offset -= cc;
138021776Sbloom 					    }
138121776Sbloom 					    goto loop;
13827502Sroot 					}
13839578Ssam 					cp++, cc--;
13849578Ssam 					if (tp->t_flags&FLUSHO ||
13859578Ssam 					    tp->t_outq.c_cc > hiwat)
13867502Sroot 						goto ovhiwat;
13879578Ssam 					continue;
13887502Sroot 				}
13897502Sroot 			}
13909578Ssam 			/*
13919578Ssam 			 * A bunch of normal characters have been found,
13929578Ssam 			 * transfer them en masse to the output queue and
13939578Ssam 			 * continue processing at the top of the loop.
13949578Ssam 			 * If there are any further characters in this
13959578Ssam 			 * <= OBUFSIZ chunk, the first should be a character
13969578Ssam 			 * requiring special handling by ttyoutput.
13979578Ssam 			 */
13987502Sroot 			tp->t_rocount = 0;
13999578Ssam 			i = b_to_q(cp, ce, &tp->t_outq);
14009578Ssam 			ce -= i;
14019578Ssam 			tp->t_col += ce;
14029578Ssam 			cp += ce, cc -= ce, tk_nout += ce;
14039578Ssam 			if (i > 0) {
14049578Ssam 				/* out of c-lists, wait a bit */
14057502Sroot 				ttstart(tp);
14067502Sroot 				sleep((caddr_t)&lbolt, TTOPRI);
140721776Sbloom 				uio->uio_iov->iov_base -= cc;
140821776Sbloom 				uio->uio_iov->iov_len += cc;
140921776Sbloom 				uio->uio_resid += cc;
141021776Sbloom 				uio->uio_offset -= cc;
141121776Sbloom 				goto loop;
14127502Sroot 			}
14139578Ssam 			if (tp->t_flags&FLUSHO || tp->t_outq.c_cc > hiwat)
14147502Sroot 				goto ovhiwat;
14157502Sroot 		}
14167502Sroot 	}
14177502Sroot 	ttstart(tp);
14188520Sroot 	return (error);
14197502Sroot 
14207502Sroot ovhiwat:
142117545Skarels 	s = spltty();
14229578Ssam 	if (cc != 0) {
14239578Ssam 		uio->uio_iov->iov_base -= cc;
14249578Ssam 		uio->uio_iov->iov_len += cc;
14259578Ssam 		uio->uio_resid += cc;
14269578Ssam 		uio->uio_offset -= cc;
14279578Ssam 	}
14289578Ssam 	/*
14299578Ssam 	 * This can only occur if FLUSHO
14309578Ssam 	 * is also set in t_flags.
14319578Ssam 	 */
14327502Sroot 	if (tp->t_outq.c_cc <= hiwat) {
14339578Ssam 		splx(s);
14347502Sroot 		goto loop;
14357502Sroot 	}
14367502Sroot 	ttstart(tp);
14379578Ssam 	if (tp->t_state&TS_NBIO) {
143817545Skarels 		splx(s);
14397822Sroot 		if (uio->uio_resid == cnt)
14408520Sroot 			return (EWOULDBLOCK);
14418520Sroot 		return (0);
14427502Sroot 	}
14437502Sroot 	tp->t_state |= TS_ASLEEP;
14447502Sroot 	sleep((caddr_t)&tp->t_outq, TTOPRI);
14459578Ssam 	splx(s);
14467502Sroot 	goto loop;
14477502Sroot }
14487502Sroot 
14497502Sroot /*
14507502Sroot  * Rubout one character from the rawq of tp
14517502Sroot  * as cleanly as possible.
14527502Sroot  */
14537502Sroot ttyrub(c, tp)
14547625Ssam 	register c;
14557625Ssam 	register struct tty *tp;
14567502Sroot {
14577502Sroot 	register char *cp;
14587502Sroot 	register int savecol;
14597502Sroot 	int s;
14607502Sroot 	char *nextc();
14617502Sroot 
14629578Ssam 	if ((tp->t_flags&ECHO) == 0)
14637502Sroot 		return;
14649578Ssam 	tp->t_flags &= ~FLUSHO;
14657502Sroot 	c &= 0377;
14669578Ssam 	if (tp->t_flags&CRTBS) {
14677502Sroot 		if (tp->t_rocount == 0) {
14687502Sroot 			/*
14697502Sroot 			 * Screwed by ttwrite; retype
14707502Sroot 			 */
14717502Sroot 			ttyretype(tp);
14727502Sroot 			return;
14737502Sroot 		}
14749578Ssam 		if (c == ('\t'|0200) || c == ('\n'|0200))
14757502Sroot 			ttyrubo(tp, 2);
14769578Ssam 		else switch (partab[c&=0177]&0177) {
14777502Sroot 
14787502Sroot 		case ORDINARY:
14797502Sroot 			if (tp->t_flags&LCASE && c >= 'A' && c <= 'Z')
14807502Sroot 				ttyrubo(tp, 2);
14817502Sroot 			else
14827502Sroot 				ttyrubo(tp, 1);
14837502Sroot 			break;
14847502Sroot 
14857502Sroot 		case VTAB:
14867502Sroot 		case BACKSPACE:
14877502Sroot 		case CONTROL:
14887502Sroot 		case RETURN:
14899578Ssam 			if (tp->t_flags&CTLECH)
14907502Sroot 				ttyrubo(tp, 2);
14917502Sroot 			break;
14927502Sroot 
14937502Sroot 		case TAB:
14947502Sroot 			if (tp->t_rocount < tp->t_rawq.c_cc) {
14957502Sroot 				ttyretype(tp);
14967502Sroot 				return;
14977502Sroot 			}
149817545Skarels 			s = spltty();
14997502Sroot 			savecol = tp->t_col;
15009578Ssam 			tp->t_state |= TS_CNTTB;
15019578Ssam 			tp->t_flags |= FLUSHO;
15027502Sroot 			tp->t_col = tp->t_rocol;
15039578Ssam 			cp = tp->t_rawq.c_cf;
15049578Ssam 			for (; cp; cp = nextc(&tp->t_rawq, cp))
15057502Sroot 				ttyecho(*cp, tp);
15069578Ssam 			tp->t_flags &= ~FLUSHO;
15079578Ssam 			tp->t_state &= ~TS_CNTTB;
15087502Sroot 			splx(s);
15097502Sroot 			/*
15107502Sroot 			 * savecol will now be length of the tab
15117502Sroot 			 */
15127502Sroot 			savecol -= tp->t_col;
15137502Sroot 			tp->t_col += savecol;
15147502Sroot 			if (savecol > 8)
15157502Sroot 				savecol = 8;		/* overflow screw */
15167502Sroot 			while (--savecol >= 0)
15177502Sroot 				(void) ttyoutput('\b', tp);
15187502Sroot 			break;
15197502Sroot 
15207502Sroot 		default:
15217502Sroot 			panic("ttyrub");
15227502Sroot 		}
15239578Ssam 	} else if (tp->t_flags&PRTERA) {
15249578Ssam 		if ((tp->t_state&TS_ERASE) == 0) {
15257502Sroot 			(void) ttyoutput('\\', tp);
15269578Ssam 			tp->t_state |= TS_ERASE;
15277502Sroot 		}
15287502Sroot 		ttyecho(c, tp);
15297502Sroot 	} else
15307502Sroot 		ttyecho(tp->t_erase, tp);
15317502Sroot 	tp->t_rocount--;
15327502Sroot }
15337502Sroot 
15347502Sroot /*
15357502Sroot  * Crt back over cnt chars perhaps
15367502Sroot  * erasing them.
15377502Sroot  */
15387502Sroot ttyrubo(tp, cnt)
15397625Ssam 	register struct tty *tp;
15407625Ssam 	int cnt;
15417502Sroot {
15429578Ssam 	register char *rubostring = tp->t_flags&CRTERA ? "\b \b" : "\b";
15437502Sroot 
15447502Sroot 	while (--cnt >= 0)
15459578Ssam 		ttyout(rubostring, tp);
15467502Sroot }
15477502Sroot 
15487502Sroot /*
15497502Sroot  * Reprint the rawq line.
15507502Sroot  * We assume c_cc has already been checked.
15517502Sroot  */
15527502Sroot ttyretype(tp)
15537625Ssam 	register struct tty *tp;
15547502Sroot {
15557502Sroot 	register char *cp;
15567502Sroot 	char *nextc();
15577502Sroot 	int s;
15587502Sroot 
15599578Ssam 	if (tp->t_rprntc != 0377)
15609578Ssam 		ttyecho(tp->t_rprntc, tp);
15617502Sroot 	(void) ttyoutput('\n', tp);
156217545Skarels 	s = spltty();
15637502Sroot 	for (cp = tp->t_canq.c_cf; cp; cp = nextc(&tp->t_canq, cp))
15647502Sroot 		ttyecho(*cp, tp);
15657502Sroot 	for (cp = tp->t_rawq.c_cf; cp; cp = nextc(&tp->t_rawq, cp))
15667502Sroot 		ttyecho(*cp, tp);
15679578Ssam 	tp->t_state &= ~TS_ERASE;
15687502Sroot 	splx(s);
15697502Sroot 	tp->t_rocount = tp->t_rawq.c_cc;
15707502Sroot 	tp->t_rocol = 0;
15717502Sroot }
15727502Sroot 
15737502Sroot /*
15747502Sroot  * Echo a typed character to the terminal
15757502Sroot  */
15767502Sroot ttyecho(c, tp)
15777625Ssam 	register c;
15787625Ssam 	register struct tty *tp;
15797502Sroot {
15807502Sroot 
15819578Ssam 	if ((tp->t_state&TS_CNTTB) == 0)
15829578Ssam 		tp->t_flags &= ~FLUSHO;
15837502Sroot 	if ((tp->t_flags&ECHO) == 0)
15847502Sroot 		return;
15857502Sroot 	c &= 0377;
15867502Sroot 	if (tp->t_flags&RAW) {
15877502Sroot 		(void) ttyoutput(c, tp);
15887502Sroot 		return;
15897502Sroot 	}
15907502Sroot 	if (c == '\r' && tp->t_flags&CRMOD)
15917502Sroot 		c = '\n';
15929578Ssam 	if (tp->t_flags&CTLECH) {
15937502Sroot 		if ((c&0177) <= 037 && c!='\t' && c!='\n' || (c&0177)==0177) {
15947502Sroot 			(void) ttyoutput('^', tp);
15957502Sroot 			c &= 0177;
15967502Sroot 			if (c == 0177)
15977502Sroot 				c = '?';
15987502Sroot 			else if (tp->t_flags&LCASE)
15997502Sroot 				c += 'a' - 1;
16007502Sroot 			else
16017502Sroot 				c += 'A' - 1;
16027502Sroot 		}
16037502Sroot 	}
16049578Ssam 	(void) ttyoutput(c&0177, tp);
16057502Sroot }
16067502Sroot 
16077502Sroot /*
16087502Sroot  * Is c a break char for tp?
16097502Sroot  */
16107502Sroot ttbreakc(c, tp)
16117625Ssam 	register c;
16127625Ssam 	register struct tty *tp;
16137502Sroot {
16149578Ssam 	return (c == '\n' || c == tp->t_eofc || c == tp->t_brkc ||
16157502Sroot 		c == '\r' && (tp->t_flags&CRMOD));
16167502Sroot }
16177502Sroot 
16187502Sroot /*
16197502Sroot  * send string cp to tp
16207502Sroot  */
16217502Sroot ttyout(cp, tp)
16227625Ssam 	register char *cp;
16237625Ssam 	register struct tty *tp;
16247502Sroot {
16257502Sroot 	register char c;
16267502Sroot 
16277502Sroot 	while (c = *cp++)
16287502Sroot 		(void) ttyoutput(c, tp);
16297502Sroot }
16307502Sroot 
16317502Sroot ttwakeup(tp)
16327502Sroot 	struct tty *tp;
16337502Sroot {
16347502Sroot 
16357502Sroot 	if (tp->t_rsel) {
16367502Sroot 		selwakeup(tp->t_rsel, tp->t_state&TS_RCOLL);
16377502Sroot 		tp->t_state &= ~TS_RCOLL;
16387502Sroot 		tp->t_rsel = 0;
16397502Sroot 	}
164012752Ssam 	if (tp->t_state & TS_ASYNC)
164112752Ssam 		gsignal(tp->t_pgrp, SIGIO);
16427502Sroot 	wakeup((caddr_t)&tp->t_rawq);
16437502Sroot }
1644