xref: /csrg-svn/sys/kern/tty.c (revision 15078)
1*15078Skarels /*	tty.c	6.3	83/09/25	*/
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 	}
1829578Ssam 	if (x >= TTYHOG/2 && putc(tp->t_stopc, &tp->t_outq) == 0) {
1839578Ssam 		tp->t_state |= TS_TBLOCK;
1849578Ssam 		ttstart(tp);
185903Sbill 	}
18639Sbill }
18739Sbill 
18839Sbill /*
189903Sbill  * Restart typewriter output following a delay
190903Sbill  * timeout.
191903Sbill  * The name of the routine is passed to the timeout
192903Sbill  * subroutine and it is called during a clock interrupt.
193121Sbill  */
194903Sbill ttrstrt(tp)
1957625Ssam 	register struct tty *tp;
196121Sbill {
197121Sbill 
1989578Ssam 	if (tp == 0)
1999578Ssam 		panic("ttrstrt");
2005408Swnj 	tp->t_state &= ~TS_TIMEOUT;
201903Sbill 	ttstart(tp);
202121Sbill }
203121Sbill 
204121Sbill /*
205903Sbill  * Start output on the typewriter. It is used from the top half
206903Sbill  * after some characters have been put on the output queue,
207903Sbill  * from the interrupt routine to transmit the next
208903Sbill  * character, and after a timeout has finished.
20939Sbill  */
210903Sbill ttstart(tp)
2117625Ssam 	register struct tty *tp;
21239Sbill {
213903Sbill 	register s;
21439Sbill 
215903Sbill 	s = spl5();
2169578Ssam 	if ((tp->t_state & (TS_TIMEOUT|TS_TTSTOP|TS_BUSY)) == 0 &&
2175622Swnj 	    tp->t_oproc)		/* kludge for pty */
218903Sbill 		(*tp->t_oproc)(tp);
219903Sbill 	splx(s);
22039Sbill }
22139Sbill 
22239Sbill /*
223903Sbill  * Common code for tty ioctls.
22439Sbill  */
2251780Sbill /*ARGSUSED*/
2267625Ssam ttioctl(tp, com, data, flag)
2277625Ssam 	register struct tty *tp;
2287625Ssam 	caddr_t data;
22939Sbill {
2308520Sroot 	int dev = tp->t_dev;
23139Sbill 	extern int nldisp;
2328556Sroot 	int s;
23312752Ssam 	register int newflags;
23439Sbill 
235903Sbill 	/*
236903Sbill 	 * If the ioctl involves modification,
237903Sbill 	 * insist on being able to write the device,
238903Sbill 	 * and hang if in the background.
239903Sbill 	 */
2407625Ssam 	switch (com) {
24139Sbill 
242915Sbill 	case TIOCSETD:
243915Sbill 	case TIOCSETP:
244915Sbill 	case TIOCSETN:
245903Sbill 	case TIOCFLUSH:
246903Sbill 	case TIOCSETC:
247903Sbill 	case TIOCSLTC:
248903Sbill 	case TIOCSPGRP:
249903Sbill 	case TIOCLBIS:
250903Sbill 	case TIOCLBIC:
251903Sbill 	case TIOCLSET:
2529325Ssam 	case TIOCSTI:
253*15078Skarels #define bit(a) (1<<(a-1))
254903Sbill 		while (tp->t_line == NTTYDISC &&
255903Sbill 		   u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp &&
256903Sbill 		   (u.u_procp->p_flag&SVFORK) == 0 &&
257*15078Skarels 		   !(u.u_procp->p_sigignore & bit(SIGTTOU)) &&
258*15078Skarels 		   !(u.u_procp->p_sigmask & bit(SIGTTOU))) {
259903Sbill 			gsignal(u.u_procp->p_pgrp, SIGTTOU);
260903Sbill 			sleep((caddr_t)&lbolt, TTOPRI);
261903Sbill 		}
262903Sbill 		break;
263903Sbill 	}
264*15078Skarels #undef	bit
265903Sbill 
2669578Ssam 	/*
2679578Ssam 	 * Process the ioctl.
2689578Ssam 	 */
2697625Ssam 	switch (com) {
270903Sbill 
2718556Sroot 	/* get discipline number */
27239Sbill 	case TIOCGETD:
2737625Ssam 		*(int *)data = tp->t_line;
27439Sbill 		break;
27539Sbill 
2768556Sroot 	/* set line discipline */
2777625Ssam 	case TIOCSETD: {
2787625Ssam 		register int t = *(int *)data;
2799578Ssam 		int error = 0;
2807625Ssam 
281*15078Skarels 		if ((unsigned) t >= nldisp)
28210851Ssam 			return (ENXIO);
2838556Sroot 		s = spl5();
28439Sbill 		if (tp->t_line)
28539Sbill 			(*linesw[tp->t_line].l_close)(tp);
28639Sbill 		if (t)
2878556Sroot 			error = (*linesw[t].l_open)(dev, tp);
2888556Sroot 		splx(s);
28910851Ssam 		if (error) {
29010851Ssam 			s = spl5();
29110851Ssam 			if (tp->t_line)
29210851Ssam 				(void) (*linesw[tp->t_line].l_open)(dev, tp);
29310851Ssam 			splx(s);
2948556Sroot 			return (error);
29510851Ssam 		}
2968556Sroot 		tp->t_line = t;
29739Sbill 		break;
2987625Ssam 	}
29939Sbill 
3008556Sroot 	/* prevent more opens on channel */
3015614Swnj 	case TIOCEXCL:
3025614Swnj 		tp->t_state |= TS_XCLUDE;
3035614Swnj 		break;
3045614Swnj 
3055614Swnj 	case TIOCNXCL:
3065614Swnj 		tp->t_state &= ~TS_XCLUDE;
3075614Swnj 		break;
3085614Swnj 
3098556Sroot 	/* hang up line on last close */
31039Sbill 	case TIOCHPCL:
3115408Swnj 		tp->t_state |= TS_HUPCLS;
31239Sbill 		break;
31339Sbill 
3143942Sbugs 	case TIOCFLUSH: {
3157625Ssam 		register int flags = *(int *)data;
3167625Ssam 
3177625Ssam 		if (flags == 0)
3183942Sbugs 			flags = FREAD|FWRITE;
3197625Ssam 		else
3207625Ssam 			flags &= FREAD|FWRITE;
32112752Ssam 		ttyflush(tp, flags);
32239Sbill 		break;
3233944Sbugs 	}
32439Sbill 
3258556Sroot 	/* return number of characters immediately available */
3267625Ssam 	case FIONREAD:
3277625Ssam 		*(off_t *)data = ttnread(tp);
328174Sbill 		break;
329174Sbill 
33013077Ssam 	case TIOCOUTQ:
33113077Ssam 		*(int *)data = tp->t_outq.c_cc;
33213077Ssam 		break;
33313077Ssam 
3348589Sroot 	case TIOCSTOP:
3358589Sroot 		s = spl5();
3369578Ssam 		if ((tp->t_state&TS_TTSTOP) == 0) {
3375573Swnj 			tp->t_state |= TS_TTSTOP;
3385573Swnj 			(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
3395573Swnj 		}
3407625Ssam 		splx(s);
3415573Swnj 		break;
3425573Swnj 
3438589Sroot 	case TIOCSTART:
3448589Sroot 		s = spl5();
3459578Ssam 		if ((tp->t_state&TS_TTSTOP) || (tp->t_flags&FLUSHO)) {
3465573Swnj 			tp->t_state &= ~TS_TTSTOP;
3479578Ssam 			tp->t_flags &= ~FLUSHO;
3485573Swnj 			ttstart(tp);
3495573Swnj 		}
3507625Ssam 		splx(s);
3515573Swnj 		break;
3525573Swnj 
3539325Ssam 	/*
3549325Ssam 	 * Simulate typing of a character at the terminal.
3559325Ssam 	 */
3569325Ssam 	case TIOCSTI:
3579325Ssam 		if (u.u_uid && u.u_ttyp != tp)
3589325Ssam 			return (EACCES);
3599578Ssam 		(*linesw[tp->t_line].l_rint)(*(char *)data, tp);
3609325Ssam 		break;
3619325Ssam 
36212752Ssam 	case TIOCSETP:
36312752Ssam 	case TIOCSETN: {
36412752Ssam 		register struct sgttyb *sg = (struct sgttyb *)data;
36512752Ssam 
36612752Ssam 		tp->t_erase = sg->sg_erase;
36712752Ssam 		tp->t_kill = sg->sg_kill;
36812752Ssam 		tp->t_ispeed = sg->sg_ispeed;
36912752Ssam 		tp->t_ospeed = sg->sg_ospeed;
37012752Ssam 		newflags = (tp->t_flags&0xffff0000) | (sg->sg_flags&0xffff);
37112752Ssam 		s = spl5();
37212752Ssam 		if (tp->t_flags&RAW || newflags&RAW || com == TIOCSETP) {
37312752Ssam 			ttywait(tp);
37412752Ssam 			ttyflush(tp, FREAD);
37512752Ssam 		} else if ((tp->t_flags&CBREAK) != (newflags&CBREAK)) {
37612752Ssam 			if (newflags&CBREAK) {
37712752Ssam 				struct clist tq;
37812752Ssam 
37912752Ssam 				catq(&tp->t_rawq, &tp->t_canq);
38012752Ssam 				tq = tp->t_rawq;
38112752Ssam 				tp->t_rawq = tp->t_canq;
38212752Ssam 				tp->t_canq = tq;
38312752Ssam 			} else {
38412752Ssam 				tp->t_flags |= PENDIN;
38513801Ssam 				newflags |= PENDIN;
38612752Ssam 				ttwakeup(tp);
38712752Ssam 			}
38812752Ssam 		}
38912752Ssam 		tp->t_flags = newflags;
39012752Ssam 		if (tp->t_flags&RAW) {
39112752Ssam 			tp->t_state &= ~TS_TTSTOP;
39212752Ssam 			ttstart(tp);
39312752Ssam 		}
39412752Ssam 		splx(s);
39512752Ssam 		break;
39612752Ssam 	}
39712752Ssam 
39812752Ssam 	/* send current parameters to user */
39912752Ssam 	case TIOCGETP: {
40012752Ssam 		register struct sgttyb *sg = (struct sgttyb *)data;
40112752Ssam 
40212752Ssam 		sg->sg_ispeed = tp->t_ispeed;
40312752Ssam 		sg->sg_ospeed = tp->t_ospeed;
40412752Ssam 		sg->sg_erase = tp->t_erase;
40512752Ssam 		sg->sg_kill = tp->t_kill;
40612752Ssam 		sg->sg_flags = tp->t_flags;
40712752Ssam 		break;
40812752Ssam 	}
40912752Ssam 
41012752Ssam 	case FIONBIO:
41112752Ssam 		if (*(int *)data)
41212752Ssam 			tp->t_state |= TS_NBIO;
41312752Ssam 		else
41412752Ssam 			tp->t_state &= ~TS_NBIO;
41512752Ssam 		break;
41612752Ssam 
41712752Ssam 	case FIOASYNC:
41812752Ssam 		if (*(int *)data)
41912752Ssam 			tp->t_state |= TS_ASYNC;
42012752Ssam 		else
42112752Ssam 			tp->t_state &= ~TS_ASYNC;
42212752Ssam 		break;
42312752Ssam 
42413077Ssam 	case TIOCGETC:
42513077Ssam 		bcopy((caddr_t)&tp->t_intrc, data, sizeof (struct tchars));
42613077Ssam 		break;
42713077Ssam 
42813077Ssam 	case TIOCSETC:
42913077Ssam 		bcopy(data, (caddr_t)&tp->t_intrc, sizeof (struct tchars));
43013077Ssam 		break;
43113077Ssam 
43212752Ssam 	/* set/get local special characters */
43312752Ssam 	case TIOCSLTC:
43412752Ssam 		bcopy(data, (caddr_t)&tp->t_suspc, sizeof (struct ltchars));
43512752Ssam 		break;
43612752Ssam 
43712752Ssam 	case TIOCGLTC:
43812752Ssam 		bcopy((caddr_t)&tp->t_suspc, data, sizeof (struct ltchars));
43912752Ssam 		break;
44012752Ssam 
44112752Ssam 	/*
44212752Ssam 	 * Modify local mode word.
44312752Ssam 	 */
44412752Ssam 	case TIOCLBIS:
44512752Ssam 		tp->t_flags |= *(int *)data << 16;
44612752Ssam 		break;
44712752Ssam 
44812752Ssam 	case TIOCLBIC:
44912752Ssam 		tp->t_flags &= ~(*(int *)data << 16);
45012752Ssam 		break;
45112752Ssam 
45212752Ssam 	case TIOCLSET:
45312752Ssam 		tp->t_flags &= 0xffff;
45412752Ssam 		tp->t_flags |= *(int *)data << 16;
45512752Ssam 		break;
45612752Ssam 
45712752Ssam 	case TIOCLGET:
45812752Ssam 		*(int *)data = tp->t_flags >> 16;
45912752Ssam 		break;
46012752Ssam 
46112752Ssam 	/* should allow SPGRP and GPGRP only if tty open for reading */
46212752Ssam 	case TIOCSPGRP:
46312752Ssam 		tp->t_pgrp = *(int *)data;
46412752Ssam 		break;
46512752Ssam 
46612752Ssam 	case TIOCGPGRP:
46712752Ssam 		*(int *)data = tp->t_pgrp;
46812752Ssam 		break;
46912752Ssam 
47039Sbill 	default:
4718556Sroot 		return (-1);
47239Sbill 	}
4738556Sroot 	return (0);
47439Sbill }
4754484Swnj 
4764484Swnj ttnread(tp)
4774484Swnj 	struct tty *tp;
4784484Swnj {
4794484Swnj 	int nread = 0;
4804484Swnj 
4819578Ssam 	if (tp->t_flags & PENDIN)
4824484Swnj 		ttypend(tp);
4834484Swnj 	nread = tp->t_canq.c_cc;
4844484Swnj 	if (tp->t_flags & (RAW|CBREAK))
4854484Swnj 		nread += tp->t_rawq.c_cc;
4864484Swnj 	return (nread);
4874484Swnj }
4884484Swnj 
4895408Swnj ttselect(dev, rw)
4904484Swnj 	dev_t dev;
4915408Swnj 	int rw;
4924484Swnj {
4934484Swnj 	register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)];
4944484Swnj 	int nread;
4955408Swnj 	int s = spl5();
4964484Swnj 
4975408Swnj 	switch (rw) {
4984484Swnj 
4994484Swnj 	case FREAD:
5004484Swnj 		nread = ttnread(tp);
5014484Swnj 		if (nread > 0)
5025408Swnj 			goto win;
5034938Swnj 		if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait)
5045408Swnj 			tp->t_state |= TS_RCOLL;
5054484Swnj 		else
5064484Swnj 			tp->t_rsel = u.u_procp;
5075408Swnj 		break;
5084484Swnj 
5095408Swnj 	case FWRITE:
5105408Swnj 		if (tp->t_outq.c_cc <= TTLOWAT(tp))
5115408Swnj 			goto win;
5125408Swnj 		if (tp->t_wsel && tp->t_wsel->p_wchan == (caddr_t)&selwait)
5135408Swnj 			tp->t_state |= TS_WCOLL;
5145408Swnj 		else
5155408Swnj 			tp->t_wsel = u.u_procp;
5165408Swnj 		break;
5174484Swnj 	}
5185408Swnj 	splx(s);
5195408Swnj 	return (0);
5205408Swnj win:
5215408Swnj 	splx(s);
5225408Swnj 	return (1);
5234484Swnj }
5247436Skre 
5257502Sroot /*
5269578Ssam  * Establish a process group for distribution of
5277502Sroot  * quits and interrupts from the tty.
5287502Sroot  */
5297502Sroot ttyopen(dev, tp)
5307625Ssam 	dev_t dev;
5317625Ssam 	register struct tty *tp;
5327502Sroot {
5337502Sroot 	register struct proc *pp;
5347502Sroot 
5357502Sroot 	pp = u.u_procp;
5367502Sroot 	tp->t_dev = dev;
5377625Ssam 	if (pp->p_pgrp == 0) {
5387502Sroot 		u.u_ttyp = tp;
5397502Sroot 		u.u_ttyd = dev;
5407502Sroot 		if (tp->t_pgrp == 0)
5417502Sroot 			tp->t_pgrp = pp->p_pid;
5427502Sroot 		pp->p_pgrp = tp->t_pgrp;
5437502Sroot 	}
5447502Sroot 	tp->t_state &= ~TS_WOPEN;
5457502Sroot 	tp->t_state |= TS_ISOPEN;
5467502Sroot 	if (tp->t_line != NTTYDISC)
54712752Ssam 		ttywflush(tp);
5488556Sroot 	return (0);
5497502Sroot }
5507502Sroot 
5517502Sroot /*
5527502Sroot  * clean tp on last close
5537502Sroot  */
5547502Sroot ttyclose(tp)
5557625Ssam 	register struct tty *tp;
5567502Sroot {
5577502Sroot 
5587502Sroot 	if (tp->t_line) {
55912752Ssam 		ttywflush(tp);
5607502Sroot 		tp->t_line = 0;
5617502Sroot 		return;
5627502Sroot 	}
5637502Sroot 	tp->t_pgrp = 0;
56412752Ssam 	ttywflush(tp);
5657502Sroot 	tp->t_state = 0;
5667502Sroot }
5677502Sroot 
5687502Sroot /*
5697502Sroot  * reinput pending characters after state switch
5707502Sroot  * call at spl5().
5717502Sroot  */
5727502Sroot ttypend(tp)
5737625Ssam 	register struct tty *tp;
5747502Sroot {
5757502Sroot 	struct clist tq;
5767502Sroot 	register c;
5777502Sroot 
5789578Ssam 	tp->t_flags &= ~PENDIN;
5799578Ssam 	tp->t_state |= TS_TYPEN;
5807502Sroot 	tq = tp->t_rawq;
5817502Sroot 	tp->t_rawq.c_cc = 0;
5827502Sroot 	tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0;
5837502Sroot 	while ((c = getc(&tq)) >= 0)
5847502Sroot 		ttyinput(c, tp);
5859578Ssam 	tp->t_state &= ~TS_TYPEN;
5867502Sroot }
5877502Sroot 
5887502Sroot /*
5899578Ssam  * Place a character on raw TTY input queue,
5909578Ssam  * putting in delimiters and waking up top
5919578Ssam  * half as needed.  Also echo if required.
5929578Ssam  * The arguments are the character and the
5939578Ssam  * appropriate tty structure.
5947502Sroot  */
5957502Sroot ttyinput(c, tp)
5967625Ssam 	register c;
5977625Ssam 	register struct tty *tp;
5987502Sroot {
5999578Ssam 	register int t_flags = tp->t_flags;
6007502Sroot 	int i;
6017502Sroot 
6029578Ssam 	/*
6039578Ssam 	 * If input is pending take it first.
6049578Ssam 	 */
6059578Ssam 	if (t_flags&PENDIN)
6067502Sroot 		ttypend(tp);
6077502Sroot 	tk_nin++;
6087502Sroot 	c &= 0377;
6099578Ssam 
6109578Ssam 	/*
6119578Ssam 	 * In tandem mode, check high water mark.
6129578Ssam 	 */
6137502Sroot 	if (t_flags&TANDEM)
6147502Sroot 		ttyblock(tp);
6159578Ssam 
6169578Ssam 	if (t_flags&RAW) {
6179578Ssam 		/*
6189578Ssam 		 * Raw mode, just put character
6199578Ssam 		 * in input q w/o interpretation.
6209578Ssam 		 */
6219578Ssam 		if (tp->t_rawq.c_cc > TTYHOG)
62212752Ssam 			ttyflush(tp, FREAD|FWRITE);
6239578Ssam 		else {
6249578Ssam 			if (putc(c, &tp->t_rawq) >= 0)
6259578Ssam 				ttwakeup(tp);
6269578Ssam 			ttyecho(c, tp);
6277502Sroot 		}
6289578Ssam 		goto endcase;
6299578Ssam 	}
6309578Ssam 
6319578Ssam 	/*
6329578Ssam 	 * Ignore any high bit added during
6339578Ssam 	 * previous ttyinput processing.
6349578Ssam 	 */
6359578Ssam 	if ((tp->t_state&TS_TYPEN) == 0)
6369578Ssam 		c &= 0177;
6379578Ssam 	/*
6389578Ssam 	 * Check for literal nexting very first
6399578Ssam 	 */
6409578Ssam 	if (tp->t_state&TS_LNCH) {
6419578Ssam 		c |= 0200;
6429578Ssam 		tp->t_state &= ~TS_LNCH;
6439578Ssam 	}
6449578Ssam 
6459578Ssam 	/*
6469578Ssam 	 * Scan for special characters.  This code
6479578Ssam 	 * is really just a big case statement with
6489578Ssam 	 * non-constant cases.  The bottom of the
6499578Ssam 	 * case statement is labeled ``endcase'', so goto
6509578Ssam 	 * it after a case match, or similar.
6519578Ssam 	 */
6529578Ssam 	if (tp->t_line == NTTYDISC) {
6539578Ssam 		if (c == tp->t_lnextc) {
6547502Sroot 			if (tp->t_flags&ECHO)
6557502Sroot 				ttyout("^\b", tp);
6569578Ssam 			tp->t_state |= TS_LNCH;
6579578Ssam 			goto endcase;
6589578Ssam 		}
6599578Ssam 		if (c == tp->t_flushc) {
6609578Ssam 			if (tp->t_flags&FLUSHO)
6619578Ssam 				tp->t_flags &= ~FLUSHO;
6627502Sroot 			else {
66312752Ssam 				ttyflush(tp, FWRITE);
6647502Sroot 				ttyecho(c, tp);
6659578Ssam 				if (tp->t_rawq.c_cc + tp->t_canq.c_cc)
6667502Sroot 					ttyretype(tp);
6679578Ssam 				tp->t_flags |= FLUSHO;
6687502Sroot 			}
6699578Ssam 			goto startoutput;
6709578Ssam 		}
6719578Ssam 		if (c == tp->t_suspc) {
6729578Ssam 			if ((tp->t_flags&NOFLSH) == 0)
67312752Ssam 				ttyflush(tp, FREAD);
6749578Ssam 			ttyecho(c, tp);
6759578Ssam 			gsignal(tp->t_pgrp, SIGTSTP);
6769578Ssam 			goto endcase;
6779578Ssam 		}
6789578Ssam 	}
6799578Ssam 
6809578Ssam 	/*
6819578Ssam 	 * Handle start/stop characters.
6829578Ssam 	 */
6839578Ssam 	if (c == tp->t_stopc) {
6849578Ssam 		if ((tp->t_state&TS_TTSTOP) == 0) {
6859578Ssam 			tp->t_state |= TS_TTSTOP;
6869578Ssam 			(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
6877502Sroot 			return;
6889578Ssam 		}
6899578Ssam 		if (c != tp->t_startc)
6909578Ssam 			return;
6919578Ssam 		goto endcase;
6929578Ssam 	}
6939578Ssam 	if (c == tp->t_startc)
6949578Ssam 		goto restartoutput;
6959578Ssam 
6969578Ssam 	/*
6979578Ssam 	 * Look for interrupt/quit chars.
6989578Ssam 	 */
6999578Ssam 	if (c == tp->t_intrc || c == tp->t_quitc) {
7009578Ssam 		if ((tp->t_flags&NOFLSH) == 0)
70112752Ssam 			ttyflush(tp, FREAD|FWRITE);
7029578Ssam 		ttyecho(c, tp);
7039578Ssam 		gsignal(tp->t_pgrp, c == tp->t_intrc ? SIGINT : SIGQUIT);
7049578Ssam 		goto endcase;
7059578Ssam 	}
7069578Ssam 
7079578Ssam 	/*
7089578Ssam 	 * Cbreak mode, don't process line editing
7099578Ssam 	 * characters; check high water mark for wakeup.
7109578Ssam 	 */
7119578Ssam 	if (t_flags&CBREAK) {
7129578Ssam 		if (tp->t_rawq.c_cc > TTYHOG) {
7137502Sroot 			if (tp->t_outq.c_cc < TTHIWAT(tp) &&
7147502Sroot 			    tp->t_line == NTTYDISC)
7157502Sroot 				(void) ttyoutput(CTRL(g), tp);
7167502Sroot 		} else if (putc(c, &tp->t_rawq) >= 0) {
7177502Sroot 			ttwakeup(tp);
7187502Sroot 			ttyecho(c, tp);
7197502Sroot 		}
7209578Ssam 		goto endcase;
7219578Ssam 	}
7229578Ssam 
7239578Ssam 	/*
7249578Ssam 	 * From here on down cooked mode character
7259578Ssam 	 * processing takes place.
7269578Ssam 	 */
7279578Ssam 	if ((tp->t_state&TS_QUOT) &&
7289578Ssam 	    (c == tp->t_erase || c == tp->t_kill)) {
7299578Ssam 		ttyrub(unputc(&tp->t_rawq), tp);
7309578Ssam 		c |= 0200;
7319578Ssam 	}
7329578Ssam 	if (c == tp->t_erase) {
7339578Ssam 		if (tp->t_rawq.c_cc)
7349578Ssam 			ttyrub(unputc(&tp->t_rawq), tp);
7359578Ssam 		goto endcase;
7369578Ssam 	}
7379578Ssam 	if (c == tp->t_kill) {
7389578Ssam 		if (tp->t_flags&CRTKIL &&
7399578Ssam 		    tp->t_rawq.c_cc == tp->t_rocount) {
7409578Ssam 			while (tp->t_rawq.c_cc)
7419578Ssam 				ttyrub(unputc(&tp->t_rawq), tp);
7429578Ssam 		} else {
7439578Ssam 			ttyecho(c, tp);
7449578Ssam 			ttyecho('\n', tp);
7459578Ssam 			while (getc(&tp->t_rawq) > 0)
7469578Ssam 				;
7479578Ssam 			tp->t_rocount = 0;
7489578Ssam 		}
7499578Ssam 		tp->t_state &= ~TS_LOCAL;
7509578Ssam 		goto endcase;
7519578Ssam 	}
7529578Ssam 
7539578Ssam 	/*
7549578Ssam 	 * New line discipline,
7559578Ssam 	 * check word erase/reprint line.
7569578Ssam 	 */
7579578Ssam 	if (tp->t_line == NTTYDISC) {
7589578Ssam 		if (c == tp->t_werasc) {
7599578Ssam 			if (tp->t_rawq.c_cc == 0)
7609578Ssam 				goto endcase;
7619578Ssam 			do {
7629578Ssam 				c = unputc(&tp->t_rawq);
7639578Ssam 				if (c != ' ' && c != '\t')
7649578Ssam 					goto erasenb;
7659578Ssam 				ttyrub(c, tp);
7669578Ssam 			} while (tp->t_rawq.c_cc);
7679578Ssam 			goto endcase;
7689578Ssam 	erasenb:
7699578Ssam 			do {
7709578Ssam 				ttyrub(c, tp);
7719578Ssam 				if (tp->t_rawq.c_cc == 0)
7729578Ssam 					goto endcase;
7739578Ssam 				c = unputc(&tp->t_rawq);
7749578Ssam 			} while (c != ' ' && c != '\t');
7759578Ssam 			(void) putc(c, &tp->t_rawq);
7769578Ssam 			goto endcase;
7779578Ssam 		}
7789578Ssam 		if (c == tp->t_rprntc) {
7799578Ssam 			ttyretype(tp);
7809578Ssam 			goto endcase;
7819578Ssam 		}
7829578Ssam 	}
7839578Ssam 
7849578Ssam 	/*
7859578Ssam 	 * Check for input buffer overflow
7869578Ssam 	 */
78710391Ssam 	if (tp->t_rawq.c_cc+tp->t_canq.c_cc >= TTYHOG) {
78810391Ssam 		if (tp->t_line == NTTYDISC)
78910391Ssam 			(void) ttyoutput(CTRL(g), tp);
7909578Ssam 		goto endcase;
79110391Ssam 	}
7929578Ssam 
7939578Ssam 	/*
7949578Ssam 	 * Put data char in q for user and
7959578Ssam 	 * wakeup on seeing a line delimiter.
7969578Ssam 	 */
7979578Ssam 	if (putc(c, &tp->t_rawq) >= 0) {
7989578Ssam 		if (ttbreakc(c, tp)) {
7999578Ssam 			tp->t_rocount = 0;
8009578Ssam 			catq(&tp->t_rawq, &tp->t_canq);
8017502Sroot 			ttwakeup(tp);
8029578Ssam 		} else if (tp->t_rocount++ == 0)
8039578Ssam 			tp->t_rocol = tp->t_col;
8049578Ssam 		tp->t_state &= ~TS_QUOT;
8059578Ssam 		if (c == '\\')
8069578Ssam 			tp->t_state |= TS_QUOT;
8079578Ssam 		if (tp->t_state&TS_ERASE) {
8089578Ssam 			tp->t_state &= ~TS_ERASE;
8099578Ssam 			(void) ttyoutput('/', tp);
8109578Ssam 		}
8119578Ssam 		i = tp->t_col;
8127502Sroot 		ttyecho(c, tp);
8139578Ssam 		if (c == tp->t_eofc && tp->t_flags&ECHO) {
8149578Ssam 			i = MIN(2, tp->t_col - i);
8159578Ssam 			while (i > 0) {
8169578Ssam 				(void) ttyoutput('\b', tp);
8179578Ssam 				i--;
8189578Ssam 			}
8199578Ssam 		}
8207502Sroot 	}
8219578Ssam 
8229578Ssam endcase:
8239578Ssam 	/*
8249578Ssam 	 * If DEC-style start/stop is enabled don't restart
8259578Ssam 	 * output until seeing the start character.
8269578Ssam 	 */
8279578Ssam 	if (tp->t_flags&DECCTQ && tp->t_state&TS_TTSTOP &&
8289578Ssam 	    tp->t_startc != tp->t_stopc)
8297502Sroot 		return;
8309578Ssam 
8319578Ssam restartoutput:
8327502Sroot 	tp->t_state &= ~TS_TTSTOP;
8339578Ssam 	tp->t_flags &= ~FLUSHO;
8349578Ssam 
8359578Ssam startoutput:
8367502Sroot 	ttstart(tp);
8377502Sroot }
8387502Sroot 
8397502Sroot /*
8409578Ssam  * Put character on TTY output queue, adding delays,
8417502Sroot  * expanding tabs, and handling the CR/NL bit.
8429578Ssam  * This is called both from the top half for output,
8439578Ssam  * and from interrupt level for echoing.
8447502Sroot  * The arguments are the character and the tty structure.
8457502Sroot  * Returns < 0 if putc succeeds, otherwise returns char to resend
8467502Sroot  * Must be recursive.
8477502Sroot  */
8487502Sroot ttyoutput(c, tp)
8497502Sroot 	register c;
8507502Sroot 	register struct tty *tp;
8517502Sroot {
8527502Sroot 	register char *colp;
8537502Sroot 	register ctype;
8547502Sroot 
8559578Ssam 	if (tp->t_flags & (RAW|LITOUT)) {
8569578Ssam 		if (tp->t_flags&FLUSHO)
8577502Sroot 			return (-1);
8587502Sroot 		if (putc(c, &tp->t_outq))
8597625Ssam 			return (c);
8607502Sroot 		tk_nout++;
8617502Sroot 		return (-1);
8627502Sroot 	}
8639578Ssam 
8647502Sroot 	/*
8659578Ssam 	 * Ignore EOT in normal mode to avoid
8669578Ssam 	 * hanging up certain terminals.
8677502Sroot 	 */
8687502Sroot 	c &= 0177;
8699578Ssam 	if (c == CEOT && (tp->t_flags&CBREAK) == 0)
8707502Sroot 		return (-1);
8717502Sroot 	/*
8727502Sroot 	 * Turn tabs to spaces as required
8737502Sroot 	 */
8749578Ssam 	if (c == '\t' && (tp->t_flags&TBDELAY) == XTABS) {
8757502Sroot 		register int s;
8767502Sroot 
8777502Sroot 		c = 8 - (tp->t_col&7);
8789578Ssam 		if ((tp->t_flags&FLUSHO) == 0) {
8797502Sroot 			s = spl5();		/* don't interrupt tabs */
8807502Sroot 			c -= b_to_q("        ", c, &tp->t_outq);
8817502Sroot 			tk_nout += c;
8827502Sroot 			splx(s);
8837502Sroot 		}
8847502Sroot 		tp->t_col += c;
8857502Sroot 		return (c ? -1 : '\t');
8867502Sroot 	}
8877502Sroot 	tk_nout++;
8887502Sroot 	/*
8897502Sroot 	 * for upper-case-only terminals,
8907502Sroot 	 * generate escapes.
8917502Sroot 	 */
8927502Sroot 	if (tp->t_flags&LCASE) {
8937502Sroot 		colp = "({)}!|^~'`";
8947625Ssam 		while (*colp++)
8957625Ssam 			if (c == *colp++) {
8967502Sroot 				if (ttyoutput('\\', tp) >= 0)
8977502Sroot 					return (c);
8987502Sroot 				c = colp[-2];
8997502Sroot 				break;
9007502Sroot 			}
9019578Ssam 		if ('A' <= c && c <= 'Z') {
9027502Sroot 			if (ttyoutput('\\', tp) >= 0)
9037502Sroot 				return (c);
9049578Ssam 		} else if ('a' <= c && c <= 'z')
9057502Sroot 			c += 'A' - 'a';
9067502Sroot 	}
9079578Ssam 
9087502Sroot 	/*
9097502Sroot 	 * turn <nl> to <cr><lf> if desired.
9107502Sroot 	 */
9119578Ssam 	if (c == '\n' && tp->t_flags&CRMOD)
9127502Sroot 		if (ttyoutput('\r', tp) >= 0)
9137502Sroot 			return (c);
9149578Ssam 	if (c == '~' && tp->t_flags&TILDE)
9157502Sroot 		c = '`';
9169578Ssam 	if ((tp->t_flags&FLUSHO) == 0 && putc(c, &tp->t_outq))
9177502Sroot 		return (c);
9187502Sroot 	/*
9197502Sroot 	 * Calculate delays.
9207502Sroot 	 * The numbers here represent clock ticks
9217502Sroot 	 * and are not necessarily optimal for all terminals.
9227502Sroot 	 * The delays are indicated by characters above 0200.
9237502Sroot 	 * In raw mode there are no delays and the
9247502Sroot 	 * transmission path is 8 bits wide.
9259578Ssam 	 *
9269578Ssam 	 * SHOULD JUST ALLOW USER TO SPECIFY DELAYS
9277502Sroot 	 */
9287502Sroot 	colp = &tp->t_col;
9297502Sroot 	ctype = partab[c];
9307502Sroot 	c = 0;
9317502Sroot 	switch (ctype&077) {
9327502Sroot 
9337502Sroot 	case ORDINARY:
9347502Sroot 		(*colp)++;
9357502Sroot 
9367502Sroot 	case CONTROL:
9377502Sroot 		break;
9387502Sroot 
9397502Sroot 	case BACKSPACE:
9407502Sroot 		if (*colp)
9417502Sroot 			(*colp)--;
9427502Sroot 		break;
9437502Sroot 
94413821Ssam 	/*
94513821Ssam 	 * This macro is close enough to the correct thing;
94613821Ssam 	 * it should be replaced by real user settable delays
94713821Ssam 	 * in any event...
94813821Ssam 	 */
94913821Ssam #define	mstohz(ms)	(((ms) * hz) >> 10)
9507502Sroot 	case NEWLINE:
9517502Sroot 		ctype = (tp->t_flags >> 8) & 03;
9527625Ssam 		if (ctype == 1) { /* tty 37 */
95312752Ssam 			if (*colp > 0)
95413863Ssam 				c = max((((unsigned)*colp) >> 4) + 3,
95513863Ssam 				    (unsigned)6);
9569578Ssam 		} else if (ctype == 2) /* vt05 */
95713821Ssam 			c = mstohz(100);
9587502Sroot 		*colp = 0;
9597502Sroot 		break;
9607502Sroot 
9617502Sroot 	case TAB:
9627502Sroot 		ctype = (tp->t_flags >> 10) & 03;
9637625Ssam 		if (ctype == 1) { /* tty 37 */
9647502Sroot 			c = 1 - (*colp | ~07);
9657625Ssam 			if (c < 5)
9667502Sroot 				c = 0;
9677502Sroot 		}
9687502Sroot 		*colp |= 07;
9697502Sroot 		(*colp)++;
9707502Sroot 		break;
9717502Sroot 
9727502Sroot 	case VTAB:
9739578Ssam 		if (tp->t_flags&VTDELAY) /* tty 37 */
9747502Sroot 			c = 0177;
9757502Sroot 		break;
9767502Sroot 
9777502Sroot 	case RETURN:
9787502Sroot 		ctype = (tp->t_flags >> 12) & 03;
9799578Ssam 		if (ctype == 1) /* tn 300 */
98013821Ssam 			c = mstohz(83);
9819578Ssam 		else if (ctype == 2) /* ti 700 */
98213821Ssam 			c = mstohz(166);
9839578Ssam 		else if (ctype == 3) { /* concept 100 */
9847502Sroot 			int i;
9859578Ssam 
9867502Sroot 			if ((i = *colp) >= 0)
9879578Ssam 				for (; i < 9; i++)
9887502Sroot 					(void) putc(0177, &tp->t_outq);
9897502Sroot 		}
9907502Sroot 		*colp = 0;
9917502Sroot 	}
9929578Ssam 	if (c && (tp->t_flags&FLUSHO) == 0)
9937502Sroot 		(void) putc(c|0200, &tp->t_outq);
9947502Sroot 	return (-1);
9957502Sroot }
99613821Ssam #undef mstohz
9977502Sroot 
9987502Sroot /*
9997502Sroot  * Called from device's read routine after it has
10007502Sroot  * calculated the tty-structure given as argument.
10017502Sroot  */
10027722Swnj ttread(tp, uio)
10037625Ssam 	register struct tty *tp;
10047722Swnj 	struct uio *uio;
10057502Sroot {
10067502Sroot 	register struct clist *qp;
10079578Ssam 	register c, t_flags;
10089859Ssam 	int s, first, error = 0;
10097502Sroot 
10107502Sroot 	if ((tp->t_state&TS_CARR_ON)==0)
10118520Sroot 		return (EIO);
10127502Sroot loop:
10139578Ssam 	/*
10149578Ssam 	 * Take any pending input first.
10159578Ssam 	 */
10169859Ssam 	s = spl5();
10179578Ssam 	if (tp->t_flags&PENDIN)
10187502Sroot 		ttypend(tp);
10199859Ssam 	splx(s);
10209578Ssam 
10219578Ssam 	/*
10229578Ssam 	 * Hang process if it's in the background.
10239578Ssam 	 */
10247502Sroot 	while (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) {
10257502Sroot 		if (u.u_signal[SIGTTIN] == SIG_IGN ||
10267502Sroot 		    u.u_signal[SIGTTIN] == SIG_HOLD ||
10277502Sroot /*
10287502Sroot 		    (u.u_procp->p_flag&SDETACH) ||
10297502Sroot */
10307502Sroot 		    u.u_procp->p_flag&SVFORK)
10318520Sroot 			return (EIO);
10327502Sroot 		gsignal(u.u_procp->p_pgrp, SIGTTIN);
10337502Sroot 		sleep((caddr_t)&lbolt, TTIPRI);
10347502Sroot 	}
10359578Ssam 	t_flags = tp->t_flags;
10369578Ssam 
10379578Ssam 	/*
10389578Ssam 	 * In raw mode take characters directly from the
10399578Ssam 	 * raw queue w/o processing.  Interlock against
10409578Ssam 	 * device interrupts when interrogating rawq.
10419578Ssam 	 */
10429578Ssam 	if (t_flags&RAW) {
10439859Ssam 		s = spl5();
10447502Sroot 		if (tp->t_rawq.c_cc <= 0) {
10459578Ssam 			if ((tp->t_state&TS_CARR_ON) == 0 ||
10467502Sroot 			    (tp->t_state&TS_NBIO)) {
10479859Ssam 				splx(s);
10489578Ssam 				return (0);
10497502Sroot 			}
10507502Sroot 			sleep((caddr_t)&tp->t_rawq, TTIPRI);
10519859Ssam 			splx(s);
10527502Sroot 			goto loop;
10537502Sroot 		}
10549859Ssam 		splx(s);
105514938Smckusick  		while (!error && tp->t_rawq.c_cc && uio->uio_resid)
105614938Smckusick  			error = ureadc(getc(&tp->t_rawq), uio);
10579859Ssam 		goto checktandem;
10589578Ssam 	}
10599578Ssam 
10609578Ssam 	/*
10619578Ssam 	 * In cbreak mode use the rawq, otherwise
10629578Ssam 	 * take characters from the canonicalized q.
10639578Ssam 	 */
10649578Ssam 	qp = t_flags&CBREAK ? &tp->t_rawq : &tp->t_canq;
10659578Ssam 
10669578Ssam 	/*
10679578Ssam 	 * No input, sleep on rawq awaiting hardware
10689578Ssam 	 * receipt and notification.
10699578Ssam 	 */
10709859Ssam 	s = spl5();
10719578Ssam 	if (qp->c_cc <= 0) {
10729578Ssam 		if ((tp->t_state&TS_CARR_ON) == 0 ||
10739578Ssam 		    (tp->t_state&TS_NBIO)) {
10749859Ssam 			splx(s);
10759578Ssam 			return (EWOULDBLOCK);
10767502Sroot 		}
10779578Ssam 		sleep((caddr_t)&tp->t_rawq, TTIPRI);
10789859Ssam 		splx(s);
10799578Ssam 		goto loop;
10809578Ssam 	}
10819859Ssam 	splx(s);
10829578Ssam 
10839578Ssam 	/*
10849578Ssam 	 * Input present, perform input mapping
10859578Ssam 	 * and processing (we're not in raw mode).
10869578Ssam 	 */
10879578Ssam 	first = 1;
10889578Ssam 	while ((c = getc(qp)) >= 0) {
10899578Ssam 		if (t_flags&CRMOD && c == '\r')
10909578Ssam 			c = '\n';
10919578Ssam 		/*
10929578Ssam 		 * Hack lower case simulation on
10939578Ssam 		 * upper case only terminals.
10949578Ssam 		 */
10959578Ssam 		if (t_flags&LCASE && c <= 0177)
10969578Ssam 			if (tp->t_state&TS_BKSL) {
10979578Ssam 				if (maptab[c])
10989578Ssam 					c = maptab[c];
10999578Ssam 				tp->t_state &= ~TS_BKSL;
11009578Ssam 			} else if (c >= 'A' && c <= 'Z')
11019578Ssam 				c += 'a' - 'A';
11029578Ssam 			else if (c == '\\') {
11039578Ssam 				tp->t_state |= TS_BKSL;
11049578Ssam 				continue;
11057502Sroot 			}
11069578Ssam 		/*
11079578Ssam 		 * Check for delayed suspend character.
11089578Ssam 		 */
11099578Ssam 		if (tp->t_line == NTTYDISC && c == tp->t_dsuspc) {
11109578Ssam 			gsignal(tp->t_pgrp, SIGTSTP);
11119578Ssam 			if (first) {
11129578Ssam 				sleep((caddr_t)&lbolt, TTIPRI);
11139578Ssam 				goto loop;
11149578Ssam 			}
11159578Ssam 			break;
11167502Sroot 		}
11179578Ssam 		/*
11189578Ssam 		 * Interpret EOF only in cooked mode.
11199578Ssam 		 */
11209578Ssam 		if (c == tp->t_eofc && (t_flags&CBREAK) == 0)
11219578Ssam 			break;
11229578Ssam 		/*
11239578Ssam 		 * Give user character.
11249578Ssam 		 */
112514938Smckusick  		error = ureadc(c & 0177, uio);
11269578Ssam 		if (error)
11279578Ssam 			break;
112814938Smckusick  		if (uio->uio_resid == 0)
11299578Ssam 			break;
11309578Ssam 		/*
11319578Ssam 		 * In cooked mode check for a "break character"
11329578Ssam 		 * marking the end of a "line of input".
11339578Ssam 		 */
11349578Ssam 		if ((t_flags&CBREAK) == 0 && ttbreakc(c, tp))
11359578Ssam 			break;
11369578Ssam 		first = 0;
11377502Sroot 	}
11389578Ssam 	tp->t_state &= ~TS_BKSL;
11399578Ssam 
11409859Ssam checktandem:
11419578Ssam 	/*
11429578Ssam 	 * Look to unblock output now that (presumably)
11439578Ssam 	 * the input queue has gone down.
11449578Ssam 	 */
11459859Ssam 	if (tp->t_state&TS_TBLOCK && tp->t_rawq.c_cc < TTYHOG/5)
11469578Ssam 		if (putc(tp->t_startc, &tp->t_outq) == 0) {
11477502Sroot 			tp->t_state &= ~TS_TBLOCK;
11487502Sroot 			ttstart(tp);
11497502Sroot 		}
11508520Sroot 	return (error);
11517502Sroot }
11527502Sroot 
11537502Sroot /*
11547502Sroot  * Called from the device's write routine after it has
11557502Sroot  * calculated the tty-structure given as argument.
11567502Sroot  */
11577822Sroot ttwrite(tp, uio)
11587625Ssam 	register struct tty *tp;
11599578Ssam 	register struct uio *uio;
11607502Sroot {
11617502Sroot 	register char *cp;
11629578Ssam 	register int cc, ce, c;
11639578Ssam 	int i, hiwat, cnt, error, s;
11647502Sroot 	char obuf[OBUFSIZ];
11657502Sroot 
11669578Ssam 	if ((tp->t_state&TS_CARR_ON) == 0)
11678520Sroot 		return (EIO);
11689578Ssam 	hiwat = TTHIWAT(tp);
11699578Ssam 	cnt = uio->uio_resid;
11709578Ssam 	error = 0;
11717502Sroot loop:
11729578Ssam 	/*
11739578Ssam 	 * Hang the process if it's in the background.
11749578Ssam 	 */
11757502Sroot 	while (u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp &&
11769578Ssam 	    (tp->t_flags&TOSTOP) && (u.u_procp->p_flag&SVFORK)==0 &&
11777502Sroot 	    u.u_signal[SIGTTOU] != SIG_IGN &&
11787502Sroot 	    u.u_signal[SIGTTOU] != SIG_HOLD
11797502Sroot /*
11807502Sroot 					     &&
11817502Sroot 	    (u.u_procp->p_flag&SDETACH)==0) {
11827502Sroot */
11837502Sroot 	    ) {
11847502Sroot 		gsignal(u.u_procp->p_pgrp, SIGTTOU);
11857502Sroot 		sleep((caddr_t)&lbolt, TTIPRI);
11867502Sroot 	}
11879578Ssam 
11889578Ssam 	/*
11899578Ssam 	 * Process the user's data in at most OBUFSIZ
11909578Ssam 	 * chunks.  Perform lower case simulation and
11919578Ssam 	 * similar hacks.  Keep track of high water
11929578Ssam 	 * mark, sleep on overflow awaiting device aid
11939578Ssam 	 * in acquiring new space.
11949578Ssam 	 */
11957822Sroot 	while (uio->uio_resid > 0) {
11969578Ssam 		/*
11979578Ssam 		 * Grab a hunk of data from the user.
11989578Ssam 		 */
11997822Sroot 		cc = uio->uio_iov->iov_len;
12007822Sroot 		if (cc == 0) {
12017822Sroot 			uio->uio_iovcnt--;
12027822Sroot 			uio->uio_iov++;
12037822Sroot 			if (uio->uio_iovcnt < 0)
12047822Sroot 				panic("ttwrite");
12057822Sroot 			continue;
12067822Sroot 		}
12077822Sroot 		if (cc > OBUFSIZ)
12087822Sroot 			cc = OBUFSIZ;
12097502Sroot 		cp = obuf;
121012752Ssam 		error = uiomove(cp, cc, UIO_WRITE, uio);
12118520Sroot 		if (error)
12127502Sroot 			break;
12137502Sroot 		if (tp->t_outq.c_cc > hiwat)
12147502Sroot 			goto ovhiwat;
12159578Ssam 		if (tp->t_flags&FLUSHO)
12167502Sroot 			continue;
12179578Ssam 		/*
12189578Ssam 		 * If we're mapping lower case or kludging tildes,
12199578Ssam 		 * then we've got to look at each character, so
12209578Ssam 		 * just feed the stuff to ttyoutput...
12219578Ssam 		 */
12229578Ssam 		if (tp->t_flags & (LCASE|TILDE)) {
12239578Ssam 			while (cc > 0) {
12247502Sroot 				c = *cp++;
12257502Sroot 				tp->t_rocount = 0;
12267625Ssam 				while ((c = ttyoutput(c, tp)) >= 0) {
12277502Sroot 					/* out of clists, wait a bit */
12287502Sroot 					ttstart(tp);
12297502Sroot 					sleep((caddr_t)&lbolt, TTOPRI);
12307502Sroot 					tp->t_rocount = 0;
12317502Sroot 				}
12327502Sroot 				--cc;
12337502Sroot 				if (tp->t_outq.c_cc > hiwat)
12347502Sroot 					goto ovhiwat;
12357502Sroot 			}
12367502Sroot 			continue;
12377502Sroot 		}
12389578Ssam 		/*
12399578Ssam 		 * If nothing fancy need be done, grab those characters we
12409578Ssam 		 * can handle without any of ttyoutput's processing and
12419578Ssam 		 * just transfer them to the output q.  For those chars
12429578Ssam 		 * which require special processing (as indicated by the
12439578Ssam 		 * bits in partab), call ttyoutput.  After processing
12449578Ssam 		 * a hunk of data, look for FLUSHO so ^O's will take effect
12459578Ssam 		 * immediately.
12469578Ssam 		 */
12479578Ssam 		while (cc > 0) {
12489578Ssam 			if (tp->t_flags & (RAW|LITOUT))
12497502Sroot 				ce = cc;
12507502Sroot 			else {
125112752Ssam 				ce = cc - scanc((unsigned)cc, (caddr_t)cp,
125212752Ssam 				   (caddr_t)partab, 077);
12539578Ssam 				/*
12549578Ssam 				 * If ce is zero, then we're processing
12559578Ssam 				 * a special character through ttyoutput.
12569578Ssam 				 */
12579578Ssam 				if (ce == 0) {
12587502Sroot 					tp->t_rocount = 0;
12597502Sroot 					if (ttyoutput(*cp, tp) >= 0) {
12609578Ssam 						/* no c-lists, wait a bit */
12617502Sroot 						ttstart(tp);
12627502Sroot 						sleep((caddr_t)&lbolt, TTOPRI);
12637502Sroot 						continue;
12647502Sroot 					}
12659578Ssam 					cp++, cc--;
12669578Ssam 					if (tp->t_flags&FLUSHO ||
12679578Ssam 					    tp->t_outq.c_cc > hiwat)
12687502Sroot 						goto ovhiwat;
12699578Ssam 					continue;
12707502Sroot 				}
12717502Sroot 			}
12729578Ssam 			/*
12739578Ssam 			 * A bunch of normal characters have been found,
12749578Ssam 			 * transfer them en masse to the output queue and
12759578Ssam 			 * continue processing at the top of the loop.
12769578Ssam 			 * If there are any further characters in this
12779578Ssam 			 * <= OBUFSIZ chunk, the first should be a character
12789578Ssam 			 * requiring special handling by ttyoutput.
12799578Ssam 			 */
12807502Sroot 			tp->t_rocount = 0;
12819578Ssam 			i = b_to_q(cp, ce, &tp->t_outq);
12829578Ssam 			ce -= i;
12839578Ssam 			tp->t_col += ce;
12849578Ssam 			cp += ce, cc -= ce, tk_nout += ce;
12859578Ssam 			if (i > 0) {
12869578Ssam 				/* out of c-lists, wait a bit */
12877502Sroot 				ttstart(tp);
12887502Sroot 				sleep((caddr_t)&lbolt, TTOPRI);
12897502Sroot 			}
12909578Ssam 			if (tp->t_flags&FLUSHO || tp->t_outq.c_cc > hiwat)
12917502Sroot 				goto ovhiwat;
12927502Sroot 		}
12937502Sroot 	}
12947502Sroot 	ttstart(tp);
12958520Sroot 	return (error);
12967502Sroot 
12977502Sroot ovhiwat:
12989578Ssam 	s = spl5();
12999578Ssam 	if (cc != 0) {
13009578Ssam 		uio->uio_iov->iov_base -= cc;
13019578Ssam 		uio->uio_iov->iov_len += cc;
13029578Ssam 		uio->uio_resid += cc;
13039578Ssam 		uio->uio_offset -= cc;
13049578Ssam 	}
13059578Ssam 	/*
13069578Ssam 	 * This can only occur if FLUSHO
13079578Ssam 	 * is also set in t_flags.
13089578Ssam 	 */
13097502Sroot 	if (tp->t_outq.c_cc <= hiwat) {
13109578Ssam 		splx(s);
13117502Sroot 		goto loop;
13127502Sroot 	}
13137502Sroot 	ttstart(tp);
13149578Ssam 	if (tp->t_state&TS_NBIO) {
13157822Sroot 		if (uio->uio_resid == cnt)
13168520Sroot 			return (EWOULDBLOCK);
13178520Sroot 		return (0);
13187502Sroot 	}
13197502Sroot 	tp->t_state |= TS_ASLEEP;
13207502Sroot 	sleep((caddr_t)&tp->t_outq, TTOPRI);
13219578Ssam 	splx(s);
13227502Sroot 	goto loop;
13237502Sroot }
13247502Sroot 
13257502Sroot /*
13267502Sroot  * Rubout one character from the rawq of tp
13277502Sroot  * as cleanly as possible.
13287502Sroot  */
13297502Sroot ttyrub(c, tp)
13307625Ssam 	register c;
13317625Ssam 	register struct tty *tp;
13327502Sroot {
13337502Sroot 	register char *cp;
13347502Sroot 	register int savecol;
13357502Sroot 	int s;
13367502Sroot 	char *nextc();
13377502Sroot 
13389578Ssam 	if ((tp->t_flags&ECHO) == 0)
13397502Sroot 		return;
13409578Ssam 	tp->t_flags &= ~FLUSHO;
13417502Sroot 	c &= 0377;
13429578Ssam 	if (tp->t_flags&CRTBS) {
13437502Sroot 		if (tp->t_rocount == 0) {
13447502Sroot 			/*
13457502Sroot 			 * Screwed by ttwrite; retype
13467502Sroot 			 */
13477502Sroot 			ttyretype(tp);
13487502Sroot 			return;
13497502Sroot 		}
13509578Ssam 		if (c == ('\t'|0200) || c == ('\n'|0200))
13517502Sroot 			ttyrubo(tp, 2);
13529578Ssam 		else switch (partab[c&=0177]&0177) {
13537502Sroot 
13547502Sroot 		case ORDINARY:
13557502Sroot 			if (tp->t_flags&LCASE && c >= 'A' && c <= 'Z')
13567502Sroot 				ttyrubo(tp, 2);
13577502Sroot 			else
13587502Sroot 				ttyrubo(tp, 1);
13597502Sroot 			break;
13607502Sroot 
13617502Sroot 		case VTAB:
13627502Sroot 		case BACKSPACE:
13637502Sroot 		case CONTROL:
13647502Sroot 		case RETURN:
13659578Ssam 			if (tp->t_flags&CTLECH)
13667502Sroot 				ttyrubo(tp, 2);
13677502Sroot 			break;
13687502Sroot 
13697502Sroot 		case TAB:
13707502Sroot 			if (tp->t_rocount < tp->t_rawq.c_cc) {
13717502Sroot 				ttyretype(tp);
13727502Sroot 				return;
13737502Sroot 			}
13747502Sroot 			s = spl5();
13757502Sroot 			savecol = tp->t_col;
13769578Ssam 			tp->t_state |= TS_CNTTB;
13779578Ssam 			tp->t_flags |= FLUSHO;
13787502Sroot 			tp->t_col = tp->t_rocol;
13799578Ssam 			cp = tp->t_rawq.c_cf;
13809578Ssam 			for (; cp; cp = nextc(&tp->t_rawq, cp))
13817502Sroot 				ttyecho(*cp, tp);
13829578Ssam 			tp->t_flags &= ~FLUSHO;
13839578Ssam 			tp->t_state &= ~TS_CNTTB;
13847502Sroot 			splx(s);
13857502Sroot 			/*
13867502Sroot 			 * savecol will now be length of the tab
13877502Sroot 			 */
13887502Sroot 			savecol -= tp->t_col;
13897502Sroot 			tp->t_col += savecol;
13907502Sroot 			if (savecol > 8)
13917502Sroot 				savecol = 8;		/* overflow screw */
13927502Sroot 			while (--savecol >= 0)
13937502Sroot 				(void) ttyoutput('\b', tp);
13947502Sroot 			break;
13957502Sroot 
13967502Sroot 		default:
13977502Sroot 			panic("ttyrub");
13987502Sroot 		}
13999578Ssam 	} else if (tp->t_flags&PRTERA) {
14009578Ssam 		if ((tp->t_state&TS_ERASE) == 0) {
14017502Sroot 			(void) ttyoutput('\\', tp);
14029578Ssam 			tp->t_state |= TS_ERASE;
14037502Sroot 		}
14047502Sroot 		ttyecho(c, tp);
14057502Sroot 	} else
14067502Sroot 		ttyecho(tp->t_erase, tp);
14077502Sroot 	tp->t_rocount--;
14087502Sroot }
14097502Sroot 
14107502Sroot /*
14117502Sroot  * Crt back over cnt chars perhaps
14127502Sroot  * erasing them.
14137502Sroot  */
14147502Sroot ttyrubo(tp, cnt)
14157625Ssam 	register struct tty *tp;
14167625Ssam 	int cnt;
14177502Sroot {
14189578Ssam 	register char *rubostring = tp->t_flags&CRTERA ? "\b \b" : "\b";
14197502Sroot 
14207502Sroot 	while (--cnt >= 0)
14219578Ssam 		ttyout(rubostring, tp);
14227502Sroot }
14237502Sroot 
14247502Sroot /*
14257502Sroot  * Reprint the rawq line.
14267502Sroot  * We assume c_cc has already been checked.
14277502Sroot  */
14287502Sroot ttyretype(tp)
14297625Ssam 	register struct tty *tp;
14307502Sroot {
14317502Sroot 	register char *cp;
14327502Sroot 	char *nextc();
14337502Sroot 	int s;
14347502Sroot 
14359578Ssam 	if (tp->t_rprntc != 0377)
14369578Ssam 		ttyecho(tp->t_rprntc, tp);
14377502Sroot 	(void) ttyoutput('\n', tp);
14387502Sroot 	s = spl5();
14397502Sroot 	for (cp = tp->t_canq.c_cf; cp; cp = nextc(&tp->t_canq, cp))
14407502Sroot 		ttyecho(*cp, tp);
14417502Sroot 	for (cp = tp->t_rawq.c_cf; cp; cp = nextc(&tp->t_rawq, cp))
14427502Sroot 		ttyecho(*cp, tp);
14439578Ssam 	tp->t_state &= ~TS_ERASE;
14447502Sroot 	splx(s);
14457502Sroot 	tp->t_rocount = tp->t_rawq.c_cc;
14467502Sroot 	tp->t_rocol = 0;
14477502Sroot }
14487502Sroot 
14497502Sroot /*
14507502Sroot  * Echo a typed character to the terminal
14517502Sroot  */
14527502Sroot ttyecho(c, tp)
14537625Ssam 	register c;
14547625Ssam 	register struct tty *tp;
14557502Sroot {
14567502Sroot 
14579578Ssam 	if ((tp->t_state&TS_CNTTB) == 0)
14589578Ssam 		tp->t_flags &= ~FLUSHO;
14597502Sroot 	if ((tp->t_flags&ECHO) == 0)
14607502Sroot 		return;
14617502Sroot 	c &= 0377;
14627502Sroot 	if (tp->t_flags&RAW) {
14637502Sroot 		(void) ttyoutput(c, tp);
14647502Sroot 		return;
14657502Sroot 	}
14667502Sroot 	if (c == '\r' && tp->t_flags&CRMOD)
14677502Sroot 		c = '\n';
14689578Ssam 	if (tp->t_flags&CTLECH) {
14697502Sroot 		if ((c&0177) <= 037 && c!='\t' && c!='\n' || (c&0177)==0177) {
14707502Sroot 			(void) ttyoutput('^', tp);
14717502Sroot 			c &= 0177;
14727502Sroot 			if (c == 0177)
14737502Sroot 				c = '?';
14747502Sroot 			else if (tp->t_flags&LCASE)
14757502Sroot 				c += 'a' - 1;
14767502Sroot 			else
14777502Sroot 				c += 'A' - 1;
14787502Sroot 		}
14797502Sroot 	}
14807502Sroot 	if ((tp->t_flags&LCASE) && (c >= 'A' && c <= 'Z'))
14817502Sroot 		c += 'a' - 'A';
14829578Ssam 	(void) ttyoutput(c&0177, tp);
14837502Sroot }
14847502Sroot 
14857502Sroot /*
14867502Sroot  * Is c a break char for tp?
14877502Sroot  */
14887502Sroot ttbreakc(c, tp)
14897625Ssam 	register c;
14907625Ssam 	register struct tty *tp;
14917502Sroot {
14929578Ssam 	return (c == '\n' || c == tp->t_eofc || c == tp->t_brkc ||
14937502Sroot 		c == '\r' && (tp->t_flags&CRMOD));
14947502Sroot }
14957502Sroot 
14967502Sroot /*
14977502Sroot  * send string cp to tp
14987502Sroot  */
14997502Sroot ttyout(cp, tp)
15007625Ssam 	register char *cp;
15017625Ssam 	register struct tty *tp;
15027502Sroot {
15037502Sroot 	register char c;
15047502Sroot 
15057502Sroot 	while (c = *cp++)
15067502Sroot 		(void) ttyoutput(c, tp);
15077502Sroot }
15087502Sroot 
15097502Sroot ttwakeup(tp)
15107502Sroot 	struct tty *tp;
15117502Sroot {
15127502Sroot 
15137502Sroot 	if (tp->t_rsel) {
15147502Sroot 		selwakeup(tp->t_rsel, tp->t_state&TS_RCOLL);
15157502Sroot 		tp->t_state &= ~TS_RCOLL;
15167502Sroot 		tp->t_rsel = 0;
15177502Sroot 	}
151812752Ssam 	if (tp->t_state & TS_ASYNC)
151912752Ssam 		gsignal(tp->t_pgrp, SIGIO);
15207502Sroot 	wakeup((caddr_t)&tp->t_rawq);
15217502Sroot }
15227502Sroot 
152313533Ssam #if !defined(vax)
15249578Ssam scanc(size, cp, table, mask)
15259578Ssam 	register int size;
15269578Ssam 	register char *cp, table[];
15279578Ssam 	register int mask;
15287502Sroot {
15299578Ssam 	register int i = 0;
15307502Sroot 
15319578Ssam 	while ((table[*(u_char *)(cp + i)]&mask) == 0 && i < size)
15329578Ssam 		i++;
15339578Ssam 	return (i);
15347502Sroot }
15359578Ssam #endif
1536