xref: /csrg-svn/sys/kern/tty.c (revision 10851)
1*10851Ssam /*	tty.c	4.40	83/02/10	*/
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 {
1189859Ssam 	int s;
11939Sbill 
1209859Ssam 	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);
1289859Ssam 	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 
275*10851Ssam 		if (t >= nldisp)
276*10851Ssam 			return (ENXIO);
2778556Sroot 		s = spl5();
27839Sbill 		if (tp->t_line)
27939Sbill 			(*linesw[tp->t_line].l_close)(tp);
28039Sbill 		if (t)
2818556Sroot 			error = (*linesw[t].l_open)(dev, tp);
2828556Sroot 		splx(s);
283*10851Ssam 		if (error) {
284*10851Ssam 			s = spl5();
285*10851Ssam 			if (tp->t_line)
286*10851Ssam 				(void) (*linesw[tp->t_line].l_open)(dev, tp);
287*10851Ssam 			splx(s);
2888556Sroot 			return (error);
289*10851Ssam 		}
2908556Sroot 		tp->t_line = t;
29139Sbill 		break;
2927625Ssam 	}
29339Sbill 
2948556Sroot 	/* prevent more opens on channel */
2955614Swnj 	case TIOCEXCL:
2965614Swnj 		tp->t_state |= TS_XCLUDE;
2975614Swnj 		break;
2985614Swnj 
2995614Swnj 	case TIOCNXCL:
3005614Swnj 		tp->t_state &= ~TS_XCLUDE;
3015614Swnj 		break;
3025614Swnj 
3039624Ssam 	case TIOCSET:
3049624Ssam 	case TIOCBIS: {
3059624Ssam 		u_long newflags = *(u_long *)data;
3067625Ssam 
3079624Ssam 		s = spl5();
3089624Ssam 		if (tp->t_flags&RAW || newflags&RAW)
3094484Swnj 			wflushtty(tp);
3109624Ssam 		else if ((tp->t_flags&CBREAK) != (newflags&CBREAK))
3119624Ssam 			if (newflags&CBREAK) {
3129624Ssam 				struct clist tq;
3139624Ssam 
3144484Swnj 				catq(&tp->t_rawq, &tp->t_canq);
3154484Swnj 				tq = tp->t_rawq;
3164484Swnj 				tp->t_rawq = tp->t_canq;
3174484Swnj 				tp->t_canq = tq;
3184484Swnj 			} else {
3199578Ssam 				tp->t_flags |= PENDIN;
3204484Swnj 				ttwakeup(tp);
321174Sbill 			}
3229624Ssam 		if (com == TIOCSET)
3239624Ssam 			tp->t_flags = newflags;
3249624Ssam 		else
3259624Ssam 			tp->t_flags |= newflags;
3269578Ssam 		if (tp->t_flags&RAW) {
3275408Swnj 			tp->t_state &= ~TS_TTSTOP;
3283941Sbugs 			ttstart(tp);
3293941Sbugs 		}
3309624Ssam 		splx(s);
33139Sbill 		break;
3327625Ssam 	}
33339Sbill 
3349624Ssam 	case TIOCBIC: {
3359624Ssam 		u_long newflags = *(long *)data;
3367625Ssam 
3379624Ssam 		if (tp->t_flags&RAW)
3389624Ssam 			wflushtty(tp);
3399624Ssam 		else if ((tp->t_flags&CBREAK) != (CBREAK&~newflags))
3409624Ssam 			if (newflags&CBREAK) {
3419624Ssam 				tp->t_flags |= PENDIN;
3429624Ssam 				ttwakeup(tp);
3439624Ssam 			} else {
3449624Ssam 				struct clist tq;
3459624Ssam 
3469624Ssam 				catq(&tp->t_rawq, &tp->t_canq);
3479624Ssam 				tq = tp->t_rawq;
3489624Ssam 				tp->t_rawq = tp->t_canq;
3499624Ssam 				tp->t_canq = tq;
3509624Ssam 			}
3519624Ssam 		if (tp->t_flags&RAW) {
3529624Ssam 			tp->t_state &= ~TS_TTSTOP;
3539624Ssam 			ttstart(tp);
3549624Ssam 		}
3559624Ssam 		splx(s);
35639Sbill 		break;
3577625Ssam 	}
35839Sbill 
3599624Ssam 	case TIOCGET:
3609624Ssam 		*(long *)data = tp->t_flags;
3619624Ssam 		break;
3629624Ssam 
3639624Ssam 	case TIOCCGET:
3649624Ssam 		bcopy((caddr_t)&tp->t_chars, data, sizeof (struct ttychars));
3659624Ssam 		break;
3669624Ssam 
3679624Ssam 	case TIOCCSET:
3689624Ssam 		bcopy(data, (caddr_t)&tp->t_chars, sizeof (struct ttychars));
3699624Ssam 		break;
3709624Ssam 
3718556Sroot 	/* hang up line on last close */
37239Sbill 	case TIOCHPCL:
3735408Swnj 		tp->t_state |= TS_HUPCLS;
37439Sbill 		break;
37539Sbill 
3763942Sbugs 	case TIOCFLUSH: {
3777625Ssam 		register int flags = *(int *)data;
3787625Ssam 
3797625Ssam 		if (flags == 0)
3803942Sbugs 			flags = FREAD|FWRITE;
3817625Ssam 		else
3827625Ssam 			flags &= FREAD|FWRITE;
3833942Sbugs 		flushtty(tp, flags);
38439Sbill 		break;
3853944Sbugs 	}
38639Sbill 
3878556Sroot 	/* return number of characters immediately available */
3887625Ssam 	case FIONREAD:
3897625Ssam 		*(off_t *)data = ttnread(tp);
390174Sbill 		break;
391174Sbill 
3928589Sroot 	case TIOCSTOP:
3938589Sroot 		s = spl5();
3949578Ssam 		if ((tp->t_state&TS_TTSTOP) == 0) {
3955573Swnj 			tp->t_state |= TS_TTSTOP;
3965573Swnj 			(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
3975573Swnj 		}
3987625Ssam 		splx(s);
3995573Swnj 		break;
4005573Swnj 
4018589Sroot 	case TIOCSTART:
4028589Sroot 		s = spl5();
4039578Ssam 		if ((tp->t_state&TS_TTSTOP) || (tp->t_flags&FLUSHO)) {
4045573Swnj 			tp->t_state &= ~TS_TTSTOP;
4059578Ssam 			tp->t_flags &= ~FLUSHO;
4065573Swnj 			ttstart(tp);
4075573Swnj 		}
4087625Ssam 		splx(s);
4095573Swnj 		break;
4105573Swnj 
4119325Ssam 	/*
4129325Ssam 	 * Simulate typing of a character at the terminal.
4139325Ssam 	 */
4149325Ssam 	case TIOCSTI:
4159325Ssam 		if (u.u_uid && u.u_ttyp != tp)
4169325Ssam 			return (EACCES);
4179578Ssam 		(*linesw[tp->t_line].l_rint)(*(char *)data, tp);
4189325Ssam 		break;
4199325Ssam 
42039Sbill 	default:
4219624Ssam #ifndef NOCOMPAT
4229624Ssam 		return (ottioctl(tp, com, data, flag));
4239624Ssam #else
4248556Sroot 		return (-1);
4259624Ssam #endif
42639Sbill 	}
4278556Sroot 	return (0);
42839Sbill }
4294484Swnj 
4304484Swnj ttnread(tp)
4314484Swnj 	struct tty *tp;
4324484Swnj {
4334484Swnj 	int nread = 0;
4344484Swnj 
4359578Ssam 	if (tp->t_flags & PENDIN)
4364484Swnj 		ttypend(tp);
4374484Swnj 	nread = tp->t_canq.c_cc;
4384484Swnj 	if (tp->t_flags & (RAW|CBREAK))
4394484Swnj 		nread += tp->t_rawq.c_cc;
4404484Swnj 	return (nread);
4414484Swnj }
4424484Swnj 
4435408Swnj ttselect(dev, rw)
4444484Swnj 	dev_t dev;
4455408Swnj 	int rw;
4464484Swnj {
4474484Swnj 	register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)];
4484484Swnj 	int nread;
4495408Swnj 	int s = spl5();
4504484Swnj 
4515408Swnj 	switch (rw) {
4524484Swnj 
4534484Swnj 	case FREAD:
4544484Swnj 		nread = ttnread(tp);
4554484Swnj 		if (nread > 0)
4565408Swnj 			goto win;
4574938Swnj 		if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait)
4585408Swnj 			tp->t_state |= TS_RCOLL;
4594484Swnj 		else
4604484Swnj 			tp->t_rsel = u.u_procp;
4615408Swnj 		break;
4624484Swnj 
4635408Swnj 	case FWRITE:
4645408Swnj 		if (tp->t_outq.c_cc <= TTLOWAT(tp))
4655408Swnj 			goto win;
4665408Swnj 		if (tp->t_wsel && tp->t_wsel->p_wchan == (caddr_t)&selwait)
4675408Swnj 			tp->t_state |= TS_WCOLL;
4685408Swnj 		else
4695408Swnj 			tp->t_wsel = u.u_procp;
4705408Swnj 		break;
4714484Swnj 	}
4725408Swnj 	splx(s);
4735408Swnj 	return (0);
4745408Swnj win:
4755408Swnj 	splx(s);
4765408Swnj 	return (1);
4774484Swnj }
4787436Skre 
4797502Sroot /*
4809578Ssam  * Establish a process group for distribution of
4817502Sroot  * quits and interrupts from the tty.
4827502Sroot  */
4837502Sroot ttyopen(dev, tp)
4847625Ssam 	dev_t dev;
4857625Ssam 	register struct tty *tp;
4867502Sroot {
4877502Sroot 	register struct proc *pp;
4887502Sroot 
4897502Sroot 	pp = u.u_procp;
4907502Sroot 	tp->t_dev = dev;
4917625Ssam 	if (pp->p_pgrp == 0) {
4927502Sroot 		u.u_ttyp = tp;
4937502Sroot 		u.u_ttyd = dev;
4947502Sroot 		if (tp->t_pgrp == 0)
4957502Sroot 			tp->t_pgrp = pp->p_pid;
4967502Sroot 		pp->p_pgrp = tp->t_pgrp;
4977502Sroot 	}
4987502Sroot 	tp->t_state &= ~TS_WOPEN;
4997502Sroot 	tp->t_state |= TS_ISOPEN;
5007502Sroot 	if (tp->t_line != NTTYDISC)
5017502Sroot 		wflushtty(tp);
5028556Sroot 	return (0);
5037502Sroot }
5047502Sroot 
5057502Sroot /*
5067502Sroot  * clean tp on last close
5077502Sroot  */
5087502Sroot ttyclose(tp)
5097625Ssam 	register struct tty *tp;
5107502Sroot {
5117502Sroot 
5127502Sroot 	if (tp->t_line) {
5137502Sroot 		wflushtty(tp);
5147502Sroot 		tp->t_line = 0;
5157502Sroot 		return;
5167502Sroot 	}
5177502Sroot 	tp->t_pgrp = 0;
5187502Sroot 	wflushtty(tp);
5197502Sroot 	tp->t_state = 0;
5207502Sroot }
5217502Sroot 
5227502Sroot /*
5237502Sroot  * reinput pending characters after state switch
5247502Sroot  * call at spl5().
5257502Sroot  */
5267502Sroot ttypend(tp)
5277625Ssam 	register struct tty *tp;
5287502Sroot {
5297502Sroot 	struct clist tq;
5307502Sroot 	register c;
5317502Sroot 
5329578Ssam 	tp->t_flags &= ~PENDIN;
5339578Ssam 	tp->t_state |= TS_TYPEN;
5347502Sroot 	tq = tp->t_rawq;
5357502Sroot 	tp->t_rawq.c_cc = 0;
5367502Sroot 	tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0;
5377502Sroot 	while ((c = getc(&tq)) >= 0)
5387502Sroot 		ttyinput(c, tp);
5399578Ssam 	tp->t_state &= ~TS_TYPEN;
5407502Sroot }
5417502Sroot 
5427502Sroot /*
5439578Ssam  * Place a character on raw TTY input queue,
5449578Ssam  * putting in delimiters and waking up top
5459578Ssam  * half as needed.  Also echo if required.
5469578Ssam  * The arguments are the character and the
5479578Ssam  * appropriate tty structure.
5487502Sroot  */
5497502Sroot ttyinput(c, tp)
5507625Ssam 	register c;
5517625Ssam 	register struct tty *tp;
5527502Sroot {
5539578Ssam 	register int t_flags = tp->t_flags;
5547502Sroot 	int i;
5557502Sroot 
5569578Ssam 	/*
5579578Ssam 	 * If input is pending take it first.
5589578Ssam 	 */
5599578Ssam 	if (t_flags&PENDIN)
5607502Sroot 		ttypend(tp);
5617502Sroot 	tk_nin++;
5627502Sroot 	c &= 0377;
5639578Ssam 
5649578Ssam 	/*
5659578Ssam 	 * In tandem mode, check high water mark.
5669578Ssam 	 */
5677502Sroot 	if (t_flags&TANDEM)
5687502Sroot 		ttyblock(tp);
5699578Ssam 
5709578Ssam 	if (t_flags&RAW) {
5719578Ssam 		/*
5729578Ssam 		 * Raw mode, just put character
5739578Ssam 		 * in input q w/o interpretation.
5749578Ssam 		 */
5759578Ssam 		if (tp->t_rawq.c_cc > TTYHOG)
5769578Ssam 			flushtty(tp, FREAD|FWRITE);
5779578Ssam 		else {
5789578Ssam 			if (putc(c, &tp->t_rawq) >= 0)
5799578Ssam 				ttwakeup(tp);
5809578Ssam 			ttyecho(c, tp);
5817502Sroot 		}
5829578Ssam 		goto endcase;
5839578Ssam 	}
5849578Ssam 
5859578Ssam 	/*
5869578Ssam 	 * Ignore any high bit added during
5879578Ssam 	 * previous ttyinput processing.
5889578Ssam 	 */
5899578Ssam 	if ((tp->t_state&TS_TYPEN) == 0)
5909578Ssam 		c &= 0177;
5919578Ssam 	/*
5929578Ssam 	 * Check for literal nexting very first
5939578Ssam 	 */
5949578Ssam 	if (tp->t_state&TS_LNCH) {
5959578Ssam 		c |= 0200;
5969578Ssam 		tp->t_state &= ~TS_LNCH;
5979578Ssam 	}
5989578Ssam 
5999578Ssam 	/*
6009578Ssam 	 * Scan for special characters.  This code
6019578Ssam 	 * is really just a big case statement with
6029578Ssam 	 * non-constant cases.  The bottom of the
6039578Ssam 	 * case statement is labeled ``endcase'', so goto
6049578Ssam 	 * it after a case match, or similar.
6059578Ssam 	 */
6069578Ssam 	if (tp->t_line == NTTYDISC) {
6079578Ssam 		if (c == tp->t_lnextc) {
6087502Sroot 			if (tp->t_flags&ECHO)
6097502Sroot 				ttyout("^\b", tp);
6109578Ssam 			tp->t_state |= TS_LNCH;
6119578Ssam 			goto endcase;
6129578Ssam 		}
6139578Ssam 		if (c == tp->t_flushc) {
6149578Ssam 			if (tp->t_flags&FLUSHO)
6159578Ssam 				tp->t_flags &= ~FLUSHO;
6167502Sroot 			else {
6177502Sroot 				flushtty(tp, FWRITE);
6187502Sroot 				ttyecho(c, tp);
6199578Ssam 				if (tp->t_rawq.c_cc + tp->t_canq.c_cc)
6207502Sroot 					ttyretype(tp);
6219578Ssam 				tp->t_flags |= FLUSHO;
6227502Sroot 			}
6239578Ssam 			goto startoutput;
6249578Ssam 		}
6259578Ssam 		if (c == tp->t_suspc) {
6269578Ssam 			if ((tp->t_flags&NOFLSH) == 0)
6279578Ssam 				flushtty(tp, FREAD);
6289578Ssam 			ttyecho(c, tp);
6299578Ssam 			gsignal(tp->t_pgrp, SIGTSTP);
6309578Ssam 			goto endcase;
6319578Ssam 		}
6329578Ssam 	}
6339578Ssam 
6349578Ssam 	/*
6359578Ssam 	 * Handle start/stop characters.
6369578Ssam 	 */
6379578Ssam 	if (c == tp->t_stopc) {
6389578Ssam 		if ((tp->t_state&TS_TTSTOP) == 0) {
6399578Ssam 			tp->t_state |= TS_TTSTOP;
6409578Ssam 			(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
6417502Sroot 			return;
6429578Ssam 		}
6439578Ssam 		if (c != tp->t_startc)
6449578Ssam 			return;
6459578Ssam 		goto endcase;
6469578Ssam 	}
6479578Ssam 	if (c == tp->t_startc)
6489578Ssam 		goto restartoutput;
6499578Ssam 
6509578Ssam 	/*
6519578Ssam 	 * Look for interrupt/quit chars.
6529578Ssam 	 */
6539578Ssam 	if (c == tp->t_intrc || c == tp->t_quitc) {
6549578Ssam 		if ((tp->t_flags&NOFLSH) == 0)
6559578Ssam 			flushtty(tp, FREAD|FWRITE);
6569578Ssam 		ttyecho(c, tp);
6579578Ssam 		gsignal(tp->t_pgrp, c == tp->t_intrc ? SIGINT : SIGQUIT);
6589578Ssam 		goto endcase;
6599578Ssam 	}
6609578Ssam 
6619578Ssam 	/*
6629578Ssam 	 * Cbreak mode, don't process line editing
6639578Ssam 	 * characters; check high water mark for wakeup.
6649578Ssam 	 */
6659578Ssam 	if (t_flags&CBREAK) {
6669578Ssam 		if (tp->t_rawq.c_cc > TTYHOG) {
6677502Sroot 			if (tp->t_outq.c_cc < TTHIWAT(tp) &&
6687502Sroot 			    tp->t_line == NTTYDISC)
6697502Sroot 				(void) ttyoutput(CTRL(g), tp);
6707502Sroot 		} else if (putc(c, &tp->t_rawq) >= 0) {
6717502Sroot 			ttwakeup(tp);
6727502Sroot 			ttyecho(c, tp);
6737502Sroot 		}
6749578Ssam 		goto endcase;
6759578Ssam 	}
6769578Ssam 
6779578Ssam 	/*
6789578Ssam 	 * From here on down cooked mode character
6799578Ssam 	 * processing takes place.
6809578Ssam 	 */
6819578Ssam 	if ((tp->t_state&TS_QUOT) &&
6829578Ssam 	    (c == tp->t_erase || c == tp->t_kill)) {
6839578Ssam 		ttyrub(unputc(&tp->t_rawq), tp);
6849578Ssam 		c |= 0200;
6859578Ssam 	}
6869578Ssam 	if (c == tp->t_erase) {
6879578Ssam 		if (tp->t_rawq.c_cc)
6889578Ssam 			ttyrub(unputc(&tp->t_rawq), tp);
6899578Ssam 		goto endcase;
6909578Ssam 	}
6919578Ssam 	if (c == tp->t_kill) {
6929578Ssam 		if (tp->t_flags&CRTKIL &&
6939578Ssam 		    tp->t_rawq.c_cc == tp->t_rocount) {
6949578Ssam 			while (tp->t_rawq.c_cc)
6959578Ssam 				ttyrub(unputc(&tp->t_rawq), tp);
6969578Ssam 		} else {
6979578Ssam 			ttyecho(c, tp);
6989578Ssam 			ttyecho('\n', tp);
6999578Ssam 			while (getc(&tp->t_rawq) > 0)
7009578Ssam 				;
7019578Ssam 			tp->t_rocount = 0;
7029578Ssam 		}
7039578Ssam 		tp->t_state &= ~TS_LOCAL;
7049578Ssam 		goto endcase;
7059578Ssam 	}
7069578Ssam 
7079578Ssam 	/*
7089578Ssam 	 * New line discipline,
7099578Ssam 	 * check word erase/reprint line.
7109578Ssam 	 */
7119578Ssam 	if (tp->t_line == NTTYDISC) {
7129578Ssam 		if (c == tp->t_werasc) {
7139578Ssam 			if (tp->t_rawq.c_cc == 0)
7149578Ssam 				goto endcase;
7159578Ssam 			do {
7169578Ssam 				c = unputc(&tp->t_rawq);
7179578Ssam 				if (c != ' ' && c != '\t')
7189578Ssam 					goto erasenb;
7199578Ssam 				ttyrub(c, tp);
7209578Ssam 			} while (tp->t_rawq.c_cc);
7219578Ssam 			goto endcase;
7229578Ssam 	erasenb:
7239578Ssam 			do {
7249578Ssam 				ttyrub(c, tp);
7259578Ssam 				if (tp->t_rawq.c_cc == 0)
7269578Ssam 					goto endcase;
7279578Ssam 				c = unputc(&tp->t_rawq);
7289578Ssam 			} while (c != ' ' && c != '\t');
7299578Ssam 			(void) putc(c, &tp->t_rawq);
7309578Ssam 			goto endcase;
7319578Ssam 		}
7329578Ssam 		if (c == tp->t_rprntc) {
7339578Ssam 			ttyretype(tp);
7349578Ssam 			goto endcase;
7359578Ssam 		}
7369578Ssam 	}
7379578Ssam 
7389578Ssam 	/*
7399578Ssam 	 * Check for input buffer overflow
7409578Ssam 	 */
74110391Ssam 	if (tp->t_rawq.c_cc+tp->t_canq.c_cc >= TTYHOG) {
74210391Ssam 		if (tp->t_line == NTTYDISC)
74310391Ssam 			(void) ttyoutput(CTRL(g), tp);
7449578Ssam 		goto endcase;
74510391Ssam 	}
7469578Ssam 
7479578Ssam 	/*
7489578Ssam 	 * Put data char in q for user and
7499578Ssam 	 * wakeup on seeing a line delimiter.
7509578Ssam 	 */
7519578Ssam 	if (putc(c, &tp->t_rawq) >= 0) {
7529578Ssam 		if (ttbreakc(c, tp)) {
7539578Ssam 			tp->t_rocount = 0;
7549578Ssam 			catq(&tp->t_rawq, &tp->t_canq);
7557502Sroot 			ttwakeup(tp);
7569578Ssam 		} else if (tp->t_rocount++ == 0)
7579578Ssam 			tp->t_rocol = tp->t_col;
7589578Ssam 		tp->t_state &= ~TS_QUOT;
7599578Ssam 		if (c == '\\')
7609578Ssam 			tp->t_state |= TS_QUOT;
7619578Ssam 		if (tp->t_state&TS_ERASE) {
7629578Ssam 			tp->t_state &= ~TS_ERASE;
7639578Ssam 			(void) ttyoutput('/', tp);
7649578Ssam 		}
7659578Ssam 		i = tp->t_col;
7667502Sroot 		ttyecho(c, tp);
7679578Ssam 		if (c == tp->t_eofc && tp->t_flags&ECHO) {
7689578Ssam 			i = MIN(2, tp->t_col - i);
7699578Ssam 			while (i > 0) {
7709578Ssam 				(void) ttyoutput('\b', tp);
7719578Ssam 				i--;
7729578Ssam 			}
7739578Ssam 		}
7747502Sroot 	}
7759578Ssam 
7769578Ssam endcase:
7779578Ssam 	/*
7789578Ssam 	 * If DEC-style start/stop is enabled don't restart
7799578Ssam 	 * output until seeing the start character.
7809578Ssam 	 */
7819578Ssam 	if (tp->t_flags&DECCTQ && tp->t_state&TS_TTSTOP &&
7829578Ssam 	    tp->t_startc != tp->t_stopc)
7837502Sroot 		return;
7849578Ssam 
7859578Ssam restartoutput:
7867502Sroot 	tp->t_state &= ~TS_TTSTOP;
7879578Ssam 	tp->t_flags &= ~FLUSHO;
7889578Ssam 
7899578Ssam startoutput:
7907502Sroot 	ttstart(tp);
7917502Sroot }
7927502Sroot 
7937502Sroot /*
7949578Ssam  * Put character on TTY output queue, adding delays,
7957502Sroot  * expanding tabs, and handling the CR/NL bit.
7969578Ssam  * This is called both from the top half for output,
7979578Ssam  * and from interrupt level for echoing.
7987502Sroot  * The arguments are the character and the tty structure.
7997502Sroot  * Returns < 0 if putc succeeds, otherwise returns char to resend
8007502Sroot  * Must be recursive.
8017502Sroot  */
8027502Sroot ttyoutput(c, tp)
8037502Sroot 	register c;
8047502Sroot 	register struct tty *tp;
8057502Sroot {
8067502Sroot 	register char *colp;
8077502Sroot 	register ctype;
8087502Sroot 
8099578Ssam 	if (tp->t_flags & (RAW|LITOUT)) {
8109578Ssam 		if (tp->t_flags&FLUSHO)
8117502Sroot 			return (-1);
8127502Sroot 		if (putc(c, &tp->t_outq))
8137625Ssam 			return (c);
8147502Sroot 		tk_nout++;
8157502Sroot 		return (-1);
8167502Sroot 	}
8179578Ssam 
8187502Sroot 	/*
8199578Ssam 	 * Ignore EOT in normal mode to avoid
8209578Ssam 	 * hanging up certain terminals.
8217502Sroot 	 */
8227502Sroot 	c &= 0177;
8239578Ssam 	if (c == CEOT && (tp->t_flags&CBREAK) == 0)
8247502Sroot 		return (-1);
8257502Sroot 	/*
8267502Sroot 	 * Turn tabs to spaces as required
8277502Sroot 	 */
8289578Ssam 	if (c == '\t' && (tp->t_flags&TBDELAY) == XTABS) {
8297502Sroot 		register int s;
8307502Sroot 
8317502Sroot 		c = 8 - (tp->t_col&7);
8329578Ssam 		if ((tp->t_flags&FLUSHO) == 0) {
8337502Sroot 			s = spl5();		/* don't interrupt tabs */
8347502Sroot 			c -= b_to_q("        ", c, &tp->t_outq);
8357502Sroot 			tk_nout += c;
8367502Sroot 			splx(s);
8377502Sroot 		}
8387502Sroot 		tp->t_col += c;
8397502Sroot 		return (c ? -1 : '\t');
8407502Sroot 	}
8417502Sroot 	tk_nout++;
8427502Sroot 	/*
8437502Sroot 	 * for upper-case-only terminals,
8447502Sroot 	 * generate escapes.
8457502Sroot 	 */
8467502Sroot 	if (tp->t_flags&LCASE) {
8477502Sroot 		colp = "({)}!|^~'`";
8487625Ssam 		while (*colp++)
8497625Ssam 			if (c == *colp++) {
8507502Sroot 				if (ttyoutput('\\', tp) >= 0)
8517502Sroot 					return (c);
8527502Sroot 				c = colp[-2];
8537502Sroot 				break;
8547502Sroot 			}
8559578Ssam 		if ('A' <= c && c <= 'Z') {
8567502Sroot 			if (ttyoutput('\\', tp) >= 0)
8577502Sroot 				return (c);
8589578Ssam 		} else if ('a' <= c && c <= 'z')
8597502Sroot 			c += 'A' - 'a';
8607502Sroot 	}
8619578Ssam 
8627502Sroot 	/*
8637502Sroot 	 * turn <nl> to <cr><lf> if desired.
8647502Sroot 	 */
8659578Ssam 	if (c == '\n' && tp->t_flags&CRMOD)
8667502Sroot 		if (ttyoutput('\r', tp) >= 0)
8677502Sroot 			return (c);
8689578Ssam 	if (c == '~' && tp->t_flags&TILDE)
8697502Sroot 		c = '`';
8709578Ssam 	if ((tp->t_flags&FLUSHO) == 0 && putc(c, &tp->t_outq))
8717502Sroot 		return (c);
8727502Sroot 	/*
8737502Sroot 	 * Calculate delays.
8747502Sroot 	 * The numbers here represent clock ticks
8757502Sroot 	 * and are not necessarily optimal for all terminals.
8767502Sroot 	 * The delays are indicated by characters above 0200.
8777502Sroot 	 * In raw mode there are no delays and the
8787502Sroot 	 * transmission path is 8 bits wide.
8799578Ssam 	 *
8809578Ssam 	 * SHOULD JUST ALLOW USER TO SPECIFY DELAYS
8817502Sroot 	 */
8827502Sroot 	colp = &tp->t_col;
8837502Sroot 	ctype = partab[c];
8847502Sroot 	c = 0;
8857502Sroot 	switch (ctype&077) {
8867502Sroot 
8877502Sroot 	case ORDINARY:
8887502Sroot 		(*colp)++;
8897502Sroot 
8907502Sroot 	case CONTROL:
8917502Sroot 		break;
8927502Sroot 
8937502Sroot 	case BACKSPACE:
8947502Sroot 		if (*colp)
8957502Sroot 			(*colp)--;
8967502Sroot 		break;
8977502Sroot 
8987502Sroot 	case NEWLINE:
8997502Sroot 		ctype = (tp->t_flags >> 8) & 03;
9007625Ssam 		if (ctype == 1) { /* tty 37 */
9017502Sroot 			if (*colp)
9027502Sroot 				c = max(((unsigned)*colp>>4) + 3, (unsigned)6);
9039578Ssam 		} else if (ctype == 2) /* vt05 */
9047502Sroot 			c = 6;
9057502Sroot 		*colp = 0;
9067502Sroot 		break;
9077502Sroot 
9087502Sroot 	case TAB:
9097502Sroot 		ctype = (tp->t_flags >> 10) & 03;
9107625Ssam 		if (ctype == 1) { /* tty 37 */
9117502Sroot 			c = 1 - (*colp | ~07);
9127625Ssam 			if (c < 5)
9137502Sroot 				c = 0;
9147502Sroot 		}
9157502Sroot 		*colp |= 07;
9167502Sroot 		(*colp)++;
9177502Sroot 		break;
9187502Sroot 
9197502Sroot 	case VTAB:
9209578Ssam 		if (tp->t_flags&VTDELAY) /* tty 37 */
9217502Sroot 			c = 0177;
9227502Sroot 		break;
9237502Sroot 
9247502Sroot 	case RETURN:
9257502Sroot 		ctype = (tp->t_flags >> 12) & 03;
9269578Ssam 		if (ctype == 1) /* tn 300 */
9277502Sroot 			c = 5;
9289578Ssam 		else if (ctype == 2) /* ti 700 */
9297502Sroot 			c = 10;
9309578Ssam 		else if (ctype == 3) { /* concept 100 */
9317502Sroot 			int i;
9329578Ssam 
9337502Sroot 			if ((i = *colp) >= 0)
9349578Ssam 				for (; i < 9; i++)
9357502Sroot 					(void) putc(0177, &tp->t_outq);
9367502Sroot 		}
9377502Sroot 		*colp = 0;
9387502Sroot 	}
9399578Ssam 	if (c && (tp->t_flags&FLUSHO) == 0)
9407502Sroot 		(void) putc(c|0200, &tp->t_outq);
9417502Sroot 	return (-1);
9427502Sroot }
9437502Sroot 
9447502Sroot /*
9457502Sroot  * Called from device's read routine after it has
9467502Sroot  * calculated the tty-structure given as argument.
9477502Sroot  */
9487722Swnj ttread(tp, uio)
9497625Ssam 	register struct tty *tp;
9507722Swnj 	struct uio *uio;
9517502Sroot {
9527502Sroot 	register struct clist *qp;
9539578Ssam 	register c, t_flags;
9549859Ssam 	int s, first, error = 0;
9557502Sroot 
9567502Sroot 	if ((tp->t_state&TS_CARR_ON)==0)
9578520Sroot 		return (EIO);
9587502Sroot loop:
9599578Ssam 	/*
9609578Ssam 	 * Take any pending input first.
9619578Ssam 	 */
9629859Ssam 	s = spl5();
9639578Ssam 	if (tp->t_flags&PENDIN)
9647502Sroot 		ttypend(tp);
9659859Ssam 	splx(s);
9669578Ssam 
9679578Ssam 	/*
9689578Ssam 	 * Hang process if it's in the background.
9699578Ssam 	 */
9707502Sroot 	while (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) {
9717502Sroot 		if (u.u_signal[SIGTTIN] == SIG_IGN ||
9727502Sroot 		    u.u_signal[SIGTTIN] == SIG_HOLD ||
9737502Sroot /*
9747502Sroot 		    (u.u_procp->p_flag&SDETACH) ||
9757502Sroot */
9767502Sroot 		    u.u_procp->p_flag&SVFORK)
9778520Sroot 			return (EIO);
9787502Sroot 		gsignal(u.u_procp->p_pgrp, SIGTTIN);
9797502Sroot 		sleep((caddr_t)&lbolt, TTIPRI);
9807502Sroot 	}
9819578Ssam 	t_flags = tp->t_flags;
9829578Ssam 
9839578Ssam 	/*
9849578Ssam 	 * In raw mode take characters directly from the
9859578Ssam 	 * raw queue w/o processing.  Interlock against
9869578Ssam 	 * device interrupts when interrogating rawq.
9879578Ssam 	 */
9889578Ssam 	if (t_flags&RAW) {
9899859Ssam 		s = spl5();
9907502Sroot 		if (tp->t_rawq.c_cc <= 0) {
9919578Ssam 			if ((tp->t_state&TS_CARR_ON) == 0 ||
9927502Sroot 			    (tp->t_state&TS_NBIO)) {
9939859Ssam 				splx(s);
9949578Ssam 				return (0);
9957502Sroot 			}
9967502Sroot 			sleep((caddr_t)&tp->t_rawq, TTIPRI);
9979859Ssam 			splx(s);
9987502Sroot 			goto loop;
9997502Sroot 		}
10009859Ssam 		splx(s);
10019859Ssam 		while (!error && tp->t_rawq.c_cc && uio->uio_iovcnt)
10028520Sroot 			error = passuc(getc(&tp->t_rawq), uio);
10039859Ssam 		goto checktandem;
10049578Ssam 	}
10059578Ssam 
10069578Ssam 	/*
10079578Ssam 	 * In cbreak mode use the rawq, otherwise
10089578Ssam 	 * take characters from the canonicalized q.
10099578Ssam 	 */
10109578Ssam 	qp = t_flags&CBREAK ? &tp->t_rawq : &tp->t_canq;
10119578Ssam 
10129578Ssam 	/*
10139578Ssam 	 * No input, sleep on rawq awaiting hardware
10149578Ssam 	 * receipt and notification.
10159578Ssam 	 */
10169859Ssam 	s = spl5();
10179578Ssam 	if (qp->c_cc <= 0) {
10189578Ssam 		if ((tp->t_state&TS_CARR_ON) == 0 ||
10199578Ssam 		    (tp->t_state&TS_NBIO)) {
10209859Ssam 			splx(s);
10219578Ssam 			return (EWOULDBLOCK);
10227502Sroot 		}
10239578Ssam 		sleep((caddr_t)&tp->t_rawq, TTIPRI);
10249859Ssam 		splx(s);
10259578Ssam 		goto loop;
10269578Ssam 	}
10279859Ssam 	splx(s);
10289578Ssam 
10299578Ssam 	/*
10309578Ssam 	 * Input present, perform input mapping
10319578Ssam 	 * and processing (we're not in raw mode).
10329578Ssam 	 */
10339578Ssam 	first = 1;
10349578Ssam 	while ((c = getc(qp)) >= 0) {
10359578Ssam 		if (t_flags&CRMOD && c == '\r')
10369578Ssam 			c = '\n';
10379578Ssam 		/*
10389578Ssam 		 * Hack lower case simulation on
10399578Ssam 		 * upper case only terminals.
10409578Ssam 		 */
10419578Ssam 		if (t_flags&LCASE && c <= 0177)
10429578Ssam 			if (tp->t_state&TS_BKSL) {
10439578Ssam 				if (maptab[c])
10449578Ssam 					c = maptab[c];
10459578Ssam 				tp->t_state &= ~TS_BKSL;
10469578Ssam 			} else if (c >= 'A' && c <= 'Z')
10479578Ssam 				c += 'a' - 'A';
10489578Ssam 			else if (c == '\\') {
10499578Ssam 				tp->t_state |= TS_BKSL;
10509578Ssam 				continue;
10517502Sroot 			}
10529578Ssam 		/*
10539578Ssam 		 * Check for delayed suspend character.
10549578Ssam 		 */
10559578Ssam 		if (tp->t_line == NTTYDISC && c == tp->t_dsuspc) {
10569578Ssam 			gsignal(tp->t_pgrp, SIGTSTP);
10579578Ssam 			if (first) {
10589578Ssam 				sleep((caddr_t)&lbolt, TTIPRI);
10599578Ssam 				goto loop;
10609578Ssam 			}
10619578Ssam 			break;
10627502Sroot 		}
10639578Ssam 		/*
10649578Ssam 		 * Interpret EOF only in cooked mode.
10659578Ssam 		 */
10669578Ssam 		if (c == tp->t_eofc && (t_flags&CBREAK) == 0)
10679578Ssam 			break;
10689578Ssam 		/*
10699578Ssam 		 * Give user character.
10709578Ssam 		 */
10719578Ssam 		error = passuc(c & 0177, uio);
10729578Ssam 		if (error)
10739578Ssam 			break;
10749578Ssam 		if (uio->uio_iovcnt == 0)
10759578Ssam 			break;
10769578Ssam 		/*
10779578Ssam 		 * In cooked mode check for a "break character"
10789578Ssam 		 * marking the end of a "line of input".
10799578Ssam 		 */
10809578Ssam 		if ((t_flags&CBREAK) == 0 && ttbreakc(c, tp))
10819578Ssam 			break;
10829578Ssam 		first = 0;
10837502Sroot 	}
10849578Ssam 	tp->t_state &= ~TS_BKSL;
10859578Ssam 
10869859Ssam checktandem:
10879578Ssam 	/*
10889578Ssam 	 * Look to unblock output now that (presumably)
10899578Ssam 	 * the input queue has gone down.
10909578Ssam 	 */
10919859Ssam 	if (tp->t_state&TS_TBLOCK && tp->t_rawq.c_cc < TTYHOG/5)
10929578Ssam 		if (putc(tp->t_startc, &tp->t_outq) == 0) {
10937502Sroot 			tp->t_state &= ~TS_TBLOCK;
10947502Sroot 			ttstart(tp);
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 
146610391Ssam #if !defined(vax) && !defined(sun)
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