xref: /csrg-svn/sys/kern/tty.c (revision 15720)
1*15720Skarels /*	tty.c	6.8	83/12/16	*/
239Sbill 
39760Ssam #include "../machine/reg.h"
49760Ssam 
539Sbill #include "../h/param.h"
639Sbill #include "../h/systm.h"
739Sbill #include "../h/dir.h"
839Sbill #include "../h/user.h"
99578Ssam #include "../h/ioctl.h"
1039Sbill #include "../h/tty.h"
1139Sbill #include "../h/proc.h"
1239Sbill #include "../h/inode.h"
1339Sbill #include "../h/file.h"
1439Sbill #include "../h/conf.h"
1539Sbill #include "../h/buf.h"
16340Sbill #include "../h/dk.h"
177722Swnj #include "../h/uio.h"
188154Sroot #include "../h/kernel.h"
1939Sbill 
207436Skre /*
217436Skre  * Table giving parity for characters and indicating
227436Skre  * character classes to tty driver.  In particular,
237436Skre  * if the low 6 bits are 0, then the character needs
247436Skre  * no special processing on output.
257436Skre  */
2639Sbill 
277436Skre char partab[] = {
287436Skre 	0001,0201,0201,0001,0201,0001,0001,0201,
297436Skre 	0202,0004,0003,0201,0005,0206,0201,0001,
307436Skre 	0201,0001,0001,0201,0001,0201,0201,0001,
317436Skre 	0001,0201,0201,0001,0201,0001,0001,0201,
327436Skre 	0200,0000,0000,0200,0000,0200,0200,0000,
337436Skre 	0000,0200,0200,0000,0200,0000,0000,0200,
347436Skre 	0000,0200,0200,0000,0200,0000,0000,0200,
357436Skre 	0200,0000,0000,0200,0000,0200,0200,0000,
367436Skre 	0200,0000,0000,0200,0000,0200,0200,0000,
377436Skre 	0000,0200,0200,0000,0200,0000,0000,0200,
387436Skre 	0000,0200,0200,0000,0200,0000,0000,0200,
397436Skre 	0200,0000,0000,0200,0000,0200,0200,0000,
407436Skre 	0000,0200,0200,0000,0200,0000,0000,0200,
417436Skre 	0200,0000,0000,0200,0000,0200,0200,0000,
427436Skre 	0200,0000,0000,0200,0000,0200,0200,0000,
437436Skre 	0000,0200,0200,0000,0200,0000,0000,0201,
447436Skre 
457436Skre 	/*
467436Skre 	 * 7 bit ascii ends with the last character above,
477436Skre 	 * but we contine through all 256 codes for the sake
487436Skre 	 * of the tty output routines which use special vax
497436Skre 	 * instructions which need a 256 character trt table.
507436Skre 	 */
517436Skre 
527436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
537436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
547436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
557436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
567436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
577436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
587436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
597436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
607436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
617436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
627436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
637436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
647436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
657436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
667436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
677436Skre 	0007,0007,0007,0007,0007,0007,0007,0007
687436Skre };
697436Skre 
70146Sbill /*
7139Sbill  * Input mapping table-- if an entry is non-zero, when the
7239Sbill  * corresponding character is typed preceded by "\" the escape
7339Sbill  * sequence is replaced by the table value.  Mostly used for
7439Sbill  * upper-case only terminals.
7539Sbill  */
7639Sbill char	maptab[] ={
7739Sbill 	000,000,000,000,000,000,000,000,
7839Sbill 	000,000,000,000,000,000,000,000,
7939Sbill 	000,000,000,000,000,000,000,000,
8039Sbill 	000,000,000,000,000,000,000,000,
8139Sbill 	000,'|',000,000,000,000,000,'`',
8239Sbill 	'{','}',000,000,000,000,000,000,
8339Sbill 	000,000,000,000,000,000,000,000,
8439Sbill 	000,000,000,000,000,000,000,000,
8539Sbill 	000,000,000,000,000,000,000,000,
8639Sbill 	000,000,000,000,000,000,000,000,
8739Sbill 	000,000,000,000,000,000,000,000,
8839Sbill 	000,000,000,000,000,000,'~',000,
8939Sbill 	000,'A','B','C','D','E','F','G',
9039Sbill 	'H','I','J','K','L','M','N','O',
9139Sbill 	'P','Q','R','S','T','U','V','W',
9239Sbill 	'X','Y','Z',000,000,000,000,000,
9339Sbill };
9439Sbill 
95925Sbill short	tthiwat[16] =
968954Sroot    { 100,100,100,100,100,100,100,200,200,400,400,400,650,650,1300,2000 };
97925Sbill short	ttlowat[16] =
98925Sbill    {  30, 30, 30, 30, 30, 30, 30, 50, 50,120,120,120,125,125,125,125 };
99925Sbill 
1009578Ssam struct	ttychars ttydefaults = {
1019578Ssam 	CERASE,	CKILL,	CINTR,	CQUIT,	CSTART,	CSTOP,	CEOF,
1029578Ssam 	CBRK,	CSUSP,	CDSUSP, CRPRNT, CFLUSH, CWERASE,CLNEXT
1039578Ssam };
10439Sbill 
10539Sbill ttychars(tp)
1069578Ssam 	struct tty *tp;
10739Sbill {
108174Sbill 
1099578Ssam 	tp->t_chars = ttydefaults;
11039Sbill }
11139Sbill 
11239Sbill /*
113903Sbill  * Wait for output to drain, then flush input waiting.
11439Sbill  */
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 {
12612752Ssam 	register int s = spl5();
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 
145903Sbill 	s = spl6();
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 			;
161903Sbill 		tp->t_delct = 0;
1629578Ssam 		tp->t_rocount = 0;
163903Sbill 		tp->t_rocol = 0;
1649578Ssam 		tp->t_state &= ~TS_LOCAL;
165903Sbill 	}
166903Sbill 	splx(s);
16739Sbill }
16839Sbill 
169903Sbill /*
170903Sbill  * Send stop character on input overflow.
171903Sbill  */
172903Sbill ttyblock(tp)
1737625Ssam 	register struct tty *tp;
17439Sbill {
175903Sbill 	register x;
1769578Ssam 
177903Sbill 	x = tp->t_rawq.c_cc + tp->t_canq.c_cc;
178903Sbill 	if (tp->t_rawq.c_cc > TTYHOG) {
17912752Ssam 		ttyflush(tp, FREAD|FWRITE);
1805408Swnj 		tp->t_state &= ~TS_TBLOCK;
181903Sbill 	}
18215118Skarels 	/*
18315118Skarels 	 * Block further input iff:
18415118Skarels 	 * Current input > threshold AND input is available to user program
18515118Skarels 	 */
18615118Skarels 	if (x >= TTYHOG/2 && (tp->t_delct>0 || (tp->t_flags&(RAW|CBREAK)))) {
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 
221903Sbill 	s = spl5();
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,
243903Sbill 	 * insist on being able to write the device,
244903Sbill 	 * and hang if in the background.
245903Sbill 	 */
2467625Ssam 	switch (com) {
24739Sbill 
248915Sbill 	case TIOCSETD:
249915Sbill 	case TIOCSETP:
250915Sbill 	case TIOCSETN:
251903Sbill 	case TIOCFLUSH:
252903Sbill 	case TIOCSETC:
253903Sbill 	case TIOCSLTC:
254903Sbill 	case TIOCSPGRP:
255903Sbill 	case TIOCLBIS:
256903Sbill 	case TIOCLBIC:
257903Sbill 	case TIOCLSET:
2589325Ssam 	case TIOCSTI:
25915078Skarels #define bit(a) (1<<(a-1))
260903Sbill 		while (tp->t_line == NTTYDISC &&
261903Sbill 		   u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp &&
262903Sbill 		   (u.u_procp->p_flag&SVFORK) == 0 &&
26315078Skarels 		   !(u.u_procp->p_sigignore & bit(SIGTTOU)) &&
26415078Skarels 		   !(u.u_procp->p_sigmask & bit(SIGTTOU))) {
265903Sbill 			gsignal(u.u_procp->p_pgrp, SIGTTOU);
266903Sbill 			sleep((caddr_t)&lbolt, TTOPRI);
267903Sbill 		}
268903Sbill 		break;
269903Sbill 	}
27015078Skarels #undef	bit
271903Sbill 
2729578Ssam 	/*
2739578Ssam 	 * Process the ioctl.
2749578Ssam 	 */
2757625Ssam 	switch (com) {
276903Sbill 
2778556Sroot 	/* get discipline number */
27839Sbill 	case TIOCGETD:
2797625Ssam 		*(int *)data = tp->t_line;
28039Sbill 		break;
28139Sbill 
2828556Sroot 	/* set line discipline */
2837625Ssam 	case TIOCSETD: {
2847625Ssam 		register int t = *(int *)data;
2859578Ssam 		int error = 0;
2867625Ssam 
28715078Skarels 		if ((unsigned) t >= nldisp)
28810851Ssam 			return (ENXIO);
2898556Sroot 		s = spl5();
29039Sbill 		if (tp->t_line)
29139Sbill 			(*linesw[tp->t_line].l_close)(tp);
29239Sbill 		if (t)
2938556Sroot 			error = (*linesw[t].l_open)(dev, tp);
2948556Sroot 		splx(s);
29510851Ssam 		if (error) {
29610851Ssam 			s = spl5();
29710851Ssam 			if (tp->t_line)
29810851Ssam 				(void) (*linesw[tp->t_line].l_open)(dev, tp);
29910851Ssam 			splx(s);
3008556Sroot 			return (error);
30110851Ssam 		}
3028556Sroot 		tp->t_line = t;
30339Sbill 		break;
3047625Ssam 	}
30539Sbill 
3068556Sroot 	/* prevent more opens on channel */
3075614Swnj 	case TIOCEXCL:
3085614Swnj 		tp->t_state |= TS_XCLUDE;
3095614Swnj 		break;
3105614Swnj 
3115614Swnj 	case TIOCNXCL:
3125614Swnj 		tp->t_state &= ~TS_XCLUDE;
3135614Swnj 		break;
3145614Swnj 
3158556Sroot 	/* hang up line on last close */
31639Sbill 	case TIOCHPCL:
3175408Swnj 		tp->t_state |= TS_HUPCLS;
31839Sbill 		break;
31939Sbill 
3203942Sbugs 	case TIOCFLUSH: {
3217625Ssam 		register int flags = *(int *)data;
3227625Ssam 
3237625Ssam 		if (flags == 0)
3243942Sbugs 			flags = FREAD|FWRITE;
3257625Ssam 		else
3267625Ssam 			flags &= FREAD|FWRITE;
32712752Ssam 		ttyflush(tp, flags);
32839Sbill 		break;
3293944Sbugs 	}
33039Sbill 
3318556Sroot 	/* return number of characters immediately available */
3327625Ssam 	case FIONREAD:
3337625Ssam 		*(off_t *)data = ttnread(tp);
334174Sbill 		break;
335174Sbill 
33613077Ssam 	case TIOCOUTQ:
33713077Ssam 		*(int *)data = tp->t_outq.c_cc;
33813077Ssam 		break;
33913077Ssam 
3408589Sroot 	case TIOCSTOP:
3418589Sroot 		s = spl5();
3429578Ssam 		if ((tp->t_state&TS_TTSTOP) == 0) {
3435573Swnj 			tp->t_state |= TS_TTSTOP;
3445573Swnj 			(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
3455573Swnj 		}
3467625Ssam 		splx(s);
3475573Swnj 		break;
3485573Swnj 
3498589Sroot 	case TIOCSTART:
3508589Sroot 		s = spl5();
3519578Ssam 		if ((tp->t_state&TS_TTSTOP) || (tp->t_flags&FLUSHO)) {
3525573Swnj 			tp->t_state &= ~TS_TTSTOP;
3539578Ssam 			tp->t_flags &= ~FLUSHO;
3545573Swnj 			ttstart(tp);
3555573Swnj 		}
3567625Ssam 		splx(s);
3575573Swnj 		break;
3585573Swnj 
3599325Ssam 	/*
3609325Ssam 	 * Simulate typing of a character at the terminal.
3619325Ssam 	 */
3629325Ssam 	case TIOCSTI:
3639325Ssam 		if (u.u_uid && u.u_ttyp != tp)
3649325Ssam 			return (EACCES);
3659578Ssam 		(*linesw[tp->t_line].l_rint)(*(char *)data, tp);
3669325Ssam 		break;
3679325Ssam 
36812752Ssam 	case TIOCSETP:
36912752Ssam 	case TIOCSETN: {
37012752Ssam 		register struct sgttyb *sg = (struct sgttyb *)data;
37112752Ssam 
37212752Ssam 		tp->t_erase = sg->sg_erase;
37312752Ssam 		tp->t_kill = sg->sg_kill;
37412752Ssam 		tp->t_ispeed = sg->sg_ispeed;
37512752Ssam 		tp->t_ospeed = sg->sg_ospeed;
37612752Ssam 		newflags = (tp->t_flags&0xffff0000) | (sg->sg_flags&0xffff);
37712752Ssam 		s = spl5();
37812752Ssam 		if (tp->t_flags&RAW || newflags&RAW || com == TIOCSETP) {
37912752Ssam 			ttywait(tp);
38012752Ssam 			ttyflush(tp, FREAD);
38112752Ssam 		} else if ((tp->t_flags&CBREAK) != (newflags&CBREAK)) {
38212752Ssam 			if (newflags&CBREAK) {
38312752Ssam 				struct clist tq;
38412752Ssam 
38512752Ssam 				catq(&tp->t_rawq, &tp->t_canq);
38612752Ssam 				tq = tp->t_rawq;
38712752Ssam 				tp->t_rawq = tp->t_canq;
38812752Ssam 				tp->t_canq = tq;
38912752Ssam 			} else {
39012752Ssam 				tp->t_flags |= PENDIN;
39113801Ssam 				newflags |= PENDIN;
39212752Ssam 				ttwakeup(tp);
39312752Ssam 			}
39412752Ssam 		}
39512752Ssam 		tp->t_flags = newflags;
39612752Ssam 		if (tp->t_flags&RAW) {
39712752Ssam 			tp->t_state &= ~TS_TTSTOP;
39812752Ssam 			ttstart(tp);
39912752Ssam 		}
40012752Ssam 		splx(s);
40112752Ssam 		break;
40212752Ssam 	}
40312752Ssam 
40412752Ssam 	/* send current parameters to user */
40512752Ssam 	case TIOCGETP: {
40612752Ssam 		register struct sgttyb *sg = (struct sgttyb *)data;
40712752Ssam 
40812752Ssam 		sg->sg_ispeed = tp->t_ispeed;
40912752Ssam 		sg->sg_ospeed = tp->t_ospeed;
41012752Ssam 		sg->sg_erase = tp->t_erase;
41112752Ssam 		sg->sg_kill = tp->t_kill;
41212752Ssam 		sg->sg_flags = tp->t_flags;
41312752Ssam 		break;
41412752Ssam 	}
41512752Ssam 
41612752Ssam 	case FIONBIO:
41712752Ssam 		if (*(int *)data)
41812752Ssam 			tp->t_state |= TS_NBIO;
41912752Ssam 		else
42012752Ssam 			tp->t_state &= ~TS_NBIO;
42112752Ssam 		break;
42212752Ssam 
42312752Ssam 	case FIOASYNC:
42412752Ssam 		if (*(int *)data)
42512752Ssam 			tp->t_state |= TS_ASYNC;
42612752Ssam 		else
42712752Ssam 			tp->t_state &= ~TS_ASYNC;
42812752Ssam 		break;
42912752Ssam 
43013077Ssam 	case TIOCGETC:
43113077Ssam 		bcopy((caddr_t)&tp->t_intrc, data, sizeof (struct tchars));
43213077Ssam 		break;
43313077Ssam 
43413077Ssam 	case TIOCSETC:
43513077Ssam 		bcopy(data, (caddr_t)&tp->t_intrc, sizeof (struct tchars));
43613077Ssam 		break;
43713077Ssam 
43812752Ssam 	/* set/get local special characters */
43912752Ssam 	case TIOCSLTC:
44012752Ssam 		bcopy(data, (caddr_t)&tp->t_suspc, sizeof (struct ltchars));
44112752Ssam 		break;
44212752Ssam 
44312752Ssam 	case TIOCGLTC:
44412752Ssam 		bcopy((caddr_t)&tp->t_suspc, data, sizeof (struct ltchars));
44512752Ssam 		break;
44612752Ssam 
44712752Ssam 	/*
44812752Ssam 	 * Modify local mode word.
44912752Ssam 	 */
45012752Ssam 	case TIOCLBIS:
45112752Ssam 		tp->t_flags |= *(int *)data << 16;
45212752Ssam 		break;
45312752Ssam 
45412752Ssam 	case TIOCLBIC:
45512752Ssam 		tp->t_flags &= ~(*(int *)data << 16);
45612752Ssam 		break;
45712752Ssam 
45812752Ssam 	case TIOCLSET:
45912752Ssam 		tp->t_flags &= 0xffff;
46012752Ssam 		tp->t_flags |= *(int *)data << 16;
46112752Ssam 		break;
46212752Ssam 
46312752Ssam 	case TIOCLGET:
464*15720Skarels 		*(int *)data = ((unsigned) tp->t_flags) >> 16;
46512752Ssam 		break;
46612752Ssam 
46712752Ssam 	/* should allow SPGRP and GPGRP only if tty open for reading */
46812752Ssam 	case TIOCSPGRP:
46912752Ssam 		tp->t_pgrp = *(int *)data;
47012752Ssam 		break;
47112752Ssam 
47212752Ssam 	case TIOCGPGRP:
47312752Ssam 		*(int *)data = tp->t_pgrp;
47412752Ssam 		break;
47512752Ssam 
47639Sbill 	default:
4778556Sroot 		return (-1);
47839Sbill 	}
4798556Sroot 	return (0);
48039Sbill }
4814484Swnj 
4824484Swnj ttnread(tp)
4834484Swnj 	struct tty *tp;
4844484Swnj {
4854484Swnj 	int nread = 0;
4864484Swnj 
4879578Ssam 	if (tp->t_flags & PENDIN)
4884484Swnj 		ttypend(tp);
4894484Swnj 	nread = tp->t_canq.c_cc;
4904484Swnj 	if (tp->t_flags & (RAW|CBREAK))
4914484Swnj 		nread += tp->t_rawq.c_cc;
4924484Swnj 	return (nread);
4934484Swnj }
4944484Swnj 
4955408Swnj ttselect(dev, rw)
4964484Swnj 	dev_t dev;
4975408Swnj 	int rw;
4984484Swnj {
4994484Swnj 	register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)];
5004484Swnj 	int nread;
5015408Swnj 	int s = spl5();
5024484Swnj 
5035408Swnj 	switch (rw) {
5044484Swnj 
5054484Swnj 	case FREAD:
5064484Swnj 		nread = ttnread(tp);
5074484Swnj 		if (nread > 0)
5085408Swnj 			goto win;
5094938Swnj 		if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait)
5105408Swnj 			tp->t_state |= TS_RCOLL;
5114484Swnj 		else
5124484Swnj 			tp->t_rsel = u.u_procp;
5135408Swnj 		break;
5144484Swnj 
5155408Swnj 	case FWRITE:
5165408Swnj 		if (tp->t_outq.c_cc <= TTLOWAT(tp))
5175408Swnj 			goto win;
5185408Swnj 		if (tp->t_wsel && tp->t_wsel->p_wchan == (caddr_t)&selwait)
5195408Swnj 			tp->t_state |= TS_WCOLL;
5205408Swnj 		else
5215408Swnj 			tp->t_wsel = u.u_procp;
5225408Swnj 		break;
5234484Swnj 	}
5245408Swnj 	splx(s);
5255408Swnj 	return (0);
5265408Swnj win:
5275408Swnj 	splx(s);
5285408Swnj 	return (1);
5294484Swnj }
5307436Skre 
5317502Sroot /*
5329578Ssam  * Establish a process group for distribution of
5337502Sroot  * quits and interrupts from the tty.
5347502Sroot  */
5357502Sroot ttyopen(dev, tp)
5367625Ssam 	dev_t dev;
5377625Ssam 	register struct tty *tp;
5387502Sroot {
5397502Sroot 	register struct proc *pp;
5407502Sroot 
5417502Sroot 	pp = u.u_procp;
5427502Sroot 	tp->t_dev = dev;
5437625Ssam 	if (pp->p_pgrp == 0) {
5447502Sroot 		u.u_ttyp = tp;
5457502Sroot 		u.u_ttyd = dev;
5467502Sroot 		if (tp->t_pgrp == 0)
5477502Sroot 			tp->t_pgrp = pp->p_pid;
5487502Sroot 		pp->p_pgrp = tp->t_pgrp;
5497502Sroot 	}
5507502Sroot 	tp->t_state &= ~TS_WOPEN;
5517502Sroot 	tp->t_state |= TS_ISOPEN;
5527502Sroot 	if (tp->t_line != NTTYDISC)
55312752Ssam 		ttywflush(tp);
5548556Sroot 	return (0);
5557502Sroot }
5567502Sroot 
5577502Sroot /*
5587502Sroot  * clean tp on last close
5597502Sroot  */
5607502Sroot ttyclose(tp)
5617625Ssam 	register struct tty *tp;
5627502Sroot {
5637502Sroot 
5647502Sroot 	if (tp->t_line) {
56512752Ssam 		ttywflush(tp);
5667502Sroot 		tp->t_line = 0;
5677502Sroot 		return;
5687502Sroot 	}
5697502Sroot 	tp->t_pgrp = 0;
57012752Ssam 	ttywflush(tp);
5717502Sroot 	tp->t_state = 0;
5727502Sroot }
5737502Sroot 
5747502Sroot /*
5757502Sroot  * reinput pending characters after state switch
5767502Sroot  * call at spl5().
5777502Sroot  */
5787502Sroot ttypend(tp)
5797625Ssam 	register struct tty *tp;
5807502Sroot {
5817502Sroot 	struct clist tq;
5827502Sroot 	register c;
5837502Sroot 
5849578Ssam 	tp->t_flags &= ~PENDIN;
5859578Ssam 	tp->t_state |= TS_TYPEN;
5867502Sroot 	tq = tp->t_rawq;
5877502Sroot 	tp->t_rawq.c_cc = 0;
5887502Sroot 	tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0;
5897502Sroot 	while ((c = getc(&tq)) >= 0)
5907502Sroot 		ttyinput(c, tp);
5919578Ssam 	tp->t_state &= ~TS_TYPEN;
5927502Sroot }
5937502Sroot 
5947502Sroot /*
5959578Ssam  * Place a character on raw TTY input queue,
5969578Ssam  * putting in delimiters and waking up top
5979578Ssam  * half as needed.  Also echo if required.
5989578Ssam  * The arguments are the character and the
5999578Ssam  * appropriate tty structure.
6007502Sroot  */
6017502Sroot ttyinput(c, tp)
6027625Ssam 	register c;
6037625Ssam 	register struct tty *tp;
6047502Sroot {
6059578Ssam 	register int t_flags = tp->t_flags;
6067502Sroot 	int i;
6077502Sroot 
6089578Ssam 	/*
6099578Ssam 	 * If input is pending take it first.
6109578Ssam 	 */
6119578Ssam 	if (t_flags&PENDIN)
6127502Sroot 		ttypend(tp);
6137502Sroot 	tk_nin++;
6147502Sroot 	c &= 0377;
6159578Ssam 
6169578Ssam 	/*
6179578Ssam 	 * In tandem mode, check high water mark.
6189578Ssam 	 */
6197502Sroot 	if (t_flags&TANDEM)
6207502Sroot 		ttyblock(tp);
6219578Ssam 
6229578Ssam 	if (t_flags&RAW) {
6239578Ssam 		/*
6249578Ssam 		 * Raw mode, just put character
6259578Ssam 		 * in input q w/o interpretation.
6269578Ssam 		 */
6279578Ssam 		if (tp->t_rawq.c_cc > TTYHOG)
62812752Ssam 			ttyflush(tp, FREAD|FWRITE);
6299578Ssam 		else {
6309578Ssam 			if (putc(c, &tp->t_rawq) >= 0)
6319578Ssam 				ttwakeup(tp);
6329578Ssam 			ttyecho(c, tp);
6337502Sroot 		}
6349578Ssam 		goto endcase;
6359578Ssam 	}
6369578Ssam 
6379578Ssam 	/*
6389578Ssam 	 * Ignore any high bit added during
6399578Ssam 	 * previous ttyinput processing.
6409578Ssam 	 */
6419578Ssam 	if ((tp->t_state&TS_TYPEN) == 0)
6429578Ssam 		c &= 0177;
6439578Ssam 	/*
6449578Ssam 	 * Check for literal nexting very first
6459578Ssam 	 */
6469578Ssam 	if (tp->t_state&TS_LNCH) {
6479578Ssam 		c |= 0200;
6489578Ssam 		tp->t_state &= ~TS_LNCH;
6499578Ssam 	}
6509578Ssam 
6519578Ssam 	/*
6529578Ssam 	 * Scan for special characters.  This code
6539578Ssam 	 * is really just a big case statement with
6549578Ssam 	 * non-constant cases.  The bottom of the
6559578Ssam 	 * case statement is labeled ``endcase'', so goto
6569578Ssam 	 * it after a case match, or similar.
6579578Ssam 	 */
6589578Ssam 	if (tp->t_line == NTTYDISC) {
6599578Ssam 		if (c == tp->t_lnextc) {
6607502Sroot 			if (tp->t_flags&ECHO)
6617502Sroot 				ttyout("^\b", tp);
6629578Ssam 			tp->t_state |= TS_LNCH;
6639578Ssam 			goto endcase;
6649578Ssam 		}
6659578Ssam 		if (c == tp->t_flushc) {
6669578Ssam 			if (tp->t_flags&FLUSHO)
6679578Ssam 				tp->t_flags &= ~FLUSHO;
6687502Sroot 			else {
66912752Ssam 				ttyflush(tp, FWRITE);
6707502Sroot 				ttyecho(c, tp);
6719578Ssam 				if (tp->t_rawq.c_cc + tp->t_canq.c_cc)
6727502Sroot 					ttyretype(tp);
6739578Ssam 				tp->t_flags |= FLUSHO;
6747502Sroot 			}
6759578Ssam 			goto startoutput;
6769578Ssam 		}
6779578Ssam 		if (c == tp->t_suspc) {
6789578Ssam 			if ((tp->t_flags&NOFLSH) == 0)
67912752Ssam 				ttyflush(tp, FREAD);
6809578Ssam 			ttyecho(c, tp);
6819578Ssam 			gsignal(tp->t_pgrp, SIGTSTP);
6829578Ssam 			goto endcase;
6839578Ssam 		}
6849578Ssam 	}
6859578Ssam 
6869578Ssam 	/*
6879578Ssam 	 * Handle start/stop characters.
6889578Ssam 	 */
6899578Ssam 	if (c == tp->t_stopc) {
6909578Ssam 		if ((tp->t_state&TS_TTSTOP) == 0) {
6919578Ssam 			tp->t_state |= TS_TTSTOP;
6929578Ssam 			(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
6937502Sroot 			return;
6949578Ssam 		}
6959578Ssam 		if (c != tp->t_startc)
6969578Ssam 			return;
6979578Ssam 		goto endcase;
6989578Ssam 	}
6999578Ssam 	if (c == tp->t_startc)
7009578Ssam 		goto restartoutput;
7019578Ssam 
7029578Ssam 	/*
7039578Ssam 	 * Look for interrupt/quit chars.
7049578Ssam 	 */
7059578Ssam 	if (c == tp->t_intrc || c == tp->t_quitc) {
7069578Ssam 		if ((tp->t_flags&NOFLSH) == 0)
70712752Ssam 			ttyflush(tp, FREAD|FWRITE);
7089578Ssam 		ttyecho(c, tp);
7099578Ssam 		gsignal(tp->t_pgrp, c == tp->t_intrc ? SIGINT : SIGQUIT);
7109578Ssam 		goto endcase;
7119578Ssam 	}
7129578Ssam 
7139578Ssam 	/*
7149578Ssam 	 * Cbreak mode, don't process line editing
7159578Ssam 	 * characters; check high water mark for wakeup.
7169578Ssam 	 */
7179578Ssam 	if (t_flags&CBREAK) {
7189578Ssam 		if (tp->t_rawq.c_cc > TTYHOG) {
7197502Sroot 			if (tp->t_outq.c_cc < TTHIWAT(tp) &&
7207502Sroot 			    tp->t_line == NTTYDISC)
7217502Sroot 				(void) ttyoutput(CTRL(g), tp);
7227502Sroot 		} else if (putc(c, &tp->t_rawq) >= 0) {
7237502Sroot 			ttwakeup(tp);
7247502Sroot 			ttyecho(c, tp);
7257502Sroot 		}
7269578Ssam 		goto endcase;
7279578Ssam 	}
7289578Ssam 
7299578Ssam 	/*
7309578Ssam 	 * From here on down cooked mode character
7319578Ssam 	 * processing takes place.
7329578Ssam 	 */
7339578Ssam 	if ((tp->t_state&TS_QUOT) &&
7349578Ssam 	    (c == tp->t_erase || c == tp->t_kill)) {
7359578Ssam 		ttyrub(unputc(&tp->t_rawq), tp);
7369578Ssam 		c |= 0200;
7379578Ssam 	}
7389578Ssam 	if (c == tp->t_erase) {
7399578Ssam 		if (tp->t_rawq.c_cc)
7409578Ssam 			ttyrub(unputc(&tp->t_rawq), tp);
7419578Ssam 		goto endcase;
7429578Ssam 	}
7439578Ssam 	if (c == tp->t_kill) {
7449578Ssam 		if (tp->t_flags&CRTKIL &&
7459578Ssam 		    tp->t_rawq.c_cc == tp->t_rocount) {
7469578Ssam 			while (tp->t_rawq.c_cc)
7479578Ssam 				ttyrub(unputc(&tp->t_rawq), tp);
7489578Ssam 		} else {
7499578Ssam 			ttyecho(c, tp);
7509578Ssam 			ttyecho('\n', tp);
7519578Ssam 			while (getc(&tp->t_rawq) > 0)
7529578Ssam 				;
7539578Ssam 			tp->t_rocount = 0;
7549578Ssam 		}
7559578Ssam 		tp->t_state &= ~TS_LOCAL;
7569578Ssam 		goto endcase;
7579578Ssam 	}
7589578Ssam 
7599578Ssam 	/*
7609578Ssam 	 * New line discipline,
7619578Ssam 	 * check word erase/reprint line.
7629578Ssam 	 */
7639578Ssam 	if (tp->t_line == NTTYDISC) {
7649578Ssam 		if (c == tp->t_werasc) {
7659578Ssam 			if (tp->t_rawq.c_cc == 0)
7669578Ssam 				goto endcase;
7679578Ssam 			do {
7689578Ssam 				c = unputc(&tp->t_rawq);
7699578Ssam 				if (c != ' ' && c != '\t')
7709578Ssam 					goto erasenb;
7719578Ssam 				ttyrub(c, tp);
7729578Ssam 			} while (tp->t_rawq.c_cc);
7739578Ssam 			goto endcase;
7749578Ssam 	erasenb:
7759578Ssam 			do {
7769578Ssam 				ttyrub(c, tp);
7779578Ssam 				if (tp->t_rawq.c_cc == 0)
7789578Ssam 					goto endcase;
7799578Ssam 				c = unputc(&tp->t_rawq);
7809578Ssam 			} while (c != ' ' && c != '\t');
7819578Ssam 			(void) putc(c, &tp->t_rawq);
7829578Ssam 			goto endcase;
7839578Ssam 		}
7849578Ssam 		if (c == tp->t_rprntc) {
7859578Ssam 			ttyretype(tp);
7869578Ssam 			goto endcase;
7879578Ssam 		}
7889578Ssam 	}
7899578Ssam 
7909578Ssam 	/*
7919578Ssam 	 * Check for input buffer overflow
7929578Ssam 	 */
79310391Ssam 	if (tp->t_rawq.c_cc+tp->t_canq.c_cc >= TTYHOG) {
79410391Ssam 		if (tp->t_line == NTTYDISC)
79510391Ssam 			(void) ttyoutput(CTRL(g), tp);
7969578Ssam 		goto endcase;
79710391Ssam 	}
7989578Ssam 
7999578Ssam 	/*
8009578Ssam 	 * Put data char in q for user and
8019578Ssam 	 * wakeup on seeing a line delimiter.
8029578Ssam 	 */
8039578Ssam 	if (putc(c, &tp->t_rawq) >= 0) {
8049578Ssam 		if (ttbreakc(c, tp)) {
8059578Ssam 			tp->t_rocount = 0;
8069578Ssam 			catq(&tp->t_rawq, &tp->t_canq);
8077502Sroot 			ttwakeup(tp);
8089578Ssam 		} else if (tp->t_rocount++ == 0)
8099578Ssam 			tp->t_rocol = tp->t_col;
8109578Ssam 		tp->t_state &= ~TS_QUOT;
8119578Ssam 		if (c == '\\')
8129578Ssam 			tp->t_state |= TS_QUOT;
8139578Ssam 		if (tp->t_state&TS_ERASE) {
8149578Ssam 			tp->t_state &= ~TS_ERASE;
8159578Ssam 			(void) ttyoutput('/', tp);
8169578Ssam 		}
8179578Ssam 		i = tp->t_col;
8187502Sroot 		ttyecho(c, tp);
8199578Ssam 		if (c == tp->t_eofc && tp->t_flags&ECHO) {
8209578Ssam 			i = MIN(2, tp->t_col - i);
8219578Ssam 			while (i > 0) {
8229578Ssam 				(void) ttyoutput('\b', tp);
8239578Ssam 				i--;
8249578Ssam 			}
8259578Ssam 		}
8267502Sroot 	}
8279578Ssam 
8289578Ssam endcase:
8299578Ssam 	/*
8309578Ssam 	 * If DEC-style start/stop is enabled don't restart
8319578Ssam 	 * output until seeing the start character.
8329578Ssam 	 */
8339578Ssam 	if (tp->t_flags&DECCTQ && tp->t_state&TS_TTSTOP &&
8349578Ssam 	    tp->t_startc != tp->t_stopc)
8357502Sroot 		return;
8369578Ssam 
8379578Ssam restartoutput:
8387502Sroot 	tp->t_state &= ~TS_TTSTOP;
8399578Ssam 	tp->t_flags &= ~FLUSHO;
8409578Ssam 
8419578Ssam startoutput:
8427502Sroot 	ttstart(tp);
8437502Sroot }
8447502Sroot 
8457502Sroot /*
8469578Ssam  * Put character on TTY output queue, adding delays,
8477502Sroot  * expanding tabs, and handling the CR/NL bit.
8489578Ssam  * This is called both from the top half for output,
8499578Ssam  * and from interrupt level for echoing.
8507502Sroot  * The arguments are the character and the tty structure.
8517502Sroot  * Returns < 0 if putc succeeds, otherwise returns char to resend
8527502Sroot  * Must be recursive.
8537502Sroot  */
8547502Sroot ttyoutput(c, tp)
8557502Sroot 	register c;
8567502Sroot 	register struct tty *tp;
8577502Sroot {
8587502Sroot 	register char *colp;
8597502Sroot 	register ctype;
8607502Sroot 
8619578Ssam 	if (tp->t_flags & (RAW|LITOUT)) {
8629578Ssam 		if (tp->t_flags&FLUSHO)
8637502Sroot 			return (-1);
8647502Sroot 		if (putc(c, &tp->t_outq))
8657625Ssam 			return (c);
8667502Sroot 		tk_nout++;
8677502Sroot 		return (-1);
8687502Sroot 	}
8699578Ssam 
8707502Sroot 	/*
8719578Ssam 	 * Ignore EOT in normal mode to avoid
8729578Ssam 	 * hanging up certain terminals.
8737502Sroot 	 */
8747502Sroot 	c &= 0177;
8759578Ssam 	if (c == CEOT && (tp->t_flags&CBREAK) == 0)
8767502Sroot 		return (-1);
8777502Sroot 	/*
8787502Sroot 	 * Turn tabs to spaces as required
8797502Sroot 	 */
8809578Ssam 	if (c == '\t' && (tp->t_flags&TBDELAY) == XTABS) {
8817502Sroot 		register int s;
8827502Sroot 
8837502Sroot 		c = 8 - (tp->t_col&7);
8849578Ssam 		if ((tp->t_flags&FLUSHO) == 0) {
8857502Sroot 			s = spl5();		/* don't interrupt tabs */
8867502Sroot 			c -= b_to_q("        ", c, &tp->t_outq);
8877502Sroot 			tk_nout += c;
8887502Sroot 			splx(s);
8897502Sroot 		}
8907502Sroot 		tp->t_col += c;
8917502Sroot 		return (c ? -1 : '\t');
8927502Sroot 	}
8937502Sroot 	tk_nout++;
8947502Sroot 	/*
8957502Sroot 	 * for upper-case-only terminals,
8967502Sroot 	 * generate escapes.
8977502Sroot 	 */
8987502Sroot 	if (tp->t_flags&LCASE) {
8997502Sroot 		colp = "({)}!|^~'`";
9007625Ssam 		while (*colp++)
9017625Ssam 			if (c == *colp++) {
9027502Sroot 				if (ttyoutput('\\', tp) >= 0)
9037502Sroot 					return (c);
9047502Sroot 				c = colp[-2];
9057502Sroot 				break;
9067502Sroot 			}
9079578Ssam 		if ('A' <= c && c <= 'Z') {
9087502Sroot 			if (ttyoutput('\\', tp) >= 0)
9097502Sroot 				return (c);
9109578Ssam 		} else if ('a' <= c && c <= 'z')
9117502Sroot 			c += 'A' - 'a';
9127502Sroot 	}
9139578Ssam 
9147502Sroot 	/*
9157502Sroot 	 * turn <nl> to <cr><lf> if desired.
9167502Sroot 	 */
9179578Ssam 	if (c == '\n' && tp->t_flags&CRMOD)
9187502Sroot 		if (ttyoutput('\r', tp) >= 0)
9197502Sroot 			return (c);
9209578Ssam 	if (c == '~' && tp->t_flags&TILDE)
9217502Sroot 		c = '`';
9229578Ssam 	if ((tp->t_flags&FLUSHO) == 0 && putc(c, &tp->t_outq))
9237502Sroot 		return (c);
9247502Sroot 	/*
9257502Sroot 	 * Calculate delays.
9267502Sroot 	 * The numbers here represent clock ticks
9277502Sroot 	 * and are not necessarily optimal for all terminals.
9287502Sroot 	 * The delays are indicated by characters above 0200.
9297502Sroot 	 * In raw mode there are no delays and the
9307502Sroot 	 * transmission path is 8 bits wide.
9319578Ssam 	 *
9329578Ssam 	 * SHOULD JUST ALLOW USER TO SPECIFY DELAYS
9337502Sroot 	 */
9347502Sroot 	colp = &tp->t_col;
9357502Sroot 	ctype = partab[c];
9367502Sroot 	c = 0;
9377502Sroot 	switch (ctype&077) {
9387502Sroot 
9397502Sroot 	case ORDINARY:
9407502Sroot 		(*colp)++;
9417502Sroot 
9427502Sroot 	case CONTROL:
9437502Sroot 		break;
9447502Sroot 
9457502Sroot 	case BACKSPACE:
9467502Sroot 		if (*colp)
9477502Sroot 			(*colp)--;
9487502Sroot 		break;
9497502Sroot 
95013821Ssam 	/*
95113821Ssam 	 * This macro is close enough to the correct thing;
95213821Ssam 	 * it should be replaced by real user settable delays
95313821Ssam 	 * in any event...
95413821Ssam 	 */
95513821Ssam #define	mstohz(ms)	(((ms) * hz) >> 10)
9567502Sroot 	case NEWLINE:
9577502Sroot 		ctype = (tp->t_flags >> 8) & 03;
9587625Ssam 		if (ctype == 1) { /* tty 37 */
95912752Ssam 			if (*colp > 0)
96013863Ssam 				c = max((((unsigned)*colp) >> 4) + 3,
96113863Ssam 				    (unsigned)6);
9629578Ssam 		} else if (ctype == 2) /* vt05 */
96313821Ssam 			c = mstohz(100);
9647502Sroot 		*colp = 0;
9657502Sroot 		break;
9667502Sroot 
9677502Sroot 	case TAB:
9687502Sroot 		ctype = (tp->t_flags >> 10) & 03;
9697625Ssam 		if (ctype == 1) { /* tty 37 */
9707502Sroot 			c = 1 - (*colp | ~07);
9717625Ssam 			if (c < 5)
9727502Sroot 				c = 0;
9737502Sroot 		}
9747502Sroot 		*colp |= 07;
9757502Sroot 		(*colp)++;
9767502Sroot 		break;
9777502Sroot 
9787502Sroot 	case VTAB:
9799578Ssam 		if (tp->t_flags&VTDELAY) /* tty 37 */
9807502Sroot 			c = 0177;
9817502Sroot 		break;
9827502Sroot 
9837502Sroot 	case RETURN:
9847502Sroot 		ctype = (tp->t_flags >> 12) & 03;
9859578Ssam 		if (ctype == 1) /* tn 300 */
98613821Ssam 			c = mstohz(83);
9879578Ssam 		else if (ctype == 2) /* ti 700 */
98813821Ssam 			c = mstohz(166);
9899578Ssam 		else if (ctype == 3) { /* concept 100 */
9907502Sroot 			int i;
9919578Ssam 
9927502Sroot 			if ((i = *colp) >= 0)
9939578Ssam 				for (; i < 9; i++)
9947502Sroot 					(void) putc(0177, &tp->t_outq);
9957502Sroot 		}
9967502Sroot 		*colp = 0;
9977502Sroot 	}
9989578Ssam 	if (c && (tp->t_flags&FLUSHO) == 0)
9997502Sroot 		(void) putc(c|0200, &tp->t_outq);
10007502Sroot 	return (-1);
10017502Sroot }
100213821Ssam #undef mstohz
10037502Sroot 
10047502Sroot /*
10057502Sroot  * Called from device's read routine after it has
10067502Sroot  * calculated the tty-structure given as argument.
10077502Sroot  */
10087722Swnj ttread(tp, uio)
10097625Ssam 	register struct tty *tp;
10107722Swnj 	struct uio *uio;
10117502Sroot {
10127502Sroot 	register struct clist *qp;
10139578Ssam 	register c, t_flags;
10149859Ssam 	int s, first, error = 0;
10157502Sroot 
10167502Sroot 	if ((tp->t_state&TS_CARR_ON)==0)
10178520Sroot 		return (EIO);
10187502Sroot loop:
10199578Ssam 	/*
10209578Ssam 	 * Take any pending input first.
10219578Ssam 	 */
10229859Ssam 	s = spl5();
10239578Ssam 	if (tp->t_flags&PENDIN)
10247502Sroot 		ttypend(tp);
10259859Ssam 	splx(s);
10269578Ssam 
10279578Ssam 	/*
10289578Ssam 	 * Hang process if it's in the background.
10299578Ssam 	 */
103015141Skarels #define bit(a) (1<<(a-1))
10317502Sroot 	while (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) {
103215141Skarels 		if ((u.u_procp->p_sigignore & bit(SIGTTIN)) ||
103315141Skarels 		   (u.u_procp->p_sigmask & bit(SIGTTIN)) ||
10347502Sroot /*
10357502Sroot 		    (u.u_procp->p_flag&SDETACH) ||
10367502Sroot */
10377502Sroot 		    u.u_procp->p_flag&SVFORK)
10388520Sroot 			return (EIO);
10397502Sroot 		gsignal(u.u_procp->p_pgrp, SIGTTIN);
10407502Sroot 		sleep((caddr_t)&lbolt, TTIPRI);
10417502Sroot 	}
10429578Ssam 	t_flags = tp->t_flags;
104315141Skarels #undef	bit
10449578Ssam 
10459578Ssam 	/*
10469578Ssam 	 * In raw mode take characters directly from the
10479578Ssam 	 * raw queue w/o processing.  Interlock against
10489578Ssam 	 * device interrupts when interrogating rawq.
10499578Ssam 	 */
10509578Ssam 	if (t_flags&RAW) {
10519859Ssam 		s = spl5();
10527502Sroot 		if (tp->t_rawq.c_cc <= 0) {
10539578Ssam 			if ((tp->t_state&TS_CARR_ON) == 0 ||
10547502Sroot 			    (tp->t_state&TS_NBIO)) {
10559859Ssam 				splx(s);
105615094Skarels 				return (EWOULDBLOCK);
10577502Sroot 			}
10587502Sroot 			sleep((caddr_t)&tp->t_rawq, TTIPRI);
10599859Ssam 			splx(s);
10607502Sroot 			goto loop;
10617502Sroot 		}
10629859Ssam 		splx(s);
106314938Smckusick  		while (!error && tp->t_rawq.c_cc && uio->uio_resid)
106414938Smckusick  			error = ureadc(getc(&tp->t_rawq), uio);
10659859Ssam 		goto checktandem;
10669578Ssam 	}
10679578Ssam 
10689578Ssam 	/*
10699578Ssam 	 * In cbreak mode use the rawq, otherwise
10709578Ssam 	 * take characters from the canonicalized q.
10719578Ssam 	 */
10729578Ssam 	qp = t_flags&CBREAK ? &tp->t_rawq : &tp->t_canq;
10739578Ssam 
10749578Ssam 	/*
10759578Ssam 	 * No input, sleep on rawq awaiting hardware
10769578Ssam 	 * receipt and notification.
10779578Ssam 	 */
10789859Ssam 	s = spl5();
10799578Ssam 	if (qp->c_cc <= 0) {
10809578Ssam 		if ((tp->t_state&TS_CARR_ON) == 0 ||
10819578Ssam 		    (tp->t_state&TS_NBIO)) {
10829859Ssam 			splx(s);
10839578Ssam 			return (EWOULDBLOCK);
10847502Sroot 		}
10859578Ssam 		sleep((caddr_t)&tp->t_rawq, TTIPRI);
10869859Ssam 		splx(s);
10879578Ssam 		goto loop;
10889578Ssam 	}
10899859Ssam 	splx(s);
10909578Ssam 
10919578Ssam 	/*
10929578Ssam 	 * Input present, perform input mapping
10939578Ssam 	 * and processing (we're not in raw mode).
10949578Ssam 	 */
10959578Ssam 	first = 1;
10969578Ssam 	while ((c = getc(qp)) >= 0) {
10979578Ssam 		if (t_flags&CRMOD && c == '\r')
10989578Ssam 			c = '\n';
10999578Ssam 		/*
11009578Ssam 		 * Hack lower case simulation on
11019578Ssam 		 * upper case only terminals.
11029578Ssam 		 */
11039578Ssam 		if (t_flags&LCASE && c <= 0177)
11049578Ssam 			if (tp->t_state&TS_BKSL) {
11059578Ssam 				if (maptab[c])
11069578Ssam 					c = maptab[c];
11079578Ssam 				tp->t_state &= ~TS_BKSL;
11089578Ssam 			} else if (c >= 'A' && c <= 'Z')
11099578Ssam 				c += 'a' - 'A';
11109578Ssam 			else if (c == '\\') {
11119578Ssam 				tp->t_state |= TS_BKSL;
11129578Ssam 				continue;
11137502Sroot 			}
11149578Ssam 		/*
11159578Ssam 		 * Check for delayed suspend character.
11169578Ssam 		 */
11179578Ssam 		if (tp->t_line == NTTYDISC && c == tp->t_dsuspc) {
11189578Ssam 			gsignal(tp->t_pgrp, SIGTSTP);
11199578Ssam 			if (first) {
11209578Ssam 				sleep((caddr_t)&lbolt, TTIPRI);
11219578Ssam 				goto loop;
11229578Ssam 			}
11239578Ssam 			break;
11247502Sroot 		}
11259578Ssam 		/*
11269578Ssam 		 * Interpret EOF only in cooked mode.
11279578Ssam 		 */
11289578Ssam 		if (c == tp->t_eofc && (t_flags&CBREAK) == 0)
11299578Ssam 			break;
11309578Ssam 		/*
11319578Ssam 		 * Give user character.
11329578Ssam 		 */
113314938Smckusick  		error = ureadc(c & 0177, uio);
11349578Ssam 		if (error)
11359578Ssam 			break;
113614938Smckusick  		if (uio->uio_resid == 0)
11379578Ssam 			break;
11389578Ssam 		/*
11399578Ssam 		 * In cooked mode check for a "break character"
11409578Ssam 		 * marking the end of a "line of input".
11419578Ssam 		 */
11429578Ssam 		if ((t_flags&CBREAK) == 0 && ttbreakc(c, tp))
11439578Ssam 			break;
11449578Ssam 		first = 0;
11457502Sroot 	}
11469578Ssam 	tp->t_state &= ~TS_BKSL;
11479578Ssam 
11489859Ssam checktandem:
11499578Ssam 	/*
11509578Ssam 	 * Look to unblock output now that (presumably)
11519578Ssam 	 * the input queue has gone down.
11529578Ssam 	 */
11539859Ssam 	if (tp->t_state&TS_TBLOCK && tp->t_rawq.c_cc < TTYHOG/5)
11549578Ssam 		if (putc(tp->t_startc, &tp->t_outq) == 0) {
11557502Sroot 			tp->t_state &= ~TS_TBLOCK;
11567502Sroot 			ttstart(tp);
11577502Sroot 		}
11588520Sroot 	return (error);
11597502Sroot }
11607502Sroot 
11617502Sroot /*
11627502Sroot  * Called from the device's write routine after it has
11637502Sroot  * calculated the tty-structure given as argument.
11647502Sroot  */
11657822Sroot ttwrite(tp, uio)
11667625Ssam 	register struct tty *tp;
11679578Ssam 	register struct uio *uio;
11687502Sroot {
11697502Sroot 	register char *cp;
11709578Ssam 	register int cc, ce, c;
11719578Ssam 	int i, hiwat, cnt, error, s;
11727502Sroot 	char obuf[OBUFSIZ];
11737502Sroot 
11749578Ssam 	if ((tp->t_state&TS_CARR_ON) == 0)
11758520Sroot 		return (EIO);
11769578Ssam 	hiwat = TTHIWAT(tp);
11779578Ssam 	cnt = uio->uio_resid;
11789578Ssam 	error = 0;
11797502Sroot loop:
11809578Ssam 	/*
11819578Ssam 	 * Hang the process if it's in the background.
11829578Ssam 	 */
118315141Skarels #define bit(a) (1<<(a-1))
11847502Sroot 	while (u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp &&
11859578Ssam 	    (tp->t_flags&TOSTOP) && (u.u_procp->p_flag&SVFORK)==0 &&
118615141Skarels 	    !(u.u_procp->p_sigignore & bit(SIGTTOU)) &&
118715141Skarels 	    !(u.u_procp->p_sigmask & bit(SIGTTOU))
11887502Sroot /*
11897502Sroot 					     &&
11907502Sroot 	    (u.u_procp->p_flag&SDETACH)==0) {
11917502Sroot */
11927502Sroot 	    ) {
11937502Sroot 		gsignal(u.u_procp->p_pgrp, SIGTTOU);
11947502Sroot 		sleep((caddr_t)&lbolt, TTIPRI);
11957502Sroot 	}
119615141Skarels #undef	bit
11979578Ssam 
11989578Ssam 	/*
11999578Ssam 	 * Process the user's data in at most OBUFSIZ
12009578Ssam 	 * chunks.  Perform lower case simulation and
12019578Ssam 	 * similar hacks.  Keep track of high water
12029578Ssam 	 * mark, sleep on overflow awaiting device aid
12039578Ssam 	 * in acquiring new space.
12049578Ssam 	 */
12057822Sroot 	while (uio->uio_resid > 0) {
12069578Ssam 		/*
12079578Ssam 		 * Grab a hunk of data from the user.
12089578Ssam 		 */
12097822Sroot 		cc = uio->uio_iov->iov_len;
12107822Sroot 		if (cc == 0) {
12117822Sroot 			uio->uio_iovcnt--;
12127822Sroot 			uio->uio_iov++;
12137822Sroot 			if (uio->uio_iovcnt < 0)
12147822Sroot 				panic("ttwrite");
12157822Sroot 			continue;
12167822Sroot 		}
12177822Sroot 		if (cc > OBUFSIZ)
12187822Sroot 			cc = OBUFSIZ;
12197502Sroot 		cp = obuf;
122012752Ssam 		error = uiomove(cp, cc, UIO_WRITE, uio);
12218520Sroot 		if (error)
12227502Sroot 			break;
12237502Sroot 		if (tp->t_outq.c_cc > hiwat)
12247502Sroot 			goto ovhiwat;
12259578Ssam 		if (tp->t_flags&FLUSHO)
12267502Sroot 			continue;
12279578Ssam 		/*
12289578Ssam 		 * If we're mapping lower case or kludging tildes,
12299578Ssam 		 * then we've got to look at each character, so
12309578Ssam 		 * just feed the stuff to ttyoutput...
12319578Ssam 		 */
12329578Ssam 		if (tp->t_flags & (LCASE|TILDE)) {
12339578Ssam 			while (cc > 0) {
12347502Sroot 				c = *cp++;
12357502Sroot 				tp->t_rocount = 0;
12367625Ssam 				while ((c = ttyoutput(c, tp)) >= 0) {
12377502Sroot 					/* out of clists, wait a bit */
12387502Sroot 					ttstart(tp);
12397502Sroot 					sleep((caddr_t)&lbolt, TTOPRI);
12407502Sroot 					tp->t_rocount = 0;
12417502Sroot 				}
12427502Sroot 				--cc;
12437502Sroot 				if (tp->t_outq.c_cc > hiwat)
12447502Sroot 					goto ovhiwat;
12457502Sroot 			}
12467502Sroot 			continue;
12477502Sroot 		}
12489578Ssam 		/*
12499578Ssam 		 * If nothing fancy need be done, grab those characters we
12509578Ssam 		 * can handle without any of ttyoutput's processing and
12519578Ssam 		 * just transfer them to the output q.  For those chars
12529578Ssam 		 * which require special processing (as indicated by the
12539578Ssam 		 * bits in partab), call ttyoutput.  After processing
12549578Ssam 		 * a hunk of data, look for FLUSHO so ^O's will take effect
12559578Ssam 		 * immediately.
12569578Ssam 		 */
12579578Ssam 		while (cc > 0) {
12589578Ssam 			if (tp->t_flags & (RAW|LITOUT))
12597502Sroot 				ce = cc;
12607502Sroot 			else {
126112752Ssam 				ce = cc - scanc((unsigned)cc, (caddr_t)cp,
126212752Ssam 				   (caddr_t)partab, 077);
12639578Ssam 				/*
12649578Ssam 				 * If ce is zero, then we're processing
12659578Ssam 				 * a special character through ttyoutput.
12669578Ssam 				 */
12679578Ssam 				if (ce == 0) {
12687502Sroot 					tp->t_rocount = 0;
12697502Sroot 					if (ttyoutput(*cp, tp) >= 0) {
12709578Ssam 						/* no c-lists, wait a bit */
12717502Sroot 						ttstart(tp);
12727502Sroot 						sleep((caddr_t)&lbolt, TTOPRI);
12737502Sroot 						continue;
12747502Sroot 					}
12759578Ssam 					cp++, cc--;
12769578Ssam 					if (tp->t_flags&FLUSHO ||
12779578Ssam 					    tp->t_outq.c_cc > hiwat)
12787502Sroot 						goto ovhiwat;
12799578Ssam 					continue;
12807502Sroot 				}
12817502Sroot 			}
12829578Ssam 			/*
12839578Ssam 			 * A bunch of normal characters have been found,
12849578Ssam 			 * transfer them en masse to the output queue and
12859578Ssam 			 * continue processing at the top of the loop.
12869578Ssam 			 * If there are any further characters in this
12879578Ssam 			 * <= OBUFSIZ chunk, the first should be a character
12889578Ssam 			 * requiring special handling by ttyoutput.
12899578Ssam 			 */
12907502Sroot 			tp->t_rocount = 0;
12919578Ssam 			i = b_to_q(cp, ce, &tp->t_outq);
12929578Ssam 			ce -= i;
12939578Ssam 			tp->t_col += ce;
12949578Ssam 			cp += ce, cc -= ce, tk_nout += ce;
12959578Ssam 			if (i > 0) {
12969578Ssam 				/* out of c-lists, wait a bit */
12977502Sroot 				ttstart(tp);
12987502Sroot 				sleep((caddr_t)&lbolt, TTOPRI);
12997502Sroot 			}
13009578Ssam 			if (tp->t_flags&FLUSHO || tp->t_outq.c_cc > hiwat)
13017502Sroot 				goto ovhiwat;
13027502Sroot 		}
13037502Sroot 	}
13047502Sroot 	ttstart(tp);
13058520Sroot 	return (error);
13067502Sroot 
13077502Sroot ovhiwat:
13089578Ssam 	s = spl5();
13099578Ssam 	if (cc != 0) {
13109578Ssam 		uio->uio_iov->iov_base -= cc;
13119578Ssam 		uio->uio_iov->iov_len += cc;
13129578Ssam 		uio->uio_resid += cc;
13139578Ssam 		uio->uio_offset -= cc;
13149578Ssam 	}
13159578Ssam 	/*
13169578Ssam 	 * This can only occur if FLUSHO
13179578Ssam 	 * is also set in t_flags.
13189578Ssam 	 */
13197502Sroot 	if (tp->t_outq.c_cc <= hiwat) {
13209578Ssam 		splx(s);
13217502Sroot 		goto loop;
13227502Sroot 	}
13237502Sroot 	ttstart(tp);
13249578Ssam 	if (tp->t_state&TS_NBIO) {
13257822Sroot 		if (uio->uio_resid == cnt)
13268520Sroot 			return (EWOULDBLOCK);
13278520Sroot 		return (0);
13287502Sroot 	}
13297502Sroot 	tp->t_state |= TS_ASLEEP;
13307502Sroot 	sleep((caddr_t)&tp->t_outq, TTOPRI);
13319578Ssam 	splx(s);
13327502Sroot 	goto loop;
13337502Sroot }
13347502Sroot 
13357502Sroot /*
13367502Sroot  * Rubout one character from the rawq of tp
13377502Sroot  * as cleanly as possible.
13387502Sroot  */
13397502Sroot ttyrub(c, tp)
13407625Ssam 	register c;
13417625Ssam 	register struct tty *tp;
13427502Sroot {
13437502Sroot 	register char *cp;
13447502Sroot 	register int savecol;
13457502Sroot 	int s;
13467502Sroot 	char *nextc();
13477502Sroot 
13489578Ssam 	if ((tp->t_flags&ECHO) == 0)
13497502Sroot 		return;
13509578Ssam 	tp->t_flags &= ~FLUSHO;
13517502Sroot 	c &= 0377;
13529578Ssam 	if (tp->t_flags&CRTBS) {
13537502Sroot 		if (tp->t_rocount == 0) {
13547502Sroot 			/*
13557502Sroot 			 * Screwed by ttwrite; retype
13567502Sroot 			 */
13577502Sroot 			ttyretype(tp);
13587502Sroot 			return;
13597502Sroot 		}
13609578Ssam 		if (c == ('\t'|0200) || c == ('\n'|0200))
13617502Sroot 			ttyrubo(tp, 2);
13629578Ssam 		else switch (partab[c&=0177]&0177) {
13637502Sroot 
13647502Sroot 		case ORDINARY:
13657502Sroot 			if (tp->t_flags&LCASE && c >= 'A' && c <= 'Z')
13667502Sroot 				ttyrubo(tp, 2);
13677502Sroot 			else
13687502Sroot 				ttyrubo(tp, 1);
13697502Sroot 			break;
13707502Sroot 
13717502Sroot 		case VTAB:
13727502Sroot 		case BACKSPACE:
13737502Sroot 		case CONTROL:
13747502Sroot 		case RETURN:
13759578Ssam 			if (tp->t_flags&CTLECH)
13767502Sroot 				ttyrubo(tp, 2);
13777502Sroot 			break;
13787502Sroot 
13797502Sroot 		case TAB:
13807502Sroot 			if (tp->t_rocount < tp->t_rawq.c_cc) {
13817502Sroot 				ttyretype(tp);
13827502Sroot 				return;
13837502Sroot 			}
13847502Sroot 			s = spl5();
13857502Sroot 			savecol = tp->t_col;
13869578Ssam 			tp->t_state |= TS_CNTTB;
13879578Ssam 			tp->t_flags |= FLUSHO;
13887502Sroot 			tp->t_col = tp->t_rocol;
13899578Ssam 			cp = tp->t_rawq.c_cf;
13909578Ssam 			for (; cp; cp = nextc(&tp->t_rawq, cp))
13917502Sroot 				ttyecho(*cp, tp);
13929578Ssam 			tp->t_flags &= ~FLUSHO;
13939578Ssam 			tp->t_state &= ~TS_CNTTB;
13947502Sroot 			splx(s);
13957502Sroot 			/*
13967502Sroot 			 * savecol will now be length of the tab
13977502Sroot 			 */
13987502Sroot 			savecol -= tp->t_col;
13997502Sroot 			tp->t_col += savecol;
14007502Sroot 			if (savecol > 8)
14017502Sroot 				savecol = 8;		/* overflow screw */
14027502Sroot 			while (--savecol >= 0)
14037502Sroot 				(void) ttyoutput('\b', tp);
14047502Sroot 			break;
14057502Sroot 
14067502Sroot 		default:
14077502Sroot 			panic("ttyrub");
14087502Sroot 		}
14099578Ssam 	} else if (tp->t_flags&PRTERA) {
14109578Ssam 		if ((tp->t_state&TS_ERASE) == 0) {
14117502Sroot 			(void) ttyoutput('\\', tp);
14129578Ssam 			tp->t_state |= TS_ERASE;
14137502Sroot 		}
14147502Sroot 		ttyecho(c, tp);
14157502Sroot 	} else
14167502Sroot 		ttyecho(tp->t_erase, tp);
14177502Sroot 	tp->t_rocount--;
14187502Sroot }
14197502Sroot 
14207502Sroot /*
14217502Sroot  * Crt back over cnt chars perhaps
14227502Sroot  * erasing them.
14237502Sroot  */
14247502Sroot ttyrubo(tp, cnt)
14257625Ssam 	register struct tty *tp;
14267625Ssam 	int cnt;
14277502Sroot {
14289578Ssam 	register char *rubostring = tp->t_flags&CRTERA ? "\b \b" : "\b";
14297502Sroot 
14307502Sroot 	while (--cnt >= 0)
14319578Ssam 		ttyout(rubostring, tp);
14327502Sroot }
14337502Sroot 
14347502Sroot /*
14357502Sroot  * Reprint the rawq line.
14367502Sroot  * We assume c_cc has already been checked.
14377502Sroot  */
14387502Sroot ttyretype(tp)
14397625Ssam 	register struct tty *tp;
14407502Sroot {
14417502Sroot 	register char *cp;
14427502Sroot 	char *nextc();
14437502Sroot 	int s;
14447502Sroot 
14459578Ssam 	if (tp->t_rprntc != 0377)
14469578Ssam 		ttyecho(tp->t_rprntc, tp);
14477502Sroot 	(void) ttyoutput('\n', tp);
14487502Sroot 	s = spl5();
14497502Sroot 	for (cp = tp->t_canq.c_cf; cp; cp = nextc(&tp->t_canq, cp))
14507502Sroot 		ttyecho(*cp, tp);
14517502Sroot 	for (cp = tp->t_rawq.c_cf; cp; cp = nextc(&tp->t_rawq, cp))
14527502Sroot 		ttyecho(*cp, tp);
14539578Ssam 	tp->t_state &= ~TS_ERASE;
14547502Sroot 	splx(s);
14557502Sroot 	tp->t_rocount = tp->t_rawq.c_cc;
14567502Sroot 	tp->t_rocol = 0;
14577502Sroot }
14587502Sroot 
14597502Sroot /*
14607502Sroot  * Echo a typed character to the terminal
14617502Sroot  */
14627502Sroot ttyecho(c, tp)
14637625Ssam 	register c;
14647625Ssam 	register struct tty *tp;
14657502Sroot {
14667502Sroot 
14679578Ssam 	if ((tp->t_state&TS_CNTTB) == 0)
14689578Ssam 		tp->t_flags &= ~FLUSHO;
14697502Sroot 	if ((tp->t_flags&ECHO) == 0)
14707502Sroot 		return;
14717502Sroot 	c &= 0377;
14727502Sroot 	if (tp->t_flags&RAW) {
14737502Sroot 		(void) ttyoutput(c, tp);
14747502Sroot 		return;
14757502Sroot 	}
14767502Sroot 	if (c == '\r' && tp->t_flags&CRMOD)
14777502Sroot 		c = '\n';
14789578Ssam 	if (tp->t_flags&CTLECH) {
14797502Sroot 		if ((c&0177) <= 037 && c!='\t' && c!='\n' || (c&0177)==0177) {
14807502Sroot 			(void) ttyoutput('^', tp);
14817502Sroot 			c &= 0177;
14827502Sroot 			if (c == 0177)
14837502Sroot 				c = '?';
14847502Sroot 			else if (tp->t_flags&LCASE)
14857502Sroot 				c += 'a' - 1;
14867502Sroot 			else
14877502Sroot 				c += 'A' - 1;
14887502Sroot 		}
14897502Sroot 	}
14907502Sroot 	if ((tp->t_flags&LCASE) && (c >= 'A' && c <= 'Z'))
14917502Sroot 		c += 'a' - 'A';
14929578Ssam 	(void) ttyoutput(c&0177, tp);
14937502Sroot }
14947502Sroot 
14957502Sroot /*
14967502Sroot  * Is c a break char for tp?
14977502Sroot  */
14987502Sroot ttbreakc(c, tp)
14997625Ssam 	register c;
15007625Ssam 	register struct tty *tp;
15017502Sroot {
15029578Ssam 	return (c == '\n' || c == tp->t_eofc || c == tp->t_brkc ||
15037502Sroot 		c == '\r' && (tp->t_flags&CRMOD));
15047502Sroot }
15057502Sroot 
15067502Sroot /*
15077502Sroot  * send string cp to tp
15087502Sroot  */
15097502Sroot ttyout(cp, tp)
15107625Ssam 	register char *cp;
15117625Ssam 	register struct tty *tp;
15127502Sroot {
15137502Sroot 	register char c;
15147502Sroot 
15157502Sroot 	while (c = *cp++)
15167502Sroot 		(void) ttyoutput(c, tp);
15177502Sroot }
15187502Sroot 
15197502Sroot ttwakeup(tp)
15207502Sroot 	struct tty *tp;
15217502Sroot {
15227502Sroot 
15237502Sroot 	if (tp->t_rsel) {
15247502Sroot 		selwakeup(tp->t_rsel, tp->t_state&TS_RCOLL);
15257502Sroot 		tp->t_state &= ~TS_RCOLL;
15267502Sroot 		tp->t_rsel = 0;
15277502Sroot 	}
152812752Ssam 	if (tp->t_state & TS_ASYNC)
152912752Ssam 		gsignal(tp->t_pgrp, SIGIO);
15307502Sroot 	wakeup((caddr_t)&tp->t_rawq);
15317502Sroot }
15327502Sroot 
153313533Ssam #if !defined(vax)
15349578Ssam scanc(size, cp, table, mask)
15359578Ssam 	register int size;
15369578Ssam 	register char *cp, table[];
15379578Ssam 	register int mask;
15387502Sroot {
15399578Ssam 	register int i = 0;
15407502Sroot 
15419578Ssam 	while ((table[*(u_char *)(cp + i)]&mask) == 0 && i < size)
15429578Ssam 		i++;
154315100Skarels 	return (size - i);
15447502Sroot }
15459578Ssam #endif
1546