xref: /csrg-svn/sys/kern/tty.c (revision 13863)
1*13863Ssam /*	tty.c	4.47	83/07/09	*/
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:
253903Sbill 		while (tp->t_line == NTTYDISC &&
254903Sbill 		   u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp &&
255903Sbill 		   (u.u_procp->p_flag&SVFORK) == 0 &&
256903Sbill 		   u.u_signal[SIGTTOU] != SIG_IGN &&
2578556Sroot 		   u.u_signal[SIGTTOU] != SIG_HOLD) {
258903Sbill 			gsignal(u.u_procp->p_pgrp, SIGTTOU);
259903Sbill 			sleep((caddr_t)&lbolt, TTOPRI);
260903Sbill 		}
261903Sbill 		break;
262903Sbill 	}
263903Sbill 
2649578Ssam 	/*
2659578Ssam 	 * Process the ioctl.
2669578Ssam 	 */
2677625Ssam 	switch (com) {
268903Sbill 
2698556Sroot 	/* get discipline number */
27039Sbill 	case TIOCGETD:
2717625Ssam 		*(int *)data = tp->t_line;
27239Sbill 		break;
27339Sbill 
2748556Sroot 	/* set line discipline */
2757625Ssam 	case TIOCSETD: {
2767625Ssam 		register int t = *(int *)data;
2779578Ssam 		int error = 0;
2787625Ssam 
27910851Ssam 		if (t >= nldisp)
28010851Ssam 			return (ENXIO);
2818556Sroot 		s = spl5();
28239Sbill 		if (tp->t_line)
28339Sbill 			(*linesw[tp->t_line].l_close)(tp);
28439Sbill 		if (t)
2858556Sroot 			error = (*linesw[t].l_open)(dev, tp);
2868556Sroot 		splx(s);
28710851Ssam 		if (error) {
28810851Ssam 			s = spl5();
28910851Ssam 			if (tp->t_line)
29010851Ssam 				(void) (*linesw[tp->t_line].l_open)(dev, tp);
29110851Ssam 			splx(s);
2928556Sroot 			return (error);
29310851Ssam 		}
2948556Sroot 		tp->t_line = t;
29539Sbill 		break;
2967625Ssam 	}
29739Sbill 
2988556Sroot 	/* prevent more opens on channel */
2995614Swnj 	case TIOCEXCL:
3005614Swnj 		tp->t_state |= TS_XCLUDE;
3015614Swnj 		break;
3025614Swnj 
3035614Swnj 	case TIOCNXCL:
3045614Swnj 		tp->t_state &= ~TS_XCLUDE;
3055614Swnj 		break;
3065614Swnj 
3078556Sroot 	/* hang up line on last close */
30839Sbill 	case TIOCHPCL:
3095408Swnj 		tp->t_state |= TS_HUPCLS;
31039Sbill 		break;
31139Sbill 
3123942Sbugs 	case TIOCFLUSH: {
3137625Ssam 		register int flags = *(int *)data;
3147625Ssam 
3157625Ssam 		if (flags == 0)
3163942Sbugs 			flags = FREAD|FWRITE;
3177625Ssam 		else
3187625Ssam 			flags &= FREAD|FWRITE;
31912752Ssam 		ttyflush(tp, flags);
32039Sbill 		break;
3213944Sbugs 	}
32239Sbill 
3238556Sroot 	/* return number of characters immediately available */
3247625Ssam 	case FIONREAD:
3257625Ssam 		*(off_t *)data = ttnread(tp);
326174Sbill 		break;
327174Sbill 
32813077Ssam 	case TIOCOUTQ:
32913077Ssam 		*(int *)data = tp->t_outq.c_cc;
33013077Ssam 		break;
33113077Ssam 
3328589Sroot 	case TIOCSTOP:
3338589Sroot 		s = spl5();
3349578Ssam 		if ((tp->t_state&TS_TTSTOP) == 0) {
3355573Swnj 			tp->t_state |= TS_TTSTOP;
3365573Swnj 			(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
3375573Swnj 		}
3387625Ssam 		splx(s);
3395573Swnj 		break;
3405573Swnj 
3418589Sroot 	case TIOCSTART:
3428589Sroot 		s = spl5();
3439578Ssam 		if ((tp->t_state&TS_TTSTOP) || (tp->t_flags&FLUSHO)) {
3445573Swnj 			tp->t_state &= ~TS_TTSTOP;
3459578Ssam 			tp->t_flags &= ~FLUSHO;
3465573Swnj 			ttstart(tp);
3475573Swnj 		}
3487625Ssam 		splx(s);
3495573Swnj 		break;
3505573Swnj 
3519325Ssam 	/*
3529325Ssam 	 * Simulate typing of a character at the terminal.
3539325Ssam 	 */
3549325Ssam 	case TIOCSTI:
3559325Ssam 		if (u.u_uid && u.u_ttyp != tp)
3569325Ssam 			return (EACCES);
3579578Ssam 		(*linesw[tp->t_line].l_rint)(*(char *)data, tp);
3589325Ssam 		break;
3599325Ssam 
36012752Ssam 	case TIOCSETP:
36112752Ssam 	case TIOCSETN: {
36212752Ssam 		register struct sgttyb *sg = (struct sgttyb *)data;
36312752Ssam 
36412752Ssam 		tp->t_erase = sg->sg_erase;
36512752Ssam 		tp->t_kill = sg->sg_kill;
36612752Ssam 		tp->t_ispeed = sg->sg_ispeed;
36712752Ssam 		tp->t_ospeed = sg->sg_ospeed;
36812752Ssam 		newflags = (tp->t_flags&0xffff0000) | (sg->sg_flags&0xffff);
36912752Ssam 		s = spl5();
37012752Ssam 		if (tp->t_flags&RAW || newflags&RAW || com == TIOCSETP) {
37112752Ssam 			ttywait(tp);
37212752Ssam 			ttyflush(tp, FREAD);
37312752Ssam 		} else if ((tp->t_flags&CBREAK) != (newflags&CBREAK)) {
37412752Ssam 			if (newflags&CBREAK) {
37512752Ssam 				struct clist tq;
37612752Ssam 
37712752Ssam 				catq(&tp->t_rawq, &tp->t_canq);
37812752Ssam 				tq = tp->t_rawq;
37912752Ssam 				tp->t_rawq = tp->t_canq;
38012752Ssam 				tp->t_canq = tq;
38112752Ssam 			} else {
38212752Ssam 				tp->t_flags |= PENDIN;
38313801Ssam 				newflags |= PENDIN;
38412752Ssam 				ttwakeup(tp);
38512752Ssam 			}
38612752Ssam 		}
38712752Ssam 		tp->t_flags = newflags;
38812752Ssam 		if (tp->t_flags&RAW) {
38912752Ssam 			tp->t_state &= ~TS_TTSTOP;
39012752Ssam 			ttstart(tp);
39112752Ssam 		}
39212752Ssam 		splx(s);
39312752Ssam 		break;
39412752Ssam 	}
39512752Ssam 
39612752Ssam 	/* send current parameters to user */
39712752Ssam 	case TIOCGETP: {
39812752Ssam 		register struct sgttyb *sg = (struct sgttyb *)data;
39912752Ssam 
40012752Ssam 		sg->sg_ispeed = tp->t_ispeed;
40112752Ssam 		sg->sg_ospeed = tp->t_ospeed;
40212752Ssam 		sg->sg_erase = tp->t_erase;
40312752Ssam 		sg->sg_kill = tp->t_kill;
40412752Ssam 		sg->sg_flags = tp->t_flags;
40512752Ssam 		break;
40612752Ssam 	}
40712752Ssam 
40812752Ssam 	case FIONBIO:
40912752Ssam 		if (*(int *)data)
41012752Ssam 			tp->t_state |= TS_NBIO;
41112752Ssam 		else
41212752Ssam 			tp->t_state &= ~TS_NBIO;
41312752Ssam 		break;
41412752Ssam 
41512752Ssam 	case FIOASYNC:
41612752Ssam 		if (*(int *)data)
41712752Ssam 			tp->t_state |= TS_ASYNC;
41812752Ssam 		else
41912752Ssam 			tp->t_state &= ~TS_ASYNC;
42012752Ssam 		break;
42112752Ssam 
42213077Ssam 	case TIOCGETC:
42313077Ssam 		bcopy((caddr_t)&tp->t_intrc, data, sizeof (struct tchars));
42413077Ssam 		break;
42513077Ssam 
42613077Ssam 	case TIOCSETC:
42713077Ssam 		bcopy(data, (caddr_t)&tp->t_intrc, sizeof (struct tchars));
42813077Ssam 		break;
42913077Ssam 
43012752Ssam 	/* set/get local special characters */
43112752Ssam 	case TIOCSLTC:
43212752Ssam 		bcopy(data, (caddr_t)&tp->t_suspc, sizeof (struct ltchars));
43312752Ssam 		break;
43412752Ssam 
43512752Ssam 	case TIOCGLTC:
43612752Ssam 		bcopy((caddr_t)&tp->t_suspc, data, sizeof (struct ltchars));
43712752Ssam 		break;
43812752Ssam 
43912752Ssam 	/*
44012752Ssam 	 * Modify local mode word.
44112752Ssam 	 */
44212752Ssam 	case TIOCLBIS:
44312752Ssam 		tp->t_flags |= *(int *)data << 16;
44412752Ssam 		break;
44512752Ssam 
44612752Ssam 	case TIOCLBIC:
44712752Ssam 		tp->t_flags &= ~(*(int *)data << 16);
44812752Ssam 		break;
44912752Ssam 
45012752Ssam 	case TIOCLSET:
45112752Ssam 		tp->t_flags &= 0xffff;
45212752Ssam 		tp->t_flags |= *(int *)data << 16;
45312752Ssam 		break;
45412752Ssam 
45512752Ssam 	case TIOCLGET:
45612752Ssam 		*(int *)data = tp->t_flags >> 16;
45712752Ssam 		break;
45812752Ssam 
45912752Ssam 	/* should allow SPGRP and GPGRP only if tty open for reading */
46012752Ssam 	case TIOCSPGRP:
46112752Ssam 		tp->t_pgrp = *(int *)data;
46212752Ssam 		break;
46312752Ssam 
46412752Ssam 	case TIOCGPGRP:
46512752Ssam 		*(int *)data = tp->t_pgrp;
46612752Ssam 		break;
46712752Ssam 
46839Sbill 	default:
4698556Sroot 		return (-1);
47039Sbill 	}
4718556Sroot 	return (0);
47239Sbill }
4734484Swnj 
4744484Swnj ttnread(tp)
4754484Swnj 	struct tty *tp;
4764484Swnj {
4774484Swnj 	int nread = 0;
4784484Swnj 
4799578Ssam 	if (tp->t_flags & PENDIN)
4804484Swnj 		ttypend(tp);
4814484Swnj 	nread = tp->t_canq.c_cc;
4824484Swnj 	if (tp->t_flags & (RAW|CBREAK))
4834484Swnj 		nread += tp->t_rawq.c_cc;
4844484Swnj 	return (nread);
4854484Swnj }
4864484Swnj 
4875408Swnj ttselect(dev, rw)
4884484Swnj 	dev_t dev;
4895408Swnj 	int rw;
4904484Swnj {
4914484Swnj 	register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)];
4924484Swnj 	int nread;
4935408Swnj 	int s = spl5();
4944484Swnj 
4955408Swnj 	switch (rw) {
4964484Swnj 
4974484Swnj 	case FREAD:
4984484Swnj 		nread = ttnread(tp);
4994484Swnj 		if (nread > 0)
5005408Swnj 			goto win;
5014938Swnj 		if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait)
5025408Swnj 			tp->t_state |= TS_RCOLL;
5034484Swnj 		else
5044484Swnj 			tp->t_rsel = u.u_procp;
5055408Swnj 		break;
5064484Swnj 
5075408Swnj 	case FWRITE:
5085408Swnj 		if (tp->t_outq.c_cc <= TTLOWAT(tp))
5095408Swnj 			goto win;
5105408Swnj 		if (tp->t_wsel && tp->t_wsel->p_wchan == (caddr_t)&selwait)
5115408Swnj 			tp->t_state |= TS_WCOLL;
5125408Swnj 		else
5135408Swnj 			tp->t_wsel = u.u_procp;
5145408Swnj 		break;
5154484Swnj 	}
5165408Swnj 	splx(s);
5175408Swnj 	return (0);
5185408Swnj win:
5195408Swnj 	splx(s);
5205408Swnj 	return (1);
5214484Swnj }
5227436Skre 
5237502Sroot /*
5249578Ssam  * Establish a process group for distribution of
5257502Sroot  * quits and interrupts from the tty.
5267502Sroot  */
5277502Sroot ttyopen(dev, tp)
5287625Ssam 	dev_t dev;
5297625Ssam 	register struct tty *tp;
5307502Sroot {
5317502Sroot 	register struct proc *pp;
5327502Sroot 
5337502Sroot 	pp = u.u_procp;
5347502Sroot 	tp->t_dev = dev;
5357625Ssam 	if (pp->p_pgrp == 0) {
5367502Sroot 		u.u_ttyp = tp;
5377502Sroot 		u.u_ttyd = dev;
5387502Sroot 		if (tp->t_pgrp == 0)
5397502Sroot 			tp->t_pgrp = pp->p_pid;
5407502Sroot 		pp->p_pgrp = tp->t_pgrp;
5417502Sroot 	}
5427502Sroot 	tp->t_state &= ~TS_WOPEN;
5437502Sroot 	tp->t_state |= TS_ISOPEN;
5447502Sroot 	if (tp->t_line != NTTYDISC)
54512752Ssam 		ttywflush(tp);
5468556Sroot 	return (0);
5477502Sroot }
5487502Sroot 
5497502Sroot /*
5507502Sroot  * clean tp on last close
5517502Sroot  */
5527502Sroot ttyclose(tp)
5537625Ssam 	register struct tty *tp;
5547502Sroot {
5557502Sroot 
5567502Sroot 	if (tp->t_line) {
55712752Ssam 		ttywflush(tp);
5587502Sroot 		tp->t_line = 0;
5597502Sroot 		return;
5607502Sroot 	}
5617502Sroot 	tp->t_pgrp = 0;
56212752Ssam 	ttywflush(tp);
5637502Sroot 	tp->t_state = 0;
5647502Sroot }
5657502Sroot 
5667502Sroot /*
5677502Sroot  * reinput pending characters after state switch
5687502Sroot  * call at spl5().
5697502Sroot  */
5707502Sroot ttypend(tp)
5717625Ssam 	register struct tty *tp;
5727502Sroot {
5737502Sroot 	struct clist tq;
5747502Sroot 	register c;
5757502Sroot 
5769578Ssam 	tp->t_flags &= ~PENDIN;
5779578Ssam 	tp->t_state |= TS_TYPEN;
5787502Sroot 	tq = tp->t_rawq;
5797502Sroot 	tp->t_rawq.c_cc = 0;
5807502Sroot 	tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0;
5817502Sroot 	while ((c = getc(&tq)) >= 0)
5827502Sroot 		ttyinput(c, tp);
5839578Ssam 	tp->t_state &= ~TS_TYPEN;
5847502Sroot }
5857502Sroot 
5867502Sroot /*
5879578Ssam  * Place a character on raw TTY input queue,
5889578Ssam  * putting in delimiters and waking up top
5899578Ssam  * half as needed.  Also echo if required.
5909578Ssam  * The arguments are the character and the
5919578Ssam  * appropriate tty structure.
5927502Sroot  */
5937502Sroot ttyinput(c, tp)
5947625Ssam 	register c;
5957625Ssam 	register struct tty *tp;
5967502Sroot {
5979578Ssam 	register int t_flags = tp->t_flags;
5987502Sroot 	int i;
5997502Sroot 
6009578Ssam 	/*
6019578Ssam 	 * If input is pending take it first.
6029578Ssam 	 */
6039578Ssam 	if (t_flags&PENDIN)
6047502Sroot 		ttypend(tp);
6057502Sroot 	tk_nin++;
6067502Sroot 	c &= 0377;
6079578Ssam 
6089578Ssam 	/*
6099578Ssam 	 * In tandem mode, check high water mark.
6109578Ssam 	 */
6117502Sroot 	if (t_flags&TANDEM)
6127502Sroot 		ttyblock(tp);
6139578Ssam 
6149578Ssam 	if (t_flags&RAW) {
6159578Ssam 		/*
6169578Ssam 		 * Raw mode, just put character
6179578Ssam 		 * in input q w/o interpretation.
6189578Ssam 		 */
6199578Ssam 		if (tp->t_rawq.c_cc > TTYHOG)
62012752Ssam 			ttyflush(tp, FREAD|FWRITE);
6219578Ssam 		else {
6229578Ssam 			if (putc(c, &tp->t_rawq) >= 0)
6239578Ssam 				ttwakeup(tp);
6249578Ssam 			ttyecho(c, tp);
6257502Sroot 		}
6269578Ssam 		goto endcase;
6279578Ssam 	}
6289578Ssam 
6299578Ssam 	/*
6309578Ssam 	 * Ignore any high bit added during
6319578Ssam 	 * previous ttyinput processing.
6329578Ssam 	 */
6339578Ssam 	if ((tp->t_state&TS_TYPEN) == 0)
6349578Ssam 		c &= 0177;
6359578Ssam 	/*
6369578Ssam 	 * Check for literal nexting very first
6379578Ssam 	 */
6389578Ssam 	if (tp->t_state&TS_LNCH) {
6399578Ssam 		c |= 0200;
6409578Ssam 		tp->t_state &= ~TS_LNCH;
6419578Ssam 	}
6429578Ssam 
6439578Ssam 	/*
6449578Ssam 	 * Scan for special characters.  This code
6459578Ssam 	 * is really just a big case statement with
6469578Ssam 	 * non-constant cases.  The bottom of the
6479578Ssam 	 * case statement is labeled ``endcase'', so goto
6489578Ssam 	 * it after a case match, or similar.
6499578Ssam 	 */
6509578Ssam 	if (tp->t_line == NTTYDISC) {
6519578Ssam 		if (c == tp->t_lnextc) {
6527502Sroot 			if (tp->t_flags&ECHO)
6537502Sroot 				ttyout("^\b", tp);
6549578Ssam 			tp->t_state |= TS_LNCH;
6559578Ssam 			goto endcase;
6569578Ssam 		}
6579578Ssam 		if (c == tp->t_flushc) {
6589578Ssam 			if (tp->t_flags&FLUSHO)
6599578Ssam 				tp->t_flags &= ~FLUSHO;
6607502Sroot 			else {
66112752Ssam 				ttyflush(tp, FWRITE);
6627502Sroot 				ttyecho(c, tp);
6639578Ssam 				if (tp->t_rawq.c_cc + tp->t_canq.c_cc)
6647502Sroot 					ttyretype(tp);
6659578Ssam 				tp->t_flags |= FLUSHO;
6667502Sroot 			}
6679578Ssam 			goto startoutput;
6689578Ssam 		}
6699578Ssam 		if (c == tp->t_suspc) {
6709578Ssam 			if ((tp->t_flags&NOFLSH) == 0)
67112752Ssam 				ttyflush(tp, FREAD);
6729578Ssam 			ttyecho(c, tp);
6739578Ssam 			gsignal(tp->t_pgrp, SIGTSTP);
6749578Ssam 			goto endcase;
6759578Ssam 		}
6769578Ssam 	}
6779578Ssam 
6789578Ssam 	/*
6799578Ssam 	 * Handle start/stop characters.
6809578Ssam 	 */
6819578Ssam 	if (c == tp->t_stopc) {
6829578Ssam 		if ((tp->t_state&TS_TTSTOP) == 0) {
6839578Ssam 			tp->t_state |= TS_TTSTOP;
6849578Ssam 			(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
6857502Sroot 			return;
6869578Ssam 		}
6879578Ssam 		if (c != tp->t_startc)
6889578Ssam 			return;
6899578Ssam 		goto endcase;
6909578Ssam 	}
6919578Ssam 	if (c == tp->t_startc)
6929578Ssam 		goto restartoutput;
6939578Ssam 
6949578Ssam 	/*
6959578Ssam 	 * Look for interrupt/quit chars.
6969578Ssam 	 */
6979578Ssam 	if (c == tp->t_intrc || c == tp->t_quitc) {
6989578Ssam 		if ((tp->t_flags&NOFLSH) == 0)
69912752Ssam 			ttyflush(tp, FREAD|FWRITE);
7009578Ssam 		ttyecho(c, tp);
7019578Ssam 		gsignal(tp->t_pgrp, c == tp->t_intrc ? SIGINT : SIGQUIT);
7029578Ssam 		goto endcase;
7039578Ssam 	}
7049578Ssam 
7059578Ssam 	/*
7069578Ssam 	 * Cbreak mode, don't process line editing
7079578Ssam 	 * characters; check high water mark for wakeup.
7089578Ssam 	 */
7099578Ssam 	if (t_flags&CBREAK) {
7109578Ssam 		if (tp->t_rawq.c_cc > TTYHOG) {
7117502Sroot 			if (tp->t_outq.c_cc < TTHIWAT(tp) &&
7127502Sroot 			    tp->t_line == NTTYDISC)
7137502Sroot 				(void) ttyoutput(CTRL(g), tp);
7147502Sroot 		} else if (putc(c, &tp->t_rawq) >= 0) {
7157502Sroot 			ttwakeup(tp);
7167502Sroot 			ttyecho(c, tp);
7177502Sroot 		}
7189578Ssam 		goto endcase;
7199578Ssam 	}
7209578Ssam 
7219578Ssam 	/*
7229578Ssam 	 * From here on down cooked mode character
7239578Ssam 	 * processing takes place.
7249578Ssam 	 */
7259578Ssam 	if ((tp->t_state&TS_QUOT) &&
7269578Ssam 	    (c == tp->t_erase || c == tp->t_kill)) {
7279578Ssam 		ttyrub(unputc(&tp->t_rawq), tp);
7289578Ssam 		c |= 0200;
7299578Ssam 	}
7309578Ssam 	if (c == tp->t_erase) {
7319578Ssam 		if (tp->t_rawq.c_cc)
7329578Ssam 			ttyrub(unputc(&tp->t_rawq), tp);
7339578Ssam 		goto endcase;
7349578Ssam 	}
7359578Ssam 	if (c == tp->t_kill) {
7369578Ssam 		if (tp->t_flags&CRTKIL &&
7379578Ssam 		    tp->t_rawq.c_cc == tp->t_rocount) {
7389578Ssam 			while (tp->t_rawq.c_cc)
7399578Ssam 				ttyrub(unputc(&tp->t_rawq), tp);
7409578Ssam 		} else {
7419578Ssam 			ttyecho(c, tp);
7429578Ssam 			ttyecho('\n', tp);
7439578Ssam 			while (getc(&tp->t_rawq) > 0)
7449578Ssam 				;
7459578Ssam 			tp->t_rocount = 0;
7469578Ssam 		}
7479578Ssam 		tp->t_state &= ~TS_LOCAL;
7489578Ssam 		goto endcase;
7499578Ssam 	}
7509578Ssam 
7519578Ssam 	/*
7529578Ssam 	 * New line discipline,
7539578Ssam 	 * check word erase/reprint line.
7549578Ssam 	 */
7559578Ssam 	if (tp->t_line == NTTYDISC) {
7569578Ssam 		if (c == tp->t_werasc) {
7579578Ssam 			if (tp->t_rawq.c_cc == 0)
7589578Ssam 				goto endcase;
7599578Ssam 			do {
7609578Ssam 				c = unputc(&tp->t_rawq);
7619578Ssam 				if (c != ' ' && c != '\t')
7629578Ssam 					goto erasenb;
7639578Ssam 				ttyrub(c, tp);
7649578Ssam 			} while (tp->t_rawq.c_cc);
7659578Ssam 			goto endcase;
7669578Ssam 	erasenb:
7679578Ssam 			do {
7689578Ssam 				ttyrub(c, tp);
7699578Ssam 				if (tp->t_rawq.c_cc == 0)
7709578Ssam 					goto endcase;
7719578Ssam 				c = unputc(&tp->t_rawq);
7729578Ssam 			} while (c != ' ' && c != '\t');
7739578Ssam 			(void) putc(c, &tp->t_rawq);
7749578Ssam 			goto endcase;
7759578Ssam 		}
7769578Ssam 		if (c == tp->t_rprntc) {
7779578Ssam 			ttyretype(tp);
7789578Ssam 			goto endcase;
7799578Ssam 		}
7809578Ssam 	}
7819578Ssam 
7829578Ssam 	/*
7839578Ssam 	 * Check for input buffer overflow
7849578Ssam 	 */
78510391Ssam 	if (tp->t_rawq.c_cc+tp->t_canq.c_cc >= TTYHOG) {
78610391Ssam 		if (tp->t_line == NTTYDISC)
78710391Ssam 			(void) ttyoutput(CTRL(g), tp);
7889578Ssam 		goto endcase;
78910391Ssam 	}
7909578Ssam 
7919578Ssam 	/*
7929578Ssam 	 * Put data char in q for user and
7939578Ssam 	 * wakeup on seeing a line delimiter.
7949578Ssam 	 */
7959578Ssam 	if (putc(c, &tp->t_rawq) >= 0) {
7969578Ssam 		if (ttbreakc(c, tp)) {
7979578Ssam 			tp->t_rocount = 0;
7989578Ssam 			catq(&tp->t_rawq, &tp->t_canq);
7997502Sroot 			ttwakeup(tp);
8009578Ssam 		} else if (tp->t_rocount++ == 0)
8019578Ssam 			tp->t_rocol = tp->t_col;
8029578Ssam 		tp->t_state &= ~TS_QUOT;
8039578Ssam 		if (c == '\\')
8049578Ssam 			tp->t_state |= TS_QUOT;
8059578Ssam 		if (tp->t_state&TS_ERASE) {
8069578Ssam 			tp->t_state &= ~TS_ERASE;
8079578Ssam 			(void) ttyoutput('/', tp);
8089578Ssam 		}
8099578Ssam 		i = tp->t_col;
8107502Sroot 		ttyecho(c, tp);
8119578Ssam 		if (c == tp->t_eofc && tp->t_flags&ECHO) {
8129578Ssam 			i = MIN(2, tp->t_col - i);
8139578Ssam 			while (i > 0) {
8149578Ssam 				(void) ttyoutput('\b', tp);
8159578Ssam 				i--;
8169578Ssam 			}
8179578Ssam 		}
8187502Sroot 	}
8199578Ssam 
8209578Ssam endcase:
8219578Ssam 	/*
8229578Ssam 	 * If DEC-style start/stop is enabled don't restart
8239578Ssam 	 * output until seeing the start character.
8249578Ssam 	 */
8259578Ssam 	if (tp->t_flags&DECCTQ && tp->t_state&TS_TTSTOP &&
8269578Ssam 	    tp->t_startc != tp->t_stopc)
8277502Sroot 		return;
8289578Ssam 
8299578Ssam restartoutput:
8307502Sroot 	tp->t_state &= ~TS_TTSTOP;
8319578Ssam 	tp->t_flags &= ~FLUSHO;
8329578Ssam 
8339578Ssam startoutput:
8347502Sroot 	ttstart(tp);
8357502Sroot }
8367502Sroot 
8377502Sroot /*
8389578Ssam  * Put character on TTY output queue, adding delays,
8397502Sroot  * expanding tabs, and handling the CR/NL bit.
8409578Ssam  * This is called both from the top half for output,
8419578Ssam  * and from interrupt level for echoing.
8427502Sroot  * The arguments are the character and the tty structure.
8437502Sroot  * Returns < 0 if putc succeeds, otherwise returns char to resend
8447502Sroot  * Must be recursive.
8457502Sroot  */
8467502Sroot ttyoutput(c, tp)
8477502Sroot 	register c;
8487502Sroot 	register struct tty *tp;
8497502Sroot {
8507502Sroot 	register char *colp;
8517502Sroot 	register ctype;
8527502Sroot 
8539578Ssam 	if (tp->t_flags & (RAW|LITOUT)) {
8549578Ssam 		if (tp->t_flags&FLUSHO)
8557502Sroot 			return (-1);
8567502Sroot 		if (putc(c, &tp->t_outq))
8577625Ssam 			return (c);
8587502Sroot 		tk_nout++;
8597502Sroot 		return (-1);
8607502Sroot 	}
8619578Ssam 
8627502Sroot 	/*
8639578Ssam 	 * Ignore EOT in normal mode to avoid
8649578Ssam 	 * hanging up certain terminals.
8657502Sroot 	 */
8667502Sroot 	c &= 0177;
8679578Ssam 	if (c == CEOT && (tp->t_flags&CBREAK) == 0)
8687502Sroot 		return (-1);
8697502Sroot 	/*
8707502Sroot 	 * Turn tabs to spaces as required
8717502Sroot 	 */
8729578Ssam 	if (c == '\t' && (tp->t_flags&TBDELAY) == XTABS) {
8737502Sroot 		register int s;
8747502Sroot 
8757502Sroot 		c = 8 - (tp->t_col&7);
8769578Ssam 		if ((tp->t_flags&FLUSHO) == 0) {
8777502Sroot 			s = spl5();		/* don't interrupt tabs */
8787502Sroot 			c -= b_to_q("        ", c, &tp->t_outq);
8797502Sroot 			tk_nout += c;
8807502Sroot 			splx(s);
8817502Sroot 		}
8827502Sroot 		tp->t_col += c;
8837502Sroot 		return (c ? -1 : '\t');
8847502Sroot 	}
8857502Sroot 	tk_nout++;
8867502Sroot 	/*
8877502Sroot 	 * for upper-case-only terminals,
8887502Sroot 	 * generate escapes.
8897502Sroot 	 */
8907502Sroot 	if (tp->t_flags&LCASE) {
8917502Sroot 		colp = "({)}!|^~'`";
8927625Ssam 		while (*colp++)
8937625Ssam 			if (c == *colp++) {
8947502Sroot 				if (ttyoutput('\\', tp) >= 0)
8957502Sroot 					return (c);
8967502Sroot 				c = colp[-2];
8977502Sroot 				break;
8987502Sroot 			}
8999578Ssam 		if ('A' <= c && c <= 'Z') {
9007502Sroot 			if (ttyoutput('\\', tp) >= 0)
9017502Sroot 				return (c);
9029578Ssam 		} else if ('a' <= c && c <= 'z')
9037502Sroot 			c += 'A' - 'a';
9047502Sroot 	}
9059578Ssam 
9067502Sroot 	/*
9077502Sroot 	 * turn <nl> to <cr><lf> if desired.
9087502Sroot 	 */
9099578Ssam 	if (c == '\n' && tp->t_flags&CRMOD)
9107502Sroot 		if (ttyoutput('\r', tp) >= 0)
9117502Sroot 			return (c);
9129578Ssam 	if (c == '~' && tp->t_flags&TILDE)
9137502Sroot 		c = '`';
9149578Ssam 	if ((tp->t_flags&FLUSHO) == 0 && putc(c, &tp->t_outq))
9157502Sroot 		return (c);
9167502Sroot 	/*
9177502Sroot 	 * Calculate delays.
9187502Sroot 	 * The numbers here represent clock ticks
9197502Sroot 	 * and are not necessarily optimal for all terminals.
9207502Sroot 	 * The delays are indicated by characters above 0200.
9217502Sroot 	 * In raw mode there are no delays and the
9227502Sroot 	 * transmission path is 8 bits wide.
9239578Ssam 	 *
9249578Ssam 	 * SHOULD JUST ALLOW USER TO SPECIFY DELAYS
9257502Sroot 	 */
9267502Sroot 	colp = &tp->t_col;
9277502Sroot 	ctype = partab[c];
9287502Sroot 	c = 0;
9297502Sroot 	switch (ctype&077) {
9307502Sroot 
9317502Sroot 	case ORDINARY:
9327502Sroot 		(*colp)++;
9337502Sroot 
9347502Sroot 	case CONTROL:
9357502Sroot 		break;
9367502Sroot 
9377502Sroot 	case BACKSPACE:
9387502Sroot 		if (*colp)
9397502Sroot 			(*colp)--;
9407502Sroot 		break;
9417502Sroot 
94213821Ssam 	/*
94313821Ssam 	 * This macro is close enough to the correct thing;
94413821Ssam 	 * it should be replaced by real user settable delays
94513821Ssam 	 * in any event...
94613821Ssam 	 */
94713821Ssam #define	mstohz(ms)	(((ms) * hz) >> 10)
9487502Sroot 	case NEWLINE:
9497502Sroot 		ctype = (tp->t_flags >> 8) & 03;
9507625Ssam 		if (ctype == 1) { /* tty 37 */
95112752Ssam 			if (*colp > 0)
952*13863Ssam 				c = max((((unsigned)*colp) >> 4) + 3,
953*13863Ssam 				    (unsigned)6);
9549578Ssam 		} else if (ctype == 2) /* vt05 */
95513821Ssam 			c = mstohz(100);
9567502Sroot 		*colp = 0;
9577502Sroot 		break;
9587502Sroot 
9597502Sroot 	case TAB:
9607502Sroot 		ctype = (tp->t_flags >> 10) & 03;
9617625Ssam 		if (ctype == 1) { /* tty 37 */
9627502Sroot 			c = 1 - (*colp | ~07);
9637625Ssam 			if (c < 5)
9647502Sroot 				c = 0;
9657502Sroot 		}
9667502Sroot 		*colp |= 07;
9677502Sroot 		(*colp)++;
9687502Sroot 		break;
9697502Sroot 
9707502Sroot 	case VTAB:
9719578Ssam 		if (tp->t_flags&VTDELAY) /* tty 37 */
9727502Sroot 			c = 0177;
9737502Sroot 		break;
9747502Sroot 
9757502Sroot 	case RETURN:
9767502Sroot 		ctype = (tp->t_flags >> 12) & 03;
9779578Ssam 		if (ctype == 1) /* tn 300 */
97813821Ssam 			c = mstohz(83);
9799578Ssam 		else if (ctype == 2) /* ti 700 */
98013821Ssam 			c = mstohz(166);
9819578Ssam 		else if (ctype == 3) { /* concept 100 */
9827502Sroot 			int i;
9839578Ssam 
9847502Sroot 			if ((i = *colp) >= 0)
9859578Ssam 				for (; i < 9; i++)
9867502Sroot 					(void) putc(0177, &tp->t_outq);
9877502Sroot 		}
9887502Sroot 		*colp = 0;
9897502Sroot 	}
9909578Ssam 	if (c && (tp->t_flags&FLUSHO) == 0)
9917502Sroot 		(void) putc(c|0200, &tp->t_outq);
9927502Sroot 	return (-1);
9937502Sroot }
99413821Ssam #undef mstohz
9957502Sroot 
9967502Sroot /*
9977502Sroot  * Called from device's read routine after it has
9987502Sroot  * calculated the tty-structure given as argument.
9997502Sroot  */
10007722Swnj ttread(tp, uio)
10017625Ssam 	register struct tty *tp;
10027722Swnj 	struct uio *uio;
10037502Sroot {
10047502Sroot 	register struct clist *qp;
10059578Ssam 	register c, t_flags;
10069859Ssam 	int s, first, error = 0;
10077502Sroot 
10087502Sroot 	if ((tp->t_state&TS_CARR_ON)==0)
10098520Sroot 		return (EIO);
10107502Sroot loop:
10119578Ssam 	/*
10129578Ssam 	 * Take any pending input first.
10139578Ssam 	 */
10149859Ssam 	s = spl5();
10159578Ssam 	if (tp->t_flags&PENDIN)
10167502Sroot 		ttypend(tp);
10179859Ssam 	splx(s);
10189578Ssam 
10199578Ssam 	/*
10209578Ssam 	 * Hang process if it's in the background.
10219578Ssam 	 */
10227502Sroot 	while (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) {
10237502Sroot 		if (u.u_signal[SIGTTIN] == SIG_IGN ||
10247502Sroot 		    u.u_signal[SIGTTIN] == SIG_HOLD ||
10257502Sroot /*
10267502Sroot 		    (u.u_procp->p_flag&SDETACH) ||
10277502Sroot */
10287502Sroot 		    u.u_procp->p_flag&SVFORK)
10298520Sroot 			return (EIO);
10307502Sroot 		gsignal(u.u_procp->p_pgrp, SIGTTIN);
10317502Sroot 		sleep((caddr_t)&lbolt, TTIPRI);
10327502Sroot 	}
10339578Ssam 	t_flags = tp->t_flags;
10349578Ssam 
10359578Ssam 	/*
10369578Ssam 	 * In raw mode take characters directly from the
10379578Ssam 	 * raw queue w/o processing.  Interlock against
10389578Ssam 	 * device interrupts when interrogating rawq.
10399578Ssam 	 */
10409578Ssam 	if (t_flags&RAW) {
10419859Ssam 		s = spl5();
10427502Sroot 		if (tp->t_rawq.c_cc <= 0) {
10439578Ssam 			if ((tp->t_state&TS_CARR_ON) == 0 ||
10447502Sroot 			    (tp->t_state&TS_NBIO)) {
10459859Ssam 				splx(s);
10469578Ssam 				return (0);
10477502Sroot 			}
10487502Sroot 			sleep((caddr_t)&tp->t_rawq, TTIPRI);
10499859Ssam 			splx(s);
10507502Sroot 			goto loop;
10517502Sroot 		}
10529859Ssam 		splx(s);
10539859Ssam 		while (!error && tp->t_rawq.c_cc && uio->uio_iovcnt)
10548520Sroot 			error = passuc(getc(&tp->t_rawq), uio);
10559859Ssam 		goto checktandem;
10569578Ssam 	}
10579578Ssam 
10589578Ssam 	/*
10599578Ssam 	 * In cbreak mode use the rawq, otherwise
10609578Ssam 	 * take characters from the canonicalized q.
10619578Ssam 	 */
10629578Ssam 	qp = t_flags&CBREAK ? &tp->t_rawq : &tp->t_canq;
10639578Ssam 
10649578Ssam 	/*
10659578Ssam 	 * No input, sleep on rawq awaiting hardware
10669578Ssam 	 * receipt and notification.
10679578Ssam 	 */
10689859Ssam 	s = spl5();
10699578Ssam 	if (qp->c_cc <= 0) {
10709578Ssam 		if ((tp->t_state&TS_CARR_ON) == 0 ||
10719578Ssam 		    (tp->t_state&TS_NBIO)) {
10729859Ssam 			splx(s);
10739578Ssam 			return (EWOULDBLOCK);
10747502Sroot 		}
10759578Ssam 		sleep((caddr_t)&tp->t_rawq, TTIPRI);
10769859Ssam 		splx(s);
10779578Ssam 		goto loop;
10789578Ssam 	}
10799859Ssam 	splx(s);
10809578Ssam 
10819578Ssam 	/*
10829578Ssam 	 * Input present, perform input mapping
10839578Ssam 	 * and processing (we're not in raw mode).
10849578Ssam 	 */
10859578Ssam 	first = 1;
10869578Ssam 	while ((c = getc(qp)) >= 0) {
10879578Ssam 		if (t_flags&CRMOD && c == '\r')
10889578Ssam 			c = '\n';
10899578Ssam 		/*
10909578Ssam 		 * Hack lower case simulation on
10919578Ssam 		 * upper case only terminals.
10929578Ssam 		 */
10939578Ssam 		if (t_flags&LCASE && c <= 0177)
10949578Ssam 			if (tp->t_state&TS_BKSL) {
10959578Ssam 				if (maptab[c])
10969578Ssam 					c = maptab[c];
10979578Ssam 				tp->t_state &= ~TS_BKSL;
10989578Ssam 			} else if (c >= 'A' && c <= 'Z')
10999578Ssam 				c += 'a' - 'A';
11009578Ssam 			else if (c == '\\') {
11019578Ssam 				tp->t_state |= TS_BKSL;
11029578Ssam 				continue;
11037502Sroot 			}
11049578Ssam 		/*
11059578Ssam 		 * Check for delayed suspend character.
11069578Ssam 		 */
11079578Ssam 		if (tp->t_line == NTTYDISC && c == tp->t_dsuspc) {
11089578Ssam 			gsignal(tp->t_pgrp, SIGTSTP);
11099578Ssam 			if (first) {
11109578Ssam 				sleep((caddr_t)&lbolt, TTIPRI);
11119578Ssam 				goto loop;
11129578Ssam 			}
11139578Ssam 			break;
11147502Sroot 		}
11159578Ssam 		/*
11169578Ssam 		 * Interpret EOF only in cooked mode.
11179578Ssam 		 */
11189578Ssam 		if (c == tp->t_eofc && (t_flags&CBREAK) == 0)
11199578Ssam 			break;
11209578Ssam 		/*
11219578Ssam 		 * Give user character.
11229578Ssam 		 */
11239578Ssam 		error = passuc(c & 0177, uio);
11249578Ssam 		if (error)
11259578Ssam 			break;
11269578Ssam 		if (uio->uio_iovcnt == 0)
11279578Ssam 			break;
11289578Ssam 		/*
11299578Ssam 		 * In cooked mode check for a "break character"
11309578Ssam 		 * marking the end of a "line of input".
11319578Ssam 		 */
11329578Ssam 		if ((t_flags&CBREAK) == 0 && ttbreakc(c, tp))
11339578Ssam 			break;
11349578Ssam 		first = 0;
11357502Sroot 	}
11369578Ssam 	tp->t_state &= ~TS_BKSL;
11379578Ssam 
11389859Ssam checktandem:
11399578Ssam 	/*
11409578Ssam 	 * Look to unblock output now that (presumably)
11419578Ssam 	 * the input queue has gone down.
11429578Ssam 	 */
11439859Ssam 	if (tp->t_state&TS_TBLOCK && tp->t_rawq.c_cc < TTYHOG/5)
11449578Ssam 		if (putc(tp->t_startc, &tp->t_outq) == 0) {
11457502Sroot 			tp->t_state &= ~TS_TBLOCK;
11467502Sroot 			ttstart(tp);
11477502Sroot 		}
11488520Sroot 	return (error);
11497502Sroot }
11507502Sroot 
11517502Sroot /*
11527502Sroot  * Called from the device's write routine after it has
11537502Sroot  * calculated the tty-structure given as argument.
11547502Sroot  */
11557822Sroot ttwrite(tp, uio)
11567625Ssam 	register struct tty *tp;
11579578Ssam 	register struct uio *uio;
11587502Sroot {
11597502Sroot 	register char *cp;
11609578Ssam 	register int cc, ce, c;
11619578Ssam 	int i, hiwat, cnt, error, s;
11627502Sroot 	char obuf[OBUFSIZ];
11637502Sroot 
11649578Ssam 	if ((tp->t_state&TS_CARR_ON) == 0)
11658520Sroot 		return (EIO);
11669578Ssam 	hiwat = TTHIWAT(tp);
11679578Ssam 	cnt = uio->uio_resid;
11689578Ssam 	error = 0;
11697502Sroot loop:
11709578Ssam 	/*
11719578Ssam 	 * Hang the process if it's in the background.
11729578Ssam 	 */
11737502Sroot 	while (u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp &&
11749578Ssam 	    (tp->t_flags&TOSTOP) && (u.u_procp->p_flag&SVFORK)==0 &&
11757502Sroot 	    u.u_signal[SIGTTOU] != SIG_IGN &&
11767502Sroot 	    u.u_signal[SIGTTOU] != SIG_HOLD
11777502Sroot /*
11787502Sroot 					     &&
11797502Sroot 	    (u.u_procp->p_flag&SDETACH)==0) {
11807502Sroot */
11817502Sroot 	    ) {
11827502Sroot 		gsignal(u.u_procp->p_pgrp, SIGTTOU);
11837502Sroot 		sleep((caddr_t)&lbolt, TTIPRI);
11847502Sroot 	}
11859578Ssam 
11869578Ssam 	/*
11879578Ssam 	 * Process the user's data in at most OBUFSIZ
11889578Ssam 	 * chunks.  Perform lower case simulation and
11899578Ssam 	 * similar hacks.  Keep track of high water
11909578Ssam 	 * mark, sleep on overflow awaiting device aid
11919578Ssam 	 * in acquiring new space.
11929578Ssam 	 */
11937822Sroot 	while (uio->uio_resid > 0) {
11949578Ssam 		/*
11959578Ssam 		 * Grab a hunk of data from the user.
11969578Ssam 		 */
11977822Sroot 		cc = uio->uio_iov->iov_len;
11987822Sroot 		if (cc == 0) {
11997822Sroot 			uio->uio_iovcnt--;
12007822Sroot 			uio->uio_iov++;
12017822Sroot 			if (uio->uio_iovcnt < 0)
12027822Sroot 				panic("ttwrite");
12037822Sroot 			continue;
12047822Sroot 		}
12057822Sroot 		if (cc > OBUFSIZ)
12067822Sroot 			cc = OBUFSIZ;
12077502Sroot 		cp = obuf;
120812752Ssam 		error = uiomove(cp, cc, UIO_WRITE, uio);
12098520Sroot 		if (error)
12107502Sroot 			break;
12117502Sroot 		if (tp->t_outq.c_cc > hiwat)
12127502Sroot 			goto ovhiwat;
12139578Ssam 		if (tp->t_flags&FLUSHO)
12147502Sroot 			continue;
12159578Ssam 		/*
12169578Ssam 		 * If we're mapping lower case or kludging tildes,
12179578Ssam 		 * then we've got to look at each character, so
12189578Ssam 		 * just feed the stuff to ttyoutput...
12199578Ssam 		 */
12209578Ssam 		if (tp->t_flags & (LCASE|TILDE)) {
12219578Ssam 			while (cc > 0) {
12227502Sroot 				c = *cp++;
12237502Sroot 				tp->t_rocount = 0;
12247625Ssam 				while ((c = ttyoutput(c, tp)) >= 0) {
12257502Sroot 					/* out of clists, wait a bit */
12267502Sroot 					ttstart(tp);
12277502Sroot 					sleep((caddr_t)&lbolt, TTOPRI);
12287502Sroot 					tp->t_rocount = 0;
12297502Sroot 				}
12307502Sroot 				--cc;
12317502Sroot 				if (tp->t_outq.c_cc > hiwat)
12327502Sroot 					goto ovhiwat;
12337502Sroot 			}
12347502Sroot 			continue;
12357502Sroot 		}
12369578Ssam 		/*
12379578Ssam 		 * If nothing fancy need be done, grab those characters we
12389578Ssam 		 * can handle without any of ttyoutput's processing and
12399578Ssam 		 * just transfer them to the output q.  For those chars
12409578Ssam 		 * which require special processing (as indicated by the
12419578Ssam 		 * bits in partab), call ttyoutput.  After processing
12429578Ssam 		 * a hunk of data, look for FLUSHO so ^O's will take effect
12439578Ssam 		 * immediately.
12449578Ssam 		 */
12459578Ssam 		while (cc > 0) {
12469578Ssam 			if (tp->t_flags & (RAW|LITOUT))
12477502Sroot 				ce = cc;
12487502Sroot 			else {
124912752Ssam 				ce = cc - scanc((unsigned)cc, (caddr_t)cp,
125012752Ssam 				   (caddr_t)partab, 077);
12519578Ssam 				/*
12529578Ssam 				 * If ce is zero, then we're processing
12539578Ssam 				 * a special character through ttyoutput.
12549578Ssam 				 */
12559578Ssam 				if (ce == 0) {
12567502Sroot 					tp->t_rocount = 0;
12577502Sroot 					if (ttyoutput(*cp, tp) >= 0) {
12589578Ssam 						/* no c-lists, wait a bit */
12597502Sroot 						ttstart(tp);
12607502Sroot 						sleep((caddr_t)&lbolt, TTOPRI);
12617502Sroot 						continue;
12627502Sroot 					}
12639578Ssam 					cp++, cc--;
12649578Ssam 					if (tp->t_flags&FLUSHO ||
12659578Ssam 					    tp->t_outq.c_cc > hiwat)
12667502Sroot 						goto ovhiwat;
12679578Ssam 					continue;
12687502Sroot 				}
12697502Sroot 			}
12709578Ssam 			/*
12719578Ssam 			 * A bunch of normal characters have been found,
12729578Ssam 			 * transfer them en masse to the output queue and
12739578Ssam 			 * continue processing at the top of the loop.
12749578Ssam 			 * If there are any further characters in this
12759578Ssam 			 * <= OBUFSIZ chunk, the first should be a character
12769578Ssam 			 * requiring special handling by ttyoutput.
12779578Ssam 			 */
12787502Sroot 			tp->t_rocount = 0;
12799578Ssam 			i = b_to_q(cp, ce, &tp->t_outq);
12809578Ssam 			ce -= i;
12819578Ssam 			tp->t_col += ce;
12829578Ssam 			cp += ce, cc -= ce, tk_nout += ce;
12839578Ssam 			if (i > 0) {
12849578Ssam 				/* out of c-lists, wait a bit */
12857502Sroot 				ttstart(tp);
12867502Sroot 				sleep((caddr_t)&lbolt, TTOPRI);
12877502Sroot 			}
12889578Ssam 			if (tp->t_flags&FLUSHO || tp->t_outq.c_cc > hiwat)
12897502Sroot 				goto ovhiwat;
12907502Sroot 		}
12917502Sroot 	}
12927502Sroot 	ttstart(tp);
12938520Sroot 	return (error);
12947502Sroot 
12957502Sroot ovhiwat:
12969578Ssam 	s = spl5();
12979578Ssam 	if (cc != 0) {
12989578Ssam 		uio->uio_iov->iov_base -= cc;
12999578Ssam 		uio->uio_iov->iov_len += cc;
13009578Ssam 		uio->uio_resid += cc;
13019578Ssam 		uio->uio_offset -= cc;
13029578Ssam 	}
13039578Ssam 	/*
13049578Ssam 	 * This can only occur if FLUSHO
13059578Ssam 	 * is also set in t_flags.
13069578Ssam 	 */
13077502Sroot 	if (tp->t_outq.c_cc <= hiwat) {
13089578Ssam 		splx(s);
13097502Sroot 		goto loop;
13107502Sroot 	}
13117502Sroot 	ttstart(tp);
13129578Ssam 	if (tp->t_state&TS_NBIO) {
13137822Sroot 		if (uio->uio_resid == cnt)
13148520Sroot 			return (EWOULDBLOCK);
13158520Sroot 		return (0);
13167502Sroot 	}
13177502Sroot 	tp->t_state |= TS_ASLEEP;
13187502Sroot 	sleep((caddr_t)&tp->t_outq, TTOPRI);
13199578Ssam 	splx(s);
13207502Sroot 	goto loop;
13217502Sroot }
13227502Sroot 
13237502Sroot /*
13247502Sroot  * Rubout one character from the rawq of tp
13257502Sroot  * as cleanly as possible.
13267502Sroot  */
13277502Sroot ttyrub(c, tp)
13287625Ssam 	register c;
13297625Ssam 	register struct tty *tp;
13307502Sroot {
13317502Sroot 	register char *cp;
13327502Sroot 	register int savecol;
13337502Sroot 	int s;
13347502Sroot 	char *nextc();
13357502Sroot 
13369578Ssam 	if ((tp->t_flags&ECHO) == 0)
13377502Sroot 		return;
13389578Ssam 	tp->t_flags &= ~FLUSHO;
13397502Sroot 	c &= 0377;
13409578Ssam 	if (tp->t_flags&CRTBS) {
13417502Sroot 		if (tp->t_rocount == 0) {
13427502Sroot 			/*
13437502Sroot 			 * Screwed by ttwrite; retype
13447502Sroot 			 */
13457502Sroot 			ttyretype(tp);
13467502Sroot 			return;
13477502Sroot 		}
13489578Ssam 		if (c == ('\t'|0200) || c == ('\n'|0200))
13497502Sroot 			ttyrubo(tp, 2);
13509578Ssam 		else switch (partab[c&=0177]&0177) {
13517502Sroot 
13527502Sroot 		case ORDINARY:
13537502Sroot 			if (tp->t_flags&LCASE && c >= 'A' && c <= 'Z')
13547502Sroot 				ttyrubo(tp, 2);
13557502Sroot 			else
13567502Sroot 				ttyrubo(tp, 1);
13577502Sroot 			break;
13587502Sroot 
13597502Sroot 		case VTAB:
13607502Sroot 		case BACKSPACE:
13617502Sroot 		case CONTROL:
13627502Sroot 		case RETURN:
13639578Ssam 			if (tp->t_flags&CTLECH)
13647502Sroot 				ttyrubo(tp, 2);
13657502Sroot 			break;
13667502Sroot 
13677502Sroot 		case TAB:
13687502Sroot 			if (tp->t_rocount < tp->t_rawq.c_cc) {
13697502Sroot 				ttyretype(tp);
13707502Sroot 				return;
13717502Sroot 			}
13727502Sroot 			s = spl5();
13737502Sroot 			savecol = tp->t_col;
13749578Ssam 			tp->t_state |= TS_CNTTB;
13759578Ssam 			tp->t_flags |= FLUSHO;
13767502Sroot 			tp->t_col = tp->t_rocol;
13779578Ssam 			cp = tp->t_rawq.c_cf;
13789578Ssam 			for (; cp; cp = nextc(&tp->t_rawq, cp))
13797502Sroot 				ttyecho(*cp, tp);
13809578Ssam 			tp->t_flags &= ~FLUSHO;
13819578Ssam 			tp->t_state &= ~TS_CNTTB;
13827502Sroot 			splx(s);
13837502Sroot 			/*
13847502Sroot 			 * savecol will now be length of the tab
13857502Sroot 			 */
13867502Sroot 			savecol -= tp->t_col;
13877502Sroot 			tp->t_col += savecol;
13887502Sroot 			if (savecol > 8)
13897502Sroot 				savecol = 8;		/* overflow screw */
13907502Sroot 			while (--savecol >= 0)
13917502Sroot 				(void) ttyoutput('\b', tp);
13927502Sroot 			break;
13937502Sroot 
13947502Sroot 		default:
13957502Sroot 			panic("ttyrub");
13967502Sroot 		}
13979578Ssam 	} else if (tp->t_flags&PRTERA) {
13989578Ssam 		if ((tp->t_state&TS_ERASE) == 0) {
13997502Sroot 			(void) ttyoutput('\\', tp);
14009578Ssam 			tp->t_state |= TS_ERASE;
14017502Sroot 		}
14027502Sroot 		ttyecho(c, tp);
14037502Sroot 	} else
14047502Sroot 		ttyecho(tp->t_erase, tp);
14057502Sroot 	tp->t_rocount--;
14067502Sroot }
14077502Sroot 
14087502Sroot /*
14097502Sroot  * Crt back over cnt chars perhaps
14107502Sroot  * erasing them.
14117502Sroot  */
14127502Sroot ttyrubo(tp, cnt)
14137625Ssam 	register struct tty *tp;
14147625Ssam 	int cnt;
14157502Sroot {
14169578Ssam 	register char *rubostring = tp->t_flags&CRTERA ? "\b \b" : "\b";
14177502Sroot 
14187502Sroot 	while (--cnt >= 0)
14199578Ssam 		ttyout(rubostring, tp);
14207502Sroot }
14217502Sroot 
14227502Sroot /*
14237502Sroot  * Reprint the rawq line.
14247502Sroot  * We assume c_cc has already been checked.
14257502Sroot  */
14267502Sroot ttyretype(tp)
14277625Ssam 	register struct tty *tp;
14287502Sroot {
14297502Sroot 	register char *cp;
14307502Sroot 	char *nextc();
14317502Sroot 	int s;
14327502Sroot 
14339578Ssam 	if (tp->t_rprntc != 0377)
14349578Ssam 		ttyecho(tp->t_rprntc, tp);
14357502Sroot 	(void) ttyoutput('\n', tp);
14367502Sroot 	s = spl5();
14377502Sroot 	for (cp = tp->t_canq.c_cf; cp; cp = nextc(&tp->t_canq, cp))
14387502Sroot 		ttyecho(*cp, tp);
14397502Sroot 	for (cp = tp->t_rawq.c_cf; cp; cp = nextc(&tp->t_rawq, cp))
14407502Sroot 		ttyecho(*cp, tp);
14419578Ssam 	tp->t_state &= ~TS_ERASE;
14427502Sroot 	splx(s);
14437502Sroot 	tp->t_rocount = tp->t_rawq.c_cc;
14447502Sroot 	tp->t_rocol = 0;
14457502Sroot }
14467502Sroot 
14477502Sroot /*
14487502Sroot  * Echo a typed character to the terminal
14497502Sroot  */
14507502Sroot ttyecho(c, tp)
14517625Ssam 	register c;
14527625Ssam 	register struct tty *tp;
14537502Sroot {
14547502Sroot 
14559578Ssam 	if ((tp->t_state&TS_CNTTB) == 0)
14569578Ssam 		tp->t_flags &= ~FLUSHO;
14577502Sroot 	if ((tp->t_flags&ECHO) == 0)
14587502Sroot 		return;
14597502Sroot 	c &= 0377;
14607502Sroot 	if (tp->t_flags&RAW) {
14617502Sroot 		(void) ttyoutput(c, tp);
14627502Sroot 		return;
14637502Sroot 	}
14647502Sroot 	if (c == '\r' && tp->t_flags&CRMOD)
14657502Sroot 		c = '\n';
14669578Ssam 	if (tp->t_flags&CTLECH) {
14677502Sroot 		if ((c&0177) <= 037 && c!='\t' && c!='\n' || (c&0177)==0177) {
14687502Sroot 			(void) ttyoutput('^', tp);
14697502Sroot 			c &= 0177;
14707502Sroot 			if (c == 0177)
14717502Sroot 				c = '?';
14727502Sroot 			else if (tp->t_flags&LCASE)
14737502Sroot 				c += 'a' - 1;
14747502Sroot 			else
14757502Sroot 				c += 'A' - 1;
14767502Sroot 		}
14777502Sroot 	}
14787502Sroot 	if ((tp->t_flags&LCASE) && (c >= 'A' && c <= 'Z'))
14797502Sroot 		c += 'a' - 'A';
14809578Ssam 	(void) ttyoutput(c&0177, tp);
14817502Sroot }
14827502Sroot 
14837502Sroot /*
14847502Sroot  * Is c a break char for tp?
14857502Sroot  */
14867502Sroot ttbreakc(c, tp)
14877625Ssam 	register c;
14887625Ssam 	register struct tty *tp;
14897502Sroot {
14909578Ssam 	return (c == '\n' || c == tp->t_eofc || c == tp->t_brkc ||
14917502Sroot 		c == '\r' && (tp->t_flags&CRMOD));
14927502Sroot }
14937502Sroot 
14947502Sroot /*
14957502Sroot  * send string cp to tp
14967502Sroot  */
14977502Sroot ttyout(cp, tp)
14987625Ssam 	register char *cp;
14997625Ssam 	register struct tty *tp;
15007502Sroot {
15017502Sroot 	register char c;
15027502Sroot 
15037502Sroot 	while (c = *cp++)
15047502Sroot 		(void) ttyoutput(c, tp);
15057502Sroot }
15067502Sroot 
15077502Sroot ttwakeup(tp)
15087502Sroot 	struct tty *tp;
15097502Sroot {
15107502Sroot 
15117502Sroot 	if (tp->t_rsel) {
15127502Sroot 		selwakeup(tp->t_rsel, tp->t_state&TS_RCOLL);
15137502Sroot 		tp->t_state &= ~TS_RCOLL;
15147502Sroot 		tp->t_rsel = 0;
15157502Sroot 	}
151612752Ssam 	if (tp->t_state & TS_ASYNC)
151712752Ssam 		gsignal(tp->t_pgrp, SIGIO);
15187502Sroot 	wakeup((caddr_t)&tp->t_rawq);
15197502Sroot }
15207502Sroot 
152113533Ssam #if !defined(vax)
15229578Ssam scanc(size, cp, table, mask)
15239578Ssam 	register int size;
15249578Ssam 	register char *cp, table[];
15259578Ssam 	register int mask;
15267502Sroot {
15279578Ssam 	register int i = 0;
15287502Sroot 
15299578Ssam 	while ((table[*(u_char *)(cp + i)]&mask) == 0 && i < size)
15309578Ssam 		i++;
15319578Ssam 	return (i);
15327502Sroot }
15339578Ssam #endif
1534