xref: /csrg-svn/sys/kern/tty.c (revision 9859)
1*9859Ssam /*	tty.c	4.38	82/12/19	*/
239Sbill 
39760Ssam #include "../machine/reg.h"
49760Ssam 
539Sbill #include "../h/param.h"
639Sbill #include "../h/systm.h"
739Sbill #include "../h/dir.h"
839Sbill #include "../h/user.h"
99578Ssam #include "../h/ioctl.h"
1039Sbill #include "../h/tty.h"
1139Sbill #include "../h/proc.h"
1239Sbill #include "../h/inode.h"
1339Sbill #include "../h/file.h"
1439Sbill #include "../h/conf.h"
1539Sbill #include "../h/buf.h"
16340Sbill #include "../h/dk.h"
177722Swnj #include "../h/uio.h"
188154Sroot #include "../h/kernel.h"
1939Sbill 
207436Skre /*
217436Skre  * Table giving parity for characters and indicating
227436Skre  * character classes to tty driver.  In particular,
237436Skre  * if the low 6 bits are 0, then the character needs
247436Skre  * no special processing on output.
257436Skre  */
2639Sbill 
277436Skre char partab[] = {
287436Skre 	0001,0201,0201,0001,0201,0001,0001,0201,
297436Skre 	0202,0004,0003,0201,0005,0206,0201,0001,
307436Skre 	0201,0001,0001,0201,0001,0201,0201,0001,
317436Skre 	0001,0201,0201,0001,0201,0001,0001,0201,
327436Skre 	0200,0000,0000,0200,0000,0200,0200,0000,
337436Skre 	0000,0200,0200,0000,0200,0000,0000,0200,
347436Skre 	0000,0200,0200,0000,0200,0000,0000,0200,
357436Skre 	0200,0000,0000,0200,0000,0200,0200,0000,
367436Skre 	0200,0000,0000,0200,0000,0200,0200,0000,
377436Skre 	0000,0200,0200,0000,0200,0000,0000,0200,
387436Skre 	0000,0200,0200,0000,0200,0000,0000,0200,
397436Skre 	0200,0000,0000,0200,0000,0200,0200,0000,
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,0201,
447436Skre 
457436Skre 	/*
467436Skre 	 * 7 bit ascii ends with the last character above,
477436Skre 	 * but we contine through all 256 codes for the sake
487436Skre 	 * of the tty output routines which use special vax
497436Skre 	 * instructions which need a 256 character trt table.
507436Skre 	 */
517436Skre 
527436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
537436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
547436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
557436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
567436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
577436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
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 };
697436Skre 
70146Sbill /*
7139Sbill  * Input mapping table-- if an entry is non-zero, when the
7239Sbill  * corresponding character is typed preceded by "\" the escape
7339Sbill  * sequence is replaced by the table value.  Mostly used for
7439Sbill  * upper-case only terminals.
7539Sbill  */
7639Sbill char	maptab[] ={
7739Sbill 	000,000,000,000,000,000,000,000,
7839Sbill 	000,000,000,000,000,000,000,000,
7939Sbill 	000,000,000,000,000,000,000,000,
8039Sbill 	000,000,000,000,000,000,000,000,
8139Sbill 	000,'|',000,000,000,000,000,'`',
8239Sbill 	'{','}',000,000,000,000,000,000,
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,000,000,
8839Sbill 	000,000,000,000,000,000,'~',000,
8939Sbill 	000,'A','B','C','D','E','F','G',
9039Sbill 	'H','I','J','K','L','M','N','O',
9139Sbill 	'P','Q','R','S','T','U','V','W',
9239Sbill 	'X','Y','Z',000,000,000,000,000,
9339Sbill };
9439Sbill 
95925Sbill short	tthiwat[16] =
968954Sroot    { 100,100,100,100,100,100,100,200,200,400,400,400,650,650,1300,2000 };
97925Sbill short	ttlowat[16] =
98925Sbill    {  30, 30, 30, 30, 30, 30, 30, 50, 50,120,120,120,125,125,125,125 };
99925Sbill 
1009578Ssam struct	ttychars ttydefaults = {
1019578Ssam 	CERASE,	CKILL,	CINTR,	CQUIT,	CSTART,	CSTOP,	CEOF,
1029578Ssam 	CBRK,	CSUSP,	CDSUSP, CRPRNT, CFLUSH, CWERASE,CLNEXT
1039578Ssam };
10439Sbill 
10539Sbill ttychars(tp)
1069578Ssam 	struct tty *tp;
10739Sbill {
108174Sbill 
1099578Ssam 	tp->t_chars = ttydefaults;
11039Sbill }
11139Sbill 
11239Sbill /*
113903Sbill  * Wait for output to drain, then flush input waiting.
11439Sbill  */
115903Sbill wflushtty(tp)
1165408Swnj 	register struct tty *tp;
11739Sbill {
118*9859Ssam 	int s;
11939Sbill 
120*9859Ssam 	s = spl5();
1215622Swnj 	while (tp->t_outq.c_cc && tp->t_state&TS_CARR_ON
1225622Swnj 	    && tp->t_oproc) {		/* kludge for pty */
123903Sbill 		(*tp->t_oproc)(tp);
1245408Swnj 		tp->t_state |= TS_ASLEEP;
125903Sbill 		sleep((caddr_t)&tp->t_outq, TTOPRI);
126903Sbill 	}
1275426Swnj 	flushtty(tp, FREAD);
128*9859Ssam 	splx(s);
12939Sbill }
13039Sbill 
13139Sbill /*
1329578Ssam  * Flush all TTY queues
13339Sbill  */
134903Sbill flushtty(tp, rw)
1357625Ssam 	register struct tty *tp;
13639Sbill {
137903Sbill 	register s;
138903Sbill 
139903Sbill 	s = spl6();
140903Sbill 	if (rw & FREAD) {
141903Sbill 		while (getc(&tp->t_canq) >= 0)
142903Sbill 			;
143903Sbill 		wakeup((caddr_t)&tp->t_rawq);
144903Sbill 	}
145903Sbill 	if (rw & FWRITE) {
146903Sbill 		wakeup((caddr_t)&tp->t_outq);
1475408Swnj 		tp->t_state &= ~TS_TTSTOP;
1485426Swnj 		(*cdevsw[major(tp->t_dev)].d_stop)(tp, rw);
149903Sbill 		while (getc(&tp->t_outq) >= 0)
150903Sbill 			;
151903Sbill 	}
152903Sbill 	if (rw & FREAD) {
153903Sbill 		while (getc(&tp->t_rawq) >= 0)
154903Sbill 			;
155903Sbill 		tp->t_delct = 0;
1569578Ssam 		tp->t_rocount = 0;
157903Sbill 		tp->t_rocol = 0;
1589578Ssam 		tp->t_state &= ~TS_LOCAL;
159903Sbill 	}
160903Sbill 	splx(s);
16139Sbill }
16239Sbill 
163903Sbill /*
164903Sbill  * Send stop character on input overflow.
165903Sbill  */
166903Sbill ttyblock(tp)
1677625Ssam 	register struct tty *tp;
16839Sbill {
169903Sbill 	register x;
1709578Ssam 
171903Sbill 	x = tp->t_rawq.c_cc + tp->t_canq.c_cc;
172903Sbill 	if (tp->t_rawq.c_cc > TTYHOG) {
173903Sbill 		flushtty(tp, FREAD|FWRITE);
1745408Swnj 		tp->t_state &= ~TS_TBLOCK;
175903Sbill 	}
1769578Ssam 	if (x >= TTYHOG/2 && putc(tp->t_stopc, &tp->t_outq) == 0) {
1779578Ssam 		tp->t_state |= TS_TBLOCK;
1789578Ssam 		ttstart(tp);
179903Sbill 	}
18039Sbill }
18139Sbill 
18239Sbill /*
183903Sbill  * Restart typewriter output following a delay
184903Sbill  * timeout.
185903Sbill  * The name of the routine is passed to the timeout
186903Sbill  * subroutine and it is called during a clock interrupt.
187121Sbill  */
188903Sbill ttrstrt(tp)
1897625Ssam 	register struct tty *tp;
190121Sbill {
191121Sbill 
1929578Ssam 	if (tp == 0)
1939578Ssam 		panic("ttrstrt");
1945408Swnj 	tp->t_state &= ~TS_TIMEOUT;
195903Sbill 	ttstart(tp);
196121Sbill }
197121Sbill 
198121Sbill /*
199903Sbill  * Start output on the typewriter. It is used from the top half
200903Sbill  * after some characters have been put on the output queue,
201903Sbill  * from the interrupt routine to transmit the next
202903Sbill  * character, and after a timeout has finished.
20339Sbill  */
204903Sbill ttstart(tp)
2057625Ssam 	register struct tty *tp;
20639Sbill {
207903Sbill 	register s;
20839Sbill 
209903Sbill 	s = spl5();
2109578Ssam 	if ((tp->t_state & (TS_TIMEOUT|TS_TTSTOP|TS_BUSY)) == 0 &&
2115622Swnj 	    tp->t_oproc)		/* kludge for pty */
212903Sbill 		(*tp->t_oproc)(tp);
213903Sbill 	splx(s);
21439Sbill }
21539Sbill 
21639Sbill /*
217903Sbill  * Common code for tty ioctls.
21839Sbill  */
2191780Sbill /*ARGSUSED*/
2207625Ssam ttioctl(tp, com, data, flag)
2217625Ssam 	register struct tty *tp;
2227625Ssam 	caddr_t data;
22339Sbill {
2248520Sroot 	int dev = tp->t_dev;
22539Sbill 	extern int nldisp;
2268556Sroot 	int s;
22739Sbill 
228903Sbill 	/*
229903Sbill 	 * If the ioctl involves modification,
230903Sbill 	 * insist on being able to write the device,
231903Sbill 	 * and hang if in the background.
232903Sbill 	 */
2337625Ssam 	switch (com) {
23439Sbill 
235915Sbill 	case TIOCSETD:
236915Sbill 	case TIOCSETP:
237915Sbill 	case TIOCSETN:
238903Sbill 	case TIOCFLUSH:
239903Sbill 	case TIOCSETC:
240903Sbill 	case TIOCSLTC:
241903Sbill 	case TIOCSPGRP:
242903Sbill 	case TIOCLBIS:
243903Sbill 	case TIOCLBIC:
244903Sbill 	case TIOCLSET:
2459624Ssam 	case TIOCBIS:
2469624Ssam 	case TIOCBIC:
2479624Ssam 	case TIOCSET:
2489325Ssam 	case TIOCSTI:
249903Sbill 		while (tp->t_line == NTTYDISC &&
250903Sbill 		   u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp &&
251903Sbill 		   (u.u_procp->p_flag&SVFORK) == 0 &&
252903Sbill 		   u.u_signal[SIGTTOU] != SIG_IGN &&
2538556Sroot 		   u.u_signal[SIGTTOU] != SIG_HOLD) {
254903Sbill 			gsignal(u.u_procp->p_pgrp, SIGTTOU);
255903Sbill 			sleep((caddr_t)&lbolt, TTOPRI);
256903Sbill 		}
257903Sbill 		break;
258903Sbill 	}
259903Sbill 
2609578Ssam 	/*
2619578Ssam 	 * Process the ioctl.
2629578Ssam 	 */
2637625Ssam 	switch (com) {
264903Sbill 
2658556Sroot 	/* get discipline number */
26639Sbill 	case TIOCGETD:
2677625Ssam 		*(int *)data = tp->t_line;
26839Sbill 		break;
26939Sbill 
2708556Sroot 	/* set line discipline */
2717625Ssam 	case TIOCSETD: {
2727625Ssam 		register int t = *(int *)data;
2739578Ssam 		int error = 0;
2747625Ssam 
2759578Ssam 		if (t >= nldisp) {
2769578Ssam 			u.u_error = ENXIO;
2779578Ssam 			break;
2789578Ssam 		}
2798556Sroot 		s = spl5();
28039Sbill 		if (tp->t_line)
28139Sbill 			(*linesw[tp->t_line].l_close)(tp);
28239Sbill 		if (t)
2838556Sroot 			error = (*linesw[t].l_open)(dev, tp);
2848556Sroot 		splx(s);
2858556Sroot 		if (error)
2868556Sroot 			return (error);
2878556Sroot 		tp->t_line = t;
28839Sbill 		break;
2897625Ssam 	}
29039Sbill 
2918556Sroot 	/* prevent more opens on channel */
2925614Swnj 	case TIOCEXCL:
2935614Swnj 		tp->t_state |= TS_XCLUDE;
2945614Swnj 		break;
2955614Swnj 
2965614Swnj 	case TIOCNXCL:
2975614Swnj 		tp->t_state &= ~TS_XCLUDE;
2985614Swnj 		break;
2995614Swnj 
3009624Ssam 	case TIOCSET:
3019624Ssam 	case TIOCBIS: {
3029624Ssam 		u_long newflags = *(u_long *)data;
3037625Ssam 
3049624Ssam 		s = spl5();
3059624Ssam 		if (tp->t_flags&RAW || newflags&RAW)
3064484Swnj 			wflushtty(tp);
3079624Ssam 		else if ((tp->t_flags&CBREAK) != (newflags&CBREAK))
3089624Ssam 			if (newflags&CBREAK) {
3099624Ssam 				struct clist tq;
3109624Ssam 
3114484Swnj 				catq(&tp->t_rawq, &tp->t_canq);
3124484Swnj 				tq = tp->t_rawq;
3134484Swnj 				tp->t_rawq = tp->t_canq;
3144484Swnj 				tp->t_canq = tq;
3154484Swnj 			} else {
3169578Ssam 				tp->t_flags |= PENDIN;
3174484Swnj 				ttwakeup(tp);
318174Sbill 			}
3199624Ssam 		if (com == TIOCSET)
3209624Ssam 			tp->t_flags = newflags;
3219624Ssam 		else
3229624Ssam 			tp->t_flags |= newflags;
3239578Ssam 		if (tp->t_flags&RAW) {
3245408Swnj 			tp->t_state &= ~TS_TTSTOP;
3253941Sbugs 			ttstart(tp);
3263941Sbugs 		}
3279624Ssam 		splx(s);
32839Sbill 		break;
3297625Ssam 	}
33039Sbill 
3319624Ssam 	case TIOCBIC: {
3329624Ssam 		u_long newflags = *(long *)data;
3337625Ssam 
3349624Ssam 		if (tp->t_flags&RAW)
3359624Ssam 			wflushtty(tp);
3369624Ssam 		else if ((tp->t_flags&CBREAK) != (CBREAK&~newflags))
3379624Ssam 			if (newflags&CBREAK) {
3389624Ssam 				tp->t_flags |= PENDIN;
3399624Ssam 				ttwakeup(tp);
3409624Ssam 			} else {
3419624Ssam 				struct clist tq;
3429624Ssam 
3439624Ssam 				catq(&tp->t_rawq, &tp->t_canq);
3449624Ssam 				tq = tp->t_rawq;
3459624Ssam 				tp->t_rawq = tp->t_canq;
3469624Ssam 				tp->t_canq = tq;
3479624Ssam 			}
3489624Ssam 		if (tp->t_flags&RAW) {
3499624Ssam 			tp->t_state &= ~TS_TTSTOP;
3509624Ssam 			ttstart(tp);
3519624Ssam 		}
3529624Ssam 		splx(s);
35339Sbill 		break;
3547625Ssam 	}
35539Sbill 
3569624Ssam 	case TIOCGET:
3579624Ssam 		*(long *)data = tp->t_flags;
3589624Ssam 		break;
3599624Ssam 
3609624Ssam 	case TIOCCGET:
3619624Ssam 		bcopy((caddr_t)&tp->t_chars, data, sizeof (struct ttychars));
3629624Ssam 		break;
3639624Ssam 
3649624Ssam 	case TIOCCSET:
3659624Ssam 		bcopy(data, (caddr_t)&tp->t_chars, sizeof (struct ttychars));
3669624Ssam 		break;
3679624Ssam 
3688556Sroot 	/* hang up line on last close */
36939Sbill 	case TIOCHPCL:
3705408Swnj 		tp->t_state |= TS_HUPCLS;
37139Sbill 		break;
37239Sbill 
3733942Sbugs 	case TIOCFLUSH: {
3747625Ssam 		register int flags = *(int *)data;
3757625Ssam 
3767625Ssam 		if (flags == 0)
3773942Sbugs 			flags = FREAD|FWRITE;
3787625Ssam 		else
3797625Ssam 			flags &= FREAD|FWRITE;
3803942Sbugs 		flushtty(tp, flags);
38139Sbill 		break;
3823944Sbugs 	}
38339Sbill 
3848556Sroot 	/* return number of characters immediately available */
3857625Ssam 	case FIONREAD:
3867625Ssam 		*(off_t *)data = ttnread(tp);
387174Sbill 		break;
388174Sbill 
3898589Sroot 	case TIOCSTOP:
3908589Sroot 		s = spl5();
3919578Ssam 		if ((tp->t_state&TS_TTSTOP) == 0) {
3925573Swnj 			tp->t_state |= TS_TTSTOP;
3935573Swnj 			(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
3945573Swnj 		}
3957625Ssam 		splx(s);
3965573Swnj 		break;
3975573Swnj 
3988589Sroot 	case TIOCSTART:
3998589Sroot 		s = spl5();
4009578Ssam 		if ((tp->t_state&TS_TTSTOP) || (tp->t_flags&FLUSHO)) {
4015573Swnj 			tp->t_state &= ~TS_TTSTOP;
4029578Ssam 			tp->t_flags &= ~FLUSHO;
4035573Swnj 			ttstart(tp);
4045573Swnj 		}
4057625Ssam 		splx(s);
4065573Swnj 		break;
4075573Swnj 
4089325Ssam 	/*
4099325Ssam 	 * Simulate typing of a character at the terminal.
4109325Ssam 	 */
4119325Ssam 	case TIOCSTI:
4129325Ssam 		if (u.u_uid && u.u_ttyp != tp)
4139325Ssam 			return (EACCES);
4149578Ssam 		(*linesw[tp->t_line].l_rint)(*(char *)data, tp);
4159325Ssam 		break;
4169325Ssam 
41739Sbill 	default:
4189624Ssam #ifndef NOCOMPAT
4199624Ssam 		return (ottioctl(tp, com, data, flag));
4209624Ssam #else
4218556Sroot 		return (-1);
4229624Ssam #endif
42339Sbill 	}
4248556Sroot 	return (0);
42539Sbill }
4264484Swnj 
4274484Swnj ttnread(tp)
4284484Swnj 	struct tty *tp;
4294484Swnj {
4304484Swnj 	int nread = 0;
4314484Swnj 
4329578Ssam 	if (tp->t_flags & PENDIN)
4334484Swnj 		ttypend(tp);
4344484Swnj 	nread = tp->t_canq.c_cc;
4354484Swnj 	if (tp->t_flags & (RAW|CBREAK))
4364484Swnj 		nread += tp->t_rawq.c_cc;
4374484Swnj 	return (nread);
4384484Swnj }
4394484Swnj 
4405408Swnj ttselect(dev, rw)
4414484Swnj 	dev_t dev;
4425408Swnj 	int rw;
4434484Swnj {
4444484Swnj 	register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)];
4454484Swnj 	int nread;
4465408Swnj 	int s = spl5();
4474484Swnj 
4485408Swnj 	switch (rw) {
4494484Swnj 
4504484Swnj 	case FREAD:
4514484Swnj 		nread = ttnread(tp);
4524484Swnj 		if (nread > 0)
4535408Swnj 			goto win;
4544938Swnj 		if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait)
4555408Swnj 			tp->t_state |= TS_RCOLL;
4564484Swnj 		else
4574484Swnj 			tp->t_rsel = u.u_procp;
4585408Swnj 		break;
4594484Swnj 
4605408Swnj 	case FWRITE:
4615408Swnj 		if (tp->t_outq.c_cc <= TTLOWAT(tp))
4625408Swnj 			goto win;
4635408Swnj 		if (tp->t_wsel && tp->t_wsel->p_wchan == (caddr_t)&selwait)
4645408Swnj 			tp->t_state |= TS_WCOLL;
4655408Swnj 		else
4665408Swnj 			tp->t_wsel = u.u_procp;
4675408Swnj 		break;
4684484Swnj 	}
4695408Swnj 	splx(s);
4705408Swnj 	return (0);
4715408Swnj win:
4725408Swnj 	splx(s);
4735408Swnj 	return (1);
4744484Swnj }
4757436Skre 
4767502Sroot /*
4779578Ssam  * Establish a process group for distribution of
4787502Sroot  * quits and interrupts from the tty.
4797502Sroot  */
4807502Sroot ttyopen(dev, tp)
4817625Ssam 	dev_t dev;
4827625Ssam 	register struct tty *tp;
4837502Sroot {
4847502Sroot 	register struct proc *pp;
4857502Sroot 
4867502Sroot 	pp = u.u_procp;
4877502Sroot 	tp->t_dev = dev;
4887625Ssam 	if (pp->p_pgrp == 0) {
4897502Sroot 		u.u_ttyp = tp;
4907502Sroot 		u.u_ttyd = dev;
4917502Sroot 		if (tp->t_pgrp == 0)
4927502Sroot 			tp->t_pgrp = pp->p_pid;
4937502Sroot 		pp->p_pgrp = tp->t_pgrp;
4947502Sroot 	}
4957502Sroot 	tp->t_state &= ~TS_WOPEN;
4967502Sroot 	tp->t_state |= TS_ISOPEN;
4977502Sroot 	if (tp->t_line != NTTYDISC)
4987502Sroot 		wflushtty(tp);
4998556Sroot 	return (0);
5007502Sroot }
5017502Sroot 
5027502Sroot /*
5037502Sroot  * clean tp on last close
5047502Sroot  */
5057502Sroot ttyclose(tp)
5067625Ssam 	register struct tty *tp;
5077502Sroot {
5087502Sroot 
5097502Sroot 	if (tp->t_line) {
5107502Sroot 		wflushtty(tp);
5117502Sroot 		tp->t_line = 0;
5127502Sroot 		return;
5137502Sroot 	}
5147502Sroot 	tp->t_pgrp = 0;
5157502Sroot 	wflushtty(tp);
5167502Sroot 	tp->t_state = 0;
5177502Sroot }
5187502Sroot 
5197502Sroot /*
5207502Sroot  * reinput pending characters after state switch
5217502Sroot  * call at spl5().
5227502Sroot  */
5237502Sroot ttypend(tp)
5247625Ssam 	register struct tty *tp;
5257502Sroot {
5267502Sroot 	struct clist tq;
5277502Sroot 	register c;
5287502Sroot 
5299578Ssam 	tp->t_flags &= ~PENDIN;
5309578Ssam 	tp->t_state |= TS_TYPEN;
5317502Sroot 	tq = tp->t_rawq;
5327502Sroot 	tp->t_rawq.c_cc = 0;
5337502Sroot 	tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0;
5347502Sroot 	while ((c = getc(&tq)) >= 0)
5357502Sroot 		ttyinput(c, tp);
5369578Ssam 	tp->t_state &= ~TS_TYPEN;
5377502Sroot }
5387502Sroot 
5397502Sroot /*
5409578Ssam  * Place a character on raw TTY input queue,
5419578Ssam  * putting in delimiters and waking up top
5429578Ssam  * half as needed.  Also echo if required.
5439578Ssam  * The arguments are the character and the
5449578Ssam  * appropriate tty structure.
5457502Sroot  */
5467502Sroot ttyinput(c, tp)
5477625Ssam 	register c;
5487625Ssam 	register struct tty *tp;
5497502Sroot {
5509578Ssam 	register int t_flags = tp->t_flags;
5517502Sroot 	int i;
5527502Sroot 
5539578Ssam 	/*
5549578Ssam 	 * If input is pending take it first.
5559578Ssam 	 */
5569578Ssam 	if (t_flags&PENDIN)
5577502Sroot 		ttypend(tp);
5587502Sroot 	tk_nin++;
5597502Sroot 	c &= 0377;
5609578Ssam 
5619578Ssam 	/*
5629578Ssam 	 * In tandem mode, check high water mark.
5639578Ssam 	 */
5647502Sroot 	if (t_flags&TANDEM)
5657502Sroot 		ttyblock(tp);
5669578Ssam 
5679578Ssam 	if (t_flags&RAW) {
5689578Ssam 		/*
5699578Ssam 		 * Raw mode, just put character
5709578Ssam 		 * in input q w/o interpretation.
5719578Ssam 		 */
5729578Ssam 		if (tp->t_rawq.c_cc > TTYHOG)
5739578Ssam 			flushtty(tp, FREAD|FWRITE);
5749578Ssam 		else {
5759578Ssam 			if (putc(c, &tp->t_rawq) >= 0)
5769578Ssam 				ttwakeup(tp);
5779578Ssam 			ttyecho(c, tp);
5787502Sroot 		}
5799578Ssam 		goto endcase;
5809578Ssam 	}
5819578Ssam 
5829578Ssam 	/*
5839578Ssam 	 * Ignore any high bit added during
5849578Ssam 	 * previous ttyinput processing.
5859578Ssam 	 */
5869578Ssam 	if ((tp->t_state&TS_TYPEN) == 0)
5879578Ssam 		c &= 0177;
5889578Ssam 	/*
5899578Ssam 	 * Check for literal nexting very first
5909578Ssam 	 */
5919578Ssam 	if (tp->t_state&TS_LNCH) {
5929578Ssam 		c |= 0200;
5939578Ssam 		tp->t_state &= ~TS_LNCH;
5949578Ssam 	}
5959578Ssam 
5969578Ssam 	/*
5979578Ssam 	 * Scan for special characters.  This code
5989578Ssam 	 * is really just a big case statement with
5999578Ssam 	 * non-constant cases.  The bottom of the
6009578Ssam 	 * case statement is labeled ``endcase'', so goto
6019578Ssam 	 * it after a case match, or similar.
6029578Ssam 	 */
6039578Ssam 	if (tp->t_line == NTTYDISC) {
6049578Ssam 		if (c == tp->t_lnextc) {
6057502Sroot 			if (tp->t_flags&ECHO)
6067502Sroot 				ttyout("^\b", tp);
6079578Ssam 			tp->t_state |= TS_LNCH;
6089578Ssam 			goto endcase;
6099578Ssam 		}
6109578Ssam 		if (c == tp->t_flushc) {
6119578Ssam 			if (tp->t_flags&FLUSHO)
6129578Ssam 				tp->t_flags &= ~FLUSHO;
6137502Sroot 			else {
6147502Sroot 				flushtty(tp, FWRITE);
6157502Sroot 				ttyecho(c, tp);
6169578Ssam 				if (tp->t_rawq.c_cc + tp->t_canq.c_cc)
6177502Sroot 					ttyretype(tp);
6189578Ssam 				tp->t_flags |= FLUSHO;
6197502Sroot 			}
6209578Ssam 			goto startoutput;
6219578Ssam 		}
6229578Ssam 		if (c == tp->t_suspc) {
6239578Ssam 			if ((tp->t_flags&NOFLSH) == 0)
6249578Ssam 				flushtty(tp, FREAD);
6259578Ssam 			ttyecho(c, tp);
6269578Ssam 			gsignal(tp->t_pgrp, SIGTSTP);
6279578Ssam 			goto endcase;
6289578Ssam 		}
6299578Ssam 	}
6309578Ssam 
6319578Ssam 	/*
6329578Ssam 	 * Handle start/stop characters.
6339578Ssam 	 */
6349578Ssam 	if (c == tp->t_stopc) {
6359578Ssam 		if ((tp->t_state&TS_TTSTOP) == 0) {
6369578Ssam 			tp->t_state |= TS_TTSTOP;
6379578Ssam 			(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
6387502Sroot 			return;
6399578Ssam 		}
6409578Ssam 		if (c != tp->t_startc)
6419578Ssam 			return;
6429578Ssam 		goto endcase;
6439578Ssam 	}
6449578Ssam 	if (c == tp->t_startc)
6459578Ssam 		goto restartoutput;
6469578Ssam 
6479578Ssam 	/*
6489578Ssam 	 * Look for interrupt/quit chars.
6499578Ssam 	 */
6509578Ssam 	if (c == tp->t_intrc || c == tp->t_quitc) {
6519578Ssam 		if ((tp->t_flags&NOFLSH) == 0)
6529578Ssam 			flushtty(tp, FREAD|FWRITE);
6539578Ssam 		ttyecho(c, tp);
6549578Ssam 		gsignal(tp->t_pgrp, c == tp->t_intrc ? SIGINT : SIGQUIT);
6559578Ssam 		goto endcase;
6569578Ssam 	}
6579578Ssam 
6589578Ssam 	/*
6599578Ssam 	 * Cbreak mode, don't process line editing
6609578Ssam 	 * characters; check high water mark for wakeup.
6619578Ssam 	 */
6629578Ssam 	if (t_flags&CBREAK) {
6639578Ssam 		if (tp->t_rawq.c_cc > TTYHOG) {
6647502Sroot 			if (tp->t_outq.c_cc < TTHIWAT(tp) &&
6657502Sroot 			    tp->t_line == NTTYDISC)
6667502Sroot 				(void) ttyoutput(CTRL(g), tp);
6677502Sroot 		} else if (putc(c, &tp->t_rawq) >= 0) {
6687502Sroot 			ttwakeup(tp);
6697502Sroot 			ttyecho(c, tp);
6707502Sroot 		}
6719578Ssam 		goto endcase;
6729578Ssam 	}
6739578Ssam 
6749578Ssam 	/*
6759578Ssam 	 * From here on down cooked mode character
6769578Ssam 	 * processing takes place.
6779578Ssam 	 */
6789578Ssam 	if ((tp->t_state&TS_QUOT) &&
6799578Ssam 	    (c == tp->t_erase || c == tp->t_kill)) {
6809578Ssam 		ttyrub(unputc(&tp->t_rawq), tp);
6819578Ssam 		c |= 0200;
6829578Ssam 	}
6839578Ssam 	if (c == tp->t_erase) {
6849578Ssam 		if (tp->t_rawq.c_cc)
6859578Ssam 			ttyrub(unputc(&tp->t_rawq), tp);
6869578Ssam 		goto endcase;
6879578Ssam 	}
6889578Ssam 	if (c == tp->t_kill) {
6899578Ssam 		if (tp->t_flags&CRTKIL &&
6909578Ssam 		    tp->t_rawq.c_cc == tp->t_rocount) {
6919578Ssam 			while (tp->t_rawq.c_cc)
6929578Ssam 				ttyrub(unputc(&tp->t_rawq), tp);
6939578Ssam 		} else {
6949578Ssam 			ttyecho(c, tp);
6959578Ssam 			ttyecho('\n', tp);
6969578Ssam 			while (getc(&tp->t_rawq) > 0)
6979578Ssam 				;
6989578Ssam 			tp->t_rocount = 0;
6999578Ssam 		}
7009578Ssam 		tp->t_state &= ~TS_LOCAL;
7019578Ssam 		goto endcase;
7029578Ssam 	}
7039578Ssam 
7049578Ssam 	/*
7059578Ssam 	 * New line discipline,
7069578Ssam 	 * check word erase/reprint line.
7079578Ssam 	 */
7089578Ssam 	if (tp->t_line == NTTYDISC) {
7099578Ssam 		if (c == tp->t_werasc) {
7109578Ssam 			if (tp->t_rawq.c_cc == 0)
7119578Ssam 				goto endcase;
7129578Ssam 			do {
7139578Ssam 				c = unputc(&tp->t_rawq);
7149578Ssam 				if (c != ' ' && c != '\t')
7159578Ssam 					goto erasenb;
7169578Ssam 				ttyrub(c, tp);
7179578Ssam 			} while (tp->t_rawq.c_cc);
7189578Ssam 			goto endcase;
7199578Ssam 	erasenb:
7209578Ssam 			do {
7219578Ssam 				ttyrub(c, tp);
7229578Ssam 				if (tp->t_rawq.c_cc == 0)
7239578Ssam 					goto endcase;
7249578Ssam 				c = unputc(&tp->t_rawq);
7259578Ssam 			} while (c != ' ' && c != '\t');
7269578Ssam 			(void) putc(c, &tp->t_rawq);
7279578Ssam 			goto endcase;
7289578Ssam 		}
7299578Ssam 		if (c == tp->t_rprntc) {
7309578Ssam 			ttyretype(tp);
7319578Ssam 			goto endcase;
7329578Ssam 		}
7339578Ssam 	}
7349578Ssam 
7359578Ssam 	/*
7369578Ssam 	 * Check for input buffer overflow
7379578Ssam 	 */
7389578Ssam 	if (tp->t_rawq.c_cc+tp->t_canq.c_cc >= TTYHOG)
7399578Ssam 		goto endcase;
7409578Ssam 
7419578Ssam 	/*
7429578Ssam 	 * Put data char in q for user and
7439578Ssam 	 * wakeup on seeing a line delimiter.
7449578Ssam 	 */
7459578Ssam 	if (putc(c, &tp->t_rawq) >= 0) {
7469578Ssam 		if (tp->t_rawq.c_cc + tp->t_canq.c_cc == TTYHOG
7479578Ssam 		    && tp->t_line == NTTYDISC)
7489578Ssam 			(void) ttyoutput(CTRL(g), tp);
7499578Ssam 		if (ttbreakc(c, tp)) {
7509578Ssam 			tp->t_rocount = 0;
7519578Ssam 			catq(&tp->t_rawq, &tp->t_canq);
7527502Sroot 			ttwakeup(tp);
7539578Ssam 		} else if (tp->t_rocount++ == 0)
7549578Ssam 			tp->t_rocol = tp->t_col;
7559578Ssam 		tp->t_state &= ~TS_QUOT;
7569578Ssam 		if (c == '\\')
7579578Ssam 			tp->t_state |= TS_QUOT;
7589578Ssam 		if (tp->t_state&TS_ERASE) {
7599578Ssam 			tp->t_state &= ~TS_ERASE;
7609578Ssam 			(void) ttyoutput('/', tp);
7619578Ssam 		}
7629578Ssam 		i = tp->t_col;
7637502Sroot 		ttyecho(c, tp);
7649578Ssam 		if (c == tp->t_eofc && tp->t_flags&ECHO) {
7659578Ssam 			i = MIN(2, tp->t_col - i);
7669578Ssam 			while (i > 0) {
7679578Ssam 				(void) ttyoutput('\b', tp);
7689578Ssam 				i--;
7699578Ssam 			}
7709578Ssam 		}
7717502Sroot 	}
7729578Ssam 
7739578Ssam endcase:
7749578Ssam 	/*
7759578Ssam 	 * If DEC-style start/stop is enabled don't restart
7769578Ssam 	 * output until seeing the start character.
7779578Ssam 	 */
7789578Ssam 	if (tp->t_flags&DECCTQ && tp->t_state&TS_TTSTOP &&
7799578Ssam 	    tp->t_startc != tp->t_stopc)
7807502Sroot 		return;
7819578Ssam 
7829578Ssam restartoutput:
7837502Sroot 	tp->t_state &= ~TS_TTSTOP;
7849578Ssam 	tp->t_flags &= ~FLUSHO;
7859578Ssam 
7869578Ssam startoutput:
7877502Sroot 	ttstart(tp);
7887502Sroot }
7897502Sroot 
7907502Sroot /*
7919578Ssam  * Put character on TTY output queue, adding delays,
7927502Sroot  * expanding tabs, and handling the CR/NL bit.
7939578Ssam  * This is called both from the top half for output,
7949578Ssam  * and from interrupt level for echoing.
7957502Sroot  * The arguments are the character and the tty structure.
7967502Sroot  * Returns < 0 if putc succeeds, otherwise returns char to resend
7977502Sroot  * Must be recursive.
7987502Sroot  */
7997502Sroot ttyoutput(c, tp)
8007502Sroot 	register c;
8017502Sroot 	register struct tty *tp;
8027502Sroot {
8037502Sroot 	register char *colp;
8047502Sroot 	register ctype;
8057502Sroot 
8069578Ssam 	if (tp->t_flags & (RAW|LITOUT)) {
8079578Ssam 		if (tp->t_flags&FLUSHO)
8087502Sroot 			return (-1);
8097502Sroot 		if (putc(c, &tp->t_outq))
8107625Ssam 			return (c);
8117502Sroot 		tk_nout++;
8127502Sroot 		return (-1);
8137502Sroot 	}
8149578Ssam 
8157502Sroot 	/*
8169578Ssam 	 * Ignore EOT in normal mode to avoid
8179578Ssam 	 * hanging up certain terminals.
8187502Sroot 	 */
8197502Sroot 	c &= 0177;
8209578Ssam 	if (c == CEOT && (tp->t_flags&CBREAK) == 0)
8217502Sroot 		return (-1);
8227502Sroot 	/*
8237502Sroot 	 * Turn tabs to spaces as required
8247502Sroot 	 */
8259578Ssam 	if (c == '\t' && (tp->t_flags&TBDELAY) == XTABS) {
8267502Sroot 		register int s;
8277502Sroot 
8287502Sroot 		c = 8 - (tp->t_col&7);
8299578Ssam 		if ((tp->t_flags&FLUSHO) == 0) {
8307502Sroot 			s = spl5();		/* don't interrupt tabs */
8317502Sroot 			c -= b_to_q("        ", c, &tp->t_outq);
8327502Sroot 			tk_nout += c;
8337502Sroot 			splx(s);
8347502Sroot 		}
8357502Sroot 		tp->t_col += c;
8367502Sroot 		return (c ? -1 : '\t');
8377502Sroot 	}
8387502Sroot 	tk_nout++;
8397502Sroot 	/*
8407502Sroot 	 * for upper-case-only terminals,
8417502Sroot 	 * generate escapes.
8427502Sroot 	 */
8437502Sroot 	if (tp->t_flags&LCASE) {
8447502Sroot 		colp = "({)}!|^~'`";
8457625Ssam 		while (*colp++)
8467625Ssam 			if (c == *colp++) {
8477502Sroot 				if (ttyoutput('\\', tp) >= 0)
8487502Sroot 					return (c);
8497502Sroot 				c = colp[-2];
8507502Sroot 				break;
8517502Sroot 			}
8529578Ssam 		if ('A' <= c && c <= 'Z') {
8537502Sroot 			if (ttyoutput('\\', tp) >= 0)
8547502Sroot 				return (c);
8559578Ssam 		} else if ('a' <= c && c <= 'z')
8567502Sroot 			c += 'A' - 'a';
8577502Sroot 	}
8589578Ssam 
8597502Sroot 	/*
8607502Sroot 	 * turn <nl> to <cr><lf> if desired.
8617502Sroot 	 */
8629578Ssam 	if (c == '\n' && tp->t_flags&CRMOD)
8637502Sroot 		if (ttyoutput('\r', tp) >= 0)
8647502Sroot 			return (c);
8659578Ssam 	if (c == '~' && tp->t_flags&TILDE)
8667502Sroot 		c = '`';
8679578Ssam 	if ((tp->t_flags&FLUSHO) == 0 && putc(c, &tp->t_outq))
8687502Sroot 		return (c);
8697502Sroot 	/*
8707502Sroot 	 * Calculate delays.
8717502Sroot 	 * The numbers here represent clock ticks
8727502Sroot 	 * and are not necessarily optimal for all terminals.
8737502Sroot 	 * The delays are indicated by characters above 0200.
8747502Sroot 	 * In raw mode there are no delays and the
8757502Sroot 	 * transmission path is 8 bits wide.
8769578Ssam 	 *
8779578Ssam 	 * SHOULD JUST ALLOW USER TO SPECIFY DELAYS
8787502Sroot 	 */
8797502Sroot 	colp = &tp->t_col;
8807502Sroot 	ctype = partab[c];
8817502Sroot 	c = 0;
8827502Sroot 	switch (ctype&077) {
8837502Sroot 
8847502Sroot 	case ORDINARY:
8857502Sroot 		(*colp)++;
8867502Sroot 
8877502Sroot 	case CONTROL:
8887502Sroot 		break;
8897502Sroot 
8907502Sroot 	case BACKSPACE:
8917502Sroot 		if (*colp)
8927502Sroot 			(*colp)--;
8937502Sroot 		break;
8947502Sroot 
8957502Sroot 	case NEWLINE:
8967502Sroot 		ctype = (tp->t_flags >> 8) & 03;
8977625Ssam 		if (ctype == 1) { /* tty 37 */
8987502Sroot 			if (*colp)
8997502Sroot 				c = max(((unsigned)*colp>>4) + 3, (unsigned)6);
9009578Ssam 		} else if (ctype == 2) /* vt05 */
9017502Sroot 			c = 6;
9027502Sroot 		*colp = 0;
9037502Sroot 		break;
9047502Sroot 
9057502Sroot 	case TAB:
9067502Sroot 		ctype = (tp->t_flags >> 10) & 03;
9077625Ssam 		if (ctype == 1) { /* tty 37 */
9087502Sroot 			c = 1 - (*colp | ~07);
9097625Ssam 			if (c < 5)
9107502Sroot 				c = 0;
9117502Sroot 		}
9127502Sroot 		*colp |= 07;
9137502Sroot 		(*colp)++;
9147502Sroot 		break;
9157502Sroot 
9167502Sroot 	case VTAB:
9179578Ssam 		if (tp->t_flags&VTDELAY) /* tty 37 */
9187502Sroot 			c = 0177;
9197502Sroot 		break;
9207502Sroot 
9217502Sroot 	case RETURN:
9227502Sroot 		ctype = (tp->t_flags >> 12) & 03;
9239578Ssam 		if (ctype == 1) /* tn 300 */
9247502Sroot 			c = 5;
9259578Ssam 		else if (ctype == 2) /* ti 700 */
9267502Sroot 			c = 10;
9279578Ssam 		else if (ctype == 3) { /* concept 100 */
9287502Sroot 			int i;
9299578Ssam 
9307502Sroot 			if ((i = *colp) >= 0)
9319578Ssam 				for (; i < 9; i++)
9327502Sroot 					(void) putc(0177, &tp->t_outq);
9337502Sroot 		}
9347502Sroot 		*colp = 0;
9357502Sroot 	}
9369578Ssam 	if (c && (tp->t_flags&FLUSHO) == 0)
9377502Sroot 		(void) putc(c|0200, &tp->t_outq);
9387502Sroot 	return (-1);
9397502Sroot }
9407502Sroot 
9417502Sroot /*
9427502Sroot  * Called from device's read routine after it has
9437502Sroot  * calculated the tty-structure given as argument.
9447502Sroot  */
9457722Swnj ttread(tp, uio)
9467625Ssam 	register struct tty *tp;
9477722Swnj 	struct uio *uio;
9487502Sroot {
9497502Sroot 	register struct clist *qp;
9509578Ssam 	register c, t_flags;
951*9859Ssam 	int s, first, error = 0;
9527502Sroot 
9537502Sroot 	if ((tp->t_state&TS_CARR_ON)==0)
9548520Sroot 		return (EIO);
9557502Sroot loop:
9569578Ssam 	/*
9579578Ssam 	 * Take any pending input first.
9589578Ssam 	 */
959*9859Ssam 	s = spl5();
9609578Ssam 	if (tp->t_flags&PENDIN)
9617502Sroot 		ttypend(tp);
962*9859Ssam 	splx(s);
9639578Ssam 
9649578Ssam 	/*
9659578Ssam 	 * Hang process if it's in the background.
9669578Ssam 	 */
9677502Sroot 	while (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) {
9687502Sroot 		if (u.u_signal[SIGTTIN] == SIG_IGN ||
9697502Sroot 		    u.u_signal[SIGTTIN] == SIG_HOLD ||
9707502Sroot /*
9717502Sroot 		    (u.u_procp->p_flag&SDETACH) ||
9727502Sroot */
9737502Sroot 		    u.u_procp->p_flag&SVFORK)
9748520Sroot 			return (EIO);
9757502Sroot 		gsignal(u.u_procp->p_pgrp, SIGTTIN);
9767502Sroot 		sleep((caddr_t)&lbolt, TTIPRI);
9777502Sroot 	}
9789578Ssam 	t_flags = tp->t_flags;
9799578Ssam 
9809578Ssam 	/*
9819578Ssam 	 * In raw mode take characters directly from the
9829578Ssam 	 * raw queue w/o processing.  Interlock against
9839578Ssam 	 * device interrupts when interrogating rawq.
9849578Ssam 	 */
9859578Ssam 	if (t_flags&RAW) {
986*9859Ssam 		s = spl5();
9877502Sroot 		if (tp->t_rawq.c_cc <= 0) {
9889578Ssam 			if ((tp->t_state&TS_CARR_ON) == 0 ||
9897502Sroot 			    (tp->t_state&TS_NBIO)) {
990*9859Ssam 				splx(s);
9919578Ssam 				return (0);
9927502Sroot 			}
9937502Sroot 			sleep((caddr_t)&tp->t_rawq, TTIPRI);
994*9859Ssam 			splx(s);
9957502Sroot 			goto loop;
9967502Sroot 		}
997*9859Ssam 		splx(s);
998*9859Ssam 		while (!error && tp->t_rawq.c_cc && uio->uio_iovcnt)
9998520Sroot 			error = passuc(getc(&tp->t_rawq), uio);
1000*9859Ssam 		goto checktandem;
10019578Ssam 	}
10029578Ssam 
10039578Ssam 	/*
10049578Ssam 	 * In cbreak mode use the rawq, otherwise
10059578Ssam 	 * take characters from the canonicalized q.
10069578Ssam 	 */
10079578Ssam 	qp = t_flags&CBREAK ? &tp->t_rawq : &tp->t_canq;
10089578Ssam 
10099578Ssam 	/*
10109578Ssam 	 * No input, sleep on rawq awaiting hardware
10119578Ssam 	 * receipt and notification.
10129578Ssam 	 */
1013*9859Ssam 	s = spl5();
10149578Ssam 	if (qp->c_cc <= 0) {
10159578Ssam 		if ((tp->t_state&TS_CARR_ON) == 0 ||
10169578Ssam 		    (tp->t_state&TS_NBIO)) {
1017*9859Ssam 			splx(s);
10189578Ssam 			return (EWOULDBLOCK);
10197502Sroot 		}
10209578Ssam 		sleep((caddr_t)&tp->t_rawq, TTIPRI);
1021*9859Ssam 		splx(s);
10229578Ssam 		goto loop;
10239578Ssam 	}
1024*9859Ssam 	splx(s);
10259578Ssam 
10269578Ssam 	/*
10279578Ssam 	 * Input present, perform input mapping
10289578Ssam 	 * and processing (we're not in raw mode).
10299578Ssam 	 */
10309578Ssam 	first = 1;
10319578Ssam 	while ((c = getc(qp)) >= 0) {
10329578Ssam 		if (t_flags&CRMOD && c == '\r')
10339578Ssam 			c = '\n';
10349578Ssam 		/*
10359578Ssam 		 * Hack lower case simulation on
10369578Ssam 		 * upper case only terminals.
10379578Ssam 		 */
10389578Ssam 		if (t_flags&LCASE && c <= 0177)
10399578Ssam 			if (tp->t_state&TS_BKSL) {
10409578Ssam 				if (maptab[c])
10419578Ssam 					c = maptab[c];
10429578Ssam 				tp->t_state &= ~TS_BKSL;
10439578Ssam 			} else if (c >= 'A' && c <= 'Z')
10449578Ssam 				c += 'a' - 'A';
10459578Ssam 			else if (c == '\\') {
10469578Ssam 				tp->t_state |= TS_BKSL;
10479578Ssam 				continue;
10487502Sroot 			}
10499578Ssam 		/*
10509578Ssam 		 * Check for delayed suspend character.
10519578Ssam 		 */
10529578Ssam 		if (tp->t_line == NTTYDISC && c == tp->t_dsuspc) {
10539578Ssam 			gsignal(tp->t_pgrp, SIGTSTP);
10549578Ssam 			if (first) {
10559578Ssam 				sleep((caddr_t)&lbolt, TTIPRI);
10569578Ssam 				goto loop;
10579578Ssam 			}
10589578Ssam 			break;
10597502Sroot 		}
10609578Ssam 		/*
10619578Ssam 		 * Interpret EOF only in cooked mode.
10629578Ssam 		 */
10639578Ssam 		if (c == tp->t_eofc && (t_flags&CBREAK) == 0)
10649578Ssam 			break;
10659578Ssam 		/*
10669578Ssam 		 * Give user character.
10679578Ssam 		 */
10689578Ssam 		error = passuc(c & 0177, uio);
10699578Ssam 		if (error)
10709578Ssam 			break;
10719578Ssam 		if (uio->uio_iovcnt == 0)
10729578Ssam 			break;
10739578Ssam 		/*
10749578Ssam 		 * In cooked mode check for a "break character"
10759578Ssam 		 * marking the end of a "line of input".
10769578Ssam 		 */
10779578Ssam 		if ((t_flags&CBREAK) == 0 && ttbreakc(c, tp))
10789578Ssam 			break;
10799578Ssam 		first = 0;
10807502Sroot 	}
10819578Ssam 	tp->t_state &= ~TS_BKSL;
10829578Ssam 
1083*9859Ssam checktandem:
10849578Ssam 	/*
10859578Ssam 	 * Look to unblock output now that (presumably)
10869578Ssam 	 * the input queue has gone down.
10879578Ssam 	 */
1088*9859Ssam 	if (tp->t_state&TS_TBLOCK && tp->t_rawq.c_cc < TTYHOG/5)
10899578Ssam 		if (putc(tp->t_startc, &tp->t_outq) == 0) {
10907502Sroot 			tp->t_state &= ~TS_TBLOCK;
10917502Sroot 			ttstart(tp);
10927502Sroot 		}
10938520Sroot 	return (error);
10947502Sroot }
10957502Sroot 
10967502Sroot /*
10977502Sroot  * Called from the device's write routine after it has
10987502Sroot  * calculated the tty-structure given as argument.
10997502Sroot  */
11007822Sroot ttwrite(tp, uio)
11017625Ssam 	register struct tty *tp;
11029578Ssam 	register struct uio *uio;
11037502Sroot {
11047502Sroot 	register char *cp;
11059578Ssam 	register int cc, ce, c;
11069578Ssam 	int i, hiwat, cnt, error, s;
11077502Sroot 	char obuf[OBUFSIZ];
11087502Sroot 
11099578Ssam 	if ((tp->t_state&TS_CARR_ON) == 0)
11108520Sroot 		return (EIO);
11119578Ssam 	hiwat = TTHIWAT(tp);
11129578Ssam 	cnt = uio->uio_resid;
11139578Ssam 	error = 0;
11147502Sroot loop:
11159578Ssam 	/*
11169578Ssam 	 * Hang the process if it's in the background.
11179578Ssam 	 */
11187502Sroot 	while (u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp &&
11199578Ssam 	    (tp->t_flags&TOSTOP) && (u.u_procp->p_flag&SVFORK)==0 &&
11207502Sroot 	    u.u_signal[SIGTTOU] != SIG_IGN &&
11217502Sroot 	    u.u_signal[SIGTTOU] != SIG_HOLD
11227502Sroot /*
11237502Sroot 					     &&
11247502Sroot 	    (u.u_procp->p_flag&SDETACH)==0) {
11257502Sroot */
11267502Sroot 	    ) {
11277502Sroot 		gsignal(u.u_procp->p_pgrp, SIGTTOU);
11287502Sroot 		sleep((caddr_t)&lbolt, TTIPRI);
11297502Sroot 	}
11309578Ssam 
11319578Ssam 	/*
11329578Ssam 	 * Process the user's data in at most OBUFSIZ
11339578Ssam 	 * chunks.  Perform lower case simulation and
11349578Ssam 	 * similar hacks.  Keep track of high water
11359578Ssam 	 * mark, sleep on overflow awaiting device aid
11369578Ssam 	 * in acquiring new space.
11379578Ssam 	 */
11387822Sroot 	while (uio->uio_resid > 0) {
11399578Ssam 		/*
11409578Ssam 		 * Grab a hunk of data from the user.
11419578Ssam 		 */
11427822Sroot 		cc = uio->uio_iov->iov_len;
11437822Sroot 		if (cc == 0) {
11447822Sroot 			uio->uio_iovcnt--;
11457822Sroot 			uio->uio_iov++;
11467822Sroot 			if (uio->uio_iovcnt < 0)
11477822Sroot 				panic("ttwrite");
11487822Sroot 			continue;
11497822Sroot 		}
11507822Sroot 		if (cc > OBUFSIZ)
11517822Sroot 			cc = OBUFSIZ;
11527502Sroot 		cp = obuf;
11539578Ssam 		error = uiomove(cp, (unsigned)cc, UIO_WRITE, uio);
11548520Sroot 		if (error)
11557502Sroot 			break;
11567502Sroot 		if (tp->t_outq.c_cc > hiwat)
11577502Sroot 			goto ovhiwat;
11589578Ssam 		if (tp->t_flags&FLUSHO)
11597502Sroot 			continue;
11609578Ssam 		/*
11619578Ssam 		 * If we're mapping lower case or kludging tildes,
11629578Ssam 		 * then we've got to look at each character, so
11639578Ssam 		 * just feed the stuff to ttyoutput...
11649578Ssam 		 */
11659578Ssam 		if (tp->t_flags & (LCASE|TILDE)) {
11669578Ssam 			while (cc > 0) {
11677502Sroot 				c = *cp++;
11687502Sroot 				tp->t_rocount = 0;
11697625Ssam 				while ((c = ttyoutput(c, tp)) >= 0) {
11707502Sroot 					/* out of clists, wait a bit */
11717502Sroot 					ttstart(tp);
11727502Sroot 					sleep((caddr_t)&lbolt, TTOPRI);
11737502Sroot 					tp->t_rocount = 0;
11747502Sroot 				}
11757502Sroot 				--cc;
11767502Sroot 				if (tp->t_outq.c_cc > hiwat)
11777502Sroot 					goto ovhiwat;
11787502Sroot 			}
11797502Sroot 			continue;
11807502Sroot 		}
11819578Ssam 		/*
11829578Ssam 		 * If nothing fancy need be done, grab those characters we
11839578Ssam 		 * can handle without any of ttyoutput's processing and
11849578Ssam 		 * just transfer them to the output q.  For those chars
11859578Ssam 		 * which require special processing (as indicated by the
11869578Ssam 		 * bits in partab), call ttyoutput.  After processing
11879578Ssam 		 * a hunk of data, look for FLUSHO so ^O's will take effect
11889578Ssam 		 * immediately.
11899578Ssam 		 */
11909578Ssam 		while (cc > 0) {
11919578Ssam 			if (tp->t_flags & (RAW|LITOUT))
11927502Sroot 				ce = cc;
11937502Sroot 			else {
11949578Ssam 				ce = cc - scanc(cc, cp, partab, 077);
11959578Ssam 				/*
11969578Ssam 				 * If ce is zero, then we're processing
11979578Ssam 				 * a special character through ttyoutput.
11989578Ssam 				 */
11999578Ssam 				if (ce == 0) {
12007502Sroot 					tp->t_rocount = 0;
12017502Sroot 					if (ttyoutput(*cp, tp) >= 0) {
12029578Ssam 						/* no c-lists, wait a bit */
12037502Sroot 						ttstart(tp);
12047502Sroot 						sleep((caddr_t)&lbolt, TTOPRI);
12057502Sroot 						continue;
12067502Sroot 					}
12079578Ssam 					cp++, cc--;
12089578Ssam 					if (tp->t_flags&FLUSHO ||
12099578Ssam 					    tp->t_outq.c_cc > hiwat)
12107502Sroot 						goto ovhiwat;
12119578Ssam 					continue;
12127502Sroot 				}
12137502Sroot 			}
12149578Ssam 			/*
12159578Ssam 			 * A bunch of normal characters have been found,
12169578Ssam 			 * transfer them en masse to the output queue and
12179578Ssam 			 * continue processing at the top of the loop.
12189578Ssam 			 * If there are any further characters in this
12199578Ssam 			 * <= OBUFSIZ chunk, the first should be a character
12209578Ssam 			 * requiring special handling by ttyoutput.
12219578Ssam 			 */
12227502Sroot 			tp->t_rocount = 0;
12239578Ssam 			i = b_to_q(cp, ce, &tp->t_outq);
12249578Ssam 			ce -= i;
12259578Ssam 			tp->t_col += ce;
12269578Ssam 			cp += ce, cc -= ce, tk_nout += ce;
12279578Ssam 			if (i > 0) {
12289578Ssam 				/* out of c-lists, wait a bit */
12297502Sroot 				ttstart(tp);
12307502Sroot 				sleep((caddr_t)&lbolt, TTOPRI);
12317502Sroot 			}
12329578Ssam 			if (tp->t_flags&FLUSHO || tp->t_outq.c_cc > hiwat)
12337502Sroot 				goto ovhiwat;
12347502Sroot 		}
12357502Sroot 	}
12367502Sroot 	ttstart(tp);
12378520Sroot 	return (error);
12387502Sroot 
12397502Sroot ovhiwat:
12409578Ssam 	s = spl5();
12419578Ssam 	if (cc != 0) {
12429578Ssam 		uio->uio_iov->iov_base -= cc;
12439578Ssam 		uio->uio_iov->iov_len += cc;
12449578Ssam 		uio->uio_resid += cc;
12459578Ssam 		uio->uio_offset -= cc;
12469578Ssam 	}
12479578Ssam 	/*
12489578Ssam 	 * This can only occur if FLUSHO
12499578Ssam 	 * is also set in t_flags.
12509578Ssam 	 */
12517502Sroot 	if (tp->t_outq.c_cc <= hiwat) {
12529578Ssam 		splx(s);
12537502Sroot 		goto loop;
12547502Sroot 	}
12557502Sroot 	ttstart(tp);
12569578Ssam 	if (tp->t_state&TS_NBIO) {
12577822Sroot 		if (uio->uio_resid == cnt)
12588520Sroot 			return (EWOULDBLOCK);
12598520Sroot 		return (0);
12607502Sroot 	}
12617502Sroot 	tp->t_state |= TS_ASLEEP;
12627502Sroot 	sleep((caddr_t)&tp->t_outq, TTOPRI);
12639578Ssam 	splx(s);
12647502Sroot 	goto loop;
12657502Sroot }
12667502Sroot 
12677502Sroot /*
12687502Sroot  * Rubout one character from the rawq of tp
12697502Sroot  * as cleanly as possible.
12707502Sroot  */
12717502Sroot ttyrub(c, tp)
12727625Ssam 	register c;
12737625Ssam 	register struct tty *tp;
12747502Sroot {
12757502Sroot 	register char *cp;
12767502Sroot 	register int savecol;
12777502Sroot 	int s;
12787502Sroot 	char *nextc();
12797502Sroot 
12809578Ssam 	if ((tp->t_flags&ECHO) == 0)
12817502Sroot 		return;
12829578Ssam 	tp->t_flags &= ~FLUSHO;
12837502Sroot 	c &= 0377;
12849578Ssam 	if (tp->t_flags&CRTBS) {
12857502Sroot 		if (tp->t_rocount == 0) {
12867502Sroot 			/*
12877502Sroot 			 * Screwed by ttwrite; retype
12887502Sroot 			 */
12897502Sroot 			ttyretype(tp);
12907502Sroot 			return;
12917502Sroot 		}
12929578Ssam 		if (c == ('\t'|0200) || c == ('\n'|0200))
12937502Sroot 			ttyrubo(tp, 2);
12949578Ssam 		else switch (partab[c&=0177]&0177) {
12957502Sroot 
12967502Sroot 		case ORDINARY:
12977502Sroot 			if (tp->t_flags&LCASE && c >= 'A' && c <= 'Z')
12987502Sroot 				ttyrubo(tp, 2);
12997502Sroot 			else
13007502Sroot 				ttyrubo(tp, 1);
13017502Sroot 			break;
13027502Sroot 
13037502Sroot 		case VTAB:
13047502Sroot 		case BACKSPACE:
13057502Sroot 		case CONTROL:
13067502Sroot 		case RETURN:
13079578Ssam 			if (tp->t_flags&CTLECH)
13087502Sroot 				ttyrubo(tp, 2);
13097502Sroot 			break;
13107502Sroot 
13117502Sroot 		case TAB:
13127502Sroot 			if (tp->t_rocount < tp->t_rawq.c_cc) {
13137502Sroot 				ttyretype(tp);
13147502Sroot 				return;
13157502Sroot 			}
13167502Sroot 			s = spl5();
13177502Sroot 			savecol = tp->t_col;
13189578Ssam 			tp->t_state |= TS_CNTTB;
13199578Ssam 			tp->t_flags |= FLUSHO;
13207502Sroot 			tp->t_col = tp->t_rocol;
13219578Ssam 			cp = tp->t_rawq.c_cf;
13229578Ssam 			for (; cp; cp = nextc(&tp->t_rawq, cp))
13237502Sroot 				ttyecho(*cp, tp);
13249578Ssam 			tp->t_flags &= ~FLUSHO;
13259578Ssam 			tp->t_state &= ~TS_CNTTB;
13267502Sroot 			splx(s);
13277502Sroot 			/*
13287502Sroot 			 * savecol will now be length of the tab
13297502Sroot 			 */
13307502Sroot 			savecol -= tp->t_col;
13317502Sroot 			tp->t_col += savecol;
13327502Sroot 			if (savecol > 8)
13337502Sroot 				savecol = 8;		/* overflow screw */
13347502Sroot 			while (--savecol >= 0)
13357502Sroot 				(void) ttyoutput('\b', tp);
13367502Sroot 			break;
13377502Sroot 
13387502Sroot 		default:
13397502Sroot 			panic("ttyrub");
13407502Sroot 		}
13419578Ssam 	} else if (tp->t_flags&PRTERA) {
13429578Ssam 		if ((tp->t_state&TS_ERASE) == 0) {
13437502Sroot 			(void) ttyoutput('\\', tp);
13449578Ssam 			tp->t_state |= TS_ERASE;
13457502Sroot 		}
13467502Sroot 		ttyecho(c, tp);
13477502Sroot 	} else
13487502Sroot 		ttyecho(tp->t_erase, tp);
13497502Sroot 	tp->t_rocount--;
13507502Sroot }
13517502Sroot 
13527502Sroot /*
13537502Sroot  * Crt back over cnt chars perhaps
13547502Sroot  * erasing them.
13557502Sroot  */
13567502Sroot ttyrubo(tp, cnt)
13577625Ssam 	register struct tty *tp;
13587625Ssam 	int cnt;
13597502Sroot {
13609578Ssam 	register char *rubostring = tp->t_flags&CRTERA ? "\b \b" : "\b";
13617502Sroot 
13627502Sroot 	while (--cnt >= 0)
13639578Ssam 		ttyout(rubostring, tp);
13647502Sroot }
13657502Sroot 
13667502Sroot /*
13677502Sroot  * Reprint the rawq line.
13687502Sroot  * We assume c_cc has already been checked.
13697502Sroot  */
13707502Sroot ttyretype(tp)
13717625Ssam 	register struct tty *tp;
13727502Sroot {
13737502Sroot 	register char *cp;
13747502Sroot 	char *nextc();
13757502Sroot 	int s;
13767502Sroot 
13779578Ssam 	if (tp->t_rprntc != 0377)
13789578Ssam 		ttyecho(tp->t_rprntc, tp);
13797502Sroot 	(void) ttyoutput('\n', tp);
13807502Sroot 	s = spl5();
13817502Sroot 	for (cp = tp->t_canq.c_cf; cp; cp = nextc(&tp->t_canq, cp))
13827502Sroot 		ttyecho(*cp, tp);
13837502Sroot 	for (cp = tp->t_rawq.c_cf; cp; cp = nextc(&tp->t_rawq, cp))
13847502Sroot 		ttyecho(*cp, tp);
13859578Ssam 	tp->t_state &= ~TS_ERASE;
13867502Sroot 	splx(s);
13877502Sroot 	tp->t_rocount = tp->t_rawq.c_cc;
13887502Sroot 	tp->t_rocol = 0;
13897502Sroot }
13907502Sroot 
13917502Sroot /*
13927502Sroot  * Echo a typed character to the terminal
13937502Sroot  */
13947502Sroot ttyecho(c, tp)
13957625Ssam 	register c;
13967625Ssam 	register struct tty *tp;
13977502Sroot {
13987502Sroot 
13999578Ssam 	if ((tp->t_state&TS_CNTTB) == 0)
14009578Ssam 		tp->t_flags &= ~FLUSHO;
14017502Sroot 	if ((tp->t_flags&ECHO) == 0)
14027502Sroot 		return;
14037502Sroot 	c &= 0377;
14047502Sroot 	if (tp->t_flags&RAW) {
14057502Sroot 		(void) ttyoutput(c, tp);
14067502Sroot 		return;
14077502Sroot 	}
14087502Sroot 	if (c == '\r' && tp->t_flags&CRMOD)
14097502Sroot 		c = '\n';
14109578Ssam 	if (tp->t_flags&CTLECH) {
14117502Sroot 		if ((c&0177) <= 037 && c!='\t' && c!='\n' || (c&0177)==0177) {
14127502Sroot 			(void) ttyoutput('^', tp);
14137502Sroot 			c &= 0177;
14147502Sroot 			if (c == 0177)
14157502Sroot 				c = '?';
14167502Sroot 			else if (tp->t_flags&LCASE)
14177502Sroot 				c += 'a' - 1;
14187502Sroot 			else
14197502Sroot 				c += 'A' - 1;
14207502Sroot 		}
14217502Sroot 	}
14227502Sroot 	if ((tp->t_flags&LCASE) && (c >= 'A' && c <= 'Z'))
14237502Sroot 		c += 'a' - 'A';
14249578Ssam 	(void) ttyoutput(c&0177, tp);
14257502Sroot }
14267502Sroot 
14277502Sroot /*
14287502Sroot  * Is c a break char for tp?
14297502Sroot  */
14307502Sroot ttbreakc(c, tp)
14317625Ssam 	register c;
14327625Ssam 	register struct tty *tp;
14337502Sroot {
14349578Ssam 	return (c == '\n' || c == tp->t_eofc || c == tp->t_brkc ||
14357502Sroot 		c == '\r' && (tp->t_flags&CRMOD));
14367502Sroot }
14377502Sroot 
14387502Sroot /*
14397502Sroot  * send string cp to tp
14407502Sroot  */
14417502Sroot ttyout(cp, tp)
14427625Ssam 	register char *cp;
14437625Ssam 	register struct tty *tp;
14447502Sroot {
14457502Sroot 	register char c;
14467502Sroot 
14477502Sroot 	while (c = *cp++)
14487502Sroot 		(void) ttyoutput(c, tp);
14497502Sroot }
14507502Sroot 
14517502Sroot ttwakeup(tp)
14527502Sroot 	struct tty *tp;
14537502Sroot {
14547502Sroot 
14557502Sroot 	if (tp->t_rsel) {
14567502Sroot 		selwakeup(tp->t_rsel, tp->t_state&TS_RCOLL);
14577502Sroot 		tp->t_state &= ~TS_RCOLL;
14587502Sroot 		tp->t_rsel = 0;
14597502Sroot 	}
14607502Sroot 	wakeup((caddr_t)&tp->t_rawq);
14617502Sroot }
14627502Sroot 
14639578Ssam #ifndef vax
14649578Ssam scanc(size, cp, table, mask)
14659578Ssam 	register int size;
14669578Ssam 	register char *cp, table[];
14679578Ssam 	register int mask;
14687502Sroot {
14699578Ssam 	register int i = 0;
14707502Sroot 
14719578Ssam 	while ((table[*(u_char *)(cp + i)]&mask) == 0 && i < size)
14729578Ssam 		i++;
14739578Ssam 	return (i);
14747502Sroot }
14759578Ssam #endif
1476