xref: /csrg-svn/sys/kern/tty.c (revision 17183)
1*17183Smckusick /*	tty.c	6.11	84/09/10	*/
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 {
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 			;
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 
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:
363*17183Smckusick 		if (u.u_uid && (flag & FREAD) == 0)
364*17183Smckusick 			return (EPERM);
3659325Ssam 		if (u.u_uid && u.u_ttyp != tp)
3669325Ssam 			return (EACCES);
3679578Ssam 		(*linesw[tp->t_line].l_rint)(*(char *)data, tp);
3689325Ssam 		break;
3699325Ssam 
37012752Ssam 	case TIOCSETP:
37112752Ssam 	case TIOCSETN: {
37212752Ssam 		register struct sgttyb *sg = (struct sgttyb *)data;
37312752Ssam 
37412752Ssam 		tp->t_erase = sg->sg_erase;
37512752Ssam 		tp->t_kill = sg->sg_kill;
37612752Ssam 		tp->t_ispeed = sg->sg_ispeed;
37712752Ssam 		tp->t_ospeed = sg->sg_ospeed;
37812752Ssam 		newflags = (tp->t_flags&0xffff0000) | (sg->sg_flags&0xffff);
37912752Ssam 		s = spl5();
38012752Ssam 		if (tp->t_flags&RAW || newflags&RAW || com == TIOCSETP) {
38112752Ssam 			ttywait(tp);
38212752Ssam 			ttyflush(tp, FREAD);
38312752Ssam 		} else if ((tp->t_flags&CBREAK) != (newflags&CBREAK)) {
38412752Ssam 			if (newflags&CBREAK) {
38512752Ssam 				struct clist tq;
38612752Ssam 
38712752Ssam 				catq(&tp->t_rawq, &tp->t_canq);
38812752Ssam 				tq = tp->t_rawq;
38912752Ssam 				tp->t_rawq = tp->t_canq;
39012752Ssam 				tp->t_canq = tq;
39112752Ssam 			} else {
39212752Ssam 				tp->t_flags |= PENDIN;
39313801Ssam 				newflags |= PENDIN;
39412752Ssam 				ttwakeup(tp);
39512752Ssam 			}
39612752Ssam 		}
39712752Ssam 		tp->t_flags = newflags;
39812752Ssam 		if (tp->t_flags&RAW) {
39912752Ssam 			tp->t_state &= ~TS_TTSTOP;
40012752Ssam 			ttstart(tp);
40112752Ssam 		}
40212752Ssam 		splx(s);
40312752Ssam 		break;
40412752Ssam 	}
40512752Ssam 
40612752Ssam 	/* send current parameters to user */
40712752Ssam 	case TIOCGETP: {
40812752Ssam 		register struct sgttyb *sg = (struct sgttyb *)data;
40912752Ssam 
41012752Ssam 		sg->sg_ispeed = tp->t_ispeed;
41112752Ssam 		sg->sg_ospeed = tp->t_ospeed;
41212752Ssam 		sg->sg_erase = tp->t_erase;
41312752Ssam 		sg->sg_kill = tp->t_kill;
41412752Ssam 		sg->sg_flags = tp->t_flags;
41512752Ssam 		break;
41612752Ssam 	}
41712752Ssam 
41812752Ssam 	case FIONBIO:
41912752Ssam 		if (*(int *)data)
42012752Ssam 			tp->t_state |= TS_NBIO;
42112752Ssam 		else
42212752Ssam 			tp->t_state &= ~TS_NBIO;
42312752Ssam 		break;
42412752Ssam 
42512752Ssam 	case FIOASYNC:
42612752Ssam 		if (*(int *)data)
42712752Ssam 			tp->t_state |= TS_ASYNC;
42812752Ssam 		else
42912752Ssam 			tp->t_state &= ~TS_ASYNC;
43012752Ssam 		break;
43112752Ssam 
43213077Ssam 	case TIOCGETC:
43313077Ssam 		bcopy((caddr_t)&tp->t_intrc, data, sizeof (struct tchars));
43413077Ssam 		break;
43513077Ssam 
43613077Ssam 	case TIOCSETC:
43713077Ssam 		bcopy(data, (caddr_t)&tp->t_intrc, sizeof (struct tchars));
43813077Ssam 		break;
43913077Ssam 
44012752Ssam 	/* set/get local special characters */
44112752Ssam 	case TIOCSLTC:
44212752Ssam 		bcopy(data, (caddr_t)&tp->t_suspc, sizeof (struct ltchars));
44312752Ssam 		break;
44412752Ssam 
44512752Ssam 	case TIOCGLTC:
44612752Ssam 		bcopy((caddr_t)&tp->t_suspc, data, sizeof (struct ltchars));
44712752Ssam 		break;
44812752Ssam 
44912752Ssam 	/*
45012752Ssam 	 * Modify local mode word.
45112752Ssam 	 */
45212752Ssam 	case TIOCLBIS:
45312752Ssam 		tp->t_flags |= *(int *)data << 16;
45412752Ssam 		break;
45512752Ssam 
45612752Ssam 	case TIOCLBIC:
45712752Ssam 		tp->t_flags &= ~(*(int *)data << 16);
45812752Ssam 		break;
45912752Ssam 
46012752Ssam 	case TIOCLSET:
46112752Ssam 		tp->t_flags &= 0xffff;
46212752Ssam 		tp->t_flags |= *(int *)data << 16;
46312752Ssam 		break;
46412752Ssam 
46512752Ssam 	case TIOCLGET:
46615720Skarels 		*(int *)data = ((unsigned) tp->t_flags) >> 16;
46712752Ssam 		break;
46812752Ssam 
46912752Ssam 	/* should allow SPGRP and GPGRP only if tty open for reading */
47012752Ssam 	case TIOCSPGRP:
47112752Ssam 		tp->t_pgrp = *(int *)data;
47212752Ssam 		break;
47312752Ssam 
47412752Ssam 	case TIOCGPGRP:
47512752Ssam 		*(int *)data = tp->t_pgrp;
47612752Ssam 		break;
47712752Ssam 
47839Sbill 	default:
4798556Sroot 		return (-1);
48039Sbill 	}
4818556Sroot 	return (0);
48239Sbill }
4834484Swnj 
4844484Swnj ttnread(tp)
4854484Swnj 	struct tty *tp;
4864484Swnj {
4874484Swnj 	int nread = 0;
4884484Swnj 
4899578Ssam 	if (tp->t_flags & PENDIN)
4904484Swnj 		ttypend(tp);
4914484Swnj 	nread = tp->t_canq.c_cc;
4924484Swnj 	if (tp->t_flags & (RAW|CBREAK))
4934484Swnj 		nread += tp->t_rawq.c_cc;
4944484Swnj 	return (nread);
4954484Swnj }
4964484Swnj 
4975408Swnj ttselect(dev, rw)
4984484Swnj 	dev_t dev;
4995408Swnj 	int rw;
5004484Swnj {
5014484Swnj 	register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)];
5024484Swnj 	int nread;
5035408Swnj 	int s = spl5();
5044484Swnj 
5055408Swnj 	switch (rw) {
5064484Swnj 
5074484Swnj 	case FREAD:
5084484Swnj 		nread = ttnread(tp);
5094484Swnj 		if (nread > 0)
5105408Swnj 			goto win;
5114938Swnj 		if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait)
5125408Swnj 			tp->t_state |= TS_RCOLL;
5134484Swnj 		else
5144484Swnj 			tp->t_rsel = u.u_procp;
5155408Swnj 		break;
5164484Swnj 
5175408Swnj 	case FWRITE:
5185408Swnj 		if (tp->t_outq.c_cc <= TTLOWAT(tp))
5195408Swnj 			goto win;
5205408Swnj 		if (tp->t_wsel && tp->t_wsel->p_wchan == (caddr_t)&selwait)
5215408Swnj 			tp->t_state |= TS_WCOLL;
5225408Swnj 		else
5235408Swnj 			tp->t_wsel = u.u_procp;
5245408Swnj 		break;
5254484Swnj 	}
5265408Swnj 	splx(s);
5275408Swnj 	return (0);
5285408Swnj win:
5295408Swnj 	splx(s);
5305408Swnj 	return (1);
5314484Swnj }
5327436Skre 
5337502Sroot /*
5349578Ssam  * Establish a process group for distribution of
5357502Sroot  * quits and interrupts from the tty.
5367502Sroot  */
5377502Sroot ttyopen(dev, tp)
5387625Ssam 	dev_t dev;
5397625Ssam 	register struct tty *tp;
5407502Sroot {
5417502Sroot 	register struct proc *pp;
5427502Sroot 
5437502Sroot 	pp = u.u_procp;
5447502Sroot 	tp->t_dev = dev;
5457625Ssam 	if (pp->p_pgrp == 0) {
5467502Sroot 		u.u_ttyp = tp;
5477502Sroot 		u.u_ttyd = dev;
5487502Sroot 		if (tp->t_pgrp == 0)
5497502Sroot 			tp->t_pgrp = pp->p_pid;
5507502Sroot 		pp->p_pgrp = tp->t_pgrp;
5517502Sroot 	}
5527502Sroot 	tp->t_state &= ~TS_WOPEN;
5537502Sroot 	tp->t_state |= TS_ISOPEN;
5547502Sroot 	if (tp->t_line != NTTYDISC)
55512752Ssam 		ttywflush(tp);
5568556Sroot 	return (0);
5577502Sroot }
5587502Sroot 
5597502Sroot /*
5607502Sroot  * clean tp on last close
5617502Sroot  */
5627502Sroot ttyclose(tp)
5637625Ssam 	register struct tty *tp;
5647502Sroot {
5657502Sroot 
5667502Sroot 	if (tp->t_line) {
56712752Ssam 		ttywflush(tp);
5687502Sroot 		tp->t_line = 0;
5697502Sroot 		return;
5707502Sroot 	}
5717502Sroot 	tp->t_pgrp = 0;
57212752Ssam 	ttywflush(tp);
5737502Sroot 	tp->t_state = 0;
5747502Sroot }
5757502Sroot 
5767502Sroot /*
5777502Sroot  * reinput pending characters after state switch
5787502Sroot  * call at spl5().
5797502Sroot  */
5807502Sroot ttypend(tp)
5817625Ssam 	register struct tty *tp;
5827502Sroot {
5837502Sroot 	struct clist tq;
5847502Sroot 	register c;
5857502Sroot 
5869578Ssam 	tp->t_flags &= ~PENDIN;
5879578Ssam 	tp->t_state |= TS_TYPEN;
5887502Sroot 	tq = tp->t_rawq;
5897502Sroot 	tp->t_rawq.c_cc = 0;
5907502Sroot 	tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0;
5917502Sroot 	while ((c = getc(&tq)) >= 0)
5927502Sroot 		ttyinput(c, tp);
5939578Ssam 	tp->t_state &= ~TS_TYPEN;
5947502Sroot }
5957502Sroot 
5967502Sroot /*
5979578Ssam  * Place a character on raw TTY input queue,
5989578Ssam  * putting in delimiters and waking up top
5999578Ssam  * half as needed.  Also echo if required.
6009578Ssam  * The arguments are the character and the
6019578Ssam  * appropriate tty structure.
6027502Sroot  */
6037502Sroot ttyinput(c, tp)
6047625Ssam 	register c;
6057625Ssam 	register struct tty *tp;
6067502Sroot {
6079578Ssam 	register int t_flags = tp->t_flags;
6087502Sroot 	int i;
6097502Sroot 
6109578Ssam 	/*
6119578Ssam 	 * If input is pending take it first.
6129578Ssam 	 */
6139578Ssam 	if (t_flags&PENDIN)
6147502Sroot 		ttypend(tp);
6157502Sroot 	tk_nin++;
6167502Sroot 	c &= 0377;
6179578Ssam 
6189578Ssam 	/*
6199578Ssam 	 * In tandem mode, check high water mark.
6209578Ssam 	 */
6217502Sroot 	if (t_flags&TANDEM)
6227502Sroot 		ttyblock(tp);
6239578Ssam 
6249578Ssam 	if (t_flags&RAW) {
6259578Ssam 		/*
6269578Ssam 		 * Raw mode, just put character
6279578Ssam 		 * in input q w/o interpretation.
6289578Ssam 		 */
6299578Ssam 		if (tp->t_rawq.c_cc > TTYHOG)
63012752Ssam 			ttyflush(tp, FREAD|FWRITE);
6319578Ssam 		else {
6329578Ssam 			if (putc(c, &tp->t_rawq) >= 0)
6339578Ssam 				ttwakeup(tp);
6349578Ssam 			ttyecho(c, tp);
6357502Sroot 		}
6369578Ssam 		goto endcase;
6379578Ssam 	}
6389578Ssam 
6399578Ssam 	/*
6409578Ssam 	 * Ignore any high bit added during
6419578Ssam 	 * previous ttyinput processing.
6429578Ssam 	 */
6439578Ssam 	if ((tp->t_state&TS_TYPEN) == 0)
6449578Ssam 		c &= 0177;
6459578Ssam 	/*
6469578Ssam 	 * Check for literal nexting very first
6479578Ssam 	 */
6489578Ssam 	if (tp->t_state&TS_LNCH) {
6499578Ssam 		c |= 0200;
6509578Ssam 		tp->t_state &= ~TS_LNCH;
6519578Ssam 	}
6529578Ssam 
6539578Ssam 	/*
6549578Ssam 	 * Scan for special characters.  This code
6559578Ssam 	 * is really just a big case statement with
6569578Ssam 	 * non-constant cases.  The bottom of the
6579578Ssam 	 * case statement is labeled ``endcase'', so goto
6589578Ssam 	 * it after a case match, or similar.
6599578Ssam 	 */
6609578Ssam 	if (tp->t_line == NTTYDISC) {
6619578Ssam 		if (c == tp->t_lnextc) {
6627502Sroot 			if (tp->t_flags&ECHO)
6637502Sroot 				ttyout("^\b", tp);
6649578Ssam 			tp->t_state |= TS_LNCH;
6659578Ssam 			goto endcase;
6669578Ssam 		}
6679578Ssam 		if (c == tp->t_flushc) {
6689578Ssam 			if (tp->t_flags&FLUSHO)
6699578Ssam 				tp->t_flags &= ~FLUSHO;
6707502Sroot 			else {
67112752Ssam 				ttyflush(tp, FWRITE);
6727502Sroot 				ttyecho(c, tp);
6739578Ssam 				if (tp->t_rawq.c_cc + tp->t_canq.c_cc)
6747502Sroot 					ttyretype(tp);
6759578Ssam 				tp->t_flags |= FLUSHO;
6767502Sroot 			}
6779578Ssam 			goto startoutput;
6789578Ssam 		}
6799578Ssam 		if (c == tp->t_suspc) {
6809578Ssam 			if ((tp->t_flags&NOFLSH) == 0)
68112752Ssam 				ttyflush(tp, FREAD);
6829578Ssam 			ttyecho(c, tp);
6839578Ssam 			gsignal(tp->t_pgrp, SIGTSTP);
6849578Ssam 			goto endcase;
6859578Ssam 		}
6869578Ssam 	}
6879578Ssam 
6889578Ssam 	/*
6899578Ssam 	 * Handle start/stop characters.
6909578Ssam 	 */
6919578Ssam 	if (c == tp->t_stopc) {
6929578Ssam 		if ((tp->t_state&TS_TTSTOP) == 0) {
6939578Ssam 			tp->t_state |= TS_TTSTOP;
6949578Ssam 			(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
6957502Sroot 			return;
6969578Ssam 		}
6979578Ssam 		if (c != tp->t_startc)
6989578Ssam 			return;
6999578Ssam 		goto endcase;
7009578Ssam 	}
7019578Ssam 	if (c == tp->t_startc)
7029578Ssam 		goto restartoutput;
7039578Ssam 
7049578Ssam 	/*
7059578Ssam 	 * Look for interrupt/quit chars.
7069578Ssam 	 */
7079578Ssam 	if (c == tp->t_intrc || c == tp->t_quitc) {
7089578Ssam 		if ((tp->t_flags&NOFLSH) == 0)
70912752Ssam 			ttyflush(tp, FREAD|FWRITE);
7109578Ssam 		ttyecho(c, tp);
7119578Ssam 		gsignal(tp->t_pgrp, c == tp->t_intrc ? SIGINT : SIGQUIT);
7129578Ssam 		goto endcase;
7139578Ssam 	}
7149578Ssam 
7159578Ssam 	/*
7169578Ssam 	 * Cbreak mode, don't process line editing
7179578Ssam 	 * characters; check high water mark for wakeup.
7189578Ssam 	 */
7199578Ssam 	if (t_flags&CBREAK) {
7209578Ssam 		if (tp->t_rawq.c_cc > TTYHOG) {
7217502Sroot 			if (tp->t_outq.c_cc < TTHIWAT(tp) &&
7227502Sroot 			    tp->t_line == NTTYDISC)
7237502Sroot 				(void) ttyoutput(CTRL(g), tp);
7247502Sroot 		} else if (putc(c, &tp->t_rawq) >= 0) {
7257502Sroot 			ttwakeup(tp);
7267502Sroot 			ttyecho(c, tp);
7277502Sroot 		}
7289578Ssam 		goto endcase;
7299578Ssam 	}
7309578Ssam 
7319578Ssam 	/*
7329578Ssam 	 * From here on down cooked mode character
7339578Ssam 	 * processing takes place.
7349578Ssam 	 */
7359578Ssam 	if ((tp->t_state&TS_QUOT) &&
7369578Ssam 	    (c == tp->t_erase || c == tp->t_kill)) {
7379578Ssam 		ttyrub(unputc(&tp->t_rawq), tp);
7389578Ssam 		c |= 0200;
7399578Ssam 	}
7409578Ssam 	if (c == tp->t_erase) {
7419578Ssam 		if (tp->t_rawq.c_cc)
7429578Ssam 			ttyrub(unputc(&tp->t_rawq), tp);
7439578Ssam 		goto endcase;
7449578Ssam 	}
7459578Ssam 	if (c == tp->t_kill) {
7469578Ssam 		if (tp->t_flags&CRTKIL &&
7479578Ssam 		    tp->t_rawq.c_cc == tp->t_rocount) {
7489578Ssam 			while (tp->t_rawq.c_cc)
7499578Ssam 				ttyrub(unputc(&tp->t_rawq), tp);
7509578Ssam 		} else {
7519578Ssam 			ttyecho(c, tp);
7529578Ssam 			ttyecho('\n', tp);
7539578Ssam 			while (getc(&tp->t_rawq) > 0)
7549578Ssam 				;
7559578Ssam 			tp->t_rocount = 0;
7569578Ssam 		}
7579578Ssam 		tp->t_state &= ~TS_LOCAL;
7589578Ssam 		goto endcase;
7599578Ssam 	}
7609578Ssam 
7619578Ssam 	/*
7629578Ssam 	 * New line discipline,
7639578Ssam 	 * check word erase/reprint line.
7649578Ssam 	 */
7659578Ssam 	if (tp->t_line == NTTYDISC) {
7669578Ssam 		if (c == tp->t_werasc) {
7679578Ssam 			if (tp->t_rawq.c_cc == 0)
7689578Ssam 				goto endcase;
7699578Ssam 			do {
7709578Ssam 				c = unputc(&tp->t_rawq);
7719578Ssam 				if (c != ' ' && c != '\t')
7729578Ssam 					goto erasenb;
7739578Ssam 				ttyrub(c, tp);
7749578Ssam 			} while (tp->t_rawq.c_cc);
7759578Ssam 			goto endcase;
7769578Ssam 	erasenb:
7779578Ssam 			do {
7789578Ssam 				ttyrub(c, tp);
7799578Ssam 				if (tp->t_rawq.c_cc == 0)
7809578Ssam 					goto endcase;
7819578Ssam 				c = unputc(&tp->t_rawq);
7829578Ssam 			} while (c != ' ' && c != '\t');
7839578Ssam 			(void) putc(c, &tp->t_rawq);
7849578Ssam 			goto endcase;
7859578Ssam 		}
7869578Ssam 		if (c == tp->t_rprntc) {
7879578Ssam 			ttyretype(tp);
7889578Ssam 			goto endcase;
7899578Ssam 		}
7909578Ssam 	}
7919578Ssam 
7929578Ssam 	/*
7939578Ssam 	 * Check for input buffer overflow
7949578Ssam 	 */
79510391Ssam 	if (tp->t_rawq.c_cc+tp->t_canq.c_cc >= TTYHOG) {
79610391Ssam 		if (tp->t_line == NTTYDISC)
79710391Ssam 			(void) ttyoutput(CTRL(g), tp);
7989578Ssam 		goto endcase;
79910391Ssam 	}
8009578Ssam 
8019578Ssam 	/*
8029578Ssam 	 * Put data char in q for user and
8039578Ssam 	 * wakeup on seeing a line delimiter.
8049578Ssam 	 */
8059578Ssam 	if (putc(c, &tp->t_rawq) >= 0) {
8069578Ssam 		if (ttbreakc(c, tp)) {
8079578Ssam 			tp->t_rocount = 0;
8089578Ssam 			catq(&tp->t_rawq, &tp->t_canq);
8097502Sroot 			ttwakeup(tp);
8109578Ssam 		} else if (tp->t_rocount++ == 0)
8119578Ssam 			tp->t_rocol = tp->t_col;
8129578Ssam 		tp->t_state &= ~TS_QUOT;
8139578Ssam 		if (c == '\\')
8149578Ssam 			tp->t_state |= TS_QUOT;
8159578Ssam 		if (tp->t_state&TS_ERASE) {
8169578Ssam 			tp->t_state &= ~TS_ERASE;
8179578Ssam 			(void) ttyoutput('/', tp);
8189578Ssam 		}
8199578Ssam 		i = tp->t_col;
8207502Sroot 		ttyecho(c, tp);
8219578Ssam 		if (c == tp->t_eofc && tp->t_flags&ECHO) {
8229578Ssam 			i = MIN(2, tp->t_col - i);
8239578Ssam 			while (i > 0) {
8249578Ssam 				(void) ttyoutput('\b', tp);
8259578Ssam 				i--;
8269578Ssam 			}
8279578Ssam 		}
8287502Sroot 	}
8299578Ssam 
8309578Ssam endcase:
8319578Ssam 	/*
8329578Ssam 	 * If DEC-style start/stop is enabled don't restart
8339578Ssam 	 * output until seeing the start character.
8349578Ssam 	 */
8359578Ssam 	if (tp->t_flags&DECCTQ && tp->t_state&TS_TTSTOP &&
8369578Ssam 	    tp->t_startc != tp->t_stopc)
8377502Sroot 		return;
8389578Ssam 
8399578Ssam restartoutput:
8407502Sroot 	tp->t_state &= ~TS_TTSTOP;
8419578Ssam 	tp->t_flags &= ~FLUSHO;
8429578Ssam 
8439578Ssam startoutput:
8447502Sroot 	ttstart(tp);
8457502Sroot }
8467502Sroot 
8477502Sroot /*
8489578Ssam  * Put character on TTY output queue, adding delays,
8497502Sroot  * expanding tabs, and handling the CR/NL bit.
8509578Ssam  * This is called both from the top half for output,
8519578Ssam  * and from interrupt level for echoing.
8527502Sroot  * The arguments are the character and the tty structure.
8537502Sroot  * Returns < 0 if putc succeeds, otherwise returns char to resend
8547502Sroot  * Must be recursive.
8557502Sroot  */
8567502Sroot ttyoutput(c, tp)
8577502Sroot 	register c;
8587502Sroot 	register struct tty *tp;
8597502Sroot {
8607502Sroot 	register char *colp;
8617502Sroot 	register ctype;
8627502Sroot 
8639578Ssam 	if (tp->t_flags & (RAW|LITOUT)) {
8649578Ssam 		if (tp->t_flags&FLUSHO)
8657502Sroot 			return (-1);
8667502Sroot 		if (putc(c, &tp->t_outq))
8677625Ssam 			return (c);
8687502Sroot 		tk_nout++;
8697502Sroot 		return (-1);
8707502Sroot 	}
8719578Ssam 
8727502Sroot 	/*
8739578Ssam 	 * Ignore EOT in normal mode to avoid
8749578Ssam 	 * hanging up certain terminals.
8757502Sroot 	 */
8767502Sroot 	c &= 0177;
8779578Ssam 	if (c == CEOT && (tp->t_flags&CBREAK) == 0)
8787502Sroot 		return (-1);
8797502Sroot 	/*
8807502Sroot 	 * Turn tabs to spaces as required
8817502Sroot 	 */
8829578Ssam 	if (c == '\t' && (tp->t_flags&TBDELAY) == XTABS) {
8837502Sroot 		register int s;
8847502Sroot 
8857502Sroot 		c = 8 - (tp->t_col&7);
8869578Ssam 		if ((tp->t_flags&FLUSHO) == 0) {
8877502Sroot 			s = spl5();		/* don't interrupt tabs */
8887502Sroot 			c -= b_to_q("        ", c, &tp->t_outq);
8897502Sroot 			tk_nout += c;
8907502Sroot 			splx(s);
8917502Sroot 		}
8927502Sroot 		tp->t_col += c;
8937502Sroot 		return (c ? -1 : '\t');
8947502Sroot 	}
8957502Sroot 	tk_nout++;
8967502Sroot 	/*
8977502Sroot 	 * for upper-case-only terminals,
8987502Sroot 	 * generate escapes.
8997502Sroot 	 */
9007502Sroot 	if (tp->t_flags&LCASE) {
9017502Sroot 		colp = "({)}!|^~'`";
9027625Ssam 		while (*colp++)
9037625Ssam 			if (c == *colp++) {
9047502Sroot 				if (ttyoutput('\\', tp) >= 0)
9057502Sroot 					return (c);
9067502Sroot 				c = colp[-2];
9077502Sroot 				break;
9087502Sroot 			}
9099578Ssam 		if ('A' <= c && c <= 'Z') {
9107502Sroot 			if (ttyoutput('\\', tp) >= 0)
9117502Sroot 				return (c);
9129578Ssam 		} else if ('a' <= c && c <= 'z')
9137502Sroot 			c += 'A' - 'a';
9147502Sroot 	}
9159578Ssam 
9167502Sroot 	/*
9177502Sroot 	 * turn <nl> to <cr><lf> if desired.
9187502Sroot 	 */
9199578Ssam 	if (c == '\n' && tp->t_flags&CRMOD)
9207502Sroot 		if (ttyoutput('\r', tp) >= 0)
9217502Sroot 			return (c);
9229578Ssam 	if (c == '~' && tp->t_flags&TILDE)
9237502Sroot 		c = '`';
9249578Ssam 	if ((tp->t_flags&FLUSHO) == 0 && putc(c, &tp->t_outq))
9257502Sroot 		return (c);
9267502Sroot 	/*
9277502Sroot 	 * Calculate delays.
9287502Sroot 	 * The numbers here represent clock ticks
9297502Sroot 	 * and are not necessarily optimal for all terminals.
9307502Sroot 	 * The delays are indicated by characters above 0200.
9317502Sroot 	 * In raw mode there are no delays and the
9327502Sroot 	 * transmission path is 8 bits wide.
9339578Ssam 	 *
9349578Ssam 	 * SHOULD JUST ALLOW USER TO SPECIFY DELAYS
9357502Sroot 	 */
9367502Sroot 	colp = &tp->t_col;
9377502Sroot 	ctype = partab[c];
9387502Sroot 	c = 0;
9397502Sroot 	switch (ctype&077) {
9407502Sroot 
9417502Sroot 	case ORDINARY:
9427502Sroot 		(*colp)++;
9437502Sroot 
9447502Sroot 	case CONTROL:
9457502Sroot 		break;
9467502Sroot 
9477502Sroot 	case BACKSPACE:
9487502Sroot 		if (*colp)
9497502Sroot 			(*colp)--;
9507502Sroot 		break;
9517502Sroot 
95213821Ssam 	/*
95313821Ssam 	 * This macro is close enough to the correct thing;
95413821Ssam 	 * it should be replaced by real user settable delays
95513821Ssam 	 * in any event...
95613821Ssam 	 */
95713821Ssam #define	mstohz(ms)	(((ms) * hz) >> 10)
9587502Sroot 	case NEWLINE:
9597502Sroot 		ctype = (tp->t_flags >> 8) & 03;
9607625Ssam 		if (ctype == 1) { /* tty 37 */
96112752Ssam 			if (*colp > 0)
96213863Ssam 				c = max((((unsigned)*colp) >> 4) + 3,
96313863Ssam 				    (unsigned)6);
9649578Ssam 		} else if (ctype == 2) /* vt05 */
96513821Ssam 			c = mstohz(100);
9667502Sroot 		*colp = 0;
9677502Sroot 		break;
9687502Sroot 
9697502Sroot 	case TAB:
9707502Sroot 		ctype = (tp->t_flags >> 10) & 03;
9717625Ssam 		if (ctype == 1) { /* tty 37 */
9727502Sroot 			c = 1 - (*colp | ~07);
9737625Ssam 			if (c < 5)
9747502Sroot 				c = 0;
9757502Sroot 		}
9767502Sroot 		*colp |= 07;
9777502Sroot 		(*colp)++;
9787502Sroot 		break;
9797502Sroot 
9807502Sroot 	case VTAB:
9819578Ssam 		if (tp->t_flags&VTDELAY) /* tty 37 */
9827502Sroot 			c = 0177;
9837502Sroot 		break;
9847502Sroot 
9857502Sroot 	case RETURN:
9867502Sroot 		ctype = (tp->t_flags >> 12) & 03;
9879578Ssam 		if (ctype == 1) /* tn 300 */
98813821Ssam 			c = mstohz(83);
9899578Ssam 		else if (ctype == 2) /* ti 700 */
99013821Ssam 			c = mstohz(166);
9919578Ssam 		else if (ctype == 3) { /* concept 100 */
9927502Sroot 			int i;
9939578Ssam 
9947502Sroot 			if ((i = *colp) >= 0)
9959578Ssam 				for (; i < 9; i++)
9967502Sroot 					(void) putc(0177, &tp->t_outq);
9977502Sroot 		}
9987502Sroot 		*colp = 0;
9997502Sroot 	}
10009578Ssam 	if (c && (tp->t_flags&FLUSHO) == 0)
10017502Sroot 		(void) putc(c|0200, &tp->t_outq);
10027502Sroot 	return (-1);
10037502Sroot }
100413821Ssam #undef mstohz
10057502Sroot 
10067502Sroot /*
10077502Sroot  * Called from device's read routine after it has
10087502Sroot  * calculated the tty-structure given as argument.
10097502Sroot  */
10107722Swnj ttread(tp, uio)
10117625Ssam 	register struct tty *tp;
10127722Swnj 	struct uio *uio;
10137502Sroot {
10147502Sroot 	register struct clist *qp;
10159578Ssam 	register c, t_flags;
10169859Ssam 	int s, first, error = 0;
10177502Sroot 
10187502Sroot 	if ((tp->t_state&TS_CARR_ON)==0)
10198520Sroot 		return (EIO);
10207502Sroot loop:
10219578Ssam 	/*
10229578Ssam 	 * Take any pending input first.
10239578Ssam 	 */
10249859Ssam 	s = spl5();
10259578Ssam 	if (tp->t_flags&PENDIN)
10267502Sroot 		ttypend(tp);
10279859Ssam 	splx(s);
10289578Ssam 
10299578Ssam 	/*
10309578Ssam 	 * Hang process if it's in the background.
10319578Ssam 	 */
103215141Skarels #define bit(a) (1<<(a-1))
10337502Sroot 	while (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) {
103415141Skarels 		if ((u.u_procp->p_sigignore & bit(SIGTTIN)) ||
103515141Skarels 		   (u.u_procp->p_sigmask & bit(SIGTTIN)) ||
10367502Sroot /*
10377502Sroot 		    (u.u_procp->p_flag&SDETACH) ||
10387502Sroot */
10397502Sroot 		    u.u_procp->p_flag&SVFORK)
10408520Sroot 			return (EIO);
10417502Sroot 		gsignal(u.u_procp->p_pgrp, SIGTTIN);
10427502Sroot 		sleep((caddr_t)&lbolt, TTIPRI);
10437502Sroot 	}
10449578Ssam 	t_flags = tp->t_flags;
104515141Skarels #undef	bit
10469578Ssam 
10479578Ssam 	/*
10489578Ssam 	 * In raw mode take characters directly from the
10499578Ssam 	 * raw queue w/o processing.  Interlock against
10509578Ssam 	 * device interrupts when interrogating rawq.
10519578Ssam 	 */
10529578Ssam 	if (t_flags&RAW) {
10539859Ssam 		s = spl5();
10547502Sroot 		if (tp->t_rawq.c_cc <= 0) {
10559578Ssam 			if ((tp->t_state&TS_CARR_ON) == 0 ||
10567502Sroot 			    (tp->t_state&TS_NBIO)) {
10579859Ssam 				splx(s);
105815094Skarels 				return (EWOULDBLOCK);
10597502Sroot 			}
10607502Sroot 			sleep((caddr_t)&tp->t_rawq, TTIPRI);
10619859Ssam 			splx(s);
10627502Sroot 			goto loop;
10637502Sroot 		}
10649859Ssam 		splx(s);
106514938Smckusick  		while (!error && tp->t_rawq.c_cc && uio->uio_resid)
106614938Smckusick  			error = ureadc(getc(&tp->t_rawq), uio);
10679859Ssam 		goto checktandem;
10689578Ssam 	}
10699578Ssam 
10709578Ssam 	/*
10719578Ssam 	 * In cbreak mode use the rawq, otherwise
10729578Ssam 	 * take characters from the canonicalized q.
10739578Ssam 	 */
10749578Ssam 	qp = t_flags&CBREAK ? &tp->t_rawq : &tp->t_canq;
10759578Ssam 
10769578Ssam 	/*
10779578Ssam 	 * No input, sleep on rawq awaiting hardware
10789578Ssam 	 * receipt and notification.
10799578Ssam 	 */
10809859Ssam 	s = spl5();
10819578Ssam 	if (qp->c_cc <= 0) {
10829578Ssam 		if ((tp->t_state&TS_CARR_ON) == 0 ||
10839578Ssam 		    (tp->t_state&TS_NBIO)) {
10849859Ssam 			splx(s);
10859578Ssam 			return (EWOULDBLOCK);
10867502Sroot 		}
10879578Ssam 		sleep((caddr_t)&tp->t_rawq, TTIPRI);
10889859Ssam 		splx(s);
10899578Ssam 		goto loop;
10909578Ssam 	}
10919859Ssam 	splx(s);
10929578Ssam 
10939578Ssam 	/*
10949578Ssam 	 * Input present, perform input mapping
10959578Ssam 	 * and processing (we're not in raw mode).
10969578Ssam 	 */
10979578Ssam 	first = 1;
10989578Ssam 	while ((c = getc(qp)) >= 0) {
10999578Ssam 		if (t_flags&CRMOD && c == '\r')
11009578Ssam 			c = '\n';
11019578Ssam 		/*
11029578Ssam 		 * Hack lower case simulation on
11039578Ssam 		 * upper case only terminals.
11049578Ssam 		 */
11059578Ssam 		if (t_flags&LCASE && c <= 0177)
11069578Ssam 			if (tp->t_state&TS_BKSL) {
11079578Ssam 				if (maptab[c])
11089578Ssam 					c = maptab[c];
11099578Ssam 				tp->t_state &= ~TS_BKSL;
11109578Ssam 			} else if (c >= 'A' && c <= 'Z')
11119578Ssam 				c += 'a' - 'A';
11129578Ssam 			else if (c == '\\') {
11139578Ssam 				tp->t_state |= TS_BKSL;
11149578Ssam 				continue;
11157502Sroot 			}
11169578Ssam 		/*
11179578Ssam 		 * Check for delayed suspend character.
11189578Ssam 		 */
11199578Ssam 		if (tp->t_line == NTTYDISC && c == tp->t_dsuspc) {
11209578Ssam 			gsignal(tp->t_pgrp, SIGTSTP);
11219578Ssam 			if (first) {
11229578Ssam 				sleep((caddr_t)&lbolt, TTIPRI);
11239578Ssam 				goto loop;
11249578Ssam 			}
11259578Ssam 			break;
11267502Sroot 		}
11279578Ssam 		/*
11289578Ssam 		 * Interpret EOF only in cooked mode.
11299578Ssam 		 */
11309578Ssam 		if (c == tp->t_eofc && (t_flags&CBREAK) == 0)
11319578Ssam 			break;
11329578Ssam 		/*
11339578Ssam 		 * Give user character.
11349578Ssam 		 */
113514938Smckusick  		error = ureadc(c & 0177, uio);
11369578Ssam 		if (error)
11379578Ssam 			break;
113814938Smckusick  		if (uio->uio_resid == 0)
11399578Ssam 			break;
11409578Ssam 		/*
11419578Ssam 		 * In cooked mode check for a "break character"
11429578Ssam 		 * marking the end of a "line of input".
11439578Ssam 		 */
11449578Ssam 		if ((t_flags&CBREAK) == 0 && ttbreakc(c, tp))
11459578Ssam 			break;
11469578Ssam 		first = 0;
11477502Sroot 	}
11489578Ssam 	tp->t_state &= ~TS_BKSL;
11499578Ssam 
11509859Ssam checktandem:
11519578Ssam 	/*
11529578Ssam 	 * Look to unblock output now that (presumably)
11539578Ssam 	 * the input queue has gone down.
11549578Ssam 	 */
11559859Ssam 	if (tp->t_state&TS_TBLOCK && tp->t_rawq.c_cc < TTYHOG/5)
11569578Ssam 		if (putc(tp->t_startc, &tp->t_outq) == 0) {
11577502Sroot 			tp->t_state &= ~TS_TBLOCK;
11587502Sroot 			ttstart(tp);
11597502Sroot 		}
11608520Sroot 	return (error);
11617502Sroot }
11627502Sroot 
11637502Sroot /*
11647502Sroot  * Called from the device's write routine after it has
11657502Sroot  * calculated the tty-structure given as argument.
11667502Sroot  */
11677822Sroot ttwrite(tp, uio)
11687625Ssam 	register struct tty *tp;
11699578Ssam 	register struct uio *uio;
11707502Sroot {
11717502Sroot 	register char *cp;
11729578Ssam 	register int cc, ce, c;
11739578Ssam 	int i, hiwat, cnt, error, s;
11747502Sroot 	char obuf[OBUFSIZ];
11757502Sroot 
11769578Ssam 	if ((tp->t_state&TS_CARR_ON) == 0)
11778520Sroot 		return (EIO);
11789578Ssam 	hiwat = TTHIWAT(tp);
11799578Ssam 	cnt = uio->uio_resid;
11809578Ssam 	error = 0;
11817502Sroot loop:
11829578Ssam 	/*
11839578Ssam 	 * Hang the process if it's in the background.
11849578Ssam 	 */
118515141Skarels #define bit(a) (1<<(a-1))
11867502Sroot 	while (u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp &&
11879578Ssam 	    (tp->t_flags&TOSTOP) && (u.u_procp->p_flag&SVFORK)==0 &&
118815141Skarels 	    !(u.u_procp->p_sigignore & bit(SIGTTOU)) &&
118915141Skarels 	    !(u.u_procp->p_sigmask & bit(SIGTTOU))
11907502Sroot /*
11917502Sroot 					     &&
11927502Sroot 	    (u.u_procp->p_flag&SDETACH)==0) {
11937502Sroot */
11947502Sroot 	    ) {
11957502Sroot 		gsignal(u.u_procp->p_pgrp, SIGTTOU);
11967502Sroot 		sleep((caddr_t)&lbolt, TTIPRI);
11977502Sroot 	}
119815141Skarels #undef	bit
11999578Ssam 
12009578Ssam 	/*
12019578Ssam 	 * Process the user's data in at most OBUFSIZ
12029578Ssam 	 * chunks.  Perform lower case simulation and
12039578Ssam 	 * similar hacks.  Keep track of high water
12049578Ssam 	 * mark, sleep on overflow awaiting device aid
12059578Ssam 	 * in acquiring new space.
12069578Ssam 	 */
12077822Sroot 	while (uio->uio_resid > 0) {
12089578Ssam 		/*
12099578Ssam 		 * Grab a hunk of data from the user.
12109578Ssam 		 */
12117822Sroot 		cc = uio->uio_iov->iov_len;
12127822Sroot 		if (cc == 0) {
12137822Sroot 			uio->uio_iovcnt--;
12147822Sroot 			uio->uio_iov++;
12157822Sroot 			if (uio->uio_iovcnt < 0)
12167822Sroot 				panic("ttwrite");
12177822Sroot 			continue;
12187822Sroot 		}
12197822Sroot 		if (cc > OBUFSIZ)
12207822Sroot 			cc = OBUFSIZ;
12217502Sroot 		cp = obuf;
122212752Ssam 		error = uiomove(cp, cc, UIO_WRITE, uio);
12238520Sroot 		if (error)
12247502Sroot 			break;
12257502Sroot 		if (tp->t_outq.c_cc > hiwat)
12267502Sroot 			goto ovhiwat;
12279578Ssam 		if (tp->t_flags&FLUSHO)
12287502Sroot 			continue;
12299578Ssam 		/*
12309578Ssam 		 * If we're mapping lower case or kludging tildes,
12319578Ssam 		 * then we've got to look at each character, so
12329578Ssam 		 * just feed the stuff to ttyoutput...
12339578Ssam 		 */
12349578Ssam 		if (tp->t_flags & (LCASE|TILDE)) {
12359578Ssam 			while (cc > 0) {
12367502Sroot 				c = *cp++;
12377502Sroot 				tp->t_rocount = 0;
12387625Ssam 				while ((c = ttyoutput(c, tp)) >= 0) {
12397502Sroot 					/* out of clists, wait a bit */
12407502Sroot 					ttstart(tp);
12417502Sroot 					sleep((caddr_t)&lbolt, TTOPRI);
12427502Sroot 					tp->t_rocount = 0;
12437502Sroot 				}
12447502Sroot 				--cc;
12457502Sroot 				if (tp->t_outq.c_cc > hiwat)
12467502Sroot 					goto ovhiwat;
12477502Sroot 			}
12487502Sroot 			continue;
12497502Sroot 		}
12509578Ssam 		/*
12519578Ssam 		 * If nothing fancy need be done, grab those characters we
12529578Ssam 		 * can handle without any of ttyoutput's processing and
12539578Ssam 		 * just transfer them to the output q.  For those chars
12549578Ssam 		 * which require special processing (as indicated by the
12559578Ssam 		 * bits in partab), call ttyoutput.  After processing
12569578Ssam 		 * a hunk of data, look for FLUSHO so ^O's will take effect
12579578Ssam 		 * immediately.
12589578Ssam 		 */
12599578Ssam 		while (cc > 0) {
12609578Ssam 			if (tp->t_flags & (RAW|LITOUT))
12617502Sroot 				ce = cc;
12627502Sroot 			else {
126312752Ssam 				ce = cc - scanc((unsigned)cc, (caddr_t)cp,
126412752Ssam 				   (caddr_t)partab, 077);
12659578Ssam 				/*
12669578Ssam 				 * If ce is zero, then we're processing
12679578Ssam 				 * a special character through ttyoutput.
12689578Ssam 				 */
12699578Ssam 				if (ce == 0) {
12707502Sroot 					tp->t_rocount = 0;
12717502Sroot 					if (ttyoutput(*cp, tp) >= 0) {
12729578Ssam 						/* no c-lists, wait a bit */
12737502Sroot 						ttstart(tp);
12747502Sroot 						sleep((caddr_t)&lbolt, TTOPRI);
12757502Sroot 						continue;
12767502Sroot 					}
12779578Ssam 					cp++, cc--;
12789578Ssam 					if (tp->t_flags&FLUSHO ||
12799578Ssam 					    tp->t_outq.c_cc > hiwat)
12807502Sroot 						goto ovhiwat;
12819578Ssam 					continue;
12827502Sroot 				}
12837502Sroot 			}
12849578Ssam 			/*
12859578Ssam 			 * A bunch of normal characters have been found,
12869578Ssam 			 * transfer them en masse to the output queue and
12879578Ssam 			 * continue processing at the top of the loop.
12889578Ssam 			 * If there are any further characters in this
12899578Ssam 			 * <= OBUFSIZ chunk, the first should be a character
12909578Ssam 			 * requiring special handling by ttyoutput.
12919578Ssam 			 */
12927502Sroot 			tp->t_rocount = 0;
12939578Ssam 			i = b_to_q(cp, ce, &tp->t_outq);
12949578Ssam 			ce -= i;
12959578Ssam 			tp->t_col += ce;
12969578Ssam 			cp += ce, cc -= ce, tk_nout += ce;
12979578Ssam 			if (i > 0) {
12989578Ssam 				/* out of c-lists, wait a bit */
12997502Sroot 				ttstart(tp);
13007502Sroot 				sleep((caddr_t)&lbolt, TTOPRI);
13017502Sroot 			}
13029578Ssam 			if (tp->t_flags&FLUSHO || tp->t_outq.c_cc > hiwat)
13037502Sroot 				goto ovhiwat;
13047502Sroot 		}
13057502Sroot 	}
13067502Sroot 	ttstart(tp);
13078520Sroot 	return (error);
13087502Sroot 
13097502Sroot ovhiwat:
13109578Ssam 	s = spl5();
13119578Ssam 	if (cc != 0) {
13129578Ssam 		uio->uio_iov->iov_base -= cc;
13139578Ssam 		uio->uio_iov->iov_len += cc;
13149578Ssam 		uio->uio_resid += cc;
13159578Ssam 		uio->uio_offset -= cc;
13169578Ssam 	}
13179578Ssam 	/*
13189578Ssam 	 * This can only occur if FLUSHO
13199578Ssam 	 * is also set in t_flags.
13209578Ssam 	 */
13217502Sroot 	if (tp->t_outq.c_cc <= hiwat) {
13229578Ssam 		splx(s);
13237502Sroot 		goto loop;
13247502Sroot 	}
13257502Sroot 	ttstart(tp);
13269578Ssam 	if (tp->t_state&TS_NBIO) {
13277822Sroot 		if (uio->uio_resid == cnt)
13288520Sroot 			return (EWOULDBLOCK);
13298520Sroot 		return (0);
13307502Sroot 	}
13317502Sroot 	tp->t_state |= TS_ASLEEP;
13327502Sroot 	sleep((caddr_t)&tp->t_outq, TTOPRI);
13339578Ssam 	splx(s);
13347502Sroot 	goto loop;
13357502Sroot }
13367502Sroot 
13377502Sroot /*
13387502Sroot  * Rubout one character from the rawq of tp
13397502Sroot  * as cleanly as possible.
13407502Sroot  */
13417502Sroot ttyrub(c, tp)
13427625Ssam 	register c;
13437625Ssam 	register struct tty *tp;
13447502Sroot {
13457502Sroot 	register char *cp;
13467502Sroot 	register int savecol;
13477502Sroot 	int s;
13487502Sroot 	char *nextc();
13497502Sroot 
13509578Ssam 	if ((tp->t_flags&ECHO) == 0)
13517502Sroot 		return;
13529578Ssam 	tp->t_flags &= ~FLUSHO;
13537502Sroot 	c &= 0377;
13549578Ssam 	if (tp->t_flags&CRTBS) {
13557502Sroot 		if (tp->t_rocount == 0) {
13567502Sroot 			/*
13577502Sroot 			 * Screwed by ttwrite; retype
13587502Sroot 			 */
13597502Sroot 			ttyretype(tp);
13607502Sroot 			return;
13617502Sroot 		}
13629578Ssam 		if (c == ('\t'|0200) || c == ('\n'|0200))
13637502Sroot 			ttyrubo(tp, 2);
13649578Ssam 		else switch (partab[c&=0177]&0177) {
13657502Sroot 
13667502Sroot 		case ORDINARY:
13677502Sroot 			if (tp->t_flags&LCASE && c >= 'A' && c <= 'Z')
13687502Sroot 				ttyrubo(tp, 2);
13697502Sroot 			else
13707502Sroot 				ttyrubo(tp, 1);
13717502Sroot 			break;
13727502Sroot 
13737502Sroot 		case VTAB:
13747502Sroot 		case BACKSPACE:
13757502Sroot 		case CONTROL:
13767502Sroot 		case RETURN:
13779578Ssam 			if (tp->t_flags&CTLECH)
13787502Sroot 				ttyrubo(tp, 2);
13797502Sroot 			break;
13807502Sroot 
13817502Sroot 		case TAB:
13827502Sroot 			if (tp->t_rocount < tp->t_rawq.c_cc) {
13837502Sroot 				ttyretype(tp);
13847502Sroot 				return;
13857502Sroot 			}
13867502Sroot 			s = spl5();
13877502Sroot 			savecol = tp->t_col;
13889578Ssam 			tp->t_state |= TS_CNTTB;
13899578Ssam 			tp->t_flags |= FLUSHO;
13907502Sroot 			tp->t_col = tp->t_rocol;
13919578Ssam 			cp = tp->t_rawq.c_cf;
13929578Ssam 			for (; cp; cp = nextc(&tp->t_rawq, cp))
13937502Sroot 				ttyecho(*cp, tp);
13949578Ssam 			tp->t_flags &= ~FLUSHO;
13959578Ssam 			tp->t_state &= ~TS_CNTTB;
13967502Sroot 			splx(s);
13977502Sroot 			/*
13987502Sroot 			 * savecol will now be length of the tab
13997502Sroot 			 */
14007502Sroot 			savecol -= tp->t_col;
14017502Sroot 			tp->t_col += savecol;
14027502Sroot 			if (savecol > 8)
14037502Sroot 				savecol = 8;		/* overflow screw */
14047502Sroot 			while (--savecol >= 0)
14057502Sroot 				(void) ttyoutput('\b', tp);
14067502Sroot 			break;
14077502Sroot 
14087502Sroot 		default:
14097502Sroot 			panic("ttyrub");
14107502Sroot 		}
14119578Ssam 	} else if (tp->t_flags&PRTERA) {
14129578Ssam 		if ((tp->t_state&TS_ERASE) == 0) {
14137502Sroot 			(void) ttyoutput('\\', tp);
14149578Ssam 			tp->t_state |= TS_ERASE;
14157502Sroot 		}
14167502Sroot 		ttyecho(c, tp);
14177502Sroot 	} else
14187502Sroot 		ttyecho(tp->t_erase, tp);
14197502Sroot 	tp->t_rocount--;
14207502Sroot }
14217502Sroot 
14227502Sroot /*
14237502Sroot  * Crt back over cnt chars perhaps
14247502Sroot  * erasing them.
14257502Sroot  */
14267502Sroot ttyrubo(tp, cnt)
14277625Ssam 	register struct tty *tp;
14287625Ssam 	int cnt;
14297502Sroot {
14309578Ssam 	register char *rubostring = tp->t_flags&CRTERA ? "\b \b" : "\b";
14317502Sroot 
14327502Sroot 	while (--cnt >= 0)
14339578Ssam 		ttyout(rubostring, tp);
14347502Sroot }
14357502Sroot 
14367502Sroot /*
14377502Sroot  * Reprint the rawq line.
14387502Sroot  * We assume c_cc has already been checked.
14397502Sroot  */
14407502Sroot ttyretype(tp)
14417625Ssam 	register struct tty *tp;
14427502Sroot {
14437502Sroot 	register char *cp;
14447502Sroot 	char *nextc();
14457502Sroot 	int s;
14467502Sroot 
14479578Ssam 	if (tp->t_rprntc != 0377)
14489578Ssam 		ttyecho(tp->t_rprntc, tp);
14497502Sroot 	(void) ttyoutput('\n', tp);
14507502Sroot 	s = spl5();
14517502Sroot 	for (cp = tp->t_canq.c_cf; cp; cp = nextc(&tp->t_canq, cp))
14527502Sroot 		ttyecho(*cp, tp);
14537502Sroot 	for (cp = tp->t_rawq.c_cf; cp; cp = nextc(&tp->t_rawq, cp))
14547502Sroot 		ttyecho(*cp, tp);
14559578Ssam 	tp->t_state &= ~TS_ERASE;
14567502Sroot 	splx(s);
14577502Sroot 	tp->t_rocount = tp->t_rawq.c_cc;
14587502Sroot 	tp->t_rocol = 0;
14597502Sroot }
14607502Sroot 
14617502Sroot /*
14627502Sroot  * Echo a typed character to the terminal
14637502Sroot  */
14647502Sroot ttyecho(c, tp)
14657625Ssam 	register c;
14667625Ssam 	register struct tty *tp;
14677502Sroot {
14687502Sroot 
14699578Ssam 	if ((tp->t_state&TS_CNTTB) == 0)
14709578Ssam 		tp->t_flags &= ~FLUSHO;
14717502Sroot 	if ((tp->t_flags&ECHO) == 0)
14727502Sroot 		return;
14737502Sroot 	c &= 0377;
14747502Sroot 	if (tp->t_flags&RAW) {
14757502Sroot 		(void) ttyoutput(c, tp);
14767502Sroot 		return;
14777502Sroot 	}
14787502Sroot 	if (c == '\r' && tp->t_flags&CRMOD)
14797502Sroot 		c = '\n';
14809578Ssam 	if (tp->t_flags&CTLECH) {
14817502Sroot 		if ((c&0177) <= 037 && c!='\t' && c!='\n' || (c&0177)==0177) {
14827502Sroot 			(void) ttyoutput('^', tp);
14837502Sroot 			c &= 0177;
14847502Sroot 			if (c == 0177)
14857502Sroot 				c = '?';
14867502Sroot 			else if (tp->t_flags&LCASE)
14877502Sroot 				c += 'a' - 1;
14887502Sroot 			else
14897502Sroot 				c += 'A' - 1;
14907502Sroot 		}
14917502Sroot 	}
14927502Sroot 	if ((tp->t_flags&LCASE) && (c >= 'A' && c <= 'Z'))
14937502Sroot 		c += 'a' - 'A';
14949578Ssam 	(void) ttyoutput(c&0177, tp);
14957502Sroot }
14967502Sroot 
14977502Sroot /*
14987502Sroot  * Is c a break char for tp?
14997502Sroot  */
15007502Sroot ttbreakc(c, tp)
15017625Ssam 	register c;
15027625Ssam 	register struct tty *tp;
15037502Sroot {
15049578Ssam 	return (c == '\n' || c == tp->t_eofc || c == tp->t_brkc ||
15057502Sroot 		c == '\r' && (tp->t_flags&CRMOD));
15067502Sroot }
15077502Sroot 
15087502Sroot /*
15097502Sroot  * send string cp to tp
15107502Sroot  */
15117502Sroot ttyout(cp, tp)
15127625Ssam 	register char *cp;
15137625Ssam 	register struct tty *tp;
15147502Sroot {
15157502Sroot 	register char c;
15167502Sroot 
15177502Sroot 	while (c = *cp++)
15187502Sroot 		(void) ttyoutput(c, tp);
15197502Sroot }
15207502Sroot 
15217502Sroot ttwakeup(tp)
15227502Sroot 	struct tty *tp;
15237502Sroot {
15247502Sroot 
15257502Sroot 	if (tp->t_rsel) {
15267502Sroot 		selwakeup(tp->t_rsel, tp->t_state&TS_RCOLL);
15277502Sroot 		tp->t_state &= ~TS_RCOLL;
15287502Sroot 		tp->t_rsel = 0;
15297502Sroot 	}
153012752Ssam 	if (tp->t_state & TS_ASYNC)
153112752Ssam 		gsignal(tp->t_pgrp, SIGIO);
15327502Sroot 	wakeup((caddr_t)&tp->t_rawq);
15337502Sroot }
15347502Sroot 
153513533Ssam #if !defined(vax)
15369578Ssam scanc(size, cp, table, mask)
15379578Ssam 	register int size;
15389578Ssam 	register char *cp, table[];
15399578Ssam 	register int mask;
15407502Sroot {
15419578Ssam 	register int i = 0;
15427502Sroot 
15439578Ssam 	while ((table[*(u_char *)(cp + i)]&mask) == 0 && i < size)
15449578Ssam 		i++;
154515100Skarels 	return (size - i);
15467502Sroot }
15479578Ssam #endif
1548