xref: /csrg-svn/sys/kern/tty.c (revision 9624)
1*9624Ssam /*	tty.c	4.36	82/12/13	*/
239Sbill 
339Sbill #include "../h/param.h"
439Sbill #include "../h/systm.h"
539Sbill #include "../h/dir.h"
639Sbill #include "../h/user.h"
79578Ssam #include "../h/ioctl.h"
839Sbill #include "../h/tty.h"
939Sbill #include "../h/proc.h"
1039Sbill #include "../h/inode.h"
1139Sbill #include "../h/file.h"
1239Sbill #include "../h/reg.h"
1339Sbill #include "../h/conf.h"
1439Sbill #include "../h/buf.h"
15340Sbill #include "../h/dk.h"
167722Swnj #include "../h/uio.h"
178154Sroot #include "../h/kernel.h"
1839Sbill 
197436Skre /*
207436Skre  * Table giving parity for characters and indicating
217436Skre  * character classes to tty driver.  In particular,
227436Skre  * if the low 6 bits are 0, then the character needs
237436Skre  * no special processing on output.
247436Skre  */
2539Sbill 
267436Skre char partab[] = {
277436Skre 	0001,0201,0201,0001,0201,0001,0001,0201,
287436Skre 	0202,0004,0003,0201,0005,0206,0201,0001,
297436Skre 	0201,0001,0001,0201,0001,0201,0201,0001,
307436Skre 	0001,0201,0201,0001,0201,0001,0001,0201,
317436Skre 	0200,0000,0000,0200,0000,0200,0200,0000,
327436Skre 	0000,0200,0200,0000,0200,0000,0000,0200,
337436Skre 	0000,0200,0200,0000,0200,0000,0000,0200,
347436Skre 	0200,0000,0000,0200,0000,0200,0200,0000,
357436Skre 	0200,0000,0000,0200,0000,0200,0200,0000,
367436Skre 	0000,0200,0200,0000,0200,0000,0000,0200,
377436Skre 	0000,0200,0200,0000,0200,0000,0000,0200,
387436Skre 	0200,0000,0000,0200,0000,0200,0200,0000,
397436Skre 	0000,0200,0200,0000,0200,0000,0000,0200,
407436Skre 	0200,0000,0000,0200,0000,0200,0200,0000,
417436Skre 	0200,0000,0000,0200,0000,0200,0200,0000,
427436Skre 	0000,0200,0200,0000,0200,0000,0000,0201,
437436Skre 
447436Skre 	/*
457436Skre 	 * 7 bit ascii ends with the last character above,
467436Skre 	 * but we contine through all 256 codes for the sake
477436Skre 	 * of the tty output routines which use special vax
487436Skre 	 * instructions which need a 256 character trt table.
497436Skre 	 */
507436Skre 
517436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
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 };
687436Skre 
69146Sbill /*
7039Sbill  * Input mapping table-- if an entry is non-zero, when the
7139Sbill  * corresponding character is typed preceded by "\" the escape
7239Sbill  * sequence is replaced by the table value.  Mostly used for
7339Sbill  * upper-case only terminals.
7439Sbill  */
7539Sbill char	maptab[] ={
7639Sbill 	000,000,000,000,000,000,000,000,
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,'`',
8139Sbill 	'{','}',000,000,000,000,000,000,
8239Sbill 	000,000,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,
8839Sbill 	000,'A','B','C','D','E','F','G',
8939Sbill 	'H','I','J','K','L','M','N','O',
9039Sbill 	'P','Q','R','S','T','U','V','W',
9139Sbill 	'X','Y','Z',000,000,000,000,000,
9239Sbill };
9339Sbill 
94925Sbill short	tthiwat[16] =
958954Sroot    { 100,100,100,100,100,100,100,200,200,400,400,400,650,650,1300,2000 };
96925Sbill short	ttlowat[16] =
97925Sbill    {  30, 30, 30, 30, 30, 30, 30, 50, 50,120,120,120,125,125,125,125 };
98925Sbill 
999578Ssam struct	ttychars ttydefaults = {
1009578Ssam 	CERASE,	CKILL,	CINTR,	CQUIT,	CSTART,	CSTOP,	CEOF,
1019578Ssam 	CBRK,	CSUSP,	CDSUSP, CRPRNT, CFLUSH, CWERASE,CLNEXT
1029578Ssam };
10339Sbill 
10439Sbill ttychars(tp)
1059578Ssam 	struct tty *tp;
10639Sbill {
107174Sbill 
1089578Ssam 	tp->t_chars = ttydefaults;
10939Sbill }
11039Sbill 
11139Sbill /*
112903Sbill  * Wait for output to drain, then flush input waiting.
11339Sbill  */
114903Sbill wflushtty(tp)
1155408Swnj 	register struct tty *tp;
11639Sbill {
11739Sbill 
118903Sbill 	(void) spl5();
1195622Swnj 	while (tp->t_outq.c_cc && tp->t_state&TS_CARR_ON
1205622Swnj 	    && tp->t_oproc) {		/* kludge for pty */
121903Sbill 		(*tp->t_oproc)(tp);
1225408Swnj 		tp->t_state |= TS_ASLEEP;
123903Sbill 		sleep((caddr_t)&tp->t_outq, TTOPRI);
124903Sbill 	}
1255426Swnj 	flushtty(tp, FREAD);
126903Sbill 	(void) spl0();
12739Sbill }
12839Sbill 
12939Sbill /*
1309578Ssam  * Flush all TTY queues
13139Sbill  */
132903Sbill flushtty(tp, rw)
1337625Ssam 	register struct tty *tp;
13439Sbill {
135903Sbill 	register s;
136903Sbill 
137903Sbill 	s = spl6();
138903Sbill 	if (rw & FREAD) {
139903Sbill 		while (getc(&tp->t_canq) >= 0)
140903Sbill 			;
141903Sbill 		wakeup((caddr_t)&tp->t_rawq);
142903Sbill 	}
143903Sbill 	if (rw & FWRITE) {
144903Sbill 		wakeup((caddr_t)&tp->t_outq);
1455408Swnj 		tp->t_state &= ~TS_TTSTOP;
1465426Swnj 		(*cdevsw[major(tp->t_dev)].d_stop)(tp, rw);
147903Sbill 		while (getc(&tp->t_outq) >= 0)
148903Sbill 			;
149903Sbill 	}
150903Sbill 	if (rw & FREAD) {
151903Sbill 		while (getc(&tp->t_rawq) >= 0)
152903Sbill 			;
153903Sbill 		tp->t_delct = 0;
1549578Ssam 		tp->t_rocount = 0;
155903Sbill 		tp->t_rocol = 0;
1569578Ssam 		tp->t_state &= ~TS_LOCAL;
157903Sbill 	}
158903Sbill 	splx(s);
15939Sbill }
16039Sbill 
161903Sbill /*
162903Sbill  * Send stop character on input overflow.
163903Sbill  */
164903Sbill ttyblock(tp)
1657625Ssam 	register struct tty *tp;
16639Sbill {
167903Sbill 	register x;
1689578Ssam 
169903Sbill 	x = tp->t_rawq.c_cc + tp->t_canq.c_cc;
170903Sbill 	if (tp->t_rawq.c_cc > TTYHOG) {
171903Sbill 		flushtty(tp, FREAD|FWRITE);
1725408Swnj 		tp->t_state &= ~TS_TBLOCK;
173903Sbill 	}
1749578Ssam 	if (x >= TTYHOG/2 && putc(tp->t_stopc, &tp->t_outq) == 0) {
1759578Ssam 		tp->t_state |= TS_TBLOCK;
1769578Ssam 		tp->t_char++;
1779578Ssam 		ttstart(tp);
178903Sbill 	}
17939Sbill }
18039Sbill 
18139Sbill /*
182903Sbill  * Restart typewriter output following a delay
183903Sbill  * timeout.
184903Sbill  * The name of the routine is passed to the timeout
185903Sbill  * subroutine and it is called during a clock interrupt.
186121Sbill  */
187903Sbill ttrstrt(tp)
1887625Ssam 	register struct tty *tp;
189121Sbill {
190121Sbill 
1919578Ssam 	if (tp == 0)
1929578Ssam 		panic("ttrstrt");
1935408Swnj 	tp->t_state &= ~TS_TIMEOUT;
194903Sbill 	ttstart(tp);
195121Sbill }
196121Sbill 
197121Sbill /*
198903Sbill  * Start output on the typewriter. It is used from the top half
199903Sbill  * after some characters have been put on the output queue,
200903Sbill  * from the interrupt routine to transmit the next
201903Sbill  * character, and after a timeout has finished.
20239Sbill  */
203903Sbill ttstart(tp)
2047625Ssam 	register struct tty *tp;
20539Sbill {
206903Sbill 	register s;
20739Sbill 
208903Sbill 	s = spl5();
2099578Ssam 	if ((tp->t_state & (TS_TIMEOUT|TS_TTSTOP|TS_BUSY)) == 0 &&
2105622Swnj 	    tp->t_oproc)		/* kludge for pty */
211903Sbill 		(*tp->t_oproc)(tp);
212903Sbill 	splx(s);
21339Sbill }
21439Sbill 
21539Sbill /*
216903Sbill  * Common code for tty ioctls.
21739Sbill  */
2181780Sbill /*ARGSUSED*/
2197625Ssam ttioctl(tp, com, data, flag)
2207625Ssam 	register struct tty *tp;
2217625Ssam 	caddr_t data;
22239Sbill {
2238520Sroot 	int dev = tp->t_dev;
22439Sbill 	extern int nldisp;
2258556Sroot 	int s;
22639Sbill 
227903Sbill 	/*
228903Sbill 	 * If the ioctl involves modification,
229903Sbill 	 * insist on being able to write the device,
230903Sbill 	 * and hang if in the background.
231903Sbill 	 */
2327625Ssam 	switch (com) {
23339Sbill 
234915Sbill 	case TIOCSETD:
235915Sbill 	case TIOCSETP:
236915Sbill 	case TIOCSETN:
237903Sbill 	case TIOCFLUSH:
238903Sbill 	case TIOCSETC:
239903Sbill 	case TIOCSLTC:
240903Sbill 	case TIOCSPGRP:
241903Sbill 	case TIOCLBIS:
242903Sbill 	case TIOCLBIC:
243903Sbill 	case TIOCLSET:
244*9624Ssam 	case TIOCBIS:
245*9624Ssam 	case TIOCBIC:
246*9624Ssam 	case TIOCSET:
2479325Ssam 	case TIOCSTI:
248903Sbill 		while (tp->t_line == NTTYDISC &&
249903Sbill 		   u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp &&
250903Sbill 		   (u.u_procp->p_flag&SVFORK) == 0 &&
251903Sbill 		   u.u_signal[SIGTTOU] != SIG_IGN &&
2528556Sroot 		   u.u_signal[SIGTTOU] != SIG_HOLD) {
253903Sbill 			gsignal(u.u_procp->p_pgrp, SIGTTOU);
254903Sbill 			sleep((caddr_t)&lbolt, TTOPRI);
255903Sbill 		}
256903Sbill 		break;
257903Sbill 	}
258903Sbill 
2599578Ssam 	/*
2609578Ssam 	 * Process the ioctl.
2619578Ssam 	 */
2627625Ssam 	switch (com) {
263903Sbill 
2648556Sroot 	/* get discipline number */
26539Sbill 	case TIOCGETD:
2667625Ssam 		*(int *)data = tp->t_line;
26739Sbill 		break;
26839Sbill 
2698556Sroot 	/* set line discipline */
2707625Ssam 	case TIOCSETD: {
2717625Ssam 		register int t = *(int *)data;
2729578Ssam 		int error = 0;
2737625Ssam 
2749578Ssam 		if (t >= nldisp) {
2759578Ssam 			u.u_error = ENXIO;
2769578Ssam 			break;
2779578Ssam 		}
2788556Sroot 		s = spl5();
27939Sbill 		if (tp->t_line)
28039Sbill 			(*linesw[tp->t_line].l_close)(tp);
28139Sbill 		if (t)
2828556Sroot 			error = (*linesw[t].l_open)(dev, tp);
2838556Sroot 		splx(s);
2848556Sroot 		if (error)
2858556Sroot 			return (error);
2868556Sroot 		tp->t_line = t;
28739Sbill 		break;
2887625Ssam 	}
28939Sbill 
2908556Sroot 	/* prevent more opens on channel */
2915614Swnj 	case TIOCEXCL:
2925614Swnj 		tp->t_state |= TS_XCLUDE;
2935614Swnj 		break;
2945614Swnj 
2955614Swnj 	case TIOCNXCL:
2965614Swnj 		tp->t_state &= ~TS_XCLUDE;
2975614Swnj 		break;
2985614Swnj 
299*9624Ssam 	case TIOCSET:
300*9624Ssam 	case TIOCBIS: {
301*9624Ssam 		u_long newflags = *(u_long *)data;
3027625Ssam 
303*9624Ssam 		s = spl5();
304*9624Ssam 		if (tp->t_flags&RAW || newflags&RAW)
3054484Swnj 			wflushtty(tp);
306*9624Ssam 		else if ((tp->t_flags&CBREAK) != (newflags&CBREAK))
307*9624Ssam 			if (newflags&CBREAK) {
308*9624Ssam 				struct clist tq;
309*9624Ssam 
3104484Swnj 				catq(&tp->t_rawq, &tp->t_canq);
3114484Swnj 				tq = tp->t_rawq;
3124484Swnj 				tp->t_rawq = tp->t_canq;
3134484Swnj 				tp->t_canq = tq;
3144484Swnj 			} else {
3159578Ssam 				tp->t_flags |= PENDIN;
3164484Swnj 				ttwakeup(tp);
317174Sbill 			}
318*9624Ssam 		if (com == TIOCSET)
319*9624Ssam 			tp->t_flags = newflags;
320*9624Ssam 		else
321*9624Ssam 			tp->t_flags |= newflags;
3229578Ssam 		if (tp->t_flags&RAW) {
3235408Swnj 			tp->t_state &= ~TS_TTSTOP;
3243941Sbugs 			ttstart(tp);
3253941Sbugs 		}
326*9624Ssam 		splx(s);
32739Sbill 		break;
3287625Ssam 	}
32939Sbill 
330*9624Ssam 	case TIOCBIC: {
331*9624Ssam 		u_long newflags = *(long *)data;
3327625Ssam 
333*9624Ssam 		if (tp->t_flags&RAW)
334*9624Ssam 			wflushtty(tp);
335*9624Ssam 		else if ((tp->t_flags&CBREAK) != (CBREAK&~newflags))
336*9624Ssam 			if (newflags&CBREAK) {
337*9624Ssam 				tp->t_flags |= PENDIN;
338*9624Ssam 				ttwakeup(tp);
339*9624Ssam 			} else {
340*9624Ssam 				struct clist tq;
341*9624Ssam 
342*9624Ssam 				catq(&tp->t_rawq, &tp->t_canq);
343*9624Ssam 				tq = tp->t_rawq;
344*9624Ssam 				tp->t_rawq = tp->t_canq;
345*9624Ssam 				tp->t_canq = tq;
346*9624Ssam 			}
347*9624Ssam 		if (tp->t_flags&RAW) {
348*9624Ssam 			tp->t_state &= ~TS_TTSTOP;
349*9624Ssam 			ttstart(tp);
350*9624Ssam 		}
351*9624Ssam 		splx(s);
35239Sbill 		break;
3537625Ssam 	}
35439Sbill 
355*9624Ssam 	case TIOCGET:
356*9624Ssam 		*(long *)data = tp->t_flags;
357*9624Ssam 		break;
358*9624Ssam 
359*9624Ssam 	case TIOCCGET:
360*9624Ssam 		bcopy((caddr_t)&tp->t_chars, data, sizeof (struct ttychars));
361*9624Ssam 		break;
362*9624Ssam 
363*9624Ssam 	case TIOCCSET:
364*9624Ssam 		bcopy(data, (caddr_t)&tp->t_chars, sizeof (struct ttychars));
365*9624Ssam 		break;
366*9624Ssam 
3678556Sroot 	/* hang up line on last close */
36839Sbill 	case TIOCHPCL:
3695408Swnj 		tp->t_state |= TS_HUPCLS;
37039Sbill 		break;
37139Sbill 
3723942Sbugs 	case TIOCFLUSH: {
3737625Ssam 		register int flags = *(int *)data;
3747625Ssam 
3757625Ssam 		if (flags == 0)
3763942Sbugs 			flags = FREAD|FWRITE;
3777625Ssam 		else
3787625Ssam 			flags &= FREAD|FWRITE;
3793942Sbugs 		flushtty(tp, flags);
38039Sbill 		break;
3813944Sbugs 	}
38239Sbill 
3838556Sroot 	/* return number of characters immediately available */
3847625Ssam 	case FIONREAD:
3857625Ssam 		*(off_t *)data = ttnread(tp);
386174Sbill 		break;
387174Sbill 
3888589Sroot 	case TIOCSTOP:
3898589Sroot 		s = spl5();
3909578Ssam 		if ((tp->t_state&TS_TTSTOP) == 0) {
3915573Swnj 			tp->t_state |= TS_TTSTOP;
3925573Swnj 			(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
3935573Swnj 		}
3947625Ssam 		splx(s);
3955573Swnj 		break;
3965573Swnj 
3978589Sroot 	case TIOCSTART:
3988589Sroot 		s = spl5();
3999578Ssam 		if ((tp->t_state&TS_TTSTOP) || (tp->t_flags&FLUSHO)) {
4005573Swnj 			tp->t_state &= ~TS_TTSTOP;
4019578Ssam 			tp->t_flags &= ~FLUSHO;
4025573Swnj 			ttstart(tp);
4035573Swnj 		}
4047625Ssam 		splx(s);
4055573Swnj 		break;
4065573Swnj 
4079325Ssam 	/*
4089325Ssam 	 * Simulate typing of a character at the terminal.
4099325Ssam 	 */
4109325Ssam 	case TIOCSTI:
4119325Ssam 		if (u.u_uid && u.u_ttyp != tp)
4129325Ssam 			return (EACCES);
4139578Ssam 		(*linesw[tp->t_line].l_rint)(*(char *)data, tp);
4149325Ssam 		break;
4159325Ssam 
41639Sbill 	default:
417*9624Ssam #ifndef NOCOMPAT
418*9624Ssam 		return (ottioctl(tp, com, data, flag));
419*9624Ssam #else
4208556Sroot 		return (-1);
421*9624Ssam #endif
42239Sbill 	}
4238556Sroot 	return (0);
42439Sbill }
4254484Swnj 
4264484Swnj ttnread(tp)
4274484Swnj 	struct tty *tp;
4284484Swnj {
4294484Swnj 	int nread = 0;
4304484Swnj 
4319578Ssam 	if (tp->t_flags & PENDIN)
4324484Swnj 		ttypend(tp);
4334484Swnj 	nread = tp->t_canq.c_cc;
4344484Swnj 	if (tp->t_flags & (RAW|CBREAK))
4354484Swnj 		nread += tp->t_rawq.c_cc;
4364484Swnj 	return (nread);
4374484Swnj }
4384484Swnj 
4395408Swnj ttselect(dev, rw)
4404484Swnj 	dev_t dev;
4415408Swnj 	int rw;
4424484Swnj {
4434484Swnj 	register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)];
4444484Swnj 	int nread;
4455408Swnj 	int s = spl5();
4464484Swnj 
4475408Swnj 	switch (rw) {
4484484Swnj 
4494484Swnj 	case FREAD:
4504484Swnj 		nread = ttnread(tp);
4514484Swnj 		if (nread > 0)
4525408Swnj 			goto win;
4534938Swnj 		if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait)
4545408Swnj 			tp->t_state |= TS_RCOLL;
4554484Swnj 		else
4564484Swnj 			tp->t_rsel = u.u_procp;
4575408Swnj 		break;
4584484Swnj 
4595408Swnj 	case FWRITE:
4605408Swnj 		if (tp->t_outq.c_cc <= TTLOWAT(tp))
4615408Swnj 			goto win;
4625408Swnj 		if (tp->t_wsel && tp->t_wsel->p_wchan == (caddr_t)&selwait)
4635408Swnj 			tp->t_state |= TS_WCOLL;
4645408Swnj 		else
4655408Swnj 			tp->t_wsel = u.u_procp;
4665408Swnj 		break;
4674484Swnj 	}
4685408Swnj 	splx(s);
4695408Swnj 	return (0);
4705408Swnj win:
4715408Swnj 	splx(s);
4725408Swnj 	return (1);
4734484Swnj }
4747436Skre 
4757502Sroot /*
4769578Ssam  * Establish a process group for distribution of
4777502Sroot  * quits and interrupts from the tty.
4787502Sroot  */
4797502Sroot ttyopen(dev, tp)
4807625Ssam 	dev_t dev;
4817625Ssam 	register struct tty *tp;
4827502Sroot {
4837502Sroot 	register struct proc *pp;
4847502Sroot 
4857502Sroot 	pp = u.u_procp;
4867502Sroot 	tp->t_dev = dev;
4877625Ssam 	if (pp->p_pgrp == 0) {
4887502Sroot 		u.u_ttyp = tp;
4897502Sroot 		u.u_ttyd = dev;
4907502Sroot 		if (tp->t_pgrp == 0)
4917502Sroot 			tp->t_pgrp = pp->p_pid;
4927502Sroot 		pp->p_pgrp = tp->t_pgrp;
4937502Sroot 	}
4947502Sroot 	tp->t_state &= ~TS_WOPEN;
4957502Sroot 	tp->t_state |= TS_ISOPEN;
4967502Sroot 	if (tp->t_line != NTTYDISC)
4977502Sroot 		wflushtty(tp);
4988556Sroot 	return (0);
4997502Sroot }
5007502Sroot 
5017502Sroot /*
5027502Sroot  * clean tp on last close
5037502Sroot  */
5047502Sroot ttyclose(tp)
5057625Ssam 	register struct tty *tp;
5067502Sroot {
5077502Sroot 
5087502Sroot 	if (tp->t_line) {
5097502Sroot 		wflushtty(tp);
5107502Sroot 		tp->t_line = 0;
5117502Sroot 		return;
5127502Sroot 	}
5137502Sroot 	tp->t_pgrp = 0;
5147502Sroot 	wflushtty(tp);
5157502Sroot 	tp->t_state = 0;
5167502Sroot }
5177502Sroot 
5187502Sroot /*
5197502Sroot  * reinput pending characters after state switch
5207502Sroot  * call at spl5().
5217502Sroot  */
5227502Sroot ttypend(tp)
5237625Ssam 	register struct tty *tp;
5247502Sroot {
5257502Sroot 	struct clist tq;
5267502Sroot 	register c;
5277502Sroot 
5289578Ssam 	tp->t_flags &= ~PENDIN;
5299578Ssam 	tp->t_state |= TS_TYPEN;
5307502Sroot 	tq = tp->t_rawq;
5317502Sroot 	tp->t_rawq.c_cc = 0;
5327502Sroot 	tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0;
5337502Sroot 	while ((c = getc(&tq)) >= 0)
5347502Sroot 		ttyinput(c, tp);
5359578Ssam 	tp->t_state &= ~TS_TYPEN;
5367502Sroot }
5377502Sroot 
5387502Sroot /*
5399578Ssam  * Place a character on raw TTY input queue,
5409578Ssam  * putting in delimiters and waking up top
5419578Ssam  * half as needed.  Also echo if required.
5429578Ssam  * The arguments are the character and the
5439578Ssam  * appropriate tty structure.
5447502Sroot  */
5457502Sroot ttyinput(c, tp)
5467625Ssam 	register c;
5477625Ssam 	register struct tty *tp;
5487502Sroot {
5499578Ssam 	register int t_flags = tp->t_flags;
5507502Sroot 	int i;
5517502Sroot 
5529578Ssam 	/*
5539578Ssam 	 * If input is pending take it first.
5549578Ssam 	 */
5559578Ssam 	if (t_flags&PENDIN)
5567502Sroot 		ttypend(tp);
5577502Sroot 	tk_nin++;
5587502Sroot 	c &= 0377;
5599578Ssam 
5609578Ssam 	/*
5619578Ssam 	 * In tandem mode, check high water mark.
5629578Ssam 	 */
5637502Sroot 	if (t_flags&TANDEM)
5647502Sroot 		ttyblock(tp);
5659578Ssam 
5669578Ssam 	if (t_flags&RAW) {
5679578Ssam 		/*
5689578Ssam 		 * Raw mode, just put character
5699578Ssam 		 * in input q w/o interpretation.
5709578Ssam 		 */
5719578Ssam 		if (tp->t_rawq.c_cc > TTYHOG)
5729578Ssam 			flushtty(tp, FREAD|FWRITE);
5739578Ssam 		else {
5749578Ssam 			if (putc(c, &tp->t_rawq) >= 0)
5759578Ssam 				ttwakeup(tp);
5769578Ssam 			ttyecho(c, tp);
5777502Sroot 		}
5789578Ssam 		goto endcase;
5799578Ssam 	}
5809578Ssam 
5819578Ssam 	/*
5829578Ssam 	 * Ignore any high bit added during
5839578Ssam 	 * previous ttyinput processing.
5849578Ssam 	 */
5859578Ssam 	if ((tp->t_state&TS_TYPEN) == 0)
5869578Ssam 		c &= 0177;
5879578Ssam 	/*
5889578Ssam 	 * Check for literal nexting very first
5899578Ssam 	 */
5909578Ssam 	if (tp->t_state&TS_LNCH) {
5919578Ssam 		c |= 0200;
5929578Ssam 		tp->t_state &= ~TS_LNCH;
5939578Ssam 	}
5949578Ssam 
5959578Ssam 	/*
5969578Ssam 	 * Scan for special characters.  This code
5979578Ssam 	 * is really just a big case statement with
5989578Ssam 	 * non-constant cases.  The bottom of the
5999578Ssam 	 * case statement is labeled ``endcase'', so goto
6009578Ssam 	 * it after a case match, or similar.
6019578Ssam 	 */
6029578Ssam 	if (tp->t_line == NTTYDISC) {
6039578Ssam 		if (c == tp->t_lnextc) {
6047502Sroot 			if (tp->t_flags&ECHO)
6057502Sroot 				ttyout("^\b", tp);
6069578Ssam 			tp->t_state |= TS_LNCH;
6079578Ssam 			goto endcase;
6089578Ssam 		}
6099578Ssam 		if (c == tp->t_flushc) {
6109578Ssam 			if (tp->t_flags&FLUSHO)
6119578Ssam 				tp->t_flags &= ~FLUSHO;
6127502Sroot 			else {
6137502Sroot 				flushtty(tp, FWRITE);
6147502Sroot 				ttyecho(c, tp);
6159578Ssam 				if (tp->t_rawq.c_cc + tp->t_canq.c_cc)
6167502Sroot 					ttyretype(tp);
6179578Ssam 				tp->t_flags |= FLUSHO;
6187502Sroot 			}
6199578Ssam 			goto startoutput;
6209578Ssam 		}
6219578Ssam 		if (c == tp->t_suspc) {
6229578Ssam 			if ((tp->t_flags&NOFLSH) == 0)
6239578Ssam 				flushtty(tp, FREAD);
6249578Ssam 			ttyecho(c, tp);
6259578Ssam 			gsignal(tp->t_pgrp, SIGTSTP);
6269578Ssam 			goto endcase;
6279578Ssam 		}
6289578Ssam 	}
6299578Ssam 
6309578Ssam 	/*
6319578Ssam 	 * Handle start/stop characters.
6329578Ssam 	 */
6339578Ssam 	if (c == tp->t_stopc) {
6349578Ssam 		if ((tp->t_state&TS_TTSTOP) == 0) {
6359578Ssam 			tp->t_state |= TS_TTSTOP;
6369578Ssam 			(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
6377502Sroot 			return;
6389578Ssam 		}
6399578Ssam 		if (c != tp->t_startc)
6409578Ssam 			return;
6419578Ssam 		goto endcase;
6429578Ssam 	}
6439578Ssam 	if (c == tp->t_startc)
6449578Ssam 		goto restartoutput;
6459578Ssam 
6469578Ssam 	/*
6479578Ssam 	 * Look for interrupt/quit chars.
6489578Ssam 	 */
6499578Ssam 	if (c == tp->t_intrc || c == tp->t_quitc) {
6509578Ssam 		if ((tp->t_flags&NOFLSH) == 0)
6519578Ssam 			flushtty(tp, FREAD|FWRITE);
6529578Ssam 		ttyecho(c, tp);
6539578Ssam 		gsignal(tp->t_pgrp, c == tp->t_intrc ? SIGINT : SIGQUIT);
6549578Ssam 		goto endcase;
6559578Ssam 	}
6569578Ssam 
6579578Ssam 	/*
6589578Ssam 	 * Cbreak mode, don't process line editing
6599578Ssam 	 * characters; check high water mark for wakeup.
6609578Ssam 	 */
6619578Ssam 	if (t_flags&CBREAK) {
6629578Ssam 		if (tp->t_rawq.c_cc > TTYHOG) {
6637502Sroot 			if (tp->t_outq.c_cc < TTHIWAT(tp) &&
6647502Sroot 			    tp->t_line == NTTYDISC)
6657502Sroot 				(void) ttyoutput(CTRL(g), tp);
6667502Sroot 		} else if (putc(c, &tp->t_rawq) >= 0) {
6677502Sroot 			ttwakeup(tp);
6687502Sroot 			ttyecho(c, tp);
6697502Sroot 		}
6709578Ssam 		goto endcase;
6719578Ssam 	}
6729578Ssam 
6739578Ssam 	/*
6749578Ssam 	 * From here on down cooked mode character
6759578Ssam 	 * processing takes place.
6769578Ssam 	 */
6779578Ssam 	if ((tp->t_state&TS_QUOT) &&
6789578Ssam 	    (c == tp->t_erase || c == tp->t_kill)) {
6799578Ssam 		ttyrub(unputc(&tp->t_rawq), tp);
6809578Ssam 		c |= 0200;
6819578Ssam 	}
6829578Ssam 	if (c == tp->t_erase) {
6839578Ssam 		if (tp->t_rawq.c_cc)
6849578Ssam 			ttyrub(unputc(&tp->t_rawq), tp);
6859578Ssam 		goto endcase;
6869578Ssam 	}
6879578Ssam 	if (c == tp->t_kill) {
6889578Ssam 		if (tp->t_flags&CRTKIL &&
6899578Ssam 		    tp->t_rawq.c_cc == tp->t_rocount) {
6909578Ssam 			while (tp->t_rawq.c_cc)
6919578Ssam 				ttyrub(unputc(&tp->t_rawq), tp);
6929578Ssam 		} else {
6939578Ssam 			ttyecho(c, tp);
6949578Ssam 			ttyecho('\n', tp);
6959578Ssam 			while (getc(&tp->t_rawq) > 0)
6969578Ssam 				;
6979578Ssam 			tp->t_rocount = 0;
6989578Ssam 		}
6999578Ssam 		tp->t_state &= ~TS_LOCAL;
7009578Ssam 		goto endcase;
7019578Ssam 	}
7029578Ssam 
7039578Ssam 	/*
7049578Ssam 	 * New line discipline,
7059578Ssam 	 * check word erase/reprint line.
7069578Ssam 	 */
7079578Ssam 	if (tp->t_line == NTTYDISC) {
7089578Ssam 		if (c == tp->t_werasc) {
7099578Ssam 			if (tp->t_rawq.c_cc == 0)
7109578Ssam 				goto endcase;
7119578Ssam 			do {
7129578Ssam 				c = unputc(&tp->t_rawq);
7139578Ssam 				if (c != ' ' && c != '\t')
7149578Ssam 					goto erasenb;
7159578Ssam 				ttyrub(c, tp);
7169578Ssam 			} while (tp->t_rawq.c_cc);
7179578Ssam 			goto endcase;
7189578Ssam 	erasenb:
7199578Ssam 			do {
7209578Ssam 				ttyrub(c, tp);
7219578Ssam 				if (tp->t_rawq.c_cc == 0)
7229578Ssam 					goto endcase;
7239578Ssam 				c = unputc(&tp->t_rawq);
7249578Ssam 			} while (c != ' ' && c != '\t');
7259578Ssam 			(void) putc(c, &tp->t_rawq);
7269578Ssam 			goto endcase;
7279578Ssam 		}
7289578Ssam 		if (c == tp->t_rprntc) {
7299578Ssam 			ttyretype(tp);
7309578Ssam 			goto endcase;
7319578Ssam 		}
7329578Ssam 	}
7339578Ssam 
7349578Ssam 	/*
7359578Ssam 	 * Check for input buffer overflow
7369578Ssam 	 */
7379578Ssam 	if (tp->t_rawq.c_cc+tp->t_canq.c_cc >= TTYHOG)
7389578Ssam 		goto endcase;
7399578Ssam 
7409578Ssam 	/*
7419578Ssam 	 * Put data char in q for user and
7429578Ssam 	 * wakeup on seeing a line delimiter.
7439578Ssam 	 */
7449578Ssam 	if (putc(c, &tp->t_rawq) >= 0) {
7459578Ssam 		if (tp->t_rawq.c_cc + tp->t_canq.c_cc == TTYHOG
7469578Ssam 		    && tp->t_line == NTTYDISC)
7479578Ssam 			(void) ttyoutput(CTRL(g), tp);
7489578Ssam 		if (ttbreakc(c, tp)) {
7499578Ssam 			tp->t_rocount = 0;
7509578Ssam 			catq(&tp->t_rawq, &tp->t_canq);
7517502Sroot 			ttwakeup(tp);
7529578Ssam 		} else if (tp->t_rocount++ == 0)
7539578Ssam 			tp->t_rocol = tp->t_col;
7549578Ssam 		tp->t_state &= ~TS_QUOT;
7559578Ssam 		if (c == '\\')
7569578Ssam 			tp->t_state |= TS_QUOT;
7579578Ssam 		if (tp->t_state&TS_ERASE) {
7589578Ssam 			tp->t_state &= ~TS_ERASE;
7599578Ssam 			(void) ttyoutput('/', tp);
7609578Ssam 		}
7619578Ssam 		i = tp->t_col;
7627502Sroot 		ttyecho(c, tp);
7639578Ssam 		if (c == tp->t_eofc && tp->t_flags&ECHO) {
7649578Ssam 			i = MIN(2, tp->t_col - i);
7659578Ssam 			while (i > 0) {
7669578Ssam 				(void) ttyoutput('\b', tp);
7679578Ssam 				i--;
7689578Ssam 			}
7699578Ssam 		}
7707502Sroot 	}
7719578Ssam 
7729578Ssam endcase:
7739578Ssam 	/*
7749578Ssam 	 * If DEC-style start/stop is enabled don't restart
7759578Ssam 	 * output until seeing the start character.
7769578Ssam 	 */
7779578Ssam 	if (tp->t_flags&DECCTQ && tp->t_state&TS_TTSTOP &&
7789578Ssam 	    tp->t_startc != tp->t_stopc)
7797502Sroot 		return;
7809578Ssam 
7819578Ssam restartoutput:
7827502Sroot 	tp->t_state &= ~TS_TTSTOP;
7839578Ssam 	tp->t_flags &= ~FLUSHO;
7849578Ssam 
7859578Ssam startoutput:
7867502Sroot 	ttstart(tp);
7877502Sroot }
7887502Sroot 
7897502Sroot /*
7909578Ssam  * Put character on TTY output queue, adding delays,
7917502Sroot  * expanding tabs, and handling the CR/NL bit.
7929578Ssam  * This is called both from the top half for output,
7939578Ssam  * and from interrupt level for echoing.
7947502Sroot  * The arguments are the character and the tty structure.
7957502Sroot  * Returns < 0 if putc succeeds, otherwise returns char to resend
7967502Sroot  * Must be recursive.
7977502Sroot  */
7987502Sroot ttyoutput(c, tp)
7997502Sroot 	register c;
8007502Sroot 	register struct tty *tp;
8017502Sroot {
8027502Sroot 	register char *colp;
8037502Sroot 	register ctype;
8047502Sroot 
8059578Ssam 	if (tp->t_flags & (RAW|LITOUT)) {
8069578Ssam 		if (tp->t_flags&FLUSHO)
8077502Sroot 			return (-1);
8087502Sroot 		if (putc(c, &tp->t_outq))
8097625Ssam 			return (c);
8107502Sroot 		tk_nout++;
8117502Sroot 		return (-1);
8127502Sroot 	}
8139578Ssam 
8147502Sroot 	/*
8159578Ssam 	 * Ignore EOT in normal mode to avoid
8169578Ssam 	 * hanging up certain terminals.
8177502Sroot 	 */
8187502Sroot 	c &= 0177;
8199578Ssam 	if (c == CEOT && (tp->t_flags&CBREAK) == 0)
8207502Sroot 		return (-1);
8217502Sroot 	/*
8227502Sroot 	 * Turn tabs to spaces as required
8237502Sroot 	 */
8249578Ssam 	if (c == '\t' && (tp->t_flags&TBDELAY) == XTABS) {
8257502Sroot 		register int s;
8267502Sroot 
8277502Sroot 		c = 8 - (tp->t_col&7);
8289578Ssam 		if ((tp->t_flags&FLUSHO) == 0) {
8297502Sroot 			s = spl5();		/* don't interrupt tabs */
8307502Sroot 			c -= b_to_q("        ", c, &tp->t_outq);
8317502Sroot 			tk_nout += c;
8327502Sroot 			splx(s);
8337502Sroot 		}
8347502Sroot 		tp->t_col += c;
8357502Sroot 		return (c ? -1 : '\t');
8367502Sroot 	}
8377502Sroot 	tk_nout++;
8387502Sroot 	/*
8397502Sroot 	 * for upper-case-only terminals,
8407502Sroot 	 * generate escapes.
8417502Sroot 	 */
8427502Sroot 	if (tp->t_flags&LCASE) {
8437502Sroot 		colp = "({)}!|^~'`";
8447625Ssam 		while (*colp++)
8457625Ssam 			if (c == *colp++) {
8467502Sroot 				if (ttyoutput('\\', tp) >= 0)
8477502Sroot 					return (c);
8487502Sroot 				c = colp[-2];
8497502Sroot 				break;
8507502Sroot 			}
8519578Ssam 		if ('A' <= c && c <= 'Z') {
8527502Sroot 			if (ttyoutput('\\', tp) >= 0)
8537502Sroot 				return (c);
8549578Ssam 		} else if ('a' <= c && c <= 'z')
8557502Sroot 			c += 'A' - 'a';
8567502Sroot 	}
8579578Ssam 
8587502Sroot 	/*
8597502Sroot 	 * turn <nl> to <cr><lf> if desired.
8607502Sroot 	 */
8619578Ssam 	if (c == '\n' && tp->t_flags&CRMOD)
8627502Sroot 		if (ttyoutput('\r', tp) >= 0)
8637502Sroot 			return (c);
8649578Ssam 	if (c == '~' && tp->t_flags&TILDE)
8657502Sroot 		c = '`';
8669578Ssam 	if ((tp->t_flags&FLUSHO) == 0 && putc(c, &tp->t_outq))
8677502Sroot 		return (c);
8687502Sroot 	/*
8697502Sroot 	 * Calculate delays.
8707502Sroot 	 * The numbers here represent clock ticks
8717502Sroot 	 * and are not necessarily optimal for all terminals.
8727502Sroot 	 * The delays are indicated by characters above 0200.
8737502Sroot 	 * In raw mode there are no delays and the
8747502Sroot 	 * transmission path is 8 bits wide.
8759578Ssam 	 *
8769578Ssam 	 * SHOULD JUST ALLOW USER TO SPECIFY DELAYS
8777502Sroot 	 */
8787502Sroot 	colp = &tp->t_col;
8797502Sroot 	ctype = partab[c];
8807502Sroot 	c = 0;
8817502Sroot 	switch (ctype&077) {
8827502Sroot 
8837502Sroot 	case ORDINARY:
8847502Sroot 		(*colp)++;
8857502Sroot 
8867502Sroot 	case CONTROL:
8877502Sroot 		break;
8887502Sroot 
8897502Sroot 	case BACKSPACE:
8907502Sroot 		if (*colp)
8917502Sroot 			(*colp)--;
8927502Sroot 		break;
8937502Sroot 
8947502Sroot 	case NEWLINE:
8957502Sroot 		ctype = (tp->t_flags >> 8) & 03;
8967625Ssam 		if (ctype == 1) { /* tty 37 */
8977502Sroot 			if (*colp)
8987502Sroot 				c = max(((unsigned)*colp>>4) + 3, (unsigned)6);
8999578Ssam 		} else if (ctype == 2) /* vt05 */
9007502Sroot 			c = 6;
9017502Sroot 		*colp = 0;
9027502Sroot 		break;
9037502Sroot 
9047502Sroot 	case TAB:
9057502Sroot 		ctype = (tp->t_flags >> 10) & 03;
9067625Ssam 		if (ctype == 1) { /* tty 37 */
9077502Sroot 			c = 1 - (*colp | ~07);
9087625Ssam 			if (c < 5)
9097502Sroot 				c = 0;
9107502Sroot 		}
9117502Sroot 		*colp |= 07;
9127502Sroot 		(*colp)++;
9137502Sroot 		break;
9147502Sroot 
9157502Sroot 	case VTAB:
9169578Ssam 		if (tp->t_flags&VTDELAY) /* tty 37 */
9177502Sroot 			c = 0177;
9187502Sroot 		break;
9197502Sroot 
9207502Sroot 	case RETURN:
9217502Sroot 		ctype = (tp->t_flags >> 12) & 03;
9229578Ssam 		if (ctype == 1) /* tn 300 */
9237502Sroot 			c = 5;
9249578Ssam 		else if (ctype == 2) /* ti 700 */
9257502Sroot 			c = 10;
9269578Ssam 		else if (ctype == 3) { /* concept 100 */
9277502Sroot 			int i;
9289578Ssam 
9297502Sroot 			if ((i = *colp) >= 0)
9309578Ssam 				for (; i < 9; i++)
9317502Sroot 					(void) putc(0177, &tp->t_outq);
9327502Sroot 		}
9337502Sroot 		*colp = 0;
9347502Sroot 	}
9359578Ssam 	if (c && (tp->t_flags&FLUSHO) == 0)
9367502Sroot 		(void) putc(c|0200, &tp->t_outq);
9377502Sroot 	return (-1);
9387502Sroot }
9397502Sroot 
9407502Sroot /*
9417502Sroot  * Called from device's read routine after it has
9427502Sroot  * calculated the tty-structure given as argument.
9437502Sroot  */
9447722Swnj ttread(tp, uio)
9457625Ssam 	register struct tty *tp;
9467722Swnj 	struct uio *uio;
9477502Sroot {
9487502Sroot 	register struct clist *qp;
9499578Ssam 	register c, t_flags;
9509578Ssam 	int first, error = 0;
9517502Sroot 
9527502Sroot 	if ((tp->t_state&TS_CARR_ON)==0)
9538520Sroot 		return (EIO);
9547502Sroot loop:
9559578Ssam 	/*
9569578Ssam 	 * Take any pending input first.
9579578Ssam 	 */
9587502Sroot 	(void) spl5();
9599578Ssam 	if (tp->t_flags&PENDIN)
9607502Sroot 		ttypend(tp);
9617502Sroot 	(void) spl0();
9629578Ssam 
9639578Ssam 	/*
9649578Ssam 	 * Hang process if it's in the background.
9659578Ssam 	 */
9667502Sroot 	while (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) {
9677502Sroot 		if (u.u_signal[SIGTTIN] == SIG_IGN ||
9687502Sroot 		    u.u_signal[SIGTTIN] == SIG_HOLD ||
9697502Sroot /*
9707502Sroot 		    (u.u_procp->p_flag&SDETACH) ||
9717502Sroot */
9727502Sroot 		    u.u_procp->p_flag&SVFORK)
9738520Sroot 			return (EIO);
9747502Sroot 		gsignal(u.u_procp->p_pgrp, SIGTTIN);
9757502Sroot 		sleep((caddr_t)&lbolt, TTIPRI);
9767502Sroot 	}
9779578Ssam 	t_flags = tp->t_flags;
9789578Ssam 
9799578Ssam 	/*
9809578Ssam 	 * In raw mode take characters directly from the
9819578Ssam 	 * raw queue w/o processing.  Interlock against
9829578Ssam 	 * device interrupts when interrogating rawq.
9839578Ssam 	 */
9849578Ssam 	if (t_flags&RAW) {
9857502Sroot 		(void) spl5();
9867502Sroot 		if (tp->t_rawq.c_cc <= 0) {
9879578Ssam 			if ((tp->t_state&TS_CARR_ON) == 0 ||
9887502Sroot 			    (tp->t_state&TS_NBIO)) {
9897502Sroot 				(void) spl0();
9909578Ssam 				return (0);
9917502Sroot 			}
9927502Sroot 			sleep((caddr_t)&tp->t_rawq, TTIPRI);
9937502Sroot 			(void) spl0();
9947502Sroot 			goto loop;
9957502Sroot 		}
9967502Sroot 		(void) spl0();
9977722Swnj 		while (tp->t_rawq.c_cc && uio->uio_iovcnt) {
9988520Sroot 			error = passuc(getc(&tp->t_rawq), uio);
9998520Sroot 			if (error)
10007722Swnj 				break;
10017722Swnj 		}
10028520Sroot 		return (error);
10039578Ssam 	}
10049578Ssam 
10059578Ssam 	/*
10069578Ssam 	 * In cbreak mode use the rawq, otherwise
10079578Ssam 	 * take characters from the canonicalized q.
10089578Ssam 	 */
10099578Ssam 	qp = t_flags&CBREAK ? &tp->t_rawq : &tp->t_canq;
10109578Ssam 
10119578Ssam 	/*
10129578Ssam 	 * No input, sleep on rawq awaiting hardware
10139578Ssam 	 * receipt and notification.
10149578Ssam 	 */
10159578Ssam 	(void) spl5();
10169578Ssam 	if (qp->c_cc <= 0) {
10179578Ssam 		if ((tp->t_state&TS_CARR_ON) == 0 ||
10189578Ssam 		    (tp->t_state&TS_NBIO)) {
10197502Sroot 			(void) spl0();
10209578Ssam 			return (EWOULDBLOCK);
10217502Sroot 		}
10229578Ssam 		sleep((caddr_t)&tp->t_rawq, TTIPRI);
10237502Sroot 		(void) spl0();
10249578Ssam 		goto loop;
10259578Ssam 	}
10269578Ssam 	(void) spl0();
10279578Ssam 
10289578Ssam 	/*
10299578Ssam 	 * Input present, perform input mapping
10309578Ssam 	 * and processing (we're not in raw mode).
10319578Ssam 	 */
10329578Ssam 	first = 1;
10339578Ssam 	while ((c = getc(qp)) >= 0) {
10349578Ssam 		if (t_flags&CRMOD && c == '\r')
10359578Ssam 			c = '\n';
10369578Ssam 		/*
10379578Ssam 		 * Hack lower case simulation on
10389578Ssam 		 * upper case only terminals.
10399578Ssam 		 */
10409578Ssam 		if (t_flags&LCASE && c <= 0177)
10419578Ssam 			if (tp->t_state&TS_BKSL) {
10429578Ssam 				if (maptab[c])
10439578Ssam 					c = maptab[c];
10449578Ssam 				tp->t_state &= ~TS_BKSL;
10459578Ssam 			} else if (c >= 'A' && c <= 'Z')
10469578Ssam 				c += 'a' - 'A';
10479578Ssam 			else if (c == '\\') {
10489578Ssam 				tp->t_state |= TS_BKSL;
10499578Ssam 				continue;
10507502Sroot 			}
10519578Ssam 		/*
10529578Ssam 		 * Check for delayed suspend character.
10539578Ssam 		 */
10549578Ssam 		if (tp->t_line == NTTYDISC && c == tp->t_dsuspc) {
10559578Ssam 			gsignal(tp->t_pgrp, SIGTSTP);
10569578Ssam 			if (first) {
10579578Ssam 				sleep((caddr_t)&lbolt, TTIPRI);
10589578Ssam 				goto loop;
10599578Ssam 			}
10609578Ssam 			break;
10617502Sroot 		}
10629578Ssam 		/*
10639578Ssam 		 * Interpret EOF only in cooked mode.
10649578Ssam 		 */
10659578Ssam 		if (c == tp->t_eofc && (t_flags&CBREAK) == 0)
10669578Ssam 			break;
10679578Ssam 		/*
10689578Ssam 		 * Give user character.
10699578Ssam 		 */
10709578Ssam 		error = passuc(c & 0177, uio);
10719578Ssam 		if (error)
10729578Ssam 			break;
10739578Ssam 		if (uio->uio_iovcnt == 0)
10749578Ssam 			break;
10759578Ssam 		/*
10769578Ssam 		 * In cooked mode check for a "break character"
10779578Ssam 		 * marking the end of a "line of input".
10789578Ssam 		 */
10799578Ssam 		if ((t_flags&CBREAK) == 0 && ttbreakc(c, tp))
10809578Ssam 			break;
10819578Ssam 		first = 0;
10827502Sroot 	}
10839578Ssam 	tp->t_state &= ~TS_BKSL;
10849578Ssam 
10859578Ssam 	/*
10869578Ssam 	 * Look to unblock output now that (presumably)
10879578Ssam 	 * the input queue has gone down.
10889578Ssam 	 */
10897502Sroot 	if (tp->t_state&TS_TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) {
10909578Ssam 		if (putc(tp->t_startc, &tp->t_outq) == 0) {
10917502Sroot 			tp->t_state &= ~TS_TBLOCK;
10927502Sroot 			ttstart(tp);
10937502Sroot 		}
10947502Sroot 		tp->t_char = 0;
10957502Sroot 	}
10968520Sroot 	return (error);
10977502Sroot }
10987502Sroot 
10997502Sroot /*
11007502Sroot  * Called from the device's write routine after it has
11017502Sroot  * calculated the tty-structure given as argument.
11027502Sroot  */
11037822Sroot ttwrite(tp, uio)
11047625Ssam 	register struct tty *tp;
11059578Ssam 	register struct uio *uio;
11067502Sroot {
11077502Sroot 	register char *cp;
11089578Ssam 	register int cc, ce, c;
11099578Ssam 	int i, hiwat, cnt, error, s;
11107502Sroot 	char obuf[OBUFSIZ];
11117502Sroot 
11129578Ssam 	if ((tp->t_state&TS_CARR_ON) == 0)
11138520Sroot 		return (EIO);
11149578Ssam 	hiwat = TTHIWAT(tp);
11159578Ssam 	cnt = uio->uio_resid;
11169578Ssam 	error = 0;
11177502Sroot loop:
11189578Ssam 	/*
11199578Ssam 	 * Hang the process if it's in the background.
11209578Ssam 	 */
11217502Sroot 	while (u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp &&
11229578Ssam 	    (tp->t_flags&TOSTOP) && (u.u_procp->p_flag&SVFORK)==0 &&
11237502Sroot 	    u.u_signal[SIGTTOU] != SIG_IGN &&
11247502Sroot 	    u.u_signal[SIGTTOU] != SIG_HOLD
11257502Sroot /*
11267502Sroot 					     &&
11277502Sroot 	    (u.u_procp->p_flag&SDETACH)==0) {
11287502Sroot */
11297502Sroot 	    ) {
11307502Sroot 		gsignal(u.u_procp->p_pgrp, SIGTTOU);
11317502Sroot 		sleep((caddr_t)&lbolt, TTIPRI);
11327502Sroot 	}
11339578Ssam 
11349578Ssam 	/*
11359578Ssam 	 * Process the user's data in at most OBUFSIZ
11369578Ssam 	 * chunks.  Perform lower case simulation and
11379578Ssam 	 * similar hacks.  Keep track of high water
11389578Ssam 	 * mark, sleep on overflow awaiting device aid
11399578Ssam 	 * in acquiring new space.
11409578Ssam 	 */
11417822Sroot 	while (uio->uio_resid > 0) {
11429578Ssam 		/*
11439578Ssam 		 * Grab a hunk of data from the user.
11449578Ssam 		 */
11457822Sroot 		cc = uio->uio_iov->iov_len;
11467822Sroot 		if (cc == 0) {
11477822Sroot 			uio->uio_iovcnt--;
11487822Sroot 			uio->uio_iov++;
11497822Sroot 			if (uio->uio_iovcnt < 0)
11507822Sroot 				panic("ttwrite");
11517822Sroot 			continue;
11527822Sroot 		}
11537822Sroot 		if (cc > OBUFSIZ)
11547822Sroot 			cc = OBUFSIZ;
11557502Sroot 		cp = obuf;
11569578Ssam 		error = uiomove(cp, (unsigned)cc, UIO_WRITE, uio);
11578520Sroot 		if (error)
11587502Sroot 			break;
11597502Sroot 		if (tp->t_outq.c_cc > hiwat)
11607502Sroot 			goto ovhiwat;
11619578Ssam 		if (tp->t_flags&FLUSHO)
11627502Sroot 			continue;
11639578Ssam 		/*
11649578Ssam 		 * If we're mapping lower case or kludging tildes,
11659578Ssam 		 * then we've got to look at each character, so
11669578Ssam 		 * just feed the stuff to ttyoutput...
11679578Ssam 		 */
11689578Ssam 		if (tp->t_flags & (LCASE|TILDE)) {
11699578Ssam 			while (cc > 0) {
11707502Sroot 				c = *cp++;
11717502Sroot 				tp->t_rocount = 0;
11727625Ssam 				while ((c = ttyoutput(c, tp)) >= 0) {
11737502Sroot 					/* out of clists, wait a bit */
11747502Sroot 					ttstart(tp);
11757502Sroot 					sleep((caddr_t)&lbolt, TTOPRI);
11767502Sroot 					tp->t_rocount = 0;
11777502Sroot 				}
11787502Sroot 				--cc;
11797502Sroot 				if (tp->t_outq.c_cc > hiwat)
11807502Sroot 					goto ovhiwat;
11817502Sroot 			}
11827502Sroot 			continue;
11837502Sroot 		}
11849578Ssam 		/*
11859578Ssam 		 * If nothing fancy need be done, grab those characters we
11869578Ssam 		 * can handle without any of ttyoutput's processing and
11879578Ssam 		 * just transfer them to the output q.  For those chars
11889578Ssam 		 * which require special processing (as indicated by the
11899578Ssam 		 * bits in partab), call ttyoutput.  After processing
11909578Ssam 		 * a hunk of data, look for FLUSHO so ^O's will take effect
11919578Ssam 		 * immediately.
11929578Ssam 		 */
11939578Ssam 		while (cc > 0) {
11949578Ssam 			if (tp->t_flags & (RAW|LITOUT))
11957502Sroot 				ce = cc;
11967502Sroot 			else {
11979578Ssam 				ce = cc - scanc(cc, cp, partab, 077);
11989578Ssam 				/*
11999578Ssam 				 * If ce is zero, then we're processing
12009578Ssam 				 * a special character through ttyoutput.
12019578Ssam 				 */
12029578Ssam 				if (ce == 0) {
12037502Sroot 					tp->t_rocount = 0;
12047502Sroot 					if (ttyoutput(*cp, tp) >= 0) {
12059578Ssam 						/* no c-lists, wait a bit */
12067502Sroot 						ttstart(tp);
12077502Sroot 						sleep((caddr_t)&lbolt, TTOPRI);
12087502Sroot 						continue;
12097502Sroot 					}
12109578Ssam 					cp++, cc--;
12119578Ssam 					if (tp->t_flags&FLUSHO ||
12129578Ssam 					    tp->t_outq.c_cc > hiwat)
12137502Sroot 						goto ovhiwat;
12149578Ssam 					continue;
12157502Sroot 				}
12167502Sroot 			}
12179578Ssam 			/*
12189578Ssam 			 * A bunch of normal characters have been found,
12199578Ssam 			 * transfer them en masse to the output queue and
12209578Ssam 			 * continue processing at the top of the loop.
12219578Ssam 			 * If there are any further characters in this
12229578Ssam 			 * <= OBUFSIZ chunk, the first should be a character
12239578Ssam 			 * requiring special handling by ttyoutput.
12249578Ssam 			 */
12257502Sroot 			tp->t_rocount = 0;
12269578Ssam 			i = b_to_q(cp, ce, &tp->t_outq);
12279578Ssam 			ce -= i;
12289578Ssam 			tp->t_col += ce;
12299578Ssam 			cp += ce, cc -= ce, tk_nout += ce;
12309578Ssam 			if (i > 0) {
12319578Ssam 				/* out of c-lists, wait a bit */
12327502Sroot 				ttstart(tp);
12337502Sroot 				sleep((caddr_t)&lbolt, TTOPRI);
12347502Sroot 			}
12359578Ssam 			if (tp->t_flags&FLUSHO || tp->t_outq.c_cc > hiwat)
12367502Sroot 				goto ovhiwat;
12377502Sroot 		}
12387502Sroot 	}
12397502Sroot 	ttstart(tp);
12408520Sroot 	return (error);
12417502Sroot 
12427502Sroot ovhiwat:
12439578Ssam 	s = spl5();
12449578Ssam 	if (cc != 0) {
12459578Ssam 		uio->uio_iov->iov_base -= cc;
12469578Ssam 		uio->uio_iov->iov_len += cc;
12479578Ssam 		uio->uio_resid += cc;
12489578Ssam 		uio->uio_offset -= cc;
12499578Ssam 	}
12509578Ssam 	/*
12519578Ssam 	 * This can only occur if FLUSHO
12529578Ssam 	 * is also set in t_flags.
12539578Ssam 	 */
12547502Sroot 	if (tp->t_outq.c_cc <= hiwat) {
12559578Ssam 		splx(s);
12567502Sroot 		goto loop;
12577502Sroot 	}
12587502Sroot 	ttstart(tp);
12599578Ssam 	if (tp->t_state&TS_NBIO) {
12607822Sroot 		if (uio->uio_resid == cnt)
12618520Sroot 			return (EWOULDBLOCK);
12628520Sroot 		return (0);
12637502Sroot 	}
12647502Sroot 	tp->t_state |= TS_ASLEEP;
12657502Sroot 	sleep((caddr_t)&tp->t_outq, TTOPRI);
12669578Ssam 	splx(s);
12677502Sroot 	goto loop;
12687502Sroot }
12697502Sroot 
12707502Sroot /*
12717502Sroot  * Rubout one character from the rawq of tp
12727502Sroot  * as cleanly as possible.
12737502Sroot  */
12747502Sroot ttyrub(c, tp)
12757625Ssam 	register c;
12767625Ssam 	register struct tty *tp;
12777502Sroot {
12787502Sroot 	register char *cp;
12797502Sroot 	register int savecol;
12807502Sroot 	int s;
12817502Sroot 	char *nextc();
12827502Sroot 
12839578Ssam 	if ((tp->t_flags&ECHO) == 0)
12847502Sroot 		return;
12859578Ssam 	tp->t_flags &= ~FLUSHO;
12867502Sroot 	c &= 0377;
12879578Ssam 	if (tp->t_flags&CRTBS) {
12887502Sroot 		if (tp->t_rocount == 0) {
12897502Sroot 			/*
12907502Sroot 			 * Screwed by ttwrite; retype
12917502Sroot 			 */
12927502Sroot 			ttyretype(tp);
12937502Sroot 			return;
12947502Sroot 		}
12959578Ssam 		if (c == ('\t'|0200) || c == ('\n'|0200))
12967502Sroot 			ttyrubo(tp, 2);
12979578Ssam 		else switch (partab[c&=0177]&0177) {
12987502Sroot 
12997502Sroot 		case ORDINARY:
13007502Sroot 			if (tp->t_flags&LCASE && c >= 'A' && c <= 'Z')
13017502Sroot 				ttyrubo(tp, 2);
13027502Sroot 			else
13037502Sroot 				ttyrubo(tp, 1);
13047502Sroot 			break;
13057502Sroot 
13067502Sroot 		case VTAB:
13077502Sroot 		case BACKSPACE:
13087502Sroot 		case CONTROL:
13097502Sroot 		case RETURN:
13109578Ssam 			if (tp->t_flags&CTLECH)
13117502Sroot 				ttyrubo(tp, 2);
13127502Sroot 			break;
13137502Sroot 
13147502Sroot 		case TAB:
13157502Sroot 			if (tp->t_rocount < tp->t_rawq.c_cc) {
13167502Sroot 				ttyretype(tp);
13177502Sroot 				return;
13187502Sroot 			}
13197502Sroot 			s = spl5();
13207502Sroot 			savecol = tp->t_col;
13219578Ssam 			tp->t_state |= TS_CNTTB;
13229578Ssam 			tp->t_flags |= FLUSHO;
13237502Sroot 			tp->t_col = tp->t_rocol;
13249578Ssam 			cp = tp->t_rawq.c_cf;
13259578Ssam 			for (; cp; cp = nextc(&tp->t_rawq, cp))
13267502Sroot 				ttyecho(*cp, tp);
13279578Ssam 			tp->t_flags &= ~FLUSHO;
13289578Ssam 			tp->t_state &= ~TS_CNTTB;
13297502Sroot 			splx(s);
13307502Sroot 			/*
13317502Sroot 			 * savecol will now be length of the tab
13327502Sroot 			 */
13337502Sroot 			savecol -= tp->t_col;
13347502Sroot 			tp->t_col += savecol;
13357502Sroot 			if (savecol > 8)
13367502Sroot 				savecol = 8;		/* overflow screw */
13377502Sroot 			while (--savecol >= 0)
13387502Sroot 				(void) ttyoutput('\b', tp);
13397502Sroot 			break;
13407502Sroot 
13417502Sroot 		default:
13427502Sroot 			panic("ttyrub");
13437502Sroot 		}
13449578Ssam 	} else if (tp->t_flags&PRTERA) {
13459578Ssam 		if ((tp->t_state&TS_ERASE) == 0) {
13467502Sroot 			(void) ttyoutput('\\', tp);
13479578Ssam 			tp->t_state |= TS_ERASE;
13487502Sroot 		}
13497502Sroot 		ttyecho(c, tp);
13507502Sroot 	} else
13517502Sroot 		ttyecho(tp->t_erase, tp);
13527502Sroot 	tp->t_rocount--;
13537502Sroot }
13547502Sroot 
13557502Sroot /*
13567502Sroot  * Crt back over cnt chars perhaps
13577502Sroot  * erasing them.
13587502Sroot  */
13597502Sroot ttyrubo(tp, cnt)
13607625Ssam 	register struct tty *tp;
13617625Ssam 	int cnt;
13627502Sroot {
13639578Ssam 	register char *rubostring = tp->t_flags&CRTERA ? "\b \b" : "\b";
13647502Sroot 
13657502Sroot 	while (--cnt >= 0)
13669578Ssam 		ttyout(rubostring, tp);
13677502Sroot }
13687502Sroot 
13697502Sroot /*
13707502Sroot  * Reprint the rawq line.
13717502Sroot  * We assume c_cc has already been checked.
13727502Sroot  */
13737502Sroot ttyretype(tp)
13747625Ssam 	register struct tty *tp;
13757502Sroot {
13767502Sroot 	register char *cp;
13777502Sroot 	char *nextc();
13787502Sroot 	int s;
13797502Sroot 
13809578Ssam 	if (tp->t_rprntc != 0377)
13819578Ssam 		ttyecho(tp->t_rprntc, tp);
13827502Sroot 	(void) ttyoutput('\n', tp);
13837502Sroot 	s = spl5();
13847502Sroot 	for (cp = tp->t_canq.c_cf; cp; cp = nextc(&tp->t_canq, cp))
13857502Sroot 		ttyecho(*cp, tp);
13867502Sroot 	for (cp = tp->t_rawq.c_cf; cp; cp = nextc(&tp->t_rawq, cp))
13877502Sroot 		ttyecho(*cp, tp);
13889578Ssam 	tp->t_state &= ~TS_ERASE;
13897502Sroot 	splx(s);
13907502Sroot 	tp->t_rocount = tp->t_rawq.c_cc;
13917502Sroot 	tp->t_rocol = 0;
13927502Sroot }
13937502Sroot 
13947502Sroot /*
13957502Sroot  * Echo a typed character to the terminal
13967502Sroot  */
13977502Sroot ttyecho(c, tp)
13987625Ssam 	register c;
13997625Ssam 	register struct tty *tp;
14007502Sroot {
14017502Sroot 
14029578Ssam 	if ((tp->t_state&TS_CNTTB) == 0)
14039578Ssam 		tp->t_flags &= ~FLUSHO;
14047502Sroot 	if ((tp->t_flags&ECHO) == 0)
14057502Sroot 		return;
14067502Sroot 	c &= 0377;
14077502Sroot 	if (tp->t_flags&RAW) {
14087502Sroot 		(void) ttyoutput(c, tp);
14097502Sroot 		return;
14107502Sroot 	}
14117502Sroot 	if (c == '\r' && tp->t_flags&CRMOD)
14127502Sroot 		c = '\n';
14139578Ssam 	if (tp->t_flags&CTLECH) {
14147502Sroot 		if ((c&0177) <= 037 && c!='\t' && c!='\n' || (c&0177)==0177) {
14157502Sroot 			(void) ttyoutput('^', tp);
14167502Sroot 			c &= 0177;
14177502Sroot 			if (c == 0177)
14187502Sroot 				c = '?';
14197502Sroot 			else if (tp->t_flags&LCASE)
14207502Sroot 				c += 'a' - 1;
14217502Sroot 			else
14227502Sroot 				c += 'A' - 1;
14237502Sroot 		}
14247502Sroot 	}
14257502Sroot 	if ((tp->t_flags&LCASE) && (c >= 'A' && c <= 'Z'))
14267502Sroot 		c += 'a' - 'A';
14279578Ssam 	(void) ttyoutput(c&0177, tp);
14287502Sroot }
14297502Sroot 
14307502Sroot /*
14317502Sroot  * Is c a break char for tp?
14327502Sroot  */
14337502Sroot ttbreakc(c, tp)
14347625Ssam 	register c;
14357625Ssam 	register struct tty *tp;
14367502Sroot {
14379578Ssam 	return (c == '\n' || c == tp->t_eofc || c == tp->t_brkc ||
14387502Sroot 		c == '\r' && (tp->t_flags&CRMOD));
14397502Sroot }
14407502Sroot 
14417502Sroot /*
14427502Sroot  * send string cp to tp
14437502Sroot  */
14447502Sroot ttyout(cp, tp)
14457625Ssam 	register char *cp;
14467625Ssam 	register struct tty *tp;
14477502Sroot {
14487502Sroot 	register char c;
14497502Sroot 
14507502Sroot 	while (c = *cp++)
14517502Sroot 		(void) ttyoutput(c, tp);
14527502Sroot }
14537502Sroot 
14547502Sroot ttwakeup(tp)
14557502Sroot 	struct tty *tp;
14567502Sroot {
14577502Sroot 
14587502Sroot 	if (tp->t_rsel) {
14597502Sroot 		selwakeup(tp->t_rsel, tp->t_state&TS_RCOLL);
14607502Sroot 		tp->t_state &= ~TS_RCOLL;
14617502Sroot 		tp->t_rsel = 0;
14627502Sroot 	}
14637502Sroot 	wakeup((caddr_t)&tp->t_rawq);
14647502Sroot }
14657502Sroot 
14669578Ssam #ifndef vax
14679578Ssam scanc(size, cp, table, mask)
14689578Ssam 	register int size;
14699578Ssam 	register char *cp, table[];
14709578Ssam 	register int mask;
14717502Sroot {
14729578Ssam 	register int i = 0;
14737502Sroot 
14749578Ssam 	while ((table[*(u_char *)(cp + i)]&mask) == 0 && i < size)
14759578Ssam 		i++;
14769578Ssam 	return (i);
14777502Sroot }
14789578Ssam #endif
1479