xref: /csrg-svn/sys/kern/tty.c (revision 9578)
1*9578Ssam /*	tty.c	4.35	82/12/07	*/
239Sbill 
339Sbill #include "../h/param.h"
439Sbill #include "../h/systm.h"
539Sbill #include "../h/dir.h"
639Sbill #include "../h/user.h"
7*9578Ssam #include "../h/ioctl.h"
839Sbill #include "../h/tty.h"
939Sbill #include "../h/proc.h"
1039Sbill #include "../h/inode.h"
1139Sbill #include "../h/file.h"
1239Sbill #include "../h/reg.h"
1339Sbill #include "../h/conf.h"
1439Sbill #include "../h/buf.h"
15340Sbill #include "../h/dk.h"
167722Swnj #include "../h/uio.h"
178154Sroot #include "../h/kernel.h"
1839Sbill 
197436Skre /*
207436Skre  * Table giving parity for characters and indicating
217436Skre  * character classes to tty driver.  In particular,
227436Skre  * if the low 6 bits are 0, then the character needs
237436Skre  * no special processing on output.
247436Skre  */
2539Sbill 
267436Skre char partab[] = {
277436Skre 	0001,0201,0201,0001,0201,0001,0001,0201,
287436Skre 	0202,0004,0003,0201,0005,0206,0201,0001,
297436Skre 	0201,0001,0001,0201,0001,0201,0201,0001,
307436Skre 	0001,0201,0201,0001,0201,0001,0001,0201,
317436Skre 	0200,0000,0000,0200,0000,0200,0200,0000,
327436Skre 	0000,0200,0200,0000,0200,0000,0000,0200,
337436Skre 	0000,0200,0200,0000,0200,0000,0000,0200,
347436Skre 	0200,0000,0000,0200,0000,0200,0200,0000,
357436Skre 	0200,0000,0000,0200,0000,0200,0200,0000,
367436Skre 	0000,0200,0200,0000,0200,0000,0000,0200,
377436Skre 	0000,0200,0200,0000,0200,0000,0000,0200,
387436Skre 	0200,0000,0000,0200,0000,0200,0200,0000,
397436Skre 	0000,0200,0200,0000,0200,0000,0000,0200,
407436Skre 	0200,0000,0000,0200,0000,0200,0200,0000,
417436Skre 	0200,0000,0000,0200,0000,0200,0200,0000,
427436Skre 	0000,0200,0200,0000,0200,0000,0000,0201,
437436Skre 
447436Skre 	/*
457436Skre 	 * 7 bit ascii ends with the last character above,
467436Skre 	 * but we contine through all 256 codes for the sake
477436Skre 	 * of the tty output routines which use special vax
487436Skre 	 * instructions which need a 256 character trt table.
497436Skre 	 */
507436Skre 
517436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
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 };
687436Skre 
69146Sbill /*
7039Sbill  * Input mapping table-- if an entry is non-zero, when the
7139Sbill  * corresponding character is typed preceded by "\" the escape
7239Sbill  * sequence is replaced by the table value.  Mostly used for
7339Sbill  * upper-case only terminals.
7439Sbill  */
7539Sbill char	maptab[] ={
7639Sbill 	000,000,000,000,000,000,000,000,
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,'`',
8139Sbill 	'{','}',000,000,000,000,000,000,
8239Sbill 	000,000,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,
8839Sbill 	000,'A','B','C','D','E','F','G',
8939Sbill 	'H','I','J','K','L','M','N','O',
9039Sbill 	'P','Q','R','S','T','U','V','W',
9139Sbill 	'X','Y','Z',000,000,000,000,000,
9239Sbill };
9339Sbill 
94925Sbill short	tthiwat[16] =
958954Sroot    { 100,100,100,100,100,100,100,200,200,400,400,400,650,650,1300,2000 };
96925Sbill short	ttlowat[16] =
97925Sbill    {  30, 30, 30, 30, 30, 30, 30, 50, 50,120,120,120,125,125,125,125 };
98925Sbill 
99*9578Ssam struct	ttychars ttydefaults = {
100*9578Ssam 	CERASE,	CKILL,	CINTR,	CQUIT,	CSTART,	CSTOP,	CEOF,
101*9578Ssam 	CBRK,	CSUSP,	CDSUSP, CRPRNT, CFLUSH, CWERASE,CLNEXT
102*9578Ssam };
10339Sbill 
10439Sbill ttychars(tp)
105*9578Ssam 	struct tty *tp;
10639Sbill {
107174Sbill 
108*9578Ssam 	tp->t_chars = ttydefaults;
10939Sbill }
11039Sbill 
11139Sbill /*
112903Sbill  * Wait for output to drain, then flush input waiting.
11339Sbill  */
114903Sbill wflushtty(tp)
1155408Swnj 	register struct tty *tp;
11639Sbill {
11739Sbill 
118903Sbill 	(void) spl5();
1195622Swnj 	while (tp->t_outq.c_cc && tp->t_state&TS_CARR_ON
1205622Swnj 	    && tp->t_oproc) {		/* kludge for pty */
121903Sbill 		(*tp->t_oproc)(tp);
1225408Swnj 		tp->t_state |= TS_ASLEEP;
123903Sbill 		sleep((caddr_t)&tp->t_outq, TTOPRI);
124903Sbill 	}
1255426Swnj 	flushtty(tp, FREAD);
126903Sbill 	(void) spl0();
12739Sbill }
12839Sbill 
12939Sbill /*
130*9578Ssam  * Flush all TTY queues
13139Sbill  */
132903Sbill flushtty(tp, rw)
1337625Ssam 	register struct tty *tp;
13439Sbill {
135903Sbill 	register s;
136903Sbill 
137903Sbill 	s = spl6();
138903Sbill 	if (rw & FREAD) {
139903Sbill 		while (getc(&tp->t_canq) >= 0)
140903Sbill 			;
141903Sbill 		wakeup((caddr_t)&tp->t_rawq);
142903Sbill 	}
143903Sbill 	if (rw & FWRITE) {
144903Sbill 		wakeup((caddr_t)&tp->t_outq);
1455408Swnj 		tp->t_state &= ~TS_TTSTOP;
1465426Swnj 		(*cdevsw[major(tp->t_dev)].d_stop)(tp, rw);
147903Sbill 		while (getc(&tp->t_outq) >= 0)
148903Sbill 			;
149903Sbill 	}
150903Sbill 	if (rw & FREAD) {
151903Sbill 		while (getc(&tp->t_rawq) >= 0)
152903Sbill 			;
153903Sbill 		tp->t_delct = 0;
154*9578Ssam 		tp->t_rocount = 0;
155903Sbill 		tp->t_rocol = 0;
156*9578Ssam 		tp->t_state &= ~TS_LOCAL;
157903Sbill 	}
158903Sbill 	splx(s);
15939Sbill }
16039Sbill 
161903Sbill /*
162903Sbill  * Send stop character on input overflow.
163903Sbill  */
164903Sbill ttyblock(tp)
1657625Ssam 	register struct tty *tp;
16639Sbill {
167903Sbill 	register x;
168*9578Ssam 
169903Sbill 	x = tp->t_rawq.c_cc + tp->t_canq.c_cc;
170903Sbill 	if (tp->t_rawq.c_cc > TTYHOG) {
171903Sbill 		flushtty(tp, FREAD|FWRITE);
1725408Swnj 		tp->t_state &= ~TS_TBLOCK;
173903Sbill 	}
174*9578Ssam 	if (x >= TTYHOG/2 && putc(tp->t_stopc, &tp->t_outq) == 0) {
175*9578Ssam 		tp->t_state |= TS_TBLOCK;
176*9578Ssam 		tp->t_char++;
177*9578Ssam 		ttstart(tp);
178903Sbill 	}
17939Sbill }
18039Sbill 
18139Sbill /*
182903Sbill  * Restart typewriter output following a delay
183903Sbill  * timeout.
184903Sbill  * The name of the routine is passed to the timeout
185903Sbill  * subroutine and it is called during a clock interrupt.
186121Sbill  */
187903Sbill ttrstrt(tp)
1887625Ssam 	register struct tty *tp;
189121Sbill {
190121Sbill 
191*9578Ssam 	if (tp == 0)
192*9578Ssam 		panic("ttrstrt");
1935408Swnj 	tp->t_state &= ~TS_TIMEOUT;
194903Sbill 	ttstart(tp);
195121Sbill }
196121Sbill 
197121Sbill /*
198903Sbill  * Start output on the typewriter. It is used from the top half
199903Sbill  * after some characters have been put on the output queue,
200903Sbill  * from the interrupt routine to transmit the next
201903Sbill  * character, and after a timeout has finished.
20239Sbill  */
203903Sbill ttstart(tp)
2047625Ssam 	register struct tty *tp;
20539Sbill {
206903Sbill 	register s;
20739Sbill 
208903Sbill 	s = spl5();
209*9578Ssam 	if ((tp->t_state & (TS_TIMEOUT|TS_TTSTOP|TS_BUSY)) == 0 &&
2105622Swnj 	    tp->t_oproc)		/* kludge for pty */
211903Sbill 		(*tp->t_oproc)(tp);
212903Sbill 	splx(s);
21339Sbill }
21439Sbill 
21539Sbill /*
216903Sbill  * Common code for tty ioctls.
21739Sbill  */
2181780Sbill /*ARGSUSED*/
2197625Ssam ttioctl(tp, com, data, flag)
2207625Ssam 	register struct tty *tp;
2217625Ssam 	caddr_t data;
22239Sbill {
2238520Sroot 	int dev = tp->t_dev;
22439Sbill 	extern int nldisp;
2258556Sroot 	int s;
22639Sbill 
227903Sbill 	/*
228903Sbill 	 * If the ioctl involves modification,
229903Sbill 	 * insist on being able to write the device,
230903Sbill 	 * and hang if in the background.
231903Sbill 	 */
2327625Ssam 	switch (com) {
23339Sbill 
234915Sbill 	case TIOCSETD:
235915Sbill 	case TIOCSETP:
236915Sbill 	case TIOCSETN:
237903Sbill 	case TIOCFLUSH:
238903Sbill 	case TIOCSETC:
239903Sbill 	case TIOCSLTC:
240903Sbill 	case TIOCSPGRP:
241903Sbill 	case TIOCLBIS:
242903Sbill 	case TIOCLBIC:
243903Sbill 	case TIOCLSET:
2449325Ssam 	case TIOCSTI:
245903Sbill 		while (tp->t_line == NTTYDISC &&
246903Sbill 		   u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp &&
247903Sbill 		   (u.u_procp->p_flag&SVFORK) == 0 &&
248903Sbill 		   u.u_signal[SIGTTOU] != SIG_IGN &&
2498556Sroot 		   u.u_signal[SIGTTOU] != SIG_HOLD) {
250903Sbill 			gsignal(u.u_procp->p_pgrp, SIGTTOU);
251903Sbill 			sleep((caddr_t)&lbolt, TTOPRI);
252903Sbill 		}
253903Sbill 		break;
254903Sbill 	}
255903Sbill 
256*9578Ssam 	/*
257*9578Ssam 	 * Process the ioctl.
258*9578Ssam 	 */
2597625Ssam 	switch (com) {
260903Sbill 
2618556Sroot 	/* get discipline number */
26239Sbill 	case TIOCGETD:
2637625Ssam 		*(int *)data = tp->t_line;
26439Sbill 		break;
26539Sbill 
2668556Sroot 	/* set line discipline */
2677625Ssam 	case TIOCSETD: {
2687625Ssam 		register int t = *(int *)data;
269*9578Ssam 		int error = 0;
2707625Ssam 
271*9578Ssam 		if (t >= nldisp) {
272*9578Ssam 			u.u_error = ENXIO;
273*9578Ssam 			break;
274*9578Ssam 		}
2758556Sroot 		s = spl5();
27639Sbill 		if (tp->t_line)
27739Sbill 			(*linesw[tp->t_line].l_close)(tp);
27839Sbill 		if (t)
2798556Sroot 			error = (*linesw[t].l_open)(dev, tp);
2808556Sroot 		splx(s);
2818556Sroot 		if (error)
2828556Sroot 			return (error);
2838556Sroot 		tp->t_line = t;
28439Sbill 		break;
2857625Ssam 	}
28639Sbill 
2878556Sroot 	/* prevent more opens on channel */
2885614Swnj 	case TIOCEXCL:
2895614Swnj 		tp->t_state |= TS_XCLUDE;
2905614Swnj 		break;
2915614Swnj 
2925614Swnj 	case TIOCNXCL:
2935614Swnj 		tp->t_state &= ~TS_XCLUDE;
2945614Swnj 		break;
2955614Swnj 
2968556Sroot 	/* set new parameters */
29739Sbill 	case TIOCSETP:
2987625Ssam 	case TIOCSETN: {
2997625Ssam 		register struct sgttyb *sg = (struct sgttyb *)data;
3007625Ssam 		struct clist tq;
3017625Ssam 
302121Sbill 		(void) spl5();
3037625Ssam 		if (tp->t_flags&RAW || sg->sg_flags&RAW || com == TIOCSETP)
3044484Swnj 			wflushtty(tp);
3057625Ssam 		else if ((tp->t_flags&CBREAK) != (sg->sg_flags&CBREAK)) {
306*9578Ssam 			if (sg->sg_flags&CBREAK) {
3074484Swnj 				catq(&tp->t_rawq, &tp->t_canq);
3084484Swnj 				tq = tp->t_rawq;
3094484Swnj 				tp->t_rawq = tp->t_canq;
3104484Swnj 				tp->t_canq = tq;
3114484Swnj 			} else {
312*9578Ssam 				tp->t_flags |= PENDIN;
3134484Swnj 				ttwakeup(tp);
314174Sbill 			}
315174Sbill 		}
3167625Ssam 		tp->t_ispeed = sg->sg_ispeed;
3177625Ssam 		tp->t_ospeed = sg->sg_ospeed;
3187625Ssam 		tp->t_erase = sg->sg_erase;
3197625Ssam 		tp->t_kill = sg->sg_kill;
320*9578Ssam 		tp->t_flags &= ~0xffff;
321*9578Ssam 		tp->t_flags |= sg->sg_flags;
322*9578Ssam 		if (tp->t_flags&RAW) {
3235408Swnj 			tp->t_state &= ~TS_TTSTOP;
3243941Sbugs 			ttstart(tp);
3253941Sbugs 		}
326121Sbill 		(void) spl0();
32739Sbill 		break;
3287625Ssam 	}
32939Sbill 
3308556Sroot 	/* send current parameters to user */
3317625Ssam 	case TIOCGETP: {
3327625Ssam 		register struct sgttyb *sg = (struct sgttyb *)data;
3337625Ssam 
3347625Ssam 		sg->sg_ispeed = tp->t_ispeed;
3357625Ssam 		sg->sg_ospeed = tp->t_ospeed;
3367625Ssam 		sg->sg_erase = tp->t_erase;
3377625Ssam 		sg->sg_kill = tp->t_kill;
3387625Ssam 		sg->sg_flags = tp->t_flags;
33939Sbill 		break;
3407625Ssam 	}
34139Sbill 
3428556Sroot 	/* hang up line on last close */
34339Sbill 	case TIOCHPCL:
3445408Swnj 		tp->t_state |= TS_HUPCLS;
34539Sbill 		break;
34639Sbill 
3473942Sbugs 	case TIOCFLUSH: {
3487625Ssam 		register int flags = *(int *)data;
3497625Ssam 
3507625Ssam 		if (flags == 0)
3513942Sbugs 			flags = FREAD|FWRITE;
3527625Ssam 		else
3537625Ssam 			flags &= FREAD|FWRITE;
3543942Sbugs 		flushtty(tp, flags);
35539Sbill 		break;
3563944Sbugs 	}
35739Sbill 
358*9578Ssam 	/* set and fetch special characters */
359*9578Ssam 	/* THIS SHOULD USE struct ttychars */
360*9578Ssam 	case TIOCSETC:
361*9578Ssam 		bcopy(data, (caddr_t)&tp->t_intrc, sizeof (struct tchars));
362*9578Ssam 		break;
363*9578Ssam 
364*9578Ssam 	case TIOCGETC:
365*9578Ssam 		bcopy((caddr_t)&tp->t_intrc, data, sizeof (struct tchars));
366*9578Ssam 		break;
367*9578Ssam 
368*9578Ssam /* BEGIN DEFUNCT */
3697625Ssam 	case FIONBIO:
3707625Ssam 		if (*(int *)data)
3715408Swnj 			tp->t_state |= TS_NBIO;
3725408Swnj 		else
3735408Swnj 			tp->t_state &= ~TS_NBIO;
3745408Swnj 		break;
3755408Swnj 
376*9578Ssam 	/* set/get local special characters */
377*9578Ssam 	case TIOCSLTC:
378*9578Ssam 		bcopy(data, (caddr_t)&tp->t_suspc, sizeof (struct ltchars));
3796216Swnj 		break;
3806216Swnj 
381*9578Ssam 	case TIOCGLTC:
382*9578Ssam 		bcopy((caddr_t)&tp->t_suspc, data, sizeof (struct ltchars));
38339Sbill 		break;
38439Sbill 
385*9578Ssam 	/*
386*9578Ssam 	 * Modify local mode word.
387*9578Ssam 	 */
388*9578Ssam 	case TIOCLBIS:
389*9578Ssam 		tp->t_flags |= *(int *)data << 16;
39039Sbill 		break;
39139Sbill 
392*9578Ssam 	case TIOCLBIC:
393*9578Ssam 		tp->t_flags &= ~(*(int *)data << 16);
394174Sbill 		break;
395174Sbill 
396*9578Ssam 	case TIOCLSET:
397*9578Ssam 		tp->t_flags &= 0xffff;
398*9578Ssam 		tp->t_flags |= *(int *)data << 16;
399174Sbill 		break;
400174Sbill 
401*9578Ssam 	case TIOCLGET:
402*9578Ssam 		*(int *)data = tp->t_flags >> 16;
403*9578Ssam 		break;
404*9578Ssam /* END DEFUNCT */
405*9578Ssam 
4068556Sroot 	/* return number of characters immediately available */
4077625Ssam 	case FIONREAD:
4087625Ssam 		*(off_t *)data = ttnread(tp);
409174Sbill 		break;
410174Sbill 
4118556Sroot 	/* should allow SPGRP and GPGRP only if tty open for reading */
412174Sbill 	case TIOCSPGRP:
4137625Ssam 		tp->t_pgrp = *(int *)data;
414174Sbill 		break;
415174Sbill 
416174Sbill 	case TIOCGPGRP:
4177625Ssam 		*(int *)data = tp->t_pgrp;
418174Sbill 		break;
419174Sbill 
4208589Sroot 	case TIOCSTOP:
4218589Sroot 		s = spl5();
422*9578Ssam 		if ((tp->t_state&TS_TTSTOP) == 0) {
4235573Swnj 			tp->t_state |= TS_TTSTOP;
4245573Swnj 			(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
4255573Swnj 		}
4267625Ssam 		splx(s);
4275573Swnj 		break;
4285573Swnj 
4298589Sroot 	case TIOCSTART:
4308589Sroot 		s = spl5();
431*9578Ssam 		if ((tp->t_state&TS_TTSTOP) || (tp->t_flags&FLUSHO)) {
4325573Swnj 			tp->t_state &= ~TS_TTSTOP;
433*9578Ssam 			tp->t_flags &= ~FLUSHO;
4345573Swnj 			ttstart(tp);
4355573Swnj 		}
4367625Ssam 		splx(s);
4375573Swnj 		break;
4385573Swnj 
4399325Ssam 	/*
4409325Ssam 	 * Simulate typing of a character at the terminal.
4419325Ssam 	 */
4429325Ssam 	case TIOCSTI:
4439325Ssam 		if (u.u_uid && u.u_ttyp != tp)
4449325Ssam 			return (EACCES);
445*9578Ssam 		(*linesw[tp->t_line].l_rint)(*(char *)data, tp);
4469325Ssam 		break;
4479325Ssam 
44839Sbill 	default:
4498556Sroot 		return (-1);
45039Sbill 	}
4518556Sroot 	return (0);
45239Sbill }
4534484Swnj 
4544484Swnj ttnread(tp)
4554484Swnj 	struct tty *tp;
4564484Swnj {
4574484Swnj 	int nread = 0;
4584484Swnj 
459*9578Ssam 	if (tp->t_flags & PENDIN)
4604484Swnj 		ttypend(tp);
4614484Swnj 	nread = tp->t_canq.c_cc;
4624484Swnj 	if (tp->t_flags & (RAW|CBREAK))
4634484Swnj 		nread += tp->t_rawq.c_cc;
4644484Swnj 	return (nread);
4654484Swnj }
4664484Swnj 
4675408Swnj ttselect(dev, rw)
4684484Swnj 	dev_t dev;
4695408Swnj 	int rw;
4704484Swnj {
4714484Swnj 	register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)];
4724484Swnj 	int nread;
4735408Swnj 	int s = spl5();
4744484Swnj 
4755408Swnj 	switch (rw) {
4764484Swnj 
4774484Swnj 	case FREAD:
4784484Swnj 		nread = ttnread(tp);
4794484Swnj 		if (nread > 0)
4805408Swnj 			goto win;
4814938Swnj 		if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait)
4825408Swnj 			tp->t_state |= TS_RCOLL;
4834484Swnj 		else
4844484Swnj 			tp->t_rsel = u.u_procp;
4855408Swnj 		break;
4864484Swnj 
4875408Swnj 	case FWRITE:
4885408Swnj 		if (tp->t_outq.c_cc <= TTLOWAT(tp))
4895408Swnj 			goto win;
4905408Swnj 		if (tp->t_wsel && tp->t_wsel->p_wchan == (caddr_t)&selwait)
4915408Swnj 			tp->t_state |= TS_WCOLL;
4925408Swnj 		else
4935408Swnj 			tp->t_wsel = u.u_procp;
4945408Swnj 		break;
4954484Swnj 	}
4965408Swnj 	splx(s);
4975408Swnj 	return (0);
4985408Swnj win:
4995408Swnj 	splx(s);
5005408Swnj 	return (1);
5014484Swnj }
5027436Skre 
5037502Sroot /*
504*9578Ssam  * Establish a process group for distribution of
5057502Sroot  * quits and interrupts from the tty.
5067502Sroot  */
5077502Sroot ttyopen(dev, tp)
5087625Ssam 	dev_t dev;
5097625Ssam 	register struct tty *tp;
5107502Sroot {
5117502Sroot 	register struct proc *pp;
5127502Sroot 
5137502Sroot 	pp = u.u_procp;
5147502Sroot 	tp->t_dev = dev;
5157625Ssam 	if (pp->p_pgrp == 0) {
5167502Sroot 		u.u_ttyp = tp;
5177502Sroot 		u.u_ttyd = dev;
5187502Sroot 		if (tp->t_pgrp == 0)
5197502Sroot 			tp->t_pgrp = pp->p_pid;
5207502Sroot 		pp->p_pgrp = tp->t_pgrp;
5217502Sroot 	}
5227502Sroot 	tp->t_state &= ~TS_WOPEN;
5237502Sroot 	tp->t_state |= TS_ISOPEN;
5247502Sroot 	if (tp->t_line != NTTYDISC)
5257502Sroot 		wflushtty(tp);
5268556Sroot 	return (0);
5277502Sroot }
5287502Sroot 
5297502Sroot /*
5307502Sroot  * clean tp on last close
5317502Sroot  */
5327502Sroot ttyclose(tp)
5337625Ssam 	register struct tty *tp;
5347502Sroot {
5357502Sroot 
5367502Sroot 	if (tp->t_line) {
5377502Sroot 		wflushtty(tp);
5387502Sroot 		tp->t_line = 0;
5397502Sroot 		return;
5407502Sroot 	}
5417502Sroot 	tp->t_pgrp = 0;
5427502Sroot 	wflushtty(tp);
5437502Sroot 	tp->t_state = 0;
5447502Sroot }
5457502Sroot 
5467502Sroot /*
5477502Sroot  * reinput pending characters after state switch
5487502Sroot  * call at spl5().
5497502Sroot  */
5507502Sroot ttypend(tp)
5517625Ssam 	register struct tty *tp;
5527502Sroot {
5537502Sroot 	struct clist tq;
5547502Sroot 	register c;
5557502Sroot 
556*9578Ssam 	tp->t_flags &= ~PENDIN;
557*9578Ssam 	tp->t_state |= TS_TYPEN;
5587502Sroot 	tq = tp->t_rawq;
5597502Sroot 	tp->t_rawq.c_cc = 0;
5607502Sroot 	tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0;
5617502Sroot 	while ((c = getc(&tq)) >= 0)
5627502Sroot 		ttyinput(c, tp);
563*9578Ssam 	tp->t_state &= ~TS_TYPEN;
5647502Sroot }
5657502Sroot 
5667502Sroot /*
567*9578Ssam  * Place a character on raw TTY input queue,
568*9578Ssam  * putting in delimiters and waking up top
569*9578Ssam  * half as needed.  Also echo if required.
570*9578Ssam  * The arguments are the character and the
571*9578Ssam  * appropriate tty structure.
5727502Sroot  */
5737502Sroot ttyinput(c, tp)
5747625Ssam 	register c;
5757625Ssam 	register struct tty *tp;
5767502Sroot {
577*9578Ssam 	register int t_flags = tp->t_flags;
5787502Sroot 	int i;
5797502Sroot 
580*9578Ssam 	/*
581*9578Ssam 	 * If input is pending take it first.
582*9578Ssam 	 */
583*9578Ssam 	if (t_flags&PENDIN)
5847502Sroot 		ttypend(tp);
5857502Sroot 	tk_nin++;
5867502Sroot 	c &= 0377;
587*9578Ssam 
588*9578Ssam 	/*
589*9578Ssam 	 * In tandem mode, check high water mark.
590*9578Ssam 	 */
5917502Sroot 	if (t_flags&TANDEM)
5927502Sroot 		ttyblock(tp);
593*9578Ssam 
594*9578Ssam 	if (t_flags&RAW) {
595*9578Ssam 		/*
596*9578Ssam 		 * Raw mode, just put character
597*9578Ssam 		 * in input q w/o interpretation.
598*9578Ssam 		 */
599*9578Ssam 		if (tp->t_rawq.c_cc > TTYHOG)
600*9578Ssam 			flushtty(tp, FREAD|FWRITE);
601*9578Ssam 		else {
602*9578Ssam 			if (putc(c, &tp->t_rawq) >= 0)
603*9578Ssam 				ttwakeup(tp);
604*9578Ssam 			ttyecho(c, tp);
6057502Sroot 		}
606*9578Ssam 		goto endcase;
607*9578Ssam 	}
608*9578Ssam 
609*9578Ssam 	/*
610*9578Ssam 	 * Ignore any high bit added during
611*9578Ssam 	 * previous ttyinput processing.
612*9578Ssam 	 */
613*9578Ssam 	if ((tp->t_state&TS_TYPEN) == 0)
614*9578Ssam 		c &= 0177;
615*9578Ssam 	/*
616*9578Ssam 	 * Check for literal nexting very first
617*9578Ssam 	 */
618*9578Ssam 	if (tp->t_state&TS_LNCH) {
619*9578Ssam 		c |= 0200;
620*9578Ssam 		tp->t_state &= ~TS_LNCH;
621*9578Ssam 	}
622*9578Ssam 
623*9578Ssam 	/*
624*9578Ssam 	 * Scan for special characters.  This code
625*9578Ssam 	 * is really just a big case statement with
626*9578Ssam 	 * non-constant cases.  The bottom of the
627*9578Ssam 	 * case statement is labeled ``endcase'', so goto
628*9578Ssam 	 * it after a case match, or similar.
629*9578Ssam 	 */
630*9578Ssam 	if (tp->t_line == NTTYDISC) {
631*9578Ssam 		if (c == tp->t_lnextc) {
6327502Sroot 			if (tp->t_flags&ECHO)
6337502Sroot 				ttyout("^\b", tp);
634*9578Ssam 			tp->t_state |= TS_LNCH;
635*9578Ssam 			goto endcase;
636*9578Ssam 		}
637*9578Ssam 		if (c == tp->t_flushc) {
638*9578Ssam 			if (tp->t_flags&FLUSHO)
639*9578Ssam 				tp->t_flags &= ~FLUSHO;
6407502Sroot 			else {
6417502Sroot 				flushtty(tp, FWRITE);
6427502Sroot 				ttyecho(c, tp);
643*9578Ssam 				if (tp->t_rawq.c_cc + tp->t_canq.c_cc)
6447502Sroot 					ttyretype(tp);
645*9578Ssam 				tp->t_flags |= FLUSHO;
6467502Sroot 			}
647*9578Ssam 			goto startoutput;
648*9578Ssam 		}
649*9578Ssam 		if (c == tp->t_suspc) {
650*9578Ssam 			if ((tp->t_flags&NOFLSH) == 0)
651*9578Ssam 				flushtty(tp, FREAD);
652*9578Ssam 			ttyecho(c, tp);
653*9578Ssam 			gsignal(tp->t_pgrp, SIGTSTP);
654*9578Ssam 			goto endcase;
655*9578Ssam 		}
656*9578Ssam 	}
657*9578Ssam 
658*9578Ssam 	/*
659*9578Ssam 	 * Handle start/stop characters.
660*9578Ssam 	 */
661*9578Ssam 	if (c == tp->t_stopc) {
662*9578Ssam 		if ((tp->t_state&TS_TTSTOP) == 0) {
663*9578Ssam 			tp->t_state |= TS_TTSTOP;
664*9578Ssam 			(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
6657502Sroot 			return;
666*9578Ssam 		}
667*9578Ssam 		if (c != tp->t_startc)
668*9578Ssam 			return;
669*9578Ssam 		goto endcase;
670*9578Ssam 	}
671*9578Ssam 	if (c == tp->t_startc)
672*9578Ssam 		goto restartoutput;
673*9578Ssam 
674*9578Ssam 	/*
675*9578Ssam 	 * Look for interrupt/quit chars.
676*9578Ssam 	 */
677*9578Ssam 	if (c == tp->t_intrc || c == tp->t_quitc) {
678*9578Ssam 		if ((tp->t_flags&NOFLSH) == 0)
679*9578Ssam 			flushtty(tp, FREAD|FWRITE);
680*9578Ssam 		ttyecho(c, tp);
681*9578Ssam 		gsignal(tp->t_pgrp, c == tp->t_intrc ? SIGINT : SIGQUIT);
682*9578Ssam 		goto endcase;
683*9578Ssam 	}
684*9578Ssam 
685*9578Ssam 	/*
686*9578Ssam 	 * Cbreak mode, don't process line editing
687*9578Ssam 	 * characters; check high water mark for wakeup.
688*9578Ssam 	 */
689*9578Ssam 	if (t_flags&CBREAK) {
690*9578Ssam 		if (tp->t_rawq.c_cc > TTYHOG) {
6917502Sroot 			if (tp->t_outq.c_cc < TTHIWAT(tp) &&
6927502Sroot 			    tp->t_line == NTTYDISC)
6937502Sroot 				(void) ttyoutput(CTRL(g), tp);
6947502Sroot 		} else if (putc(c, &tp->t_rawq) >= 0) {
6957502Sroot 			ttwakeup(tp);
6967502Sroot 			ttyecho(c, tp);
6977502Sroot 		}
698*9578Ssam 		goto endcase;
699*9578Ssam 	}
700*9578Ssam 
701*9578Ssam 	/*
702*9578Ssam 	 * From here on down cooked mode character
703*9578Ssam 	 * processing takes place.
704*9578Ssam 	 */
705*9578Ssam 	if ((tp->t_state&TS_QUOT) &&
706*9578Ssam 	    (c == tp->t_erase || c == tp->t_kill)) {
707*9578Ssam 		ttyrub(unputc(&tp->t_rawq), tp);
708*9578Ssam 		c |= 0200;
709*9578Ssam 	}
710*9578Ssam 	if (c == tp->t_erase) {
711*9578Ssam 		if (tp->t_rawq.c_cc)
712*9578Ssam 			ttyrub(unputc(&tp->t_rawq), tp);
713*9578Ssam 		goto endcase;
714*9578Ssam 	}
715*9578Ssam 	if (c == tp->t_kill) {
716*9578Ssam 		if (tp->t_flags&CRTKIL &&
717*9578Ssam 		    tp->t_rawq.c_cc == tp->t_rocount) {
718*9578Ssam 			while (tp->t_rawq.c_cc)
719*9578Ssam 				ttyrub(unputc(&tp->t_rawq), tp);
720*9578Ssam 		} else {
721*9578Ssam 			ttyecho(c, tp);
722*9578Ssam 			ttyecho('\n', tp);
723*9578Ssam 			while (getc(&tp->t_rawq) > 0)
724*9578Ssam 				;
725*9578Ssam 			tp->t_rocount = 0;
726*9578Ssam 		}
727*9578Ssam 		tp->t_state &= ~TS_LOCAL;
728*9578Ssam 		goto endcase;
729*9578Ssam 	}
730*9578Ssam 
731*9578Ssam 	/*
732*9578Ssam 	 * New line discipline,
733*9578Ssam 	 * check word erase/reprint line.
734*9578Ssam 	 */
735*9578Ssam 	if (tp->t_line == NTTYDISC) {
736*9578Ssam 		if (c == tp->t_werasc) {
737*9578Ssam 			if (tp->t_rawq.c_cc == 0)
738*9578Ssam 				goto endcase;
739*9578Ssam 			do {
740*9578Ssam 				c = unputc(&tp->t_rawq);
741*9578Ssam 				if (c != ' ' && c != '\t')
742*9578Ssam 					goto erasenb;
743*9578Ssam 				ttyrub(c, tp);
744*9578Ssam 			} while (tp->t_rawq.c_cc);
745*9578Ssam 			goto endcase;
746*9578Ssam 	erasenb:
747*9578Ssam 			do {
748*9578Ssam 				ttyrub(c, tp);
749*9578Ssam 				if (tp->t_rawq.c_cc == 0)
750*9578Ssam 					goto endcase;
751*9578Ssam 				c = unputc(&tp->t_rawq);
752*9578Ssam 			} while (c != ' ' && c != '\t');
753*9578Ssam 			(void) putc(c, &tp->t_rawq);
754*9578Ssam 			goto endcase;
755*9578Ssam 		}
756*9578Ssam 		if (c == tp->t_rprntc) {
757*9578Ssam 			ttyretype(tp);
758*9578Ssam 			goto endcase;
759*9578Ssam 		}
760*9578Ssam 	}
761*9578Ssam 
762*9578Ssam 	/*
763*9578Ssam 	 * Check for input buffer overflow
764*9578Ssam 	 */
765*9578Ssam 	if (tp->t_rawq.c_cc+tp->t_canq.c_cc >= TTYHOG)
766*9578Ssam 		goto endcase;
767*9578Ssam 
768*9578Ssam 	/*
769*9578Ssam 	 * Put data char in q for user and
770*9578Ssam 	 * wakeup on seeing a line delimiter.
771*9578Ssam 	 */
772*9578Ssam 	if (putc(c, &tp->t_rawq) >= 0) {
773*9578Ssam 		if (tp->t_rawq.c_cc + tp->t_canq.c_cc == TTYHOG
774*9578Ssam 		    && tp->t_line == NTTYDISC)
775*9578Ssam 			(void) ttyoutput(CTRL(g), tp);
776*9578Ssam 		if (ttbreakc(c, tp)) {
777*9578Ssam 			tp->t_rocount = 0;
778*9578Ssam 			catq(&tp->t_rawq, &tp->t_canq);
7797502Sroot 			ttwakeup(tp);
780*9578Ssam 		} else if (tp->t_rocount++ == 0)
781*9578Ssam 			tp->t_rocol = tp->t_col;
782*9578Ssam 		tp->t_state &= ~TS_QUOT;
783*9578Ssam 		if (c == '\\')
784*9578Ssam 			tp->t_state |= TS_QUOT;
785*9578Ssam 		if (tp->t_state&TS_ERASE) {
786*9578Ssam 			tp->t_state &= ~TS_ERASE;
787*9578Ssam 			(void) ttyoutput('/', tp);
788*9578Ssam 		}
789*9578Ssam 		i = tp->t_col;
7907502Sroot 		ttyecho(c, tp);
791*9578Ssam 		if (c == tp->t_eofc && tp->t_flags&ECHO) {
792*9578Ssam 			i = MIN(2, tp->t_col - i);
793*9578Ssam 			while (i > 0) {
794*9578Ssam 				(void) ttyoutput('\b', tp);
795*9578Ssam 				i--;
796*9578Ssam 			}
797*9578Ssam 		}
7987502Sroot 	}
799*9578Ssam 
800*9578Ssam endcase:
801*9578Ssam 	/*
802*9578Ssam 	 * If DEC-style start/stop is enabled don't restart
803*9578Ssam 	 * output until seeing the start character.
804*9578Ssam 	 */
805*9578Ssam 	if (tp->t_flags&DECCTQ && tp->t_state&TS_TTSTOP &&
806*9578Ssam 	    tp->t_startc != tp->t_stopc)
8077502Sroot 		return;
808*9578Ssam 
809*9578Ssam restartoutput:
8107502Sroot 	tp->t_state &= ~TS_TTSTOP;
811*9578Ssam 	tp->t_flags &= ~FLUSHO;
812*9578Ssam 
813*9578Ssam startoutput:
8147502Sroot 	ttstart(tp);
8157502Sroot }
8167502Sroot 
8177502Sroot /*
818*9578Ssam  * Put character on TTY output queue, adding delays,
8197502Sroot  * expanding tabs, and handling the CR/NL bit.
820*9578Ssam  * This is called both from the top half for output,
821*9578Ssam  * and from interrupt level for echoing.
8227502Sroot  * The arguments are the character and the tty structure.
8237502Sroot  * Returns < 0 if putc succeeds, otherwise returns char to resend
8247502Sroot  * Must be recursive.
8257502Sroot  */
8267502Sroot ttyoutput(c, tp)
8277502Sroot 	register c;
8287502Sroot 	register struct tty *tp;
8297502Sroot {
8307502Sroot 	register char *colp;
8317502Sroot 	register ctype;
8327502Sroot 
833*9578Ssam 	if (tp->t_flags & (RAW|LITOUT)) {
834*9578Ssam 		if (tp->t_flags&FLUSHO)
8357502Sroot 			return (-1);
8367502Sroot 		if (putc(c, &tp->t_outq))
8377625Ssam 			return (c);
8387502Sroot 		tk_nout++;
8397502Sroot 		return (-1);
8407502Sroot 	}
841*9578Ssam 
8427502Sroot 	/*
843*9578Ssam 	 * Ignore EOT in normal mode to avoid
844*9578Ssam 	 * hanging up certain terminals.
8457502Sroot 	 */
8467502Sroot 	c &= 0177;
847*9578Ssam 	if (c == CEOT && (tp->t_flags&CBREAK) == 0)
8487502Sroot 		return (-1);
8497502Sroot 	/*
8507502Sroot 	 * Turn tabs to spaces as required
8517502Sroot 	 */
852*9578Ssam 	if (c == '\t' && (tp->t_flags&TBDELAY) == XTABS) {
8537502Sroot 		register int s;
8547502Sroot 
8557502Sroot 		c = 8 - (tp->t_col&7);
856*9578Ssam 		if ((tp->t_flags&FLUSHO) == 0) {
8577502Sroot 			s = spl5();		/* don't interrupt tabs */
8587502Sroot 			c -= b_to_q("        ", c, &tp->t_outq);
8597502Sroot 			tk_nout += c;
8607502Sroot 			splx(s);
8617502Sroot 		}
8627502Sroot 		tp->t_col += c;
8637502Sroot 		return (c ? -1 : '\t');
8647502Sroot 	}
8657502Sroot 	tk_nout++;
8667502Sroot 	/*
8677502Sroot 	 * for upper-case-only terminals,
8687502Sroot 	 * generate escapes.
8697502Sroot 	 */
8707502Sroot 	if (tp->t_flags&LCASE) {
8717502Sroot 		colp = "({)}!|^~'`";
8727625Ssam 		while (*colp++)
8737625Ssam 			if (c == *colp++) {
8747502Sroot 				if (ttyoutput('\\', tp) >= 0)
8757502Sroot 					return (c);
8767502Sroot 				c = colp[-2];
8777502Sroot 				break;
8787502Sroot 			}
879*9578Ssam 		if ('A' <= c && c <= 'Z') {
8807502Sroot 			if (ttyoutput('\\', tp) >= 0)
8817502Sroot 				return (c);
882*9578Ssam 		} else if ('a' <= c && c <= 'z')
8837502Sroot 			c += 'A' - 'a';
8847502Sroot 	}
885*9578Ssam 
8867502Sroot 	/*
8877502Sroot 	 * turn <nl> to <cr><lf> if desired.
8887502Sroot 	 */
889*9578Ssam 	if (c == '\n' && tp->t_flags&CRMOD)
8907502Sroot 		if (ttyoutput('\r', tp) >= 0)
8917502Sroot 			return (c);
892*9578Ssam 	if (c == '~' && tp->t_flags&TILDE)
8937502Sroot 		c = '`';
894*9578Ssam 	if ((tp->t_flags&FLUSHO) == 0 && putc(c, &tp->t_outq))
8957502Sroot 		return (c);
8967502Sroot 	/*
8977502Sroot 	 * Calculate delays.
8987502Sroot 	 * The numbers here represent clock ticks
8997502Sroot 	 * and are not necessarily optimal for all terminals.
9007502Sroot 	 * The delays are indicated by characters above 0200.
9017502Sroot 	 * In raw mode there are no delays and the
9027502Sroot 	 * transmission path is 8 bits wide.
903*9578Ssam 	 *
904*9578Ssam 	 * SHOULD JUST ALLOW USER TO SPECIFY DELAYS
9057502Sroot 	 */
9067502Sroot 	colp = &tp->t_col;
9077502Sroot 	ctype = partab[c];
9087502Sroot 	c = 0;
9097502Sroot 	switch (ctype&077) {
9107502Sroot 
9117502Sroot 	case ORDINARY:
9127502Sroot 		(*colp)++;
9137502Sroot 
9147502Sroot 	case CONTROL:
9157502Sroot 		break;
9167502Sroot 
9177502Sroot 	case BACKSPACE:
9187502Sroot 		if (*colp)
9197502Sroot 			(*colp)--;
9207502Sroot 		break;
9217502Sroot 
9227502Sroot 	case NEWLINE:
9237502Sroot 		ctype = (tp->t_flags >> 8) & 03;
9247625Ssam 		if (ctype == 1) { /* tty 37 */
9257502Sroot 			if (*colp)
9267502Sroot 				c = max(((unsigned)*colp>>4) + 3, (unsigned)6);
927*9578Ssam 		} else if (ctype == 2) /* vt05 */
9287502Sroot 			c = 6;
9297502Sroot 		*colp = 0;
9307502Sroot 		break;
9317502Sroot 
9327502Sroot 	case TAB:
9337502Sroot 		ctype = (tp->t_flags >> 10) & 03;
9347625Ssam 		if (ctype == 1) { /* tty 37 */
9357502Sroot 			c = 1 - (*colp | ~07);
9367625Ssam 			if (c < 5)
9377502Sroot 				c = 0;
9387502Sroot 		}
9397502Sroot 		*colp |= 07;
9407502Sroot 		(*colp)++;
9417502Sroot 		break;
9427502Sroot 
9437502Sroot 	case VTAB:
944*9578Ssam 		if (tp->t_flags&VTDELAY) /* tty 37 */
9457502Sroot 			c = 0177;
9467502Sroot 		break;
9477502Sroot 
9487502Sroot 	case RETURN:
9497502Sroot 		ctype = (tp->t_flags >> 12) & 03;
950*9578Ssam 		if (ctype == 1) /* tn 300 */
9517502Sroot 			c = 5;
952*9578Ssam 		else if (ctype == 2) /* ti 700 */
9537502Sroot 			c = 10;
954*9578Ssam 		else if (ctype == 3) { /* concept 100 */
9557502Sroot 			int i;
956*9578Ssam 
9577502Sroot 			if ((i = *colp) >= 0)
958*9578Ssam 				for (; i < 9; i++)
9597502Sroot 					(void) putc(0177, &tp->t_outq);
9607502Sroot 		}
9617502Sroot 		*colp = 0;
9627502Sroot 	}
963*9578Ssam 	if (c && (tp->t_flags&FLUSHO) == 0)
9647502Sroot 		(void) putc(c|0200, &tp->t_outq);
9657502Sroot 	return (-1);
9667502Sroot }
9677502Sroot 
9687502Sroot /*
9697502Sroot  * Called from device's read routine after it has
9707502Sroot  * calculated the tty-structure given as argument.
9717502Sroot  */
9727722Swnj ttread(tp, uio)
9737625Ssam 	register struct tty *tp;
9747722Swnj 	struct uio *uio;
9757502Sroot {
9767502Sroot 	register struct clist *qp;
977*9578Ssam 	register c, t_flags;
978*9578Ssam 	int first, error = 0;
9797502Sroot 
9807502Sroot 	if ((tp->t_state&TS_CARR_ON)==0)
9818520Sroot 		return (EIO);
9827502Sroot loop:
983*9578Ssam 	/*
984*9578Ssam 	 * Take any pending input first.
985*9578Ssam 	 */
9867502Sroot 	(void) spl5();
987*9578Ssam 	if (tp->t_flags&PENDIN)
9887502Sroot 		ttypend(tp);
9897502Sroot 	(void) spl0();
990*9578Ssam 
991*9578Ssam 	/*
992*9578Ssam 	 * Hang process if it's in the background.
993*9578Ssam 	 */
9947502Sroot 	while (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) {
9957502Sroot 		if (u.u_signal[SIGTTIN] == SIG_IGN ||
9967502Sroot 		    u.u_signal[SIGTTIN] == SIG_HOLD ||
9977502Sroot /*
9987502Sroot 		    (u.u_procp->p_flag&SDETACH) ||
9997502Sroot */
10007502Sroot 		    u.u_procp->p_flag&SVFORK)
10018520Sroot 			return (EIO);
10027502Sroot 		gsignal(u.u_procp->p_pgrp, SIGTTIN);
10037502Sroot 		sleep((caddr_t)&lbolt, TTIPRI);
10047502Sroot 	}
1005*9578Ssam 	t_flags = tp->t_flags;
1006*9578Ssam 
1007*9578Ssam 	/*
1008*9578Ssam 	 * In raw mode take characters directly from the
1009*9578Ssam 	 * raw queue w/o processing.  Interlock against
1010*9578Ssam 	 * device interrupts when interrogating rawq.
1011*9578Ssam 	 */
1012*9578Ssam 	if (t_flags&RAW) {
10137502Sroot 		(void) spl5();
10147502Sroot 		if (tp->t_rawq.c_cc <= 0) {
1015*9578Ssam 			if ((tp->t_state&TS_CARR_ON) == 0 ||
10167502Sroot 			    (tp->t_state&TS_NBIO)) {
10177502Sroot 				(void) spl0();
1018*9578Ssam 				return (0);
10197502Sroot 			}
10207502Sroot 			sleep((caddr_t)&tp->t_rawq, TTIPRI);
10217502Sroot 			(void) spl0();
10227502Sroot 			goto loop;
10237502Sroot 		}
10247502Sroot 		(void) spl0();
10257722Swnj 		while (tp->t_rawq.c_cc && uio->uio_iovcnt) {
10268520Sroot 			error = passuc(getc(&tp->t_rawq), uio);
10278520Sroot 			if (error)
10287722Swnj 				break;
10297722Swnj 		}
10308520Sroot 		return (error);
1031*9578Ssam 	}
1032*9578Ssam 
1033*9578Ssam 	/*
1034*9578Ssam 	 * In cbreak mode use the rawq, otherwise
1035*9578Ssam 	 * take characters from the canonicalized q.
1036*9578Ssam 	 */
1037*9578Ssam 	qp = t_flags&CBREAK ? &tp->t_rawq : &tp->t_canq;
1038*9578Ssam 
1039*9578Ssam 	/*
1040*9578Ssam 	 * No input, sleep on rawq awaiting hardware
1041*9578Ssam 	 * receipt and notification.
1042*9578Ssam 	 */
1043*9578Ssam 	(void) spl5();
1044*9578Ssam 	if (qp->c_cc <= 0) {
1045*9578Ssam 		if ((tp->t_state&TS_CARR_ON) == 0 ||
1046*9578Ssam 		    (tp->t_state&TS_NBIO)) {
10477502Sroot 			(void) spl0();
1048*9578Ssam 			return (EWOULDBLOCK);
10497502Sroot 		}
1050*9578Ssam 		sleep((caddr_t)&tp->t_rawq, TTIPRI);
10517502Sroot 		(void) spl0();
1052*9578Ssam 		goto loop;
1053*9578Ssam 	}
1054*9578Ssam 	(void) spl0();
1055*9578Ssam 
1056*9578Ssam 	/*
1057*9578Ssam 	 * Input present, perform input mapping
1058*9578Ssam 	 * and processing (we're not in raw mode).
1059*9578Ssam 	 */
1060*9578Ssam 	first = 1;
1061*9578Ssam 	while ((c = getc(qp)) >= 0) {
1062*9578Ssam 		if (t_flags&CRMOD && c == '\r')
1063*9578Ssam 			c = '\n';
1064*9578Ssam 		/*
1065*9578Ssam 		 * Hack lower case simulation on
1066*9578Ssam 		 * upper case only terminals.
1067*9578Ssam 		 */
1068*9578Ssam 		if (t_flags&LCASE && c <= 0177)
1069*9578Ssam 			if (tp->t_state&TS_BKSL) {
1070*9578Ssam 				if (maptab[c])
1071*9578Ssam 					c = maptab[c];
1072*9578Ssam 				tp->t_state &= ~TS_BKSL;
1073*9578Ssam 			} else if (c >= 'A' && c <= 'Z')
1074*9578Ssam 				c += 'a' - 'A';
1075*9578Ssam 			else if (c == '\\') {
1076*9578Ssam 				tp->t_state |= TS_BKSL;
1077*9578Ssam 				continue;
10787502Sroot 			}
1079*9578Ssam 		/*
1080*9578Ssam 		 * Check for delayed suspend character.
1081*9578Ssam 		 */
1082*9578Ssam 		if (tp->t_line == NTTYDISC && c == tp->t_dsuspc) {
1083*9578Ssam 			gsignal(tp->t_pgrp, SIGTSTP);
1084*9578Ssam 			if (first) {
1085*9578Ssam 				sleep((caddr_t)&lbolt, TTIPRI);
1086*9578Ssam 				goto loop;
1087*9578Ssam 			}
1088*9578Ssam 			break;
10897502Sroot 		}
1090*9578Ssam 		/*
1091*9578Ssam 		 * Interpret EOF only in cooked mode.
1092*9578Ssam 		 */
1093*9578Ssam 		if (c == tp->t_eofc && (t_flags&CBREAK) == 0)
1094*9578Ssam 			break;
1095*9578Ssam 		/*
1096*9578Ssam 		 * Give user character.
1097*9578Ssam 		 */
1098*9578Ssam 		error = passuc(c & 0177, uio);
1099*9578Ssam 		if (error)
1100*9578Ssam 			break;
1101*9578Ssam 		if (uio->uio_iovcnt == 0)
1102*9578Ssam 			break;
1103*9578Ssam 		/*
1104*9578Ssam 		 * In cooked mode check for a "break character"
1105*9578Ssam 		 * marking the end of a "line of input".
1106*9578Ssam 		 */
1107*9578Ssam 		if ((t_flags&CBREAK) == 0 && ttbreakc(c, tp))
1108*9578Ssam 			break;
1109*9578Ssam 		first = 0;
11107502Sroot 	}
1111*9578Ssam 	tp->t_state &= ~TS_BKSL;
1112*9578Ssam 
1113*9578Ssam 	/*
1114*9578Ssam 	 * Look to unblock output now that (presumably)
1115*9578Ssam 	 * the input queue has gone down.
1116*9578Ssam 	 */
11177502Sroot 	if (tp->t_state&TS_TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) {
1118*9578Ssam 		if (putc(tp->t_startc, &tp->t_outq) == 0) {
11197502Sroot 			tp->t_state &= ~TS_TBLOCK;
11207502Sroot 			ttstart(tp);
11217502Sroot 		}
11227502Sroot 		tp->t_char = 0;
11237502Sroot 	}
11248520Sroot 	return (error);
11257502Sroot }
11267502Sroot 
11277502Sroot /*
11287502Sroot  * Called from the device's write routine after it has
11297502Sroot  * calculated the tty-structure given as argument.
11307502Sroot  */
11317822Sroot ttwrite(tp, uio)
11327625Ssam 	register struct tty *tp;
1133*9578Ssam 	register struct uio *uio;
11347502Sroot {
11357502Sroot 	register char *cp;
1136*9578Ssam 	register int cc, ce, c;
1137*9578Ssam 	int i, hiwat, cnt, error, s;
11387502Sroot 	char obuf[OBUFSIZ];
11397502Sroot 
1140*9578Ssam 	if ((tp->t_state&TS_CARR_ON) == 0)
11418520Sroot 		return (EIO);
1142*9578Ssam 	hiwat = TTHIWAT(tp);
1143*9578Ssam 	cnt = uio->uio_resid;
1144*9578Ssam 	error = 0;
11457502Sroot loop:
1146*9578Ssam 	/*
1147*9578Ssam 	 * Hang the process if it's in the background.
1148*9578Ssam 	 */
11497502Sroot 	while (u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp &&
1150*9578Ssam 	    (tp->t_flags&TOSTOP) && (u.u_procp->p_flag&SVFORK)==0 &&
11517502Sroot 	    u.u_signal[SIGTTOU] != SIG_IGN &&
11527502Sroot 	    u.u_signal[SIGTTOU] != SIG_HOLD
11537502Sroot /*
11547502Sroot 					     &&
11557502Sroot 	    (u.u_procp->p_flag&SDETACH)==0) {
11567502Sroot */
11577502Sroot 	    ) {
11587502Sroot 		gsignal(u.u_procp->p_pgrp, SIGTTOU);
11597502Sroot 		sleep((caddr_t)&lbolt, TTIPRI);
11607502Sroot 	}
1161*9578Ssam 
1162*9578Ssam 	/*
1163*9578Ssam 	 * Process the user's data in at most OBUFSIZ
1164*9578Ssam 	 * chunks.  Perform lower case simulation and
1165*9578Ssam 	 * similar hacks.  Keep track of high water
1166*9578Ssam 	 * mark, sleep on overflow awaiting device aid
1167*9578Ssam 	 * in acquiring new space.
1168*9578Ssam 	 */
11697822Sroot 	while (uio->uio_resid > 0) {
1170*9578Ssam 		/*
1171*9578Ssam 		 * Grab a hunk of data from the user.
1172*9578Ssam 		 */
11737822Sroot 		cc = uio->uio_iov->iov_len;
11747822Sroot 		if (cc == 0) {
11757822Sroot 			uio->uio_iovcnt--;
11767822Sroot 			uio->uio_iov++;
11777822Sroot 			if (uio->uio_iovcnt < 0)
11787822Sroot 				panic("ttwrite");
11797822Sroot 			continue;
11807822Sroot 		}
11817822Sroot 		if (cc > OBUFSIZ)
11827822Sroot 			cc = OBUFSIZ;
11837502Sroot 		cp = obuf;
1184*9578Ssam 		error = uiomove(cp, (unsigned)cc, UIO_WRITE, uio);
11858520Sroot 		if (error)
11867502Sroot 			break;
11877502Sroot 		if (tp->t_outq.c_cc > hiwat)
11887502Sroot 			goto ovhiwat;
1189*9578Ssam 		if (tp->t_flags&FLUSHO)
11907502Sroot 			continue;
1191*9578Ssam 		/*
1192*9578Ssam 		 * If we're mapping lower case or kludging tildes,
1193*9578Ssam 		 * then we've got to look at each character, so
1194*9578Ssam 		 * just feed the stuff to ttyoutput...
1195*9578Ssam 		 */
1196*9578Ssam 		if (tp->t_flags & (LCASE|TILDE)) {
1197*9578Ssam 			while (cc > 0) {
11987502Sroot 				c = *cp++;
11997502Sroot 				tp->t_rocount = 0;
12007625Ssam 				while ((c = ttyoutput(c, tp)) >= 0) {
12017502Sroot 					/* out of clists, wait a bit */
12027502Sroot 					ttstart(tp);
12037502Sroot 					sleep((caddr_t)&lbolt, TTOPRI);
12047502Sroot 					tp->t_rocount = 0;
12057502Sroot 				}
12067502Sroot 				--cc;
12077502Sroot 				if (tp->t_outq.c_cc > hiwat)
12087502Sroot 					goto ovhiwat;
12097502Sroot 			}
12107502Sroot 			continue;
12117502Sroot 		}
1212*9578Ssam 		/*
1213*9578Ssam 		 * If nothing fancy need be done, grab those characters we
1214*9578Ssam 		 * can handle without any of ttyoutput's processing and
1215*9578Ssam 		 * just transfer them to the output q.  For those chars
1216*9578Ssam 		 * which require special processing (as indicated by the
1217*9578Ssam 		 * bits in partab), call ttyoutput.  After processing
1218*9578Ssam 		 * a hunk of data, look for FLUSHO so ^O's will take effect
1219*9578Ssam 		 * immediately.
1220*9578Ssam 		 */
1221*9578Ssam 		while (cc > 0) {
1222*9578Ssam 			if (tp->t_flags & (RAW|LITOUT))
12237502Sroot 				ce = cc;
12247502Sroot 			else {
1225*9578Ssam 				ce = cc - scanc(cc, cp, partab, 077);
1226*9578Ssam 				/*
1227*9578Ssam 				 * If ce is zero, then we're processing
1228*9578Ssam 				 * a special character through ttyoutput.
1229*9578Ssam 				 */
1230*9578Ssam 				if (ce == 0) {
12317502Sroot 					tp->t_rocount = 0;
12327502Sroot 					if (ttyoutput(*cp, tp) >= 0) {
1233*9578Ssam 						/* no c-lists, wait a bit */
12347502Sroot 						ttstart(tp);
12357502Sroot 						sleep((caddr_t)&lbolt, TTOPRI);
12367502Sroot 						continue;
12377502Sroot 					}
1238*9578Ssam 					cp++, cc--;
1239*9578Ssam 					if (tp->t_flags&FLUSHO ||
1240*9578Ssam 					    tp->t_outq.c_cc > hiwat)
12417502Sroot 						goto ovhiwat;
1242*9578Ssam 					continue;
12437502Sroot 				}
12447502Sroot 			}
1245*9578Ssam 			/*
1246*9578Ssam 			 * A bunch of normal characters have been found,
1247*9578Ssam 			 * transfer them en masse to the output queue and
1248*9578Ssam 			 * continue processing at the top of the loop.
1249*9578Ssam 			 * If there are any further characters in this
1250*9578Ssam 			 * <= OBUFSIZ chunk, the first should be a character
1251*9578Ssam 			 * requiring special handling by ttyoutput.
1252*9578Ssam 			 */
12537502Sroot 			tp->t_rocount = 0;
1254*9578Ssam 			i = b_to_q(cp, ce, &tp->t_outq);
1255*9578Ssam 			ce -= i;
1256*9578Ssam 			tp->t_col += ce;
1257*9578Ssam 			cp += ce, cc -= ce, tk_nout += ce;
1258*9578Ssam 			if (i > 0) {
1259*9578Ssam 				/* out of c-lists, wait a bit */
12607502Sroot 				ttstart(tp);
12617502Sroot 				sleep((caddr_t)&lbolt, TTOPRI);
12627502Sroot 			}
1263*9578Ssam 			if (tp->t_flags&FLUSHO || tp->t_outq.c_cc > hiwat)
12647502Sroot 				goto ovhiwat;
12657502Sroot 		}
12667502Sroot 	}
12677502Sroot 	ttstart(tp);
12688520Sroot 	return (error);
12697502Sroot 
12707502Sroot ovhiwat:
1271*9578Ssam 	s = spl5();
1272*9578Ssam 	if (cc != 0) {
1273*9578Ssam 		uio->uio_iov->iov_base -= cc;
1274*9578Ssam 		uio->uio_iov->iov_len += cc;
1275*9578Ssam 		uio->uio_resid += cc;
1276*9578Ssam 		uio->uio_offset -= cc;
1277*9578Ssam 	}
1278*9578Ssam 	/*
1279*9578Ssam 	 * This can only occur if FLUSHO
1280*9578Ssam 	 * is also set in t_flags.
1281*9578Ssam 	 */
12827502Sroot 	if (tp->t_outq.c_cc <= hiwat) {
1283*9578Ssam 		splx(s);
12847502Sroot 		goto loop;
12857502Sroot 	}
12867502Sroot 	ttstart(tp);
1287*9578Ssam 	if (tp->t_state&TS_NBIO) {
12887822Sroot 		if (uio->uio_resid == cnt)
12898520Sroot 			return (EWOULDBLOCK);
12908520Sroot 		return (0);
12917502Sroot 	}
12927502Sroot 	tp->t_state |= TS_ASLEEP;
12937502Sroot 	sleep((caddr_t)&tp->t_outq, TTOPRI);
1294*9578Ssam 	splx(s);
12957502Sroot 	goto loop;
12967502Sroot }
12977502Sroot 
12987502Sroot /*
12997502Sroot  * Rubout one character from the rawq of tp
13007502Sroot  * as cleanly as possible.
13017502Sroot  */
13027502Sroot ttyrub(c, tp)
13037625Ssam 	register c;
13047625Ssam 	register struct tty *tp;
13057502Sroot {
13067502Sroot 	register char *cp;
13077502Sroot 	register int savecol;
13087502Sroot 	int s;
13097502Sroot 	char *nextc();
13107502Sroot 
1311*9578Ssam 	if ((tp->t_flags&ECHO) == 0)
13127502Sroot 		return;
1313*9578Ssam 	tp->t_flags &= ~FLUSHO;
13147502Sroot 	c &= 0377;
1315*9578Ssam 	if (tp->t_flags&CRTBS) {
13167502Sroot 		if (tp->t_rocount == 0) {
13177502Sroot 			/*
13187502Sroot 			 * Screwed by ttwrite; retype
13197502Sroot 			 */
13207502Sroot 			ttyretype(tp);
13217502Sroot 			return;
13227502Sroot 		}
1323*9578Ssam 		if (c == ('\t'|0200) || c == ('\n'|0200))
13247502Sroot 			ttyrubo(tp, 2);
1325*9578Ssam 		else switch (partab[c&=0177]&0177) {
13267502Sroot 
13277502Sroot 		case ORDINARY:
13287502Sroot 			if (tp->t_flags&LCASE && c >= 'A' && c <= 'Z')
13297502Sroot 				ttyrubo(tp, 2);
13307502Sroot 			else
13317502Sroot 				ttyrubo(tp, 1);
13327502Sroot 			break;
13337502Sroot 
13347502Sroot 		case VTAB:
13357502Sroot 		case BACKSPACE:
13367502Sroot 		case CONTROL:
13377502Sroot 		case RETURN:
1338*9578Ssam 			if (tp->t_flags&CTLECH)
13397502Sroot 				ttyrubo(tp, 2);
13407502Sroot 			break;
13417502Sroot 
13427502Sroot 		case TAB:
13437502Sroot 			if (tp->t_rocount < tp->t_rawq.c_cc) {
13447502Sroot 				ttyretype(tp);
13457502Sroot 				return;
13467502Sroot 			}
13477502Sroot 			s = spl5();
13487502Sroot 			savecol = tp->t_col;
1349*9578Ssam 			tp->t_state |= TS_CNTTB;
1350*9578Ssam 			tp->t_flags |= FLUSHO;
13517502Sroot 			tp->t_col = tp->t_rocol;
1352*9578Ssam 			cp = tp->t_rawq.c_cf;
1353*9578Ssam 			for (; cp; cp = nextc(&tp->t_rawq, cp))
13547502Sroot 				ttyecho(*cp, tp);
1355*9578Ssam 			tp->t_flags &= ~FLUSHO;
1356*9578Ssam 			tp->t_state &= ~TS_CNTTB;
13577502Sroot 			splx(s);
13587502Sroot 			/*
13597502Sroot 			 * savecol will now be length of the tab
13607502Sroot 			 */
13617502Sroot 			savecol -= tp->t_col;
13627502Sroot 			tp->t_col += savecol;
13637502Sroot 			if (savecol > 8)
13647502Sroot 				savecol = 8;		/* overflow screw */
13657502Sroot 			while (--savecol >= 0)
13667502Sroot 				(void) ttyoutput('\b', tp);
13677502Sroot 			break;
13687502Sroot 
13697502Sroot 		default:
13707502Sroot 			panic("ttyrub");
13717502Sroot 		}
1372*9578Ssam 	} else if (tp->t_flags&PRTERA) {
1373*9578Ssam 		if ((tp->t_state&TS_ERASE) == 0) {
13747502Sroot 			(void) ttyoutput('\\', tp);
1375*9578Ssam 			tp->t_state |= TS_ERASE;
13767502Sroot 		}
13777502Sroot 		ttyecho(c, tp);
13787502Sroot 	} else
13797502Sroot 		ttyecho(tp->t_erase, tp);
13807502Sroot 	tp->t_rocount--;
13817502Sroot }
13827502Sroot 
13837502Sroot /*
13847502Sroot  * Crt back over cnt chars perhaps
13857502Sroot  * erasing them.
13867502Sroot  */
13877502Sroot ttyrubo(tp, cnt)
13887625Ssam 	register struct tty *tp;
13897625Ssam 	int cnt;
13907502Sroot {
1391*9578Ssam 	register char *rubostring = tp->t_flags&CRTERA ? "\b \b" : "\b";
13927502Sroot 
13937502Sroot 	while (--cnt >= 0)
1394*9578Ssam 		ttyout(rubostring, tp);
13957502Sroot }
13967502Sroot 
13977502Sroot /*
13987502Sroot  * Reprint the rawq line.
13997502Sroot  * We assume c_cc has already been checked.
14007502Sroot  */
14017502Sroot ttyretype(tp)
14027625Ssam 	register struct tty *tp;
14037502Sroot {
14047502Sroot 	register char *cp;
14057502Sroot 	char *nextc();
14067502Sroot 	int s;
14077502Sroot 
1408*9578Ssam 	if (tp->t_rprntc != 0377)
1409*9578Ssam 		ttyecho(tp->t_rprntc, tp);
14107502Sroot 	(void) ttyoutput('\n', tp);
14117502Sroot 	s = spl5();
14127502Sroot 	for (cp = tp->t_canq.c_cf; cp; cp = nextc(&tp->t_canq, cp))
14137502Sroot 		ttyecho(*cp, tp);
14147502Sroot 	for (cp = tp->t_rawq.c_cf; cp; cp = nextc(&tp->t_rawq, cp))
14157502Sroot 		ttyecho(*cp, tp);
1416*9578Ssam 	tp->t_state &= ~TS_ERASE;
14177502Sroot 	splx(s);
14187502Sroot 	tp->t_rocount = tp->t_rawq.c_cc;
14197502Sroot 	tp->t_rocol = 0;
14207502Sroot }
14217502Sroot 
14227502Sroot /*
14237502Sroot  * Echo a typed character to the terminal
14247502Sroot  */
14257502Sroot ttyecho(c, tp)
14267625Ssam 	register c;
14277625Ssam 	register struct tty *tp;
14287502Sroot {
14297502Sroot 
1430*9578Ssam 	if ((tp->t_state&TS_CNTTB) == 0)
1431*9578Ssam 		tp->t_flags &= ~FLUSHO;
14327502Sroot 	if ((tp->t_flags&ECHO) == 0)
14337502Sroot 		return;
14347502Sroot 	c &= 0377;
14357502Sroot 	if (tp->t_flags&RAW) {
14367502Sroot 		(void) ttyoutput(c, tp);
14377502Sroot 		return;
14387502Sroot 	}
14397502Sroot 	if (c == '\r' && tp->t_flags&CRMOD)
14407502Sroot 		c = '\n';
1441*9578Ssam 	if (tp->t_flags&CTLECH) {
14427502Sroot 		if ((c&0177) <= 037 && c!='\t' && c!='\n' || (c&0177)==0177) {
14437502Sroot 			(void) ttyoutput('^', tp);
14447502Sroot 			c &= 0177;
14457502Sroot 			if (c == 0177)
14467502Sroot 				c = '?';
14477502Sroot 			else if (tp->t_flags&LCASE)
14487502Sroot 				c += 'a' - 1;
14497502Sroot 			else
14507502Sroot 				c += 'A' - 1;
14517502Sroot 		}
14527502Sroot 	}
14537502Sroot 	if ((tp->t_flags&LCASE) && (c >= 'A' && c <= 'Z'))
14547502Sroot 		c += 'a' - 'A';
1455*9578Ssam 	(void) ttyoutput(c&0177, tp);
14567502Sroot }
14577502Sroot 
14587502Sroot /*
14597502Sroot  * Is c a break char for tp?
14607502Sroot  */
14617502Sroot ttbreakc(c, tp)
14627625Ssam 	register c;
14637625Ssam 	register struct tty *tp;
14647502Sroot {
1465*9578Ssam 	return (c == '\n' || c == tp->t_eofc || c == tp->t_brkc ||
14667502Sroot 		c == '\r' && (tp->t_flags&CRMOD));
14677502Sroot }
14687502Sroot 
14697502Sroot /*
14707502Sroot  * send string cp to tp
14717502Sroot  */
14727502Sroot ttyout(cp, tp)
14737625Ssam 	register char *cp;
14747625Ssam 	register struct tty *tp;
14757502Sroot {
14767502Sroot 	register char c;
14777502Sroot 
14787502Sroot 	while (c = *cp++)
14797502Sroot 		(void) ttyoutput(c, tp);
14807502Sroot }
14817502Sroot 
14827502Sroot ttwakeup(tp)
14837502Sroot 	struct tty *tp;
14847502Sroot {
14857502Sroot 
14867502Sroot 	if (tp->t_rsel) {
14877502Sroot 		selwakeup(tp->t_rsel, tp->t_state&TS_RCOLL);
14887502Sroot 		tp->t_state &= ~TS_RCOLL;
14897502Sroot 		tp->t_rsel = 0;
14907502Sroot 	}
14917502Sroot 	wakeup((caddr_t)&tp->t_rawq);
14927502Sroot }
14937502Sroot 
1494*9578Ssam #ifndef vax
1495*9578Ssam scanc(size, cp, table, mask)
1496*9578Ssam 	register int size;
1497*9578Ssam 	register char *cp, table[];
1498*9578Ssam 	register int mask;
14997502Sroot {
1500*9578Ssam 	register int i = 0;
15017502Sroot 
1502*9578Ssam 	while ((table[*(u_char *)(cp + i)]&mask) == 0 && i < size)
1503*9578Ssam 		i++;
1504*9578Ssam 	return (i);
15057502Sroot }
1506*9578Ssam #endif
1507