xref: /csrg-svn/sys/kern/tty.c (revision 9760)
1*9760Ssam /*	tty.c	4.37	82/12/17	*/
239Sbill 
3*9760Ssam #include "../machine/reg.h"
4*9760Ssam 
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 {
11839Sbill 
119903Sbill 	(void) spl5();
1205622Swnj 	while (tp->t_outq.c_cc && tp->t_state&TS_CARR_ON
1215622Swnj 	    && tp->t_oproc) {		/* kludge for pty */
122903Sbill 		(*tp->t_oproc)(tp);
1235408Swnj 		tp->t_state |= TS_ASLEEP;
124903Sbill 		sleep((caddr_t)&tp->t_outq, TTOPRI);
125903Sbill 	}
1265426Swnj 	flushtty(tp, FREAD);
127903Sbill 	(void) spl0();
12839Sbill }
12939Sbill 
13039Sbill /*
1319578Ssam  * Flush all TTY queues
13239Sbill  */
133903Sbill flushtty(tp, rw)
1347625Ssam 	register struct tty *tp;
13539Sbill {
136903Sbill 	register s;
137903Sbill 
138903Sbill 	s = spl6();
139903Sbill 	if (rw & FREAD) {
140903Sbill 		while (getc(&tp->t_canq) >= 0)
141903Sbill 			;
142903Sbill 		wakeup((caddr_t)&tp->t_rawq);
143903Sbill 	}
144903Sbill 	if (rw & FWRITE) {
145903Sbill 		wakeup((caddr_t)&tp->t_outq);
1465408Swnj 		tp->t_state &= ~TS_TTSTOP;
1475426Swnj 		(*cdevsw[major(tp->t_dev)].d_stop)(tp, rw);
148903Sbill 		while (getc(&tp->t_outq) >= 0)
149903Sbill 			;
150903Sbill 	}
151903Sbill 	if (rw & FREAD) {
152903Sbill 		while (getc(&tp->t_rawq) >= 0)
153903Sbill 			;
154903Sbill 		tp->t_delct = 0;
1559578Ssam 		tp->t_rocount = 0;
156903Sbill 		tp->t_rocol = 0;
1579578Ssam 		tp->t_state &= ~TS_LOCAL;
158903Sbill 	}
159903Sbill 	splx(s);
16039Sbill }
16139Sbill 
162903Sbill /*
163903Sbill  * Send stop character on input overflow.
164903Sbill  */
165903Sbill ttyblock(tp)
1667625Ssam 	register struct tty *tp;
16739Sbill {
168903Sbill 	register x;
1699578Ssam 
170903Sbill 	x = tp->t_rawq.c_cc + tp->t_canq.c_cc;
171903Sbill 	if (tp->t_rawq.c_cc > TTYHOG) {
172903Sbill 		flushtty(tp, FREAD|FWRITE);
1735408Swnj 		tp->t_state &= ~TS_TBLOCK;
174903Sbill 	}
1759578Ssam 	if (x >= TTYHOG/2 && putc(tp->t_stopc, &tp->t_outq) == 0) {
1769578Ssam 		tp->t_state |= TS_TBLOCK;
1779578Ssam 		tp->t_char++;
1789578Ssam 		ttstart(tp);
179903Sbill 	}
18039Sbill }
18139Sbill 
18239Sbill /*
183903Sbill  * Restart typewriter output following a delay
184903Sbill  * timeout.
185903Sbill  * The name of the routine is passed to the timeout
186903Sbill  * subroutine and it is called during a clock interrupt.
187121Sbill  */
188903Sbill ttrstrt(tp)
1897625Ssam 	register struct tty *tp;
190121Sbill {
191121Sbill 
1929578Ssam 	if (tp == 0)
1939578Ssam 		panic("ttrstrt");
1945408Swnj 	tp->t_state &= ~TS_TIMEOUT;
195903Sbill 	ttstart(tp);
196121Sbill }
197121Sbill 
198121Sbill /*
199903Sbill  * Start output on the typewriter. It is used from the top half
200903Sbill  * after some characters have been put on the output queue,
201903Sbill  * from the interrupt routine to transmit the next
202903Sbill  * character, and after a timeout has finished.
20339Sbill  */
204903Sbill ttstart(tp)
2057625Ssam 	register struct tty *tp;
20639Sbill {
207903Sbill 	register s;
20839Sbill 
209903Sbill 	s = spl5();
2109578Ssam 	if ((tp->t_state & (TS_TIMEOUT|TS_TTSTOP|TS_BUSY)) == 0 &&
2115622Swnj 	    tp->t_oproc)		/* kludge for pty */
212903Sbill 		(*tp->t_oproc)(tp);
213903Sbill 	splx(s);
21439Sbill }
21539Sbill 
21639Sbill /*
217903Sbill  * Common code for tty ioctls.
21839Sbill  */
2191780Sbill /*ARGSUSED*/
2207625Ssam ttioctl(tp, com, data, flag)
2217625Ssam 	register struct tty *tp;
2227625Ssam 	caddr_t data;
22339Sbill {
2248520Sroot 	int dev = tp->t_dev;
22539Sbill 	extern int nldisp;
2268556Sroot 	int s;
22739Sbill 
228903Sbill 	/*
229903Sbill 	 * If the ioctl involves modification,
230903Sbill 	 * insist on being able to write the device,
231903Sbill 	 * and hang if in the background.
232903Sbill 	 */
2337625Ssam 	switch (com) {
23439Sbill 
235915Sbill 	case TIOCSETD:
236915Sbill 	case TIOCSETP:
237915Sbill 	case TIOCSETN:
238903Sbill 	case TIOCFLUSH:
239903Sbill 	case TIOCSETC:
240903Sbill 	case TIOCSLTC:
241903Sbill 	case TIOCSPGRP:
242903Sbill 	case TIOCLBIS:
243903Sbill 	case TIOCLBIC:
244903Sbill 	case TIOCLSET:
2459624Ssam 	case TIOCBIS:
2469624Ssam 	case TIOCBIC:
2479624Ssam 	case TIOCSET:
2489325Ssam 	case TIOCSTI:
249903Sbill 		while (tp->t_line == NTTYDISC &&
250903Sbill 		   u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp &&
251903Sbill 		   (u.u_procp->p_flag&SVFORK) == 0 &&
252903Sbill 		   u.u_signal[SIGTTOU] != SIG_IGN &&
2538556Sroot 		   u.u_signal[SIGTTOU] != SIG_HOLD) {
254903Sbill 			gsignal(u.u_procp->p_pgrp, SIGTTOU);
255903Sbill 			sleep((caddr_t)&lbolt, TTOPRI);
256903Sbill 		}
257903Sbill 		break;
258903Sbill 	}
259903Sbill 
2609578Ssam 	/*
2619578Ssam 	 * Process the ioctl.
2629578Ssam 	 */
2637625Ssam 	switch (com) {
264903Sbill 
2658556Sroot 	/* get discipline number */
26639Sbill 	case TIOCGETD:
2677625Ssam 		*(int *)data = tp->t_line;
26839Sbill 		break;
26939Sbill 
2708556Sroot 	/* set line discipline */
2717625Ssam 	case TIOCSETD: {
2727625Ssam 		register int t = *(int *)data;
2739578Ssam 		int error = 0;
2747625Ssam 
2759578Ssam 		if (t >= nldisp) {
2769578Ssam 			u.u_error = ENXIO;
2779578Ssam 			break;
2789578Ssam 		}
2798556Sroot 		s = spl5();
28039Sbill 		if (tp->t_line)
28139Sbill 			(*linesw[tp->t_line].l_close)(tp);
28239Sbill 		if (t)
2838556Sroot 			error = (*linesw[t].l_open)(dev, tp);
2848556Sroot 		splx(s);
2858556Sroot 		if (error)
2868556Sroot 			return (error);
2878556Sroot 		tp->t_line = t;
28839Sbill 		break;
2897625Ssam 	}
29039Sbill 
2918556Sroot 	/* prevent more opens on channel */
2925614Swnj 	case TIOCEXCL:
2935614Swnj 		tp->t_state |= TS_XCLUDE;
2945614Swnj 		break;
2955614Swnj 
2965614Swnj 	case TIOCNXCL:
2975614Swnj 		tp->t_state &= ~TS_XCLUDE;
2985614Swnj 		break;
2995614Swnj 
3009624Ssam 	case TIOCSET:
3019624Ssam 	case TIOCBIS: {
3029624Ssam 		u_long newflags = *(u_long *)data;
3037625Ssam 
3049624Ssam 		s = spl5();
3059624Ssam 		if (tp->t_flags&RAW || newflags&RAW)
3064484Swnj 			wflushtty(tp);
3079624Ssam 		else if ((tp->t_flags&CBREAK) != (newflags&CBREAK))
3089624Ssam 			if (newflags&CBREAK) {
3099624Ssam 				struct clist tq;
3109624Ssam 
3114484Swnj 				catq(&tp->t_rawq, &tp->t_canq);
3124484Swnj 				tq = tp->t_rawq;
3134484Swnj 				tp->t_rawq = tp->t_canq;
3144484Swnj 				tp->t_canq = tq;
3154484Swnj 			} else {
3169578Ssam 				tp->t_flags |= PENDIN;
3174484Swnj 				ttwakeup(tp);
318174Sbill 			}
3199624Ssam 		if (com == TIOCSET)
3209624Ssam 			tp->t_flags = newflags;
3219624Ssam 		else
3229624Ssam 			tp->t_flags |= newflags;
3239578Ssam 		if (tp->t_flags&RAW) {
3245408Swnj 			tp->t_state &= ~TS_TTSTOP;
3253941Sbugs 			ttstart(tp);
3263941Sbugs 		}
3279624Ssam 		splx(s);
32839Sbill 		break;
3297625Ssam 	}
33039Sbill 
3319624Ssam 	case TIOCBIC: {
3329624Ssam 		u_long newflags = *(long *)data;
3337625Ssam 
3349624Ssam 		if (tp->t_flags&RAW)
3359624Ssam 			wflushtty(tp);
3369624Ssam 		else if ((tp->t_flags&CBREAK) != (CBREAK&~newflags))
3379624Ssam 			if (newflags&CBREAK) {
3389624Ssam 				tp->t_flags |= PENDIN;
3399624Ssam 				ttwakeup(tp);
3409624Ssam 			} else {
3419624Ssam 				struct clist tq;
3429624Ssam 
3439624Ssam 				catq(&tp->t_rawq, &tp->t_canq);
3449624Ssam 				tq = tp->t_rawq;
3459624Ssam 				tp->t_rawq = tp->t_canq;
3469624Ssam 				tp->t_canq = tq;
3479624Ssam 			}
3489624Ssam 		if (tp->t_flags&RAW) {
3499624Ssam 			tp->t_state &= ~TS_TTSTOP;
3509624Ssam 			ttstart(tp);
3519624Ssam 		}
3529624Ssam 		splx(s);
35339Sbill 		break;
3547625Ssam 	}
35539Sbill 
3569624Ssam 	case TIOCGET:
3579624Ssam 		*(long *)data = tp->t_flags;
3589624Ssam 		break;
3599624Ssam 
3609624Ssam 	case TIOCCGET:
3619624Ssam 		bcopy((caddr_t)&tp->t_chars, data, sizeof (struct ttychars));
3629624Ssam 		break;
3639624Ssam 
3649624Ssam 	case TIOCCSET:
3659624Ssam 		bcopy(data, (caddr_t)&tp->t_chars, sizeof (struct ttychars));
3669624Ssam 		break;
3679624Ssam 
3688556Sroot 	/* hang up line on last close */
36939Sbill 	case TIOCHPCL:
3705408Swnj 		tp->t_state |= TS_HUPCLS;
37139Sbill 		break;
37239Sbill 
3733942Sbugs 	case TIOCFLUSH: {
3747625Ssam 		register int flags = *(int *)data;
3757625Ssam 
3767625Ssam 		if (flags == 0)
3773942Sbugs 			flags = FREAD|FWRITE;
3787625Ssam 		else
3797625Ssam 			flags &= FREAD|FWRITE;
3803942Sbugs 		flushtty(tp, flags);
38139Sbill 		break;
3823944Sbugs 	}
38339Sbill 
3848556Sroot 	/* return number of characters immediately available */
3857625Ssam 	case FIONREAD:
3867625Ssam 		*(off_t *)data = ttnread(tp);
387174Sbill 		break;
388174Sbill 
3898589Sroot 	case TIOCSTOP:
3908589Sroot 		s = spl5();
3919578Ssam 		if ((tp->t_state&TS_TTSTOP) == 0) {
3925573Swnj 			tp->t_state |= TS_TTSTOP;
3935573Swnj 			(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
3945573Swnj 		}
3957625Ssam 		splx(s);
3965573Swnj 		break;
3975573Swnj 
3988589Sroot 	case TIOCSTART:
3998589Sroot 		s = spl5();
4009578Ssam 		if ((tp->t_state&TS_TTSTOP) || (tp->t_flags&FLUSHO)) {
4015573Swnj 			tp->t_state &= ~TS_TTSTOP;
4029578Ssam 			tp->t_flags &= ~FLUSHO;
4035573Swnj 			ttstart(tp);
4045573Swnj 		}
4057625Ssam 		splx(s);
4065573Swnj 		break;
4075573Swnj 
4089325Ssam 	/*
4099325Ssam 	 * Simulate typing of a character at the terminal.
4109325Ssam 	 */
4119325Ssam 	case TIOCSTI:
4129325Ssam 		if (u.u_uid && u.u_ttyp != tp)
4139325Ssam 			return (EACCES);
4149578Ssam 		(*linesw[tp->t_line].l_rint)(*(char *)data, tp);
4159325Ssam 		break;
4169325Ssam 
41739Sbill 	default:
4189624Ssam #ifndef NOCOMPAT
4199624Ssam 		return (ottioctl(tp, com, data, flag));
4209624Ssam #else
4218556Sroot 		return (-1);
4229624Ssam #endif
42339Sbill 	}
4248556Sroot 	return (0);
42539Sbill }
4264484Swnj 
4274484Swnj ttnread(tp)
4284484Swnj 	struct tty *tp;
4294484Swnj {
4304484Swnj 	int nread = 0;
4314484Swnj 
4329578Ssam 	if (tp->t_flags & PENDIN)
4334484Swnj 		ttypend(tp);
4344484Swnj 	nread = tp->t_canq.c_cc;
4354484Swnj 	if (tp->t_flags & (RAW|CBREAK))
4364484Swnj 		nread += tp->t_rawq.c_cc;
4374484Swnj 	return (nread);
4384484Swnj }
4394484Swnj 
4405408Swnj ttselect(dev, rw)
4414484Swnj 	dev_t dev;
4425408Swnj 	int rw;
4434484Swnj {
4444484Swnj 	register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)];
4454484Swnj 	int nread;
4465408Swnj 	int s = spl5();
4474484Swnj 
4485408Swnj 	switch (rw) {
4494484Swnj 
4504484Swnj 	case FREAD:
4514484Swnj 		nread = ttnread(tp);
4524484Swnj 		if (nread > 0)
4535408Swnj 			goto win;
4544938Swnj 		if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait)
4555408Swnj 			tp->t_state |= TS_RCOLL;
4564484Swnj 		else
4574484Swnj 			tp->t_rsel = u.u_procp;
4585408Swnj 		break;
4594484Swnj 
4605408Swnj 	case FWRITE:
4615408Swnj 		if (tp->t_outq.c_cc <= TTLOWAT(tp))
4625408Swnj 			goto win;
4635408Swnj 		if (tp->t_wsel && tp->t_wsel->p_wchan == (caddr_t)&selwait)
4645408Swnj 			tp->t_state |= TS_WCOLL;
4655408Swnj 		else
4665408Swnj 			tp->t_wsel = u.u_procp;
4675408Swnj 		break;
4684484Swnj 	}
4695408Swnj 	splx(s);
4705408Swnj 	return (0);
4715408Swnj win:
4725408Swnj 	splx(s);
4735408Swnj 	return (1);
4744484Swnj }
4757436Skre 
4767502Sroot /*
4779578Ssam  * Establish a process group for distribution of
4787502Sroot  * quits and interrupts from the tty.
4797502Sroot  */
4807502Sroot ttyopen(dev, tp)
4817625Ssam 	dev_t dev;
4827625Ssam 	register struct tty *tp;
4837502Sroot {
4847502Sroot 	register struct proc *pp;
4857502Sroot 
4867502Sroot 	pp = u.u_procp;
4877502Sroot 	tp->t_dev = dev;
4887625Ssam 	if (pp->p_pgrp == 0) {
4897502Sroot 		u.u_ttyp = tp;
4907502Sroot 		u.u_ttyd = dev;
4917502Sroot 		if (tp->t_pgrp == 0)
4927502Sroot 			tp->t_pgrp = pp->p_pid;
4937502Sroot 		pp->p_pgrp = tp->t_pgrp;
4947502Sroot 	}
4957502Sroot 	tp->t_state &= ~TS_WOPEN;
4967502Sroot 	tp->t_state |= TS_ISOPEN;
4977502Sroot 	if (tp->t_line != NTTYDISC)
4987502Sroot 		wflushtty(tp);
4998556Sroot 	return (0);
5007502Sroot }
5017502Sroot 
5027502Sroot /*
5037502Sroot  * clean tp on last close
5047502Sroot  */
5057502Sroot ttyclose(tp)
5067625Ssam 	register struct tty *tp;
5077502Sroot {
5087502Sroot 
5097502Sroot 	if (tp->t_line) {
5107502Sroot 		wflushtty(tp);
5117502Sroot 		tp->t_line = 0;
5127502Sroot 		return;
5137502Sroot 	}
5147502Sroot 	tp->t_pgrp = 0;
5157502Sroot 	wflushtty(tp);
5167502Sroot 	tp->t_state = 0;
5177502Sroot }
5187502Sroot 
5197502Sroot /*
5207502Sroot  * reinput pending characters after state switch
5217502Sroot  * call at spl5().
5227502Sroot  */
5237502Sroot ttypend(tp)
5247625Ssam 	register struct tty *tp;
5257502Sroot {
5267502Sroot 	struct clist tq;
5277502Sroot 	register c;
5287502Sroot 
5299578Ssam 	tp->t_flags &= ~PENDIN;
5309578Ssam 	tp->t_state |= TS_TYPEN;
5317502Sroot 	tq = tp->t_rawq;
5327502Sroot 	tp->t_rawq.c_cc = 0;
5337502Sroot 	tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0;
5347502Sroot 	while ((c = getc(&tq)) >= 0)
5357502Sroot 		ttyinput(c, tp);
5369578Ssam 	tp->t_state &= ~TS_TYPEN;
5377502Sroot }
5387502Sroot 
5397502Sroot /*
5409578Ssam  * Place a character on raw TTY input queue,
5419578Ssam  * putting in delimiters and waking up top
5429578Ssam  * half as needed.  Also echo if required.
5439578Ssam  * The arguments are the character and the
5449578Ssam  * appropriate tty structure.
5457502Sroot  */
5467502Sroot ttyinput(c, tp)
5477625Ssam 	register c;
5487625Ssam 	register struct tty *tp;
5497502Sroot {
5509578Ssam 	register int t_flags = tp->t_flags;
5517502Sroot 	int i;
5527502Sroot 
5539578Ssam 	/*
5549578Ssam 	 * If input is pending take it first.
5559578Ssam 	 */
5569578Ssam 	if (t_flags&PENDIN)
5577502Sroot 		ttypend(tp);
5587502Sroot 	tk_nin++;
5597502Sroot 	c &= 0377;
5609578Ssam 
5619578Ssam 	/*
5629578Ssam 	 * In tandem mode, check high water mark.
5639578Ssam 	 */
5647502Sroot 	if (t_flags&TANDEM)
5657502Sroot 		ttyblock(tp);
5669578Ssam 
5679578Ssam 	if (t_flags&RAW) {
5689578Ssam 		/*
5699578Ssam 		 * Raw mode, just put character
5709578Ssam 		 * in input q w/o interpretation.
5719578Ssam 		 */
5729578Ssam 		if (tp->t_rawq.c_cc > TTYHOG)
5739578Ssam 			flushtty(tp, FREAD|FWRITE);
5749578Ssam 		else {
5759578Ssam 			if (putc(c, &tp->t_rawq) >= 0)
5769578Ssam 				ttwakeup(tp);
5779578Ssam 			ttyecho(c, tp);
5787502Sroot 		}
5799578Ssam 		goto endcase;
5809578Ssam 	}
5819578Ssam 
5829578Ssam 	/*
5839578Ssam 	 * Ignore any high bit added during
5849578Ssam 	 * previous ttyinput processing.
5859578Ssam 	 */
5869578Ssam 	if ((tp->t_state&TS_TYPEN) == 0)
5879578Ssam 		c &= 0177;
5889578Ssam 	/*
5899578Ssam 	 * Check for literal nexting very first
5909578Ssam 	 */
5919578Ssam 	if (tp->t_state&TS_LNCH) {
5929578Ssam 		c |= 0200;
5939578Ssam 		tp->t_state &= ~TS_LNCH;
5949578Ssam 	}
5959578Ssam 
5969578Ssam 	/*
5979578Ssam 	 * Scan for special characters.  This code
5989578Ssam 	 * is really just a big case statement with
5999578Ssam 	 * non-constant cases.  The bottom of the
6009578Ssam 	 * case statement is labeled ``endcase'', so goto
6019578Ssam 	 * it after a case match, or similar.
6029578Ssam 	 */
6039578Ssam 	if (tp->t_line == NTTYDISC) {
6049578Ssam 		if (c == tp->t_lnextc) {
6057502Sroot 			if (tp->t_flags&ECHO)
6067502Sroot 				ttyout("^\b", tp);
6079578Ssam 			tp->t_state |= TS_LNCH;
6089578Ssam 			goto endcase;
6099578Ssam 		}
6109578Ssam 		if (c == tp->t_flushc) {
6119578Ssam 			if (tp->t_flags&FLUSHO)
6129578Ssam 				tp->t_flags &= ~FLUSHO;
6137502Sroot 			else {
6147502Sroot 				flushtty(tp, FWRITE);
6157502Sroot 				ttyecho(c, tp);
6169578Ssam 				if (tp->t_rawq.c_cc + tp->t_canq.c_cc)
6177502Sroot 					ttyretype(tp);
6189578Ssam 				tp->t_flags |= FLUSHO;
6197502Sroot 			}
6209578Ssam 			goto startoutput;
6219578Ssam 		}
6229578Ssam 		if (c == tp->t_suspc) {
6239578Ssam 			if ((tp->t_flags&NOFLSH) == 0)
6249578Ssam 				flushtty(tp, FREAD);
6259578Ssam 			ttyecho(c, tp);
6269578Ssam 			gsignal(tp->t_pgrp, SIGTSTP);
6279578Ssam 			goto endcase;
6289578Ssam 		}
6299578Ssam 	}
6309578Ssam 
6319578Ssam 	/*
6329578Ssam 	 * Handle start/stop characters.
6339578Ssam 	 */
6349578Ssam 	if (c == tp->t_stopc) {
6359578Ssam 		if ((tp->t_state&TS_TTSTOP) == 0) {
6369578Ssam 			tp->t_state |= TS_TTSTOP;
6379578Ssam 			(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
6387502Sroot 			return;
6399578Ssam 		}
6409578Ssam 		if (c != tp->t_startc)
6419578Ssam 			return;
6429578Ssam 		goto endcase;
6439578Ssam 	}
6449578Ssam 	if (c == tp->t_startc)
6459578Ssam 		goto restartoutput;
6469578Ssam 
6479578Ssam 	/*
6489578Ssam 	 * Look for interrupt/quit chars.
6499578Ssam 	 */
6509578Ssam 	if (c == tp->t_intrc || c == tp->t_quitc) {
6519578Ssam 		if ((tp->t_flags&NOFLSH) == 0)
6529578Ssam 			flushtty(tp, FREAD|FWRITE);
6539578Ssam 		ttyecho(c, tp);
6549578Ssam 		gsignal(tp->t_pgrp, c == tp->t_intrc ? SIGINT : SIGQUIT);
6559578Ssam 		goto endcase;
6569578Ssam 	}
6579578Ssam 
6589578Ssam 	/*
6599578Ssam 	 * Cbreak mode, don't process line editing
6609578Ssam 	 * characters; check high water mark for wakeup.
6619578Ssam 	 */
6629578Ssam 	if (t_flags&CBREAK) {
6639578Ssam 		if (tp->t_rawq.c_cc > TTYHOG) {
6647502Sroot 			if (tp->t_outq.c_cc < TTHIWAT(tp) &&
6657502Sroot 			    tp->t_line == NTTYDISC)
6667502Sroot 				(void) ttyoutput(CTRL(g), tp);
6677502Sroot 		} else if (putc(c, &tp->t_rawq) >= 0) {
6687502Sroot 			ttwakeup(tp);
6697502Sroot 			ttyecho(c, tp);
6707502Sroot 		}
6719578Ssam 		goto endcase;
6729578Ssam 	}
6739578Ssam 
6749578Ssam 	/*
6759578Ssam 	 * From here on down cooked mode character
6769578Ssam 	 * processing takes place.
6779578Ssam 	 */
6789578Ssam 	if ((tp->t_state&TS_QUOT) &&
6799578Ssam 	    (c == tp->t_erase || c == tp->t_kill)) {
6809578Ssam 		ttyrub(unputc(&tp->t_rawq), tp);
6819578Ssam 		c |= 0200;
6829578Ssam 	}
6839578Ssam 	if (c == tp->t_erase) {
6849578Ssam 		if (tp->t_rawq.c_cc)
6859578Ssam 			ttyrub(unputc(&tp->t_rawq), tp);
6869578Ssam 		goto endcase;
6879578Ssam 	}
6889578Ssam 	if (c == tp->t_kill) {
6899578Ssam 		if (tp->t_flags&CRTKIL &&
6909578Ssam 		    tp->t_rawq.c_cc == tp->t_rocount) {
6919578Ssam 			while (tp->t_rawq.c_cc)
6929578Ssam 				ttyrub(unputc(&tp->t_rawq), tp);
6939578Ssam 		} else {
6949578Ssam 			ttyecho(c, tp);
6959578Ssam 			ttyecho('\n', tp);
6969578Ssam 			while (getc(&tp->t_rawq) > 0)
6979578Ssam 				;
6989578Ssam 			tp->t_rocount = 0;
6999578Ssam 		}
7009578Ssam 		tp->t_state &= ~TS_LOCAL;
7019578Ssam 		goto endcase;
7029578Ssam 	}
7039578Ssam 
7049578Ssam 	/*
7059578Ssam 	 * New line discipline,
7069578Ssam 	 * check word erase/reprint line.
7079578Ssam 	 */
7089578Ssam 	if (tp->t_line == NTTYDISC) {
7099578Ssam 		if (c == tp->t_werasc) {
7109578Ssam 			if (tp->t_rawq.c_cc == 0)
7119578Ssam 				goto endcase;
7129578Ssam 			do {
7139578Ssam 				c = unputc(&tp->t_rawq);
7149578Ssam 				if (c != ' ' && c != '\t')
7159578Ssam 					goto erasenb;
7169578Ssam 				ttyrub(c, tp);
7179578Ssam 			} while (tp->t_rawq.c_cc);
7189578Ssam 			goto endcase;
7199578Ssam 	erasenb:
7209578Ssam 			do {
7219578Ssam 				ttyrub(c, tp);
7229578Ssam 				if (tp->t_rawq.c_cc == 0)
7239578Ssam 					goto endcase;
7249578Ssam 				c = unputc(&tp->t_rawq);
7259578Ssam 			} while (c != ' ' && c != '\t');
7269578Ssam 			(void) putc(c, &tp->t_rawq);
7279578Ssam 			goto endcase;
7289578Ssam 		}
7299578Ssam 		if (c == tp->t_rprntc) {
7309578Ssam 			ttyretype(tp);
7319578Ssam 			goto endcase;
7329578Ssam 		}
7339578Ssam 	}
7349578Ssam 
7359578Ssam 	/*
7369578Ssam 	 * Check for input buffer overflow
7379578Ssam 	 */
7389578Ssam 	if (tp->t_rawq.c_cc+tp->t_canq.c_cc >= TTYHOG)
7399578Ssam 		goto endcase;
7409578Ssam 
7419578Ssam 	/*
7429578Ssam 	 * Put data char in q for user and
7439578Ssam 	 * wakeup on seeing a line delimiter.
7449578Ssam 	 */
7459578Ssam 	if (putc(c, &tp->t_rawq) >= 0) {
7469578Ssam 		if (tp->t_rawq.c_cc + tp->t_canq.c_cc == TTYHOG
7479578Ssam 		    && tp->t_line == NTTYDISC)
7489578Ssam 			(void) ttyoutput(CTRL(g), tp);
7499578Ssam 		if (ttbreakc(c, tp)) {
7509578Ssam 			tp->t_rocount = 0;
7519578Ssam 			catq(&tp->t_rawq, &tp->t_canq);
7527502Sroot 			ttwakeup(tp);
7539578Ssam 		} else if (tp->t_rocount++ == 0)
7549578Ssam 			tp->t_rocol = tp->t_col;
7559578Ssam 		tp->t_state &= ~TS_QUOT;
7569578Ssam 		if (c == '\\')
7579578Ssam 			tp->t_state |= TS_QUOT;
7589578Ssam 		if (tp->t_state&TS_ERASE) {
7599578Ssam 			tp->t_state &= ~TS_ERASE;
7609578Ssam 			(void) ttyoutput('/', tp);
7619578Ssam 		}
7629578Ssam 		i = tp->t_col;
7637502Sroot 		ttyecho(c, tp);
7649578Ssam 		if (c == tp->t_eofc && tp->t_flags&ECHO) {
7659578Ssam 			i = MIN(2, tp->t_col - i);
7669578Ssam 			while (i > 0) {
7679578Ssam 				(void) ttyoutput('\b', tp);
7689578Ssam 				i--;
7699578Ssam 			}
7709578Ssam 		}
7717502Sroot 	}
7729578Ssam 
7739578Ssam endcase:
7749578Ssam 	/*
7759578Ssam 	 * If DEC-style start/stop is enabled don't restart
7769578Ssam 	 * output until seeing the start character.
7779578Ssam 	 */
7789578Ssam 	if (tp->t_flags&DECCTQ && tp->t_state&TS_TTSTOP &&
7799578Ssam 	    tp->t_startc != tp->t_stopc)
7807502Sroot 		return;
7819578Ssam 
7829578Ssam restartoutput:
7837502Sroot 	tp->t_state &= ~TS_TTSTOP;
7849578Ssam 	tp->t_flags &= ~FLUSHO;
7859578Ssam 
7869578Ssam startoutput:
7877502Sroot 	ttstart(tp);
7887502Sroot }
7897502Sroot 
7907502Sroot /*
7919578Ssam  * Put character on TTY output queue, adding delays,
7927502Sroot  * expanding tabs, and handling the CR/NL bit.
7939578Ssam  * This is called both from the top half for output,
7949578Ssam  * and from interrupt level for echoing.
7957502Sroot  * The arguments are the character and the tty structure.
7967502Sroot  * Returns < 0 if putc succeeds, otherwise returns char to resend
7977502Sroot  * Must be recursive.
7987502Sroot  */
7997502Sroot ttyoutput(c, tp)
8007502Sroot 	register c;
8017502Sroot 	register struct tty *tp;
8027502Sroot {
8037502Sroot 	register char *colp;
8047502Sroot 	register ctype;
8057502Sroot 
8069578Ssam 	if (tp->t_flags & (RAW|LITOUT)) {
8079578Ssam 		if (tp->t_flags&FLUSHO)
8087502Sroot 			return (-1);
8097502Sroot 		if (putc(c, &tp->t_outq))
8107625Ssam 			return (c);
8117502Sroot 		tk_nout++;
8127502Sroot 		return (-1);
8137502Sroot 	}
8149578Ssam 
8157502Sroot 	/*
8169578Ssam 	 * Ignore EOT in normal mode to avoid
8179578Ssam 	 * hanging up certain terminals.
8187502Sroot 	 */
8197502Sroot 	c &= 0177;
8209578Ssam 	if (c == CEOT && (tp->t_flags&CBREAK) == 0)
8217502Sroot 		return (-1);
8227502Sroot 	/*
8237502Sroot 	 * Turn tabs to spaces as required
8247502Sroot 	 */
8259578Ssam 	if (c == '\t' && (tp->t_flags&TBDELAY) == XTABS) {
8267502Sroot 		register int s;
8277502Sroot 
8287502Sroot 		c = 8 - (tp->t_col&7);
8299578Ssam 		if ((tp->t_flags&FLUSHO) == 0) {
8307502Sroot 			s = spl5();		/* don't interrupt tabs */
8317502Sroot 			c -= b_to_q("        ", c, &tp->t_outq);
8327502Sroot 			tk_nout += c;
8337502Sroot 			splx(s);
8347502Sroot 		}
8357502Sroot 		tp->t_col += c;
8367502Sroot 		return (c ? -1 : '\t');
8377502Sroot 	}
8387502Sroot 	tk_nout++;
8397502Sroot 	/*
8407502Sroot 	 * for upper-case-only terminals,
8417502Sroot 	 * generate escapes.
8427502Sroot 	 */
8437502Sroot 	if (tp->t_flags&LCASE) {
8447502Sroot 		colp = "({)}!|^~'`";
8457625Ssam 		while (*colp++)
8467625Ssam 			if (c == *colp++) {
8477502Sroot 				if (ttyoutput('\\', tp) >= 0)
8487502Sroot 					return (c);
8497502Sroot 				c = colp[-2];
8507502Sroot 				break;
8517502Sroot 			}
8529578Ssam 		if ('A' <= c && c <= 'Z') {
8537502Sroot 			if (ttyoutput('\\', tp) >= 0)
8547502Sroot 				return (c);
8559578Ssam 		} else if ('a' <= c && c <= 'z')
8567502Sroot 			c += 'A' - 'a';
8577502Sroot 	}
8589578Ssam 
8597502Sroot 	/*
8607502Sroot 	 * turn <nl> to <cr><lf> if desired.
8617502Sroot 	 */
8629578Ssam 	if (c == '\n' && tp->t_flags&CRMOD)
8637502Sroot 		if (ttyoutput('\r', tp) >= 0)
8647502Sroot 			return (c);
8659578Ssam 	if (c == '~' && tp->t_flags&TILDE)
8667502Sroot 		c = '`';
8679578Ssam 	if ((tp->t_flags&FLUSHO) == 0 && putc(c, &tp->t_outq))
8687502Sroot 		return (c);
8697502Sroot 	/*
8707502Sroot 	 * Calculate delays.
8717502Sroot 	 * The numbers here represent clock ticks
8727502Sroot 	 * and are not necessarily optimal for all terminals.
8737502Sroot 	 * The delays are indicated by characters above 0200.
8747502Sroot 	 * In raw mode there are no delays and the
8757502Sroot 	 * transmission path is 8 bits wide.
8769578Ssam 	 *
8779578Ssam 	 * SHOULD JUST ALLOW USER TO SPECIFY DELAYS
8787502Sroot 	 */
8797502Sroot 	colp = &tp->t_col;
8807502Sroot 	ctype = partab[c];
8817502Sroot 	c = 0;
8827502Sroot 	switch (ctype&077) {
8837502Sroot 
8847502Sroot 	case ORDINARY:
8857502Sroot 		(*colp)++;
8867502Sroot 
8877502Sroot 	case CONTROL:
8887502Sroot 		break;
8897502Sroot 
8907502Sroot 	case BACKSPACE:
8917502Sroot 		if (*colp)
8927502Sroot 			(*colp)--;
8937502Sroot 		break;
8947502Sroot 
8957502Sroot 	case NEWLINE:
8967502Sroot 		ctype = (tp->t_flags >> 8) & 03;
8977625Ssam 		if (ctype == 1) { /* tty 37 */
8987502Sroot 			if (*colp)
8997502Sroot 				c = max(((unsigned)*colp>>4) + 3, (unsigned)6);
9009578Ssam 		} else if (ctype == 2) /* vt05 */
9017502Sroot 			c = 6;
9027502Sroot 		*colp = 0;
9037502Sroot 		break;
9047502Sroot 
9057502Sroot 	case TAB:
9067502Sroot 		ctype = (tp->t_flags >> 10) & 03;
9077625Ssam 		if (ctype == 1) { /* tty 37 */
9087502Sroot 			c = 1 - (*colp | ~07);
9097625Ssam 			if (c < 5)
9107502Sroot 				c = 0;
9117502Sroot 		}
9127502Sroot 		*colp |= 07;
9137502Sroot 		(*colp)++;
9147502Sroot 		break;
9157502Sroot 
9167502Sroot 	case VTAB:
9179578Ssam 		if (tp->t_flags&VTDELAY) /* tty 37 */
9187502Sroot 			c = 0177;
9197502Sroot 		break;
9207502Sroot 
9217502Sroot 	case RETURN:
9227502Sroot 		ctype = (tp->t_flags >> 12) & 03;
9239578Ssam 		if (ctype == 1) /* tn 300 */
9247502Sroot 			c = 5;
9259578Ssam 		else if (ctype == 2) /* ti 700 */
9267502Sroot 			c = 10;
9279578Ssam 		else if (ctype == 3) { /* concept 100 */
9287502Sroot 			int i;
9299578Ssam 
9307502Sroot 			if ((i = *colp) >= 0)
9319578Ssam 				for (; i < 9; i++)
9327502Sroot 					(void) putc(0177, &tp->t_outq);
9337502Sroot 		}
9347502Sroot 		*colp = 0;
9357502Sroot 	}
9369578Ssam 	if (c && (tp->t_flags&FLUSHO) == 0)
9377502Sroot 		(void) putc(c|0200, &tp->t_outq);
9387502Sroot 	return (-1);
9397502Sroot }
9407502Sroot 
9417502Sroot /*
9427502Sroot  * Called from device's read routine after it has
9437502Sroot  * calculated the tty-structure given as argument.
9447502Sroot  */
9457722Swnj ttread(tp, uio)
9467625Ssam 	register struct tty *tp;
9477722Swnj 	struct uio *uio;
9487502Sroot {
9497502Sroot 	register struct clist *qp;
9509578Ssam 	register c, t_flags;
9519578Ssam 	int first, error = 0;
9527502Sroot 
9537502Sroot 	if ((tp->t_state&TS_CARR_ON)==0)
9548520Sroot 		return (EIO);
9557502Sroot loop:
9569578Ssam 	/*
9579578Ssam 	 * Take any pending input first.
9589578Ssam 	 */
9597502Sroot 	(void) spl5();
9609578Ssam 	if (tp->t_flags&PENDIN)
9617502Sroot 		ttypend(tp);
9627502Sroot 	(void) spl0();
9639578Ssam 
9649578Ssam 	/*
9659578Ssam 	 * Hang process if it's in the background.
9669578Ssam 	 */
9677502Sroot 	while (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) {
9687502Sroot 		if (u.u_signal[SIGTTIN] == SIG_IGN ||
9697502Sroot 		    u.u_signal[SIGTTIN] == SIG_HOLD ||
9707502Sroot /*
9717502Sroot 		    (u.u_procp->p_flag&SDETACH) ||
9727502Sroot */
9737502Sroot 		    u.u_procp->p_flag&SVFORK)
9748520Sroot 			return (EIO);
9757502Sroot 		gsignal(u.u_procp->p_pgrp, SIGTTIN);
9767502Sroot 		sleep((caddr_t)&lbolt, TTIPRI);
9777502Sroot 	}
9789578Ssam 	t_flags = tp->t_flags;
9799578Ssam 
9809578Ssam 	/*
9819578Ssam 	 * In raw mode take characters directly from the
9829578Ssam 	 * raw queue w/o processing.  Interlock against
9839578Ssam 	 * device interrupts when interrogating rawq.
9849578Ssam 	 */
9859578Ssam 	if (t_flags&RAW) {
9867502Sroot 		(void) spl5();
9877502Sroot 		if (tp->t_rawq.c_cc <= 0) {
9889578Ssam 			if ((tp->t_state&TS_CARR_ON) == 0 ||
9897502Sroot 			    (tp->t_state&TS_NBIO)) {
9907502Sroot 				(void) spl0();
9919578Ssam 				return (0);
9927502Sroot 			}
9937502Sroot 			sleep((caddr_t)&tp->t_rawq, TTIPRI);
9947502Sroot 			(void) spl0();
9957502Sroot 			goto loop;
9967502Sroot 		}
9977502Sroot 		(void) spl0();
9987722Swnj 		while (tp->t_rawq.c_cc && uio->uio_iovcnt) {
9998520Sroot 			error = passuc(getc(&tp->t_rawq), uio);
10008520Sroot 			if (error)
10017722Swnj 				break;
10027722Swnj 		}
10038520Sroot 		return (error);
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 	 */
10169578Ssam 	(void) spl5();
10179578Ssam 	if (qp->c_cc <= 0) {
10189578Ssam 		if ((tp->t_state&TS_CARR_ON) == 0 ||
10199578Ssam 		    (tp->t_state&TS_NBIO)) {
10207502Sroot 			(void) spl0();
10219578Ssam 			return (EWOULDBLOCK);
10227502Sroot 		}
10239578Ssam 		sleep((caddr_t)&tp->t_rawq, TTIPRI);
10247502Sroot 		(void) spl0();
10259578Ssam 		goto loop;
10269578Ssam 	}
10279578Ssam 	(void) spl0();
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 
10869578Ssam 	/*
10879578Ssam 	 * Look to unblock output now that (presumably)
10889578Ssam 	 * the input queue has gone down.
10899578Ssam 	 */
10907502Sroot 	if (tp->t_state&TS_TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) {
10919578Ssam 		if (putc(tp->t_startc, &tp->t_outq) == 0) {
10927502Sroot 			tp->t_state &= ~TS_TBLOCK;
10937502Sroot 			ttstart(tp);
10947502Sroot 		}
10957502Sroot 		tp->t_char = 0;
10967502Sroot 	}
10978520Sroot 	return (error);
10987502Sroot }
10997502Sroot 
11007502Sroot /*
11017502Sroot  * Called from the device's write routine after it has
11027502Sroot  * calculated the tty-structure given as argument.
11037502Sroot  */
11047822Sroot ttwrite(tp, uio)
11057625Ssam 	register struct tty *tp;
11069578Ssam 	register struct uio *uio;
11077502Sroot {
11087502Sroot 	register char *cp;
11099578Ssam 	register int cc, ce, c;
11109578Ssam 	int i, hiwat, cnt, error, s;
11117502Sroot 	char obuf[OBUFSIZ];
11127502Sroot 
11139578Ssam 	if ((tp->t_state&TS_CARR_ON) == 0)
11148520Sroot 		return (EIO);
11159578Ssam 	hiwat = TTHIWAT(tp);
11169578Ssam 	cnt = uio->uio_resid;
11179578Ssam 	error = 0;
11187502Sroot loop:
11199578Ssam 	/*
11209578Ssam 	 * Hang the process if it's in the background.
11219578Ssam 	 */
11227502Sroot 	while (u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp &&
11239578Ssam 	    (tp->t_flags&TOSTOP) && (u.u_procp->p_flag&SVFORK)==0 &&
11247502Sroot 	    u.u_signal[SIGTTOU] != SIG_IGN &&
11257502Sroot 	    u.u_signal[SIGTTOU] != SIG_HOLD
11267502Sroot /*
11277502Sroot 					     &&
11287502Sroot 	    (u.u_procp->p_flag&SDETACH)==0) {
11297502Sroot */
11307502Sroot 	    ) {
11317502Sroot 		gsignal(u.u_procp->p_pgrp, SIGTTOU);
11327502Sroot 		sleep((caddr_t)&lbolt, TTIPRI);
11337502Sroot 	}
11349578Ssam 
11359578Ssam 	/*
11369578Ssam 	 * Process the user's data in at most OBUFSIZ
11379578Ssam 	 * chunks.  Perform lower case simulation and
11389578Ssam 	 * similar hacks.  Keep track of high water
11399578Ssam 	 * mark, sleep on overflow awaiting device aid
11409578Ssam 	 * in acquiring new space.
11419578Ssam 	 */
11427822Sroot 	while (uio->uio_resid > 0) {
11439578Ssam 		/*
11449578Ssam 		 * Grab a hunk of data from the user.
11459578Ssam 		 */
11467822Sroot 		cc = uio->uio_iov->iov_len;
11477822Sroot 		if (cc == 0) {
11487822Sroot 			uio->uio_iovcnt--;
11497822Sroot 			uio->uio_iov++;
11507822Sroot 			if (uio->uio_iovcnt < 0)
11517822Sroot 				panic("ttwrite");
11527822Sroot 			continue;
11537822Sroot 		}
11547822Sroot 		if (cc > OBUFSIZ)
11557822Sroot 			cc = OBUFSIZ;
11567502Sroot 		cp = obuf;
11579578Ssam 		error = uiomove(cp, (unsigned)cc, UIO_WRITE, uio);
11588520Sroot 		if (error)
11597502Sroot 			break;
11607502Sroot 		if (tp->t_outq.c_cc > hiwat)
11617502Sroot 			goto ovhiwat;
11629578Ssam 		if (tp->t_flags&FLUSHO)
11637502Sroot 			continue;
11649578Ssam 		/*
11659578Ssam 		 * If we're mapping lower case or kludging tildes,
11669578Ssam 		 * then we've got to look at each character, so
11679578Ssam 		 * just feed the stuff to ttyoutput...
11689578Ssam 		 */
11699578Ssam 		if (tp->t_flags & (LCASE|TILDE)) {
11709578Ssam 			while (cc > 0) {
11717502Sroot 				c = *cp++;
11727502Sroot 				tp->t_rocount = 0;
11737625Ssam 				while ((c = ttyoutput(c, tp)) >= 0) {
11747502Sroot 					/* out of clists, wait a bit */
11757502Sroot 					ttstart(tp);
11767502Sroot 					sleep((caddr_t)&lbolt, TTOPRI);
11777502Sroot 					tp->t_rocount = 0;
11787502Sroot 				}
11797502Sroot 				--cc;
11807502Sroot 				if (tp->t_outq.c_cc > hiwat)
11817502Sroot 					goto ovhiwat;
11827502Sroot 			}
11837502Sroot 			continue;
11847502Sroot 		}
11859578Ssam 		/*
11869578Ssam 		 * If nothing fancy need be done, grab those characters we
11879578Ssam 		 * can handle without any of ttyoutput's processing and
11889578Ssam 		 * just transfer them to the output q.  For those chars
11899578Ssam 		 * which require special processing (as indicated by the
11909578Ssam 		 * bits in partab), call ttyoutput.  After processing
11919578Ssam 		 * a hunk of data, look for FLUSHO so ^O's will take effect
11929578Ssam 		 * immediately.
11939578Ssam 		 */
11949578Ssam 		while (cc > 0) {
11959578Ssam 			if (tp->t_flags & (RAW|LITOUT))
11967502Sroot 				ce = cc;
11977502Sroot 			else {
11989578Ssam 				ce = cc - scanc(cc, cp, partab, 077);
11999578Ssam 				/*
12009578Ssam 				 * If ce is zero, then we're processing
12019578Ssam 				 * a special character through ttyoutput.
12029578Ssam 				 */
12039578Ssam 				if (ce == 0) {
12047502Sroot 					tp->t_rocount = 0;
12057502Sroot 					if (ttyoutput(*cp, tp) >= 0) {
12069578Ssam 						/* no c-lists, wait a bit */
12077502Sroot 						ttstart(tp);
12087502Sroot 						sleep((caddr_t)&lbolt, TTOPRI);
12097502Sroot 						continue;
12107502Sroot 					}
12119578Ssam 					cp++, cc--;
12129578Ssam 					if (tp->t_flags&FLUSHO ||
12139578Ssam 					    tp->t_outq.c_cc > hiwat)
12147502Sroot 						goto ovhiwat;
12159578Ssam 					continue;
12167502Sroot 				}
12177502Sroot 			}
12189578Ssam 			/*
12199578Ssam 			 * A bunch of normal characters have been found,
12209578Ssam 			 * transfer them en masse to the output queue and
12219578Ssam 			 * continue processing at the top of the loop.
12229578Ssam 			 * If there are any further characters in this
12239578Ssam 			 * <= OBUFSIZ chunk, the first should be a character
12249578Ssam 			 * requiring special handling by ttyoutput.
12259578Ssam 			 */
12267502Sroot 			tp->t_rocount = 0;
12279578Ssam 			i = b_to_q(cp, ce, &tp->t_outq);
12289578Ssam 			ce -= i;
12299578Ssam 			tp->t_col += ce;
12309578Ssam 			cp += ce, cc -= ce, tk_nout += ce;
12319578Ssam 			if (i > 0) {
12329578Ssam 				/* out of c-lists, wait a bit */
12337502Sroot 				ttstart(tp);
12347502Sroot 				sleep((caddr_t)&lbolt, TTOPRI);
12357502Sroot 			}
12369578Ssam 			if (tp->t_flags&FLUSHO || tp->t_outq.c_cc > hiwat)
12377502Sroot 				goto ovhiwat;
12387502Sroot 		}
12397502Sroot 	}
12407502Sroot 	ttstart(tp);
12418520Sroot 	return (error);
12427502Sroot 
12437502Sroot ovhiwat:
12449578Ssam 	s = spl5();
12459578Ssam 	if (cc != 0) {
12469578Ssam 		uio->uio_iov->iov_base -= cc;
12479578Ssam 		uio->uio_iov->iov_len += cc;
12489578Ssam 		uio->uio_resid += cc;
12499578Ssam 		uio->uio_offset -= cc;
12509578Ssam 	}
12519578Ssam 	/*
12529578Ssam 	 * This can only occur if FLUSHO
12539578Ssam 	 * is also set in t_flags.
12549578Ssam 	 */
12557502Sroot 	if (tp->t_outq.c_cc <= hiwat) {
12569578Ssam 		splx(s);
12577502Sroot 		goto loop;
12587502Sroot 	}
12597502Sroot 	ttstart(tp);
12609578Ssam 	if (tp->t_state&TS_NBIO) {
12617822Sroot 		if (uio->uio_resid == cnt)
12628520Sroot 			return (EWOULDBLOCK);
12638520Sroot 		return (0);
12647502Sroot 	}
12657502Sroot 	tp->t_state |= TS_ASLEEP;
12667502Sroot 	sleep((caddr_t)&tp->t_outq, TTOPRI);
12679578Ssam 	splx(s);
12687502Sroot 	goto loop;
12697502Sroot }
12707502Sroot 
12717502Sroot /*
12727502Sroot  * Rubout one character from the rawq of tp
12737502Sroot  * as cleanly as possible.
12747502Sroot  */
12757502Sroot ttyrub(c, tp)
12767625Ssam 	register c;
12777625Ssam 	register struct tty *tp;
12787502Sroot {
12797502Sroot 	register char *cp;
12807502Sroot 	register int savecol;
12817502Sroot 	int s;
12827502Sroot 	char *nextc();
12837502Sroot 
12849578Ssam 	if ((tp->t_flags&ECHO) == 0)
12857502Sroot 		return;
12869578Ssam 	tp->t_flags &= ~FLUSHO;
12877502Sroot 	c &= 0377;
12889578Ssam 	if (tp->t_flags&CRTBS) {
12897502Sroot 		if (tp->t_rocount == 0) {
12907502Sroot 			/*
12917502Sroot 			 * Screwed by ttwrite; retype
12927502Sroot 			 */
12937502Sroot 			ttyretype(tp);
12947502Sroot 			return;
12957502Sroot 		}
12969578Ssam 		if (c == ('\t'|0200) || c == ('\n'|0200))
12977502Sroot 			ttyrubo(tp, 2);
12989578Ssam 		else switch (partab[c&=0177]&0177) {
12997502Sroot 
13007502Sroot 		case ORDINARY:
13017502Sroot 			if (tp->t_flags&LCASE && c >= 'A' && c <= 'Z')
13027502Sroot 				ttyrubo(tp, 2);
13037502Sroot 			else
13047502Sroot 				ttyrubo(tp, 1);
13057502Sroot 			break;
13067502Sroot 
13077502Sroot 		case VTAB:
13087502Sroot 		case BACKSPACE:
13097502Sroot 		case CONTROL:
13107502Sroot 		case RETURN:
13119578Ssam 			if (tp->t_flags&CTLECH)
13127502Sroot 				ttyrubo(tp, 2);
13137502Sroot 			break;
13147502Sroot 
13157502Sroot 		case TAB:
13167502Sroot 			if (tp->t_rocount < tp->t_rawq.c_cc) {
13177502Sroot 				ttyretype(tp);
13187502Sroot 				return;
13197502Sroot 			}
13207502Sroot 			s = spl5();
13217502Sroot 			savecol = tp->t_col;
13229578Ssam 			tp->t_state |= TS_CNTTB;
13239578Ssam 			tp->t_flags |= FLUSHO;
13247502Sroot 			tp->t_col = tp->t_rocol;
13259578Ssam 			cp = tp->t_rawq.c_cf;
13269578Ssam 			for (; cp; cp = nextc(&tp->t_rawq, cp))
13277502Sroot 				ttyecho(*cp, tp);
13289578Ssam 			tp->t_flags &= ~FLUSHO;
13299578Ssam 			tp->t_state &= ~TS_CNTTB;
13307502Sroot 			splx(s);
13317502Sroot 			/*
13327502Sroot 			 * savecol will now be length of the tab
13337502Sroot 			 */
13347502Sroot 			savecol -= tp->t_col;
13357502Sroot 			tp->t_col += savecol;
13367502Sroot 			if (savecol > 8)
13377502Sroot 				savecol = 8;		/* overflow screw */
13387502Sroot 			while (--savecol >= 0)
13397502Sroot 				(void) ttyoutput('\b', tp);
13407502Sroot 			break;
13417502Sroot 
13427502Sroot 		default:
13437502Sroot 			panic("ttyrub");
13447502Sroot 		}
13459578Ssam 	} else if (tp->t_flags&PRTERA) {
13469578Ssam 		if ((tp->t_state&TS_ERASE) == 0) {
13477502Sroot 			(void) ttyoutput('\\', tp);
13489578Ssam 			tp->t_state |= TS_ERASE;
13497502Sroot 		}
13507502Sroot 		ttyecho(c, tp);
13517502Sroot 	} else
13527502Sroot 		ttyecho(tp->t_erase, tp);
13537502Sroot 	tp->t_rocount--;
13547502Sroot }
13557502Sroot 
13567502Sroot /*
13577502Sroot  * Crt back over cnt chars perhaps
13587502Sroot  * erasing them.
13597502Sroot  */
13607502Sroot ttyrubo(tp, cnt)
13617625Ssam 	register struct tty *tp;
13627625Ssam 	int cnt;
13637502Sroot {
13649578Ssam 	register char *rubostring = tp->t_flags&CRTERA ? "\b \b" : "\b";
13657502Sroot 
13667502Sroot 	while (--cnt >= 0)
13679578Ssam 		ttyout(rubostring, tp);
13687502Sroot }
13697502Sroot 
13707502Sroot /*
13717502Sroot  * Reprint the rawq line.
13727502Sroot  * We assume c_cc has already been checked.
13737502Sroot  */
13747502Sroot ttyretype(tp)
13757625Ssam 	register struct tty *tp;
13767502Sroot {
13777502Sroot 	register char *cp;
13787502Sroot 	char *nextc();
13797502Sroot 	int s;
13807502Sroot 
13819578Ssam 	if (tp->t_rprntc != 0377)
13829578Ssam 		ttyecho(tp->t_rprntc, tp);
13837502Sroot 	(void) ttyoutput('\n', tp);
13847502Sroot 	s = spl5();
13857502Sroot 	for (cp = tp->t_canq.c_cf; cp; cp = nextc(&tp->t_canq, cp))
13867502Sroot 		ttyecho(*cp, tp);
13877502Sroot 	for (cp = tp->t_rawq.c_cf; cp; cp = nextc(&tp->t_rawq, cp))
13887502Sroot 		ttyecho(*cp, tp);
13899578Ssam 	tp->t_state &= ~TS_ERASE;
13907502Sroot 	splx(s);
13917502Sroot 	tp->t_rocount = tp->t_rawq.c_cc;
13927502Sroot 	tp->t_rocol = 0;
13937502Sroot }
13947502Sroot 
13957502Sroot /*
13967502Sroot  * Echo a typed character to the terminal
13977502Sroot  */
13987502Sroot ttyecho(c, tp)
13997625Ssam 	register c;
14007625Ssam 	register struct tty *tp;
14017502Sroot {
14027502Sroot 
14039578Ssam 	if ((tp->t_state&TS_CNTTB) == 0)
14049578Ssam 		tp->t_flags &= ~FLUSHO;
14057502Sroot 	if ((tp->t_flags&ECHO) == 0)
14067502Sroot 		return;
14077502Sroot 	c &= 0377;
14087502Sroot 	if (tp->t_flags&RAW) {
14097502Sroot 		(void) ttyoutput(c, tp);
14107502Sroot 		return;
14117502Sroot 	}
14127502Sroot 	if (c == '\r' && tp->t_flags&CRMOD)
14137502Sroot 		c = '\n';
14149578Ssam 	if (tp->t_flags&CTLECH) {
14157502Sroot 		if ((c&0177) <= 037 && c!='\t' && c!='\n' || (c&0177)==0177) {
14167502Sroot 			(void) ttyoutput('^', tp);
14177502Sroot 			c &= 0177;
14187502Sroot 			if (c == 0177)
14197502Sroot 				c = '?';
14207502Sroot 			else if (tp->t_flags&LCASE)
14217502Sroot 				c += 'a' - 1;
14227502Sroot 			else
14237502Sroot 				c += 'A' - 1;
14247502Sroot 		}
14257502Sroot 	}
14267502Sroot 	if ((tp->t_flags&LCASE) && (c >= 'A' && c <= 'Z'))
14277502Sroot 		c += 'a' - 'A';
14289578Ssam 	(void) ttyoutput(c&0177, tp);
14297502Sroot }
14307502Sroot 
14317502Sroot /*
14327502Sroot  * Is c a break char for tp?
14337502Sroot  */
14347502Sroot ttbreakc(c, tp)
14357625Ssam 	register c;
14367625Ssam 	register struct tty *tp;
14377502Sroot {
14389578Ssam 	return (c == '\n' || c == tp->t_eofc || c == tp->t_brkc ||
14397502Sroot 		c == '\r' && (tp->t_flags&CRMOD));
14407502Sroot }
14417502Sroot 
14427502Sroot /*
14437502Sroot  * send string cp to tp
14447502Sroot  */
14457502Sroot ttyout(cp, tp)
14467625Ssam 	register char *cp;
14477625Ssam 	register struct tty *tp;
14487502Sroot {
14497502Sroot 	register char c;
14507502Sroot 
14517502Sroot 	while (c = *cp++)
14527502Sroot 		(void) ttyoutput(c, tp);
14537502Sroot }
14547502Sroot 
14557502Sroot ttwakeup(tp)
14567502Sroot 	struct tty *tp;
14577502Sroot {
14587502Sroot 
14597502Sroot 	if (tp->t_rsel) {
14607502Sroot 		selwakeup(tp->t_rsel, tp->t_state&TS_RCOLL);
14617502Sroot 		tp->t_state &= ~TS_RCOLL;
14627502Sroot 		tp->t_rsel = 0;
14637502Sroot 	}
14647502Sroot 	wakeup((caddr_t)&tp->t_rawq);
14657502Sroot }
14667502Sroot 
14679578Ssam #ifndef vax
14689578Ssam scanc(size, cp, table, mask)
14699578Ssam 	register int size;
14709578Ssam 	register char *cp, table[];
14719578Ssam 	register int mask;
14727502Sroot {
14739578Ssam 	register int i = 0;
14747502Sroot 
14759578Ssam 	while ((table[*(u_char *)(cp + i)]&mask) == 0 && i < size)
14769578Ssam 		i++;
14779578Ssam 	return (i);
14787502Sroot }
14799578Ssam #endif
1480