xref: /csrg-svn/sys/kern/tty.c (revision 17545)
1*17545Skarels /*	tty.c	6.12	84/12/20	*/
239Sbill 
39760Ssam #include "../machine/reg.h"
49760Ssam 
517095Sbloom #include "param.h"
617095Sbloom #include "systm.h"
717095Sbloom #include "dir.h"
817095Sbloom #include "user.h"
917095Sbloom #include "ioctl.h"
1017095Sbloom #include "tty.h"
1117095Sbloom #include "proc.h"
1217095Sbloom #include "inode.h"
1317095Sbloom #include "file.h"
1417095Sbloom #include "conf.h"
1517095Sbloom #include "buf.h"
1617095Sbloom #include "dk.h"
1717095Sbloom #include "uio.h"
1817095Sbloom #include "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  */
11512752Ssam ttywflush(tp)
1165408Swnj 	register struct tty *tp;
11739Sbill {
11839Sbill 
11912752Ssam 	ttywait(tp);
12012752Ssam 	ttyflush(tp, FREAD);
12112752Ssam }
12212752Ssam 
12312752Ssam ttywait(tp)
12412752Ssam 	register struct tty *tp;
12512752Ssam {
126*17545Skarels 	register int s = spltty();
12712752Ssam 
12813809Ssam 	while ((tp->t_outq.c_cc || tp->t_state&TS_BUSY) &&
12913809Ssam 	    tp->t_state&TS_CARR_ON && tp->t_oproc) {	/* kludge for pty */
130903Sbill 		(*tp->t_oproc)(tp);
1315408Swnj 		tp->t_state |= TS_ASLEEP;
132903Sbill 		sleep((caddr_t)&tp->t_outq, TTOPRI);
133903Sbill 	}
1349859Ssam 	splx(s);
13539Sbill }
13639Sbill 
13739Sbill /*
1389578Ssam  * Flush all TTY queues
13939Sbill  */
14012752Ssam ttyflush(tp, rw)
1417625Ssam 	register struct tty *tp;
14239Sbill {
143903Sbill 	register s;
144903Sbill 
145*17545Skarels 	s = spltty();
146903Sbill 	if (rw & FREAD) {
147903Sbill 		while (getc(&tp->t_canq) >= 0)
148903Sbill 			;
149903Sbill 		wakeup((caddr_t)&tp->t_rawq);
150903Sbill 	}
151903Sbill 	if (rw & FWRITE) {
152903Sbill 		wakeup((caddr_t)&tp->t_outq);
1535408Swnj 		tp->t_state &= ~TS_TTSTOP;
1545426Swnj 		(*cdevsw[major(tp->t_dev)].d_stop)(tp, rw);
155903Sbill 		while (getc(&tp->t_outq) >= 0)
156903Sbill 			;
157903Sbill 	}
158903Sbill 	if (rw & FREAD) {
159903Sbill 		while (getc(&tp->t_rawq) >= 0)
160903Sbill 			;
1619578Ssam 		tp->t_rocount = 0;
162903Sbill 		tp->t_rocol = 0;
1639578Ssam 		tp->t_state &= ~TS_LOCAL;
164903Sbill 	}
165903Sbill 	splx(s);
16639Sbill }
16739Sbill 
168903Sbill /*
169903Sbill  * Send stop character on input overflow.
170903Sbill  */
171903Sbill ttyblock(tp)
1727625Ssam 	register struct tty *tp;
17339Sbill {
174903Sbill 	register x;
1759578Ssam 
176903Sbill 	x = tp->t_rawq.c_cc + tp->t_canq.c_cc;
177903Sbill 	if (tp->t_rawq.c_cc > TTYHOG) {
17812752Ssam 		ttyflush(tp, FREAD|FWRITE);
1795408Swnj 		tp->t_state &= ~TS_TBLOCK;
180903Sbill 	}
18115118Skarels 	/*
18215118Skarels 	 * Block further input iff:
18315118Skarels 	 * Current input > threshold AND input is available to user program
18415118Skarels 	 */
18516055Skarels 	if (x >= TTYHOG/2 &&
18616055Skarels 	    ((tp->t_flags & (RAW|CBREAK)) || (tp->t_canq.c_cc > 0))) {
18715118Skarels 		if (putc(tp->t_stopc, &tp->t_outq)==0) {
18815118Skarels 			tp->t_state |= TS_TBLOCK;
18915118Skarels 			ttstart(tp);
19015118Skarels 		}
191903Sbill 	}
19239Sbill }
19339Sbill 
19439Sbill /*
195903Sbill  * Restart typewriter output following a delay
196903Sbill  * timeout.
197903Sbill  * The name of the routine is passed to the timeout
198903Sbill  * subroutine and it is called during a clock interrupt.
199121Sbill  */
200903Sbill ttrstrt(tp)
2017625Ssam 	register struct tty *tp;
202121Sbill {
203121Sbill 
2049578Ssam 	if (tp == 0)
2059578Ssam 		panic("ttrstrt");
2065408Swnj 	tp->t_state &= ~TS_TIMEOUT;
207903Sbill 	ttstart(tp);
208121Sbill }
209121Sbill 
210121Sbill /*
211903Sbill  * Start output on the typewriter. It is used from the top half
212903Sbill  * after some characters have been put on the output queue,
213903Sbill  * from the interrupt routine to transmit the next
214903Sbill  * character, and after a timeout has finished.
21539Sbill  */
216903Sbill ttstart(tp)
2177625Ssam 	register struct tty *tp;
21839Sbill {
219903Sbill 	register s;
22039Sbill 
221*17545Skarels 	s = spltty();
2229578Ssam 	if ((tp->t_state & (TS_TIMEOUT|TS_TTSTOP|TS_BUSY)) == 0 &&
2235622Swnj 	    tp->t_oproc)		/* kludge for pty */
224903Sbill 		(*tp->t_oproc)(tp);
225903Sbill 	splx(s);
22639Sbill }
22739Sbill 
22839Sbill /*
229903Sbill  * Common code for tty ioctls.
23039Sbill  */
2311780Sbill /*ARGSUSED*/
2327625Ssam ttioctl(tp, com, data, flag)
2337625Ssam 	register struct tty *tp;
2347625Ssam 	caddr_t data;
23539Sbill {
2368520Sroot 	int dev = tp->t_dev;
23739Sbill 	extern int nldisp;
2388556Sroot 	int s;
23912752Ssam 	register int newflags;
24039Sbill 
241903Sbill 	/*
242903Sbill 	 * If the ioctl involves modification,
243*17545Skarels 	 * hang if in the background.
244903Sbill 	 */
2457625Ssam 	switch (com) {
24639Sbill 
247915Sbill 	case TIOCSETD:
248915Sbill 	case TIOCSETP:
249915Sbill 	case TIOCSETN:
250903Sbill 	case TIOCFLUSH:
251903Sbill 	case TIOCSETC:
252903Sbill 	case TIOCSLTC:
253903Sbill 	case TIOCSPGRP:
254903Sbill 	case TIOCLBIS:
255903Sbill 	case TIOCLBIC:
256903Sbill 	case TIOCLSET:
2579325Ssam 	case TIOCSTI:
25815078Skarels #define bit(a) (1<<(a-1))
259903Sbill 		while (tp->t_line == NTTYDISC &&
260903Sbill 		   u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp &&
261903Sbill 		   (u.u_procp->p_flag&SVFORK) == 0 &&
26215078Skarels 		   !(u.u_procp->p_sigignore & bit(SIGTTOU)) &&
26315078Skarels 		   !(u.u_procp->p_sigmask & bit(SIGTTOU))) {
264903Sbill 			gsignal(u.u_procp->p_pgrp, SIGTTOU);
265903Sbill 			sleep((caddr_t)&lbolt, TTOPRI);
266903Sbill 		}
267903Sbill 		break;
268903Sbill 	}
26915078Skarels #undef	bit
270903Sbill 
2719578Ssam 	/*
2729578Ssam 	 * Process the ioctl.
2739578Ssam 	 */
2747625Ssam 	switch (com) {
275903Sbill 
2768556Sroot 	/* get discipline number */
27739Sbill 	case TIOCGETD:
2787625Ssam 		*(int *)data = tp->t_line;
27939Sbill 		break;
28039Sbill 
2818556Sroot 	/* set line discipline */
2827625Ssam 	case TIOCSETD: {
2837625Ssam 		register int t = *(int *)data;
2849578Ssam 		int error = 0;
2857625Ssam 
28615078Skarels 		if ((unsigned) t >= nldisp)
28710851Ssam 			return (ENXIO);
288*17545Skarels 		s = spltty();
28939Sbill 		if (tp->t_line)
29039Sbill 			(*linesw[tp->t_line].l_close)(tp);
29139Sbill 		if (t)
2928556Sroot 			error = (*linesw[t].l_open)(dev, tp);
2938556Sroot 		splx(s);
29410851Ssam 		if (error) {
295*17545Skarels 			s = spltty();
29610851Ssam 			if (tp->t_line)
29710851Ssam 				(void) (*linesw[tp->t_line].l_open)(dev, tp);
29810851Ssam 			splx(s);
2998556Sroot 			return (error);
30010851Ssam 		}
3018556Sroot 		tp->t_line = t;
30239Sbill 		break;
3037625Ssam 	}
30439Sbill 
3058556Sroot 	/* prevent more opens on channel */
3065614Swnj 	case TIOCEXCL:
3075614Swnj 		tp->t_state |= TS_XCLUDE;
3085614Swnj 		break;
3095614Swnj 
3105614Swnj 	case TIOCNXCL:
3115614Swnj 		tp->t_state &= ~TS_XCLUDE;
3125614Swnj 		break;
3135614Swnj 
3148556Sroot 	/* hang up line on last close */
31539Sbill 	case TIOCHPCL:
3165408Swnj 		tp->t_state |= TS_HUPCLS;
31739Sbill 		break;
31839Sbill 
3193942Sbugs 	case TIOCFLUSH: {
3207625Ssam 		register int flags = *(int *)data;
3217625Ssam 
3227625Ssam 		if (flags == 0)
3233942Sbugs 			flags = FREAD|FWRITE;
3247625Ssam 		else
3257625Ssam 			flags &= FREAD|FWRITE;
32612752Ssam 		ttyflush(tp, flags);
32739Sbill 		break;
3283944Sbugs 	}
32939Sbill 
3308556Sroot 	/* return number of characters immediately available */
3317625Ssam 	case FIONREAD:
3327625Ssam 		*(off_t *)data = ttnread(tp);
333174Sbill 		break;
334174Sbill 
33513077Ssam 	case TIOCOUTQ:
33613077Ssam 		*(int *)data = tp->t_outq.c_cc;
33713077Ssam 		break;
33813077Ssam 
3398589Sroot 	case TIOCSTOP:
340*17545Skarels 		s = spltty();
3419578Ssam 		if ((tp->t_state&TS_TTSTOP) == 0) {
3425573Swnj 			tp->t_state |= TS_TTSTOP;
3435573Swnj 			(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
3445573Swnj 		}
3457625Ssam 		splx(s);
3465573Swnj 		break;
3475573Swnj 
3488589Sroot 	case TIOCSTART:
349*17545Skarels 		s = spltty();
3509578Ssam 		if ((tp->t_state&TS_TTSTOP) || (tp->t_flags&FLUSHO)) {
3515573Swnj 			tp->t_state &= ~TS_TTSTOP;
3529578Ssam 			tp->t_flags &= ~FLUSHO;
3535573Swnj 			ttstart(tp);
3545573Swnj 		}
3557625Ssam 		splx(s);
3565573Swnj 		break;
3575573Swnj 
3589325Ssam 	/*
3599325Ssam 	 * Simulate typing of a character at the terminal.
3609325Ssam 	 */
3619325Ssam 	case TIOCSTI:
36217183Smckusick 		if (u.u_uid && (flag & FREAD) == 0)
36317183Smckusick 			return (EPERM);
3649325Ssam 		if (u.u_uid && u.u_ttyp != tp)
3659325Ssam 			return (EACCES);
3669578Ssam 		(*linesw[tp->t_line].l_rint)(*(char *)data, tp);
3679325Ssam 		break;
3689325Ssam 
36912752Ssam 	case TIOCSETP:
37012752Ssam 	case TIOCSETN: {
37112752Ssam 		register struct sgttyb *sg = (struct sgttyb *)data;
37212752Ssam 
37312752Ssam 		tp->t_erase = sg->sg_erase;
37412752Ssam 		tp->t_kill = sg->sg_kill;
37512752Ssam 		tp->t_ispeed = sg->sg_ispeed;
37612752Ssam 		tp->t_ospeed = sg->sg_ospeed;
37712752Ssam 		newflags = (tp->t_flags&0xffff0000) | (sg->sg_flags&0xffff);
378*17545Skarels 		s = spltty();
37912752Ssam 		if (tp->t_flags&RAW || newflags&RAW || com == TIOCSETP) {
38012752Ssam 			ttywait(tp);
38112752Ssam 			ttyflush(tp, FREAD);
38212752Ssam 		} else if ((tp->t_flags&CBREAK) != (newflags&CBREAK)) {
38312752Ssam 			if (newflags&CBREAK) {
38412752Ssam 				struct clist tq;
38512752Ssam 
38612752Ssam 				catq(&tp->t_rawq, &tp->t_canq);
38712752Ssam 				tq = tp->t_rawq;
38812752Ssam 				tp->t_rawq = tp->t_canq;
38912752Ssam 				tp->t_canq = tq;
39012752Ssam 			} else {
39112752Ssam 				tp->t_flags |= PENDIN;
39213801Ssam 				newflags |= PENDIN;
39312752Ssam 				ttwakeup(tp);
39412752Ssam 			}
39512752Ssam 		}
39612752Ssam 		tp->t_flags = newflags;
39712752Ssam 		if (tp->t_flags&RAW) {
39812752Ssam 			tp->t_state &= ~TS_TTSTOP;
39912752Ssam 			ttstart(tp);
40012752Ssam 		}
40112752Ssam 		splx(s);
40212752Ssam 		break;
40312752Ssam 	}
40412752Ssam 
40512752Ssam 	/* send current parameters to user */
40612752Ssam 	case TIOCGETP: {
40712752Ssam 		register struct sgttyb *sg = (struct sgttyb *)data;
40812752Ssam 
40912752Ssam 		sg->sg_ispeed = tp->t_ispeed;
41012752Ssam 		sg->sg_ospeed = tp->t_ospeed;
41112752Ssam 		sg->sg_erase = tp->t_erase;
41212752Ssam 		sg->sg_kill = tp->t_kill;
41312752Ssam 		sg->sg_flags = tp->t_flags;
41412752Ssam 		break;
41512752Ssam 	}
41612752Ssam 
41712752Ssam 	case FIONBIO:
41812752Ssam 		if (*(int *)data)
41912752Ssam 			tp->t_state |= TS_NBIO;
42012752Ssam 		else
42112752Ssam 			tp->t_state &= ~TS_NBIO;
42212752Ssam 		break;
42312752Ssam 
42412752Ssam 	case FIOASYNC:
42512752Ssam 		if (*(int *)data)
42612752Ssam 			tp->t_state |= TS_ASYNC;
42712752Ssam 		else
42812752Ssam 			tp->t_state &= ~TS_ASYNC;
42912752Ssam 		break;
43012752Ssam 
43113077Ssam 	case TIOCGETC:
43213077Ssam 		bcopy((caddr_t)&tp->t_intrc, data, sizeof (struct tchars));
43313077Ssam 		break;
43413077Ssam 
43513077Ssam 	case TIOCSETC:
43613077Ssam 		bcopy(data, (caddr_t)&tp->t_intrc, sizeof (struct tchars));
43713077Ssam 		break;
43813077Ssam 
43912752Ssam 	/* set/get local special characters */
44012752Ssam 	case TIOCSLTC:
44112752Ssam 		bcopy(data, (caddr_t)&tp->t_suspc, sizeof (struct ltchars));
44212752Ssam 		break;
44312752Ssam 
44412752Ssam 	case TIOCGLTC:
44512752Ssam 		bcopy((caddr_t)&tp->t_suspc, data, sizeof (struct ltchars));
44612752Ssam 		break;
44712752Ssam 
44812752Ssam 	/*
44912752Ssam 	 * Modify local mode word.
45012752Ssam 	 */
45112752Ssam 	case TIOCLBIS:
45212752Ssam 		tp->t_flags |= *(int *)data << 16;
45312752Ssam 		break;
45412752Ssam 
45512752Ssam 	case TIOCLBIC:
45612752Ssam 		tp->t_flags &= ~(*(int *)data << 16);
45712752Ssam 		break;
45812752Ssam 
45912752Ssam 	case TIOCLSET:
46012752Ssam 		tp->t_flags &= 0xffff;
46112752Ssam 		tp->t_flags |= *(int *)data << 16;
46212752Ssam 		break;
46312752Ssam 
46412752Ssam 	case TIOCLGET:
46515720Skarels 		*(int *)data = ((unsigned) tp->t_flags) >> 16;
46612752Ssam 		break;
46712752Ssam 
468*17545Skarels 	/*
469*17545Skarels 	 * Allow SPGRP only if tty is ours and is open for reading.
470*17545Skarels 	 */
47112752Ssam 	case TIOCSPGRP:
472*17545Skarels 		{
473*17545Skarels 		struct proc *p;
474*17545Skarels 		int pgrp = *(int *)data;
475*17545Skarels 
476*17545Skarels 		if (u.u_uid && (flag & FREAD) == 0)
477*17545Skarels 			return (EPERM);
478*17545Skarels 		if (u.u_uid && u.u_ttyp != tp)
479*17545Skarels 			return (EACCES);
480*17545Skarels 		tp->t_pgrp = pgrp;
48112752Ssam 		break;
482*17545Skarels 		}
48312752Ssam 
48412752Ssam 	case TIOCGPGRP:
48512752Ssam 		*(int *)data = tp->t_pgrp;
48612752Ssam 		break;
48712752Ssam 
48839Sbill 	default:
4898556Sroot 		return (-1);
49039Sbill 	}
4918556Sroot 	return (0);
49239Sbill }
4934484Swnj 
4944484Swnj ttnread(tp)
4954484Swnj 	struct tty *tp;
4964484Swnj {
4974484Swnj 	int nread = 0;
4984484Swnj 
4999578Ssam 	if (tp->t_flags & PENDIN)
5004484Swnj 		ttypend(tp);
5014484Swnj 	nread = tp->t_canq.c_cc;
5024484Swnj 	if (tp->t_flags & (RAW|CBREAK))
5034484Swnj 		nread += tp->t_rawq.c_cc;
5044484Swnj 	return (nread);
5054484Swnj }
5064484Swnj 
5075408Swnj ttselect(dev, rw)
5084484Swnj 	dev_t dev;
5095408Swnj 	int rw;
5104484Swnj {
5114484Swnj 	register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)];
5124484Swnj 	int nread;
513*17545Skarels 	int s = spltty();
5144484Swnj 
5155408Swnj 	switch (rw) {
5164484Swnj 
5174484Swnj 	case FREAD:
5184484Swnj 		nread = ttnread(tp);
5194484Swnj 		if (nread > 0)
5205408Swnj 			goto win;
5214938Swnj 		if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait)
5225408Swnj 			tp->t_state |= TS_RCOLL;
5234484Swnj 		else
5244484Swnj 			tp->t_rsel = u.u_procp;
5255408Swnj 		break;
5264484Swnj 
5275408Swnj 	case FWRITE:
5285408Swnj 		if (tp->t_outq.c_cc <= TTLOWAT(tp))
5295408Swnj 			goto win;
5305408Swnj 		if (tp->t_wsel && tp->t_wsel->p_wchan == (caddr_t)&selwait)
5315408Swnj 			tp->t_state |= TS_WCOLL;
5325408Swnj 		else
5335408Swnj 			tp->t_wsel = u.u_procp;
5345408Swnj 		break;
5354484Swnj 	}
5365408Swnj 	splx(s);
5375408Swnj 	return (0);
5385408Swnj win:
5395408Swnj 	splx(s);
5405408Swnj 	return (1);
5414484Swnj }
5427436Skre 
5437502Sroot /*
5449578Ssam  * Establish a process group for distribution of
5457502Sroot  * quits and interrupts from the tty.
5467502Sroot  */
5477502Sroot ttyopen(dev, tp)
5487625Ssam 	dev_t dev;
5497625Ssam 	register struct tty *tp;
5507502Sroot {
5517502Sroot 	register struct proc *pp;
5527502Sroot 
5537502Sroot 	pp = u.u_procp;
5547502Sroot 	tp->t_dev = dev;
5557625Ssam 	if (pp->p_pgrp == 0) {
5567502Sroot 		u.u_ttyp = tp;
5577502Sroot 		u.u_ttyd = dev;
5587502Sroot 		if (tp->t_pgrp == 0)
5597502Sroot 			tp->t_pgrp = pp->p_pid;
5607502Sroot 		pp->p_pgrp = tp->t_pgrp;
5617502Sroot 	}
5627502Sroot 	tp->t_state &= ~TS_WOPEN;
563*17545Skarels 	if ((tp->t_state & TS_ISOPEN) == 0) {
564*17545Skarels 		tp->t_state |= TS_ISOPEN;
565*17545Skarels 		if (tp->t_line != NTTYDISC)
566*17545Skarels 			ttywflush(tp);
567*17545Skarels 	}
5688556Sroot 	return (0);
5697502Sroot }
5707502Sroot 
5717502Sroot /*
5727502Sroot  * clean tp on last close
5737502Sroot  */
5747502Sroot ttyclose(tp)
5757625Ssam 	register struct tty *tp;
5767502Sroot {
5777502Sroot 
5787502Sroot 	if (tp->t_line) {
57912752Ssam 		ttywflush(tp);
5807502Sroot 		tp->t_line = 0;
5817502Sroot 		return;
5827502Sroot 	}
5837502Sroot 	tp->t_pgrp = 0;
58412752Ssam 	ttywflush(tp);
5857502Sroot 	tp->t_state = 0;
5867502Sroot }
5877502Sroot 
5887502Sroot /*
5897502Sroot  * reinput pending characters after state switch
590*17545Skarels  * call at spltty().
5917502Sroot  */
5927502Sroot ttypend(tp)
5937625Ssam 	register struct tty *tp;
5947502Sroot {
5957502Sroot 	struct clist tq;
5967502Sroot 	register c;
5977502Sroot 
5989578Ssam 	tp->t_flags &= ~PENDIN;
5999578Ssam 	tp->t_state |= TS_TYPEN;
6007502Sroot 	tq = tp->t_rawq;
6017502Sroot 	tp->t_rawq.c_cc = 0;
6027502Sroot 	tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0;
6037502Sroot 	while ((c = getc(&tq)) >= 0)
6047502Sroot 		ttyinput(c, tp);
6059578Ssam 	tp->t_state &= ~TS_TYPEN;
6067502Sroot }
6077502Sroot 
6087502Sroot /*
6099578Ssam  * Place a character on raw TTY input queue,
6109578Ssam  * putting in delimiters and waking up top
6119578Ssam  * half as needed.  Also echo if required.
6129578Ssam  * The arguments are the character and the
6139578Ssam  * appropriate tty structure.
6147502Sroot  */
6157502Sroot ttyinput(c, tp)
6167625Ssam 	register c;
6177625Ssam 	register struct tty *tp;
6187502Sroot {
6199578Ssam 	register int t_flags = tp->t_flags;
6207502Sroot 	int i;
6217502Sroot 
6229578Ssam 	/*
6239578Ssam 	 * If input is pending take it first.
6249578Ssam 	 */
6259578Ssam 	if (t_flags&PENDIN)
6267502Sroot 		ttypend(tp);
6277502Sroot 	tk_nin++;
6287502Sroot 	c &= 0377;
6299578Ssam 
6309578Ssam 	/*
6319578Ssam 	 * In tandem mode, check high water mark.
6329578Ssam 	 */
6337502Sroot 	if (t_flags&TANDEM)
6347502Sroot 		ttyblock(tp);
6359578Ssam 
6369578Ssam 	if (t_flags&RAW) {
6379578Ssam 		/*
6389578Ssam 		 * Raw mode, just put character
6399578Ssam 		 * in input q w/o interpretation.
6409578Ssam 		 */
6419578Ssam 		if (tp->t_rawq.c_cc > TTYHOG)
64212752Ssam 			ttyflush(tp, FREAD|FWRITE);
6439578Ssam 		else {
6449578Ssam 			if (putc(c, &tp->t_rawq) >= 0)
6459578Ssam 				ttwakeup(tp);
6469578Ssam 			ttyecho(c, tp);
6477502Sroot 		}
6489578Ssam 		goto endcase;
6499578Ssam 	}
6509578Ssam 
6519578Ssam 	/*
6529578Ssam 	 * Ignore any high bit added during
6539578Ssam 	 * previous ttyinput processing.
6549578Ssam 	 */
6559578Ssam 	if ((tp->t_state&TS_TYPEN) == 0)
6569578Ssam 		c &= 0177;
6579578Ssam 	/*
6589578Ssam 	 * Check for literal nexting very first
6599578Ssam 	 */
6609578Ssam 	if (tp->t_state&TS_LNCH) {
6619578Ssam 		c |= 0200;
6629578Ssam 		tp->t_state &= ~TS_LNCH;
6639578Ssam 	}
6649578Ssam 
6659578Ssam 	/*
6669578Ssam 	 * Scan for special characters.  This code
6679578Ssam 	 * is really just a big case statement with
6689578Ssam 	 * non-constant cases.  The bottom of the
6699578Ssam 	 * case statement is labeled ``endcase'', so goto
6709578Ssam 	 * it after a case match, or similar.
6719578Ssam 	 */
6729578Ssam 	if (tp->t_line == NTTYDISC) {
6739578Ssam 		if (c == tp->t_lnextc) {
6747502Sroot 			if (tp->t_flags&ECHO)
6757502Sroot 				ttyout("^\b", tp);
6769578Ssam 			tp->t_state |= TS_LNCH;
6779578Ssam 			goto endcase;
6789578Ssam 		}
6799578Ssam 		if (c == tp->t_flushc) {
6809578Ssam 			if (tp->t_flags&FLUSHO)
6819578Ssam 				tp->t_flags &= ~FLUSHO;
6827502Sroot 			else {
68312752Ssam 				ttyflush(tp, FWRITE);
6847502Sroot 				ttyecho(c, tp);
6859578Ssam 				if (tp->t_rawq.c_cc + tp->t_canq.c_cc)
6867502Sroot 					ttyretype(tp);
6879578Ssam 				tp->t_flags |= FLUSHO;
6887502Sroot 			}
6899578Ssam 			goto startoutput;
6909578Ssam 		}
6919578Ssam 		if (c == tp->t_suspc) {
6929578Ssam 			if ((tp->t_flags&NOFLSH) == 0)
69312752Ssam 				ttyflush(tp, FREAD);
6949578Ssam 			ttyecho(c, tp);
6959578Ssam 			gsignal(tp->t_pgrp, SIGTSTP);
6969578Ssam 			goto endcase;
6979578Ssam 		}
6989578Ssam 	}
6999578Ssam 
7009578Ssam 	/*
7019578Ssam 	 * Handle start/stop characters.
7029578Ssam 	 */
7039578Ssam 	if (c == tp->t_stopc) {
7049578Ssam 		if ((tp->t_state&TS_TTSTOP) == 0) {
7059578Ssam 			tp->t_state |= TS_TTSTOP;
7069578Ssam 			(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
7077502Sroot 			return;
7089578Ssam 		}
7099578Ssam 		if (c != tp->t_startc)
7109578Ssam 			return;
7119578Ssam 		goto endcase;
7129578Ssam 	}
7139578Ssam 	if (c == tp->t_startc)
7149578Ssam 		goto restartoutput;
7159578Ssam 
7169578Ssam 	/*
7179578Ssam 	 * Look for interrupt/quit chars.
7189578Ssam 	 */
7199578Ssam 	if (c == tp->t_intrc || c == tp->t_quitc) {
7209578Ssam 		if ((tp->t_flags&NOFLSH) == 0)
72112752Ssam 			ttyflush(tp, FREAD|FWRITE);
7229578Ssam 		ttyecho(c, tp);
7239578Ssam 		gsignal(tp->t_pgrp, c == tp->t_intrc ? SIGINT : SIGQUIT);
7249578Ssam 		goto endcase;
7259578Ssam 	}
7269578Ssam 
7279578Ssam 	/*
7289578Ssam 	 * Cbreak mode, don't process line editing
7299578Ssam 	 * characters; check high water mark for wakeup.
7309578Ssam 	 */
7319578Ssam 	if (t_flags&CBREAK) {
7329578Ssam 		if (tp->t_rawq.c_cc > TTYHOG) {
7337502Sroot 			if (tp->t_outq.c_cc < TTHIWAT(tp) &&
7347502Sroot 			    tp->t_line == NTTYDISC)
7357502Sroot 				(void) ttyoutput(CTRL(g), tp);
7367502Sroot 		} else if (putc(c, &tp->t_rawq) >= 0) {
7377502Sroot 			ttwakeup(tp);
7387502Sroot 			ttyecho(c, tp);
7397502Sroot 		}
7409578Ssam 		goto endcase;
7419578Ssam 	}
7429578Ssam 
7439578Ssam 	/*
7449578Ssam 	 * From here on down cooked mode character
7459578Ssam 	 * processing takes place.
7469578Ssam 	 */
7479578Ssam 	if ((tp->t_state&TS_QUOT) &&
7489578Ssam 	    (c == tp->t_erase || c == tp->t_kill)) {
7499578Ssam 		ttyrub(unputc(&tp->t_rawq), tp);
7509578Ssam 		c |= 0200;
7519578Ssam 	}
7529578Ssam 	if (c == tp->t_erase) {
7539578Ssam 		if (tp->t_rawq.c_cc)
7549578Ssam 			ttyrub(unputc(&tp->t_rawq), tp);
7559578Ssam 		goto endcase;
7569578Ssam 	}
7579578Ssam 	if (c == tp->t_kill) {
7589578Ssam 		if (tp->t_flags&CRTKIL &&
7599578Ssam 		    tp->t_rawq.c_cc == tp->t_rocount) {
7609578Ssam 			while (tp->t_rawq.c_cc)
7619578Ssam 				ttyrub(unputc(&tp->t_rawq), tp);
7629578Ssam 		} else {
7639578Ssam 			ttyecho(c, tp);
7649578Ssam 			ttyecho('\n', tp);
7659578Ssam 			while (getc(&tp->t_rawq) > 0)
7669578Ssam 				;
7679578Ssam 			tp->t_rocount = 0;
7689578Ssam 		}
7699578Ssam 		tp->t_state &= ~TS_LOCAL;
7709578Ssam 		goto endcase;
7719578Ssam 	}
7729578Ssam 
7739578Ssam 	/*
7749578Ssam 	 * New line discipline,
7759578Ssam 	 * check word erase/reprint line.
7769578Ssam 	 */
7779578Ssam 	if (tp->t_line == NTTYDISC) {
7789578Ssam 		if (c == tp->t_werasc) {
7799578Ssam 			if (tp->t_rawq.c_cc == 0)
7809578Ssam 				goto endcase;
7819578Ssam 			do {
7829578Ssam 				c = unputc(&tp->t_rawq);
7839578Ssam 				if (c != ' ' && c != '\t')
7849578Ssam 					goto erasenb;
7859578Ssam 				ttyrub(c, tp);
7869578Ssam 			} while (tp->t_rawq.c_cc);
7879578Ssam 			goto endcase;
7889578Ssam 	erasenb:
7899578Ssam 			do {
7909578Ssam 				ttyrub(c, tp);
7919578Ssam 				if (tp->t_rawq.c_cc == 0)
7929578Ssam 					goto endcase;
7939578Ssam 				c = unputc(&tp->t_rawq);
7949578Ssam 			} while (c != ' ' && c != '\t');
7959578Ssam 			(void) putc(c, &tp->t_rawq);
7969578Ssam 			goto endcase;
7979578Ssam 		}
7989578Ssam 		if (c == tp->t_rprntc) {
7999578Ssam 			ttyretype(tp);
8009578Ssam 			goto endcase;
8019578Ssam 		}
8029578Ssam 	}
8039578Ssam 
8049578Ssam 	/*
8059578Ssam 	 * Check for input buffer overflow
8069578Ssam 	 */
80710391Ssam 	if (tp->t_rawq.c_cc+tp->t_canq.c_cc >= TTYHOG) {
80810391Ssam 		if (tp->t_line == NTTYDISC)
80910391Ssam 			(void) ttyoutput(CTRL(g), tp);
8109578Ssam 		goto endcase;
81110391Ssam 	}
8129578Ssam 
8139578Ssam 	/*
8149578Ssam 	 * Put data char in q for user and
8159578Ssam 	 * wakeup on seeing a line delimiter.
8169578Ssam 	 */
8179578Ssam 	if (putc(c, &tp->t_rawq) >= 0) {
8189578Ssam 		if (ttbreakc(c, tp)) {
8199578Ssam 			tp->t_rocount = 0;
8209578Ssam 			catq(&tp->t_rawq, &tp->t_canq);
8217502Sroot 			ttwakeup(tp);
8229578Ssam 		} else if (tp->t_rocount++ == 0)
8239578Ssam 			tp->t_rocol = tp->t_col;
8249578Ssam 		tp->t_state &= ~TS_QUOT;
8259578Ssam 		if (c == '\\')
8269578Ssam 			tp->t_state |= TS_QUOT;
8279578Ssam 		if (tp->t_state&TS_ERASE) {
8289578Ssam 			tp->t_state &= ~TS_ERASE;
8299578Ssam 			(void) ttyoutput('/', tp);
8309578Ssam 		}
8319578Ssam 		i = tp->t_col;
8327502Sroot 		ttyecho(c, tp);
8339578Ssam 		if (c == tp->t_eofc && tp->t_flags&ECHO) {
8349578Ssam 			i = MIN(2, tp->t_col - i);
8359578Ssam 			while (i > 0) {
8369578Ssam 				(void) ttyoutput('\b', tp);
8379578Ssam 				i--;
8389578Ssam 			}
8399578Ssam 		}
8407502Sroot 	}
8419578Ssam 
8429578Ssam endcase:
8439578Ssam 	/*
8449578Ssam 	 * If DEC-style start/stop is enabled don't restart
8459578Ssam 	 * output until seeing the start character.
8469578Ssam 	 */
8479578Ssam 	if (tp->t_flags&DECCTQ && tp->t_state&TS_TTSTOP &&
8489578Ssam 	    tp->t_startc != tp->t_stopc)
8497502Sroot 		return;
8509578Ssam 
8519578Ssam restartoutput:
8527502Sroot 	tp->t_state &= ~TS_TTSTOP;
8539578Ssam 	tp->t_flags &= ~FLUSHO;
8549578Ssam 
8559578Ssam startoutput:
8567502Sroot 	ttstart(tp);
8577502Sroot }
8587502Sroot 
8597502Sroot /*
8609578Ssam  * Put character on TTY output queue, adding delays,
8617502Sroot  * expanding tabs, and handling the CR/NL bit.
8629578Ssam  * This is called both from the top half for output,
8639578Ssam  * and from interrupt level for echoing.
8647502Sroot  * The arguments are the character and the tty structure.
8657502Sroot  * Returns < 0 if putc succeeds, otherwise returns char to resend
8667502Sroot  * Must be recursive.
8677502Sroot  */
8687502Sroot ttyoutput(c, tp)
8697502Sroot 	register c;
8707502Sroot 	register struct tty *tp;
8717502Sroot {
8727502Sroot 	register char *colp;
8737502Sroot 	register ctype;
8747502Sroot 
8759578Ssam 	if (tp->t_flags & (RAW|LITOUT)) {
8769578Ssam 		if (tp->t_flags&FLUSHO)
8777502Sroot 			return (-1);
8787502Sroot 		if (putc(c, &tp->t_outq))
8797625Ssam 			return (c);
8807502Sroot 		tk_nout++;
8817502Sroot 		return (-1);
8827502Sroot 	}
8839578Ssam 
8847502Sroot 	/*
8859578Ssam 	 * Ignore EOT in normal mode to avoid
8869578Ssam 	 * hanging up certain terminals.
8877502Sroot 	 */
8887502Sroot 	c &= 0177;
8899578Ssam 	if (c == CEOT && (tp->t_flags&CBREAK) == 0)
8907502Sroot 		return (-1);
8917502Sroot 	/*
8927502Sroot 	 * Turn tabs to spaces as required
8937502Sroot 	 */
8949578Ssam 	if (c == '\t' && (tp->t_flags&TBDELAY) == XTABS) {
8957502Sroot 		register int s;
8967502Sroot 
8977502Sroot 		c = 8 - (tp->t_col&7);
8989578Ssam 		if ((tp->t_flags&FLUSHO) == 0) {
899*17545Skarels 			s = spltty();		/* don't interrupt tabs */
9007502Sroot 			c -= b_to_q("        ", c, &tp->t_outq);
9017502Sroot 			tk_nout += c;
9027502Sroot 			splx(s);
9037502Sroot 		}
9047502Sroot 		tp->t_col += c;
9057502Sroot 		return (c ? -1 : '\t');
9067502Sroot 	}
9077502Sroot 	tk_nout++;
9087502Sroot 	/*
9097502Sroot 	 * for upper-case-only terminals,
9107502Sroot 	 * generate escapes.
9117502Sroot 	 */
9127502Sroot 	if (tp->t_flags&LCASE) {
9137502Sroot 		colp = "({)}!|^~'`";
9147625Ssam 		while (*colp++)
9157625Ssam 			if (c == *colp++) {
9167502Sroot 				if (ttyoutput('\\', tp) >= 0)
9177502Sroot 					return (c);
9187502Sroot 				c = colp[-2];
9197502Sroot 				break;
9207502Sroot 			}
9219578Ssam 		if ('A' <= c && c <= 'Z') {
9227502Sroot 			if (ttyoutput('\\', tp) >= 0)
9237502Sroot 				return (c);
9249578Ssam 		} else if ('a' <= c && c <= 'z')
9257502Sroot 			c += 'A' - 'a';
9267502Sroot 	}
9279578Ssam 
9287502Sroot 	/*
9297502Sroot 	 * turn <nl> to <cr><lf> if desired.
9307502Sroot 	 */
9319578Ssam 	if (c == '\n' && tp->t_flags&CRMOD)
9327502Sroot 		if (ttyoutput('\r', tp) >= 0)
9337502Sroot 			return (c);
9349578Ssam 	if (c == '~' && tp->t_flags&TILDE)
9357502Sroot 		c = '`';
9369578Ssam 	if ((tp->t_flags&FLUSHO) == 0 && putc(c, &tp->t_outq))
9377502Sroot 		return (c);
9387502Sroot 	/*
9397502Sroot 	 * Calculate delays.
9407502Sroot 	 * The numbers here represent clock ticks
9417502Sroot 	 * and are not necessarily optimal for all terminals.
9427502Sroot 	 * The delays are indicated by characters above 0200.
9437502Sroot 	 * In raw mode there are no delays and the
9447502Sroot 	 * transmission path is 8 bits wide.
9459578Ssam 	 *
9469578Ssam 	 * SHOULD JUST ALLOW USER TO SPECIFY DELAYS
9477502Sroot 	 */
9487502Sroot 	colp = &tp->t_col;
9497502Sroot 	ctype = partab[c];
9507502Sroot 	c = 0;
9517502Sroot 	switch (ctype&077) {
9527502Sroot 
9537502Sroot 	case ORDINARY:
9547502Sroot 		(*colp)++;
9557502Sroot 
9567502Sroot 	case CONTROL:
9577502Sroot 		break;
9587502Sroot 
9597502Sroot 	case BACKSPACE:
9607502Sroot 		if (*colp)
9617502Sroot 			(*colp)--;
9627502Sroot 		break;
9637502Sroot 
96413821Ssam 	/*
96513821Ssam 	 * This macro is close enough to the correct thing;
96613821Ssam 	 * it should be replaced by real user settable delays
96713821Ssam 	 * in any event...
96813821Ssam 	 */
96913821Ssam #define	mstohz(ms)	(((ms) * hz) >> 10)
9707502Sroot 	case NEWLINE:
9717502Sroot 		ctype = (tp->t_flags >> 8) & 03;
9727625Ssam 		if (ctype == 1) { /* tty 37 */
97312752Ssam 			if (*colp > 0)
97413863Ssam 				c = max((((unsigned)*colp) >> 4) + 3,
97513863Ssam 				    (unsigned)6);
9769578Ssam 		} else if (ctype == 2) /* vt05 */
97713821Ssam 			c = mstohz(100);
9787502Sroot 		*colp = 0;
9797502Sroot 		break;
9807502Sroot 
9817502Sroot 	case TAB:
9827502Sroot 		ctype = (tp->t_flags >> 10) & 03;
9837625Ssam 		if (ctype == 1) { /* tty 37 */
9847502Sroot 			c = 1 - (*colp | ~07);
9857625Ssam 			if (c < 5)
9867502Sroot 				c = 0;
9877502Sroot 		}
9887502Sroot 		*colp |= 07;
9897502Sroot 		(*colp)++;
9907502Sroot 		break;
9917502Sroot 
9927502Sroot 	case VTAB:
9939578Ssam 		if (tp->t_flags&VTDELAY) /* tty 37 */
9947502Sroot 			c = 0177;
9957502Sroot 		break;
9967502Sroot 
9977502Sroot 	case RETURN:
9987502Sroot 		ctype = (tp->t_flags >> 12) & 03;
9999578Ssam 		if (ctype == 1) /* tn 300 */
100013821Ssam 			c = mstohz(83);
10019578Ssam 		else if (ctype == 2) /* ti 700 */
100213821Ssam 			c = mstohz(166);
10039578Ssam 		else if (ctype == 3) { /* concept 100 */
10047502Sroot 			int i;
10059578Ssam 
10067502Sroot 			if ((i = *colp) >= 0)
10079578Ssam 				for (; i < 9; i++)
10087502Sroot 					(void) putc(0177, &tp->t_outq);
10097502Sroot 		}
10107502Sroot 		*colp = 0;
10117502Sroot 	}
10129578Ssam 	if (c && (tp->t_flags&FLUSHO) == 0)
10137502Sroot 		(void) putc(c|0200, &tp->t_outq);
10147502Sroot 	return (-1);
10157502Sroot }
101613821Ssam #undef mstohz
10177502Sroot 
10187502Sroot /*
10197502Sroot  * Called from device's read routine after it has
10207502Sroot  * calculated the tty-structure given as argument.
10217502Sroot  */
10227722Swnj ttread(tp, uio)
10237625Ssam 	register struct tty *tp;
10247722Swnj 	struct uio *uio;
10257502Sroot {
10267502Sroot 	register struct clist *qp;
10279578Ssam 	register c, t_flags;
10289859Ssam 	int s, first, error = 0;
10297502Sroot 
10307502Sroot 	if ((tp->t_state&TS_CARR_ON)==0)
10318520Sroot 		return (EIO);
10327502Sroot loop:
10339578Ssam 	/*
10349578Ssam 	 * Take any pending input first.
10359578Ssam 	 */
1036*17545Skarels 	s = spltty();
10379578Ssam 	if (tp->t_flags&PENDIN)
10387502Sroot 		ttypend(tp);
10399859Ssam 	splx(s);
10409578Ssam 
10419578Ssam 	/*
10429578Ssam 	 * Hang process if it's in the background.
10439578Ssam 	 */
104415141Skarels #define bit(a) (1<<(a-1))
10457502Sroot 	while (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) {
104615141Skarels 		if ((u.u_procp->p_sigignore & bit(SIGTTIN)) ||
104715141Skarels 		   (u.u_procp->p_sigmask & bit(SIGTTIN)) ||
10487502Sroot /*
10497502Sroot 		    (u.u_procp->p_flag&SDETACH) ||
10507502Sroot */
10517502Sroot 		    u.u_procp->p_flag&SVFORK)
10528520Sroot 			return (EIO);
10537502Sroot 		gsignal(u.u_procp->p_pgrp, SIGTTIN);
10547502Sroot 		sleep((caddr_t)&lbolt, TTIPRI);
10557502Sroot 	}
10569578Ssam 	t_flags = tp->t_flags;
105715141Skarels #undef	bit
10589578Ssam 
10599578Ssam 	/*
10609578Ssam 	 * In raw mode take characters directly from the
10619578Ssam 	 * raw queue w/o processing.  Interlock against
10629578Ssam 	 * device interrupts when interrogating rawq.
10639578Ssam 	 */
10649578Ssam 	if (t_flags&RAW) {
1065*17545Skarels 		s = spltty();
10667502Sroot 		if (tp->t_rawq.c_cc <= 0) {
10679578Ssam 			if ((tp->t_state&TS_CARR_ON) == 0 ||
10687502Sroot 			    (tp->t_state&TS_NBIO)) {
10699859Ssam 				splx(s);
107015094Skarels 				return (EWOULDBLOCK);
10717502Sroot 			}
10727502Sroot 			sleep((caddr_t)&tp->t_rawq, TTIPRI);
10739859Ssam 			splx(s);
10747502Sroot 			goto loop;
10757502Sroot 		}
10769859Ssam 		splx(s);
107714938Smckusick  		while (!error && tp->t_rawq.c_cc && uio->uio_resid)
107814938Smckusick  			error = ureadc(getc(&tp->t_rawq), uio);
10799859Ssam 		goto checktandem;
10809578Ssam 	}
10819578Ssam 
10829578Ssam 	/*
10839578Ssam 	 * In cbreak mode use the rawq, otherwise
10849578Ssam 	 * take characters from the canonicalized q.
10859578Ssam 	 */
10869578Ssam 	qp = t_flags&CBREAK ? &tp->t_rawq : &tp->t_canq;
10879578Ssam 
10889578Ssam 	/*
10899578Ssam 	 * No input, sleep on rawq awaiting hardware
10909578Ssam 	 * receipt and notification.
10919578Ssam 	 */
1092*17545Skarels 	s = spltty();
10939578Ssam 	if (qp->c_cc <= 0) {
10949578Ssam 		if ((tp->t_state&TS_CARR_ON) == 0 ||
10959578Ssam 		    (tp->t_state&TS_NBIO)) {
10969859Ssam 			splx(s);
10979578Ssam 			return (EWOULDBLOCK);
10987502Sroot 		}
10999578Ssam 		sleep((caddr_t)&tp->t_rawq, TTIPRI);
11009859Ssam 		splx(s);
11019578Ssam 		goto loop;
11029578Ssam 	}
11039859Ssam 	splx(s);
11049578Ssam 
11059578Ssam 	/*
11069578Ssam 	 * Input present, perform input mapping
11079578Ssam 	 * and processing (we're not in raw mode).
11089578Ssam 	 */
11099578Ssam 	first = 1;
11109578Ssam 	while ((c = getc(qp)) >= 0) {
11119578Ssam 		if (t_flags&CRMOD && c == '\r')
11129578Ssam 			c = '\n';
11139578Ssam 		/*
11149578Ssam 		 * Hack lower case simulation on
11159578Ssam 		 * upper case only terminals.
11169578Ssam 		 */
11179578Ssam 		if (t_flags&LCASE && c <= 0177)
11189578Ssam 			if (tp->t_state&TS_BKSL) {
11199578Ssam 				if (maptab[c])
11209578Ssam 					c = maptab[c];
11219578Ssam 				tp->t_state &= ~TS_BKSL;
11229578Ssam 			} else if (c >= 'A' && c <= 'Z')
11239578Ssam 				c += 'a' - 'A';
11249578Ssam 			else if (c == '\\') {
11259578Ssam 				tp->t_state |= TS_BKSL;
11269578Ssam 				continue;
11277502Sroot 			}
11289578Ssam 		/*
11299578Ssam 		 * Check for delayed suspend character.
11309578Ssam 		 */
11319578Ssam 		if (tp->t_line == NTTYDISC && c == tp->t_dsuspc) {
11329578Ssam 			gsignal(tp->t_pgrp, SIGTSTP);
11339578Ssam 			if (first) {
11349578Ssam 				sleep((caddr_t)&lbolt, TTIPRI);
11359578Ssam 				goto loop;
11369578Ssam 			}
11379578Ssam 			break;
11387502Sroot 		}
11399578Ssam 		/*
11409578Ssam 		 * Interpret EOF only in cooked mode.
11419578Ssam 		 */
11429578Ssam 		if (c == tp->t_eofc && (t_flags&CBREAK) == 0)
11439578Ssam 			break;
11449578Ssam 		/*
11459578Ssam 		 * Give user character.
11469578Ssam 		 */
114714938Smckusick  		error = ureadc(c & 0177, uio);
11489578Ssam 		if (error)
11499578Ssam 			break;
115014938Smckusick  		if (uio->uio_resid == 0)
11519578Ssam 			break;
11529578Ssam 		/*
11539578Ssam 		 * In cooked mode check for a "break character"
11549578Ssam 		 * marking the end of a "line of input".
11559578Ssam 		 */
11569578Ssam 		if ((t_flags&CBREAK) == 0 && ttbreakc(c, tp))
11579578Ssam 			break;
11589578Ssam 		first = 0;
11597502Sroot 	}
11609578Ssam 	tp->t_state &= ~TS_BKSL;
11619578Ssam 
11629859Ssam checktandem:
11639578Ssam 	/*
11649578Ssam 	 * Look to unblock output now that (presumably)
11659578Ssam 	 * the input queue has gone down.
11669578Ssam 	 */
11679859Ssam 	if (tp->t_state&TS_TBLOCK && tp->t_rawq.c_cc < TTYHOG/5)
11689578Ssam 		if (putc(tp->t_startc, &tp->t_outq) == 0) {
11697502Sroot 			tp->t_state &= ~TS_TBLOCK;
11707502Sroot 			ttstart(tp);
11717502Sroot 		}
11728520Sroot 	return (error);
11737502Sroot }
11747502Sroot 
11757502Sroot /*
11767502Sroot  * Called from the device's write routine after it has
11777502Sroot  * calculated the tty-structure given as argument.
11787502Sroot  */
11797822Sroot ttwrite(tp, uio)
11807625Ssam 	register struct tty *tp;
11819578Ssam 	register struct uio *uio;
11827502Sroot {
11837502Sroot 	register char *cp;
11849578Ssam 	register int cc, ce, c;
11859578Ssam 	int i, hiwat, cnt, error, s;
11867502Sroot 	char obuf[OBUFSIZ];
11877502Sroot 
11889578Ssam 	if ((tp->t_state&TS_CARR_ON) == 0)
11898520Sroot 		return (EIO);
11909578Ssam 	hiwat = TTHIWAT(tp);
11919578Ssam 	cnt = uio->uio_resid;
11929578Ssam 	error = 0;
11937502Sroot loop:
11949578Ssam 	/*
11959578Ssam 	 * Hang the process if it's in the background.
11969578Ssam 	 */
119715141Skarels #define bit(a) (1<<(a-1))
11987502Sroot 	while (u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp &&
11999578Ssam 	    (tp->t_flags&TOSTOP) && (u.u_procp->p_flag&SVFORK)==0 &&
120015141Skarels 	    !(u.u_procp->p_sigignore & bit(SIGTTOU)) &&
120115141Skarels 	    !(u.u_procp->p_sigmask & bit(SIGTTOU))
12027502Sroot /*
12037502Sroot 					     &&
12047502Sroot 	    (u.u_procp->p_flag&SDETACH)==0) {
12057502Sroot */
12067502Sroot 	    ) {
12077502Sroot 		gsignal(u.u_procp->p_pgrp, SIGTTOU);
12087502Sroot 		sleep((caddr_t)&lbolt, TTIPRI);
12097502Sroot 	}
121015141Skarels #undef	bit
12119578Ssam 
12129578Ssam 	/*
12139578Ssam 	 * Process the user's data in at most OBUFSIZ
12149578Ssam 	 * chunks.  Perform lower case simulation and
12159578Ssam 	 * similar hacks.  Keep track of high water
12169578Ssam 	 * mark, sleep on overflow awaiting device aid
12179578Ssam 	 * in acquiring new space.
12189578Ssam 	 */
12197822Sroot 	while (uio->uio_resid > 0) {
12209578Ssam 		/*
12219578Ssam 		 * Grab a hunk of data from the user.
12229578Ssam 		 */
12237822Sroot 		cc = uio->uio_iov->iov_len;
12247822Sroot 		if (cc == 0) {
12257822Sroot 			uio->uio_iovcnt--;
12267822Sroot 			uio->uio_iov++;
12277822Sroot 			if (uio->uio_iovcnt < 0)
12287822Sroot 				panic("ttwrite");
12297822Sroot 			continue;
12307822Sroot 		}
12317822Sroot 		if (cc > OBUFSIZ)
12327822Sroot 			cc = OBUFSIZ;
12337502Sroot 		cp = obuf;
123412752Ssam 		error = uiomove(cp, cc, UIO_WRITE, uio);
12358520Sroot 		if (error)
12367502Sroot 			break;
12377502Sroot 		if (tp->t_outq.c_cc > hiwat)
12387502Sroot 			goto ovhiwat;
12399578Ssam 		if (tp->t_flags&FLUSHO)
12407502Sroot 			continue;
12419578Ssam 		/*
12429578Ssam 		 * If we're mapping lower case or kludging tildes,
12439578Ssam 		 * then we've got to look at each character, so
12449578Ssam 		 * just feed the stuff to ttyoutput...
12459578Ssam 		 */
12469578Ssam 		if (tp->t_flags & (LCASE|TILDE)) {
12479578Ssam 			while (cc > 0) {
12487502Sroot 				c = *cp++;
12497502Sroot 				tp->t_rocount = 0;
12507625Ssam 				while ((c = ttyoutput(c, tp)) >= 0) {
12517502Sroot 					/* out of clists, wait a bit */
12527502Sroot 					ttstart(tp);
12537502Sroot 					sleep((caddr_t)&lbolt, TTOPRI);
12547502Sroot 					tp->t_rocount = 0;
12557502Sroot 				}
12567502Sroot 				--cc;
12577502Sroot 				if (tp->t_outq.c_cc > hiwat)
12587502Sroot 					goto ovhiwat;
12597502Sroot 			}
12607502Sroot 			continue;
12617502Sroot 		}
12629578Ssam 		/*
12639578Ssam 		 * If nothing fancy need be done, grab those characters we
12649578Ssam 		 * can handle without any of ttyoutput's processing and
12659578Ssam 		 * just transfer them to the output q.  For those chars
12669578Ssam 		 * which require special processing (as indicated by the
12679578Ssam 		 * bits in partab), call ttyoutput.  After processing
12689578Ssam 		 * a hunk of data, look for FLUSHO so ^O's will take effect
12699578Ssam 		 * immediately.
12709578Ssam 		 */
12719578Ssam 		while (cc > 0) {
12729578Ssam 			if (tp->t_flags & (RAW|LITOUT))
12737502Sroot 				ce = cc;
12747502Sroot 			else {
127512752Ssam 				ce = cc - scanc((unsigned)cc, (caddr_t)cp,
127612752Ssam 				   (caddr_t)partab, 077);
12779578Ssam 				/*
12789578Ssam 				 * If ce is zero, then we're processing
12799578Ssam 				 * a special character through ttyoutput.
12809578Ssam 				 */
12819578Ssam 				if (ce == 0) {
12827502Sroot 					tp->t_rocount = 0;
12837502Sroot 					if (ttyoutput(*cp, tp) >= 0) {
12849578Ssam 						/* no c-lists, wait a bit */
12857502Sroot 						ttstart(tp);
12867502Sroot 						sleep((caddr_t)&lbolt, TTOPRI);
12877502Sroot 						continue;
12887502Sroot 					}
12899578Ssam 					cp++, cc--;
12909578Ssam 					if (tp->t_flags&FLUSHO ||
12919578Ssam 					    tp->t_outq.c_cc > hiwat)
12927502Sroot 						goto ovhiwat;
12939578Ssam 					continue;
12947502Sroot 				}
12957502Sroot 			}
12969578Ssam 			/*
12979578Ssam 			 * A bunch of normal characters have been found,
12989578Ssam 			 * transfer them en masse to the output queue and
12999578Ssam 			 * continue processing at the top of the loop.
13009578Ssam 			 * If there are any further characters in this
13019578Ssam 			 * <= OBUFSIZ chunk, the first should be a character
13029578Ssam 			 * requiring special handling by ttyoutput.
13039578Ssam 			 */
13047502Sroot 			tp->t_rocount = 0;
13059578Ssam 			i = b_to_q(cp, ce, &tp->t_outq);
13069578Ssam 			ce -= i;
13079578Ssam 			tp->t_col += ce;
13089578Ssam 			cp += ce, cc -= ce, tk_nout += ce;
13099578Ssam 			if (i > 0) {
13109578Ssam 				/* out of c-lists, wait a bit */
13117502Sroot 				ttstart(tp);
13127502Sroot 				sleep((caddr_t)&lbolt, TTOPRI);
13137502Sroot 			}
13149578Ssam 			if (tp->t_flags&FLUSHO || tp->t_outq.c_cc > hiwat)
13157502Sroot 				goto ovhiwat;
13167502Sroot 		}
13177502Sroot 	}
13187502Sroot 	ttstart(tp);
13198520Sroot 	return (error);
13207502Sroot 
13217502Sroot ovhiwat:
1322*17545Skarels 	s = spltty();
13239578Ssam 	if (cc != 0) {
13249578Ssam 		uio->uio_iov->iov_base -= cc;
13259578Ssam 		uio->uio_iov->iov_len += cc;
13269578Ssam 		uio->uio_resid += cc;
13279578Ssam 		uio->uio_offset -= cc;
13289578Ssam 	}
13299578Ssam 	/*
13309578Ssam 	 * This can only occur if FLUSHO
13319578Ssam 	 * is also set in t_flags.
13329578Ssam 	 */
13337502Sroot 	if (tp->t_outq.c_cc <= hiwat) {
13349578Ssam 		splx(s);
13357502Sroot 		goto loop;
13367502Sroot 	}
13377502Sroot 	ttstart(tp);
13389578Ssam 	if (tp->t_state&TS_NBIO) {
1339*17545Skarels 		splx(s);
13407822Sroot 		if (uio->uio_resid == cnt)
13418520Sroot 			return (EWOULDBLOCK);
13428520Sroot 		return (0);
13437502Sroot 	}
13447502Sroot 	tp->t_state |= TS_ASLEEP;
13457502Sroot 	sleep((caddr_t)&tp->t_outq, TTOPRI);
13469578Ssam 	splx(s);
13477502Sroot 	goto loop;
13487502Sroot }
13497502Sroot 
13507502Sroot /*
13517502Sroot  * Rubout one character from the rawq of tp
13527502Sroot  * as cleanly as possible.
13537502Sroot  */
13547502Sroot ttyrub(c, tp)
13557625Ssam 	register c;
13567625Ssam 	register struct tty *tp;
13577502Sroot {
13587502Sroot 	register char *cp;
13597502Sroot 	register int savecol;
13607502Sroot 	int s;
13617502Sroot 	char *nextc();
13627502Sroot 
13639578Ssam 	if ((tp->t_flags&ECHO) == 0)
13647502Sroot 		return;
13659578Ssam 	tp->t_flags &= ~FLUSHO;
13667502Sroot 	c &= 0377;
13679578Ssam 	if (tp->t_flags&CRTBS) {
13687502Sroot 		if (tp->t_rocount == 0) {
13697502Sroot 			/*
13707502Sroot 			 * Screwed by ttwrite; retype
13717502Sroot 			 */
13727502Sroot 			ttyretype(tp);
13737502Sroot 			return;
13747502Sroot 		}
13759578Ssam 		if (c == ('\t'|0200) || c == ('\n'|0200))
13767502Sroot 			ttyrubo(tp, 2);
13779578Ssam 		else switch (partab[c&=0177]&0177) {
13787502Sroot 
13797502Sroot 		case ORDINARY:
13807502Sroot 			if (tp->t_flags&LCASE && c >= 'A' && c <= 'Z')
13817502Sroot 				ttyrubo(tp, 2);
13827502Sroot 			else
13837502Sroot 				ttyrubo(tp, 1);
13847502Sroot 			break;
13857502Sroot 
13867502Sroot 		case VTAB:
13877502Sroot 		case BACKSPACE:
13887502Sroot 		case CONTROL:
13897502Sroot 		case RETURN:
13909578Ssam 			if (tp->t_flags&CTLECH)
13917502Sroot 				ttyrubo(tp, 2);
13927502Sroot 			break;
13937502Sroot 
13947502Sroot 		case TAB:
13957502Sroot 			if (tp->t_rocount < tp->t_rawq.c_cc) {
13967502Sroot 				ttyretype(tp);
13977502Sroot 				return;
13987502Sroot 			}
1399*17545Skarels 			s = spltty();
14007502Sroot 			savecol = tp->t_col;
14019578Ssam 			tp->t_state |= TS_CNTTB;
14029578Ssam 			tp->t_flags |= FLUSHO;
14037502Sroot 			tp->t_col = tp->t_rocol;
14049578Ssam 			cp = tp->t_rawq.c_cf;
14059578Ssam 			for (; cp; cp = nextc(&tp->t_rawq, cp))
14067502Sroot 				ttyecho(*cp, tp);
14079578Ssam 			tp->t_flags &= ~FLUSHO;
14089578Ssam 			tp->t_state &= ~TS_CNTTB;
14097502Sroot 			splx(s);
14107502Sroot 			/*
14117502Sroot 			 * savecol will now be length of the tab
14127502Sroot 			 */
14137502Sroot 			savecol -= tp->t_col;
14147502Sroot 			tp->t_col += savecol;
14157502Sroot 			if (savecol > 8)
14167502Sroot 				savecol = 8;		/* overflow screw */
14177502Sroot 			while (--savecol >= 0)
14187502Sroot 				(void) ttyoutput('\b', tp);
14197502Sroot 			break;
14207502Sroot 
14217502Sroot 		default:
14227502Sroot 			panic("ttyrub");
14237502Sroot 		}
14249578Ssam 	} else if (tp->t_flags&PRTERA) {
14259578Ssam 		if ((tp->t_state&TS_ERASE) == 0) {
14267502Sroot 			(void) ttyoutput('\\', tp);
14279578Ssam 			tp->t_state |= TS_ERASE;
14287502Sroot 		}
14297502Sroot 		ttyecho(c, tp);
14307502Sroot 	} else
14317502Sroot 		ttyecho(tp->t_erase, tp);
14327502Sroot 	tp->t_rocount--;
14337502Sroot }
14347502Sroot 
14357502Sroot /*
14367502Sroot  * Crt back over cnt chars perhaps
14377502Sroot  * erasing them.
14387502Sroot  */
14397502Sroot ttyrubo(tp, cnt)
14407625Ssam 	register struct tty *tp;
14417625Ssam 	int cnt;
14427502Sroot {
14439578Ssam 	register char *rubostring = tp->t_flags&CRTERA ? "\b \b" : "\b";
14447502Sroot 
14457502Sroot 	while (--cnt >= 0)
14469578Ssam 		ttyout(rubostring, tp);
14477502Sroot }
14487502Sroot 
14497502Sroot /*
14507502Sroot  * Reprint the rawq line.
14517502Sroot  * We assume c_cc has already been checked.
14527502Sroot  */
14537502Sroot ttyretype(tp)
14547625Ssam 	register struct tty *tp;
14557502Sroot {
14567502Sroot 	register char *cp;
14577502Sroot 	char *nextc();
14587502Sroot 	int s;
14597502Sroot 
14609578Ssam 	if (tp->t_rprntc != 0377)
14619578Ssam 		ttyecho(tp->t_rprntc, tp);
14627502Sroot 	(void) ttyoutput('\n', tp);
1463*17545Skarels 	s = spltty();
14647502Sroot 	for (cp = tp->t_canq.c_cf; cp; cp = nextc(&tp->t_canq, cp))
14657502Sroot 		ttyecho(*cp, tp);
14667502Sroot 	for (cp = tp->t_rawq.c_cf; cp; cp = nextc(&tp->t_rawq, cp))
14677502Sroot 		ttyecho(*cp, tp);
14689578Ssam 	tp->t_state &= ~TS_ERASE;
14697502Sroot 	splx(s);
14707502Sroot 	tp->t_rocount = tp->t_rawq.c_cc;
14717502Sroot 	tp->t_rocol = 0;
14727502Sroot }
14737502Sroot 
14747502Sroot /*
14757502Sroot  * Echo a typed character to the terminal
14767502Sroot  */
14777502Sroot ttyecho(c, tp)
14787625Ssam 	register c;
14797625Ssam 	register struct tty *tp;
14807502Sroot {
14817502Sroot 
14829578Ssam 	if ((tp->t_state&TS_CNTTB) == 0)
14839578Ssam 		tp->t_flags &= ~FLUSHO;
14847502Sroot 	if ((tp->t_flags&ECHO) == 0)
14857502Sroot 		return;
14867502Sroot 	c &= 0377;
14877502Sroot 	if (tp->t_flags&RAW) {
14887502Sroot 		(void) ttyoutput(c, tp);
14897502Sroot 		return;
14907502Sroot 	}
14917502Sroot 	if (c == '\r' && tp->t_flags&CRMOD)
14927502Sroot 		c = '\n';
14939578Ssam 	if (tp->t_flags&CTLECH) {
14947502Sroot 		if ((c&0177) <= 037 && c!='\t' && c!='\n' || (c&0177)==0177) {
14957502Sroot 			(void) ttyoutput('^', tp);
14967502Sroot 			c &= 0177;
14977502Sroot 			if (c == 0177)
14987502Sroot 				c = '?';
14997502Sroot 			else if (tp->t_flags&LCASE)
15007502Sroot 				c += 'a' - 1;
15017502Sroot 			else
15027502Sroot 				c += 'A' - 1;
15037502Sroot 		}
15047502Sroot 	}
15057502Sroot 	if ((tp->t_flags&LCASE) && (c >= 'A' && c <= 'Z'))
15067502Sroot 		c += 'a' - 'A';
15079578Ssam 	(void) ttyoutput(c&0177, tp);
15087502Sroot }
15097502Sroot 
15107502Sroot /*
15117502Sroot  * Is c a break char for tp?
15127502Sroot  */
15137502Sroot ttbreakc(c, tp)
15147625Ssam 	register c;
15157625Ssam 	register struct tty *tp;
15167502Sroot {
15179578Ssam 	return (c == '\n' || c == tp->t_eofc || c == tp->t_brkc ||
15187502Sroot 		c == '\r' && (tp->t_flags&CRMOD));
15197502Sroot }
15207502Sroot 
15217502Sroot /*
15227502Sroot  * send string cp to tp
15237502Sroot  */
15247502Sroot ttyout(cp, tp)
15257625Ssam 	register char *cp;
15267625Ssam 	register struct tty *tp;
15277502Sroot {
15287502Sroot 	register char c;
15297502Sroot 
15307502Sroot 	while (c = *cp++)
15317502Sroot 		(void) ttyoutput(c, tp);
15327502Sroot }
15337502Sroot 
15347502Sroot ttwakeup(tp)
15357502Sroot 	struct tty *tp;
15367502Sroot {
15377502Sroot 
15387502Sroot 	if (tp->t_rsel) {
15397502Sroot 		selwakeup(tp->t_rsel, tp->t_state&TS_RCOLL);
15407502Sroot 		tp->t_state &= ~TS_RCOLL;
15417502Sroot 		tp->t_rsel = 0;
15427502Sroot 	}
154312752Ssam 	if (tp->t_state & TS_ASYNC)
154412752Ssam 		gsignal(tp->t_pgrp, SIGIO);
15457502Sroot 	wakeup((caddr_t)&tp->t_rawq);
15467502Sroot }
15477502Sroot 
154813533Ssam #if !defined(vax)
15499578Ssam scanc(size, cp, table, mask)
15509578Ssam 	register int size;
15519578Ssam 	register char *cp, table[];
15529578Ssam 	register int mask;
15537502Sroot {
15549578Ssam 	register int i = 0;
15557502Sroot 
15569578Ssam 	while ((table[*(u_char *)(cp + i)]&mask) == 0 && i < size)
15579578Ssam 		i++;
155815100Skarels 	return (size - i);
15597502Sroot }
15609578Ssam #endif
1561