xref: /csrg-svn/sys/kern/tty.c (revision 8954)
1*8954Sroot /*	tty.c	4.33	82/10/31	*/
239Sbill 
339Sbill /*
4903Sbill  * TTY subroutines common to more than one line discipline
539Sbill  */
639Sbill #include "../h/param.h"
739Sbill #include "../h/systm.h"
839Sbill #include "../h/dir.h"
939Sbill #include "../h/user.h"
1039Sbill #include "../h/tty.h"
1139Sbill #include "../h/proc.h"
1239Sbill #include "../h/inode.h"
1339Sbill #include "../h/file.h"
1439Sbill #include "../h/reg.h"
1539Sbill #include "../h/conf.h"
1639Sbill #include "../h/buf.h"
17340Sbill #include "../h/dk.h"
187722Swnj #include "../h/uio.h"
198154Sroot #include "../h/kernel.h"
2039Sbill 
217436Skre /*
227436Skre  * Table giving parity for characters and indicating
237436Skre  * character classes to tty driver.  In particular,
247436Skre  * if the low 6 bits are 0, then the character needs
257436Skre  * no special processing on output.
267436Skre  */
2739Sbill 
287436Skre char partab[] = {
297436Skre 	0001,0201,0201,0001,0201,0001,0001,0201,
307436Skre 	0202,0004,0003,0201,0005,0206,0201,0001,
317436Skre 	0201,0001,0001,0201,0001,0201,0201,0001,
327436Skre 	0001,0201,0201,0001,0201,0001,0001,0201,
337436Skre 	0200,0000,0000,0200,0000,0200,0200,0000,
347436Skre 	0000,0200,0200,0000,0200,0000,0000,0200,
357436Skre 	0000,0200,0200,0000,0200,0000,0000,0200,
367436Skre 	0200,0000,0000,0200,0000,0200,0200,0000,
377436Skre 	0200,0000,0000,0200,0000,0200,0200,0000,
387436Skre 	0000,0200,0200,0000,0200,0000,0000,0200,
397436Skre 	0000,0200,0200,0000,0200,0000,0000,0200,
407436Skre 	0200,0000,0000,0200,0000,0200,0200,0000,
417436Skre 	0000,0200,0200,0000,0200,0000,0000,0200,
427436Skre 	0200,0000,0000,0200,0000,0200,0200,0000,
437436Skre 	0200,0000,0000,0200,0000,0200,0200,0000,
447436Skre 	0000,0200,0200,0000,0200,0000,0000,0201,
457436Skre 
467436Skre 	/*
477436Skre 	 * 7 bit ascii ends with the last character above,
487436Skre 	 * but we contine through all 256 codes for the sake
497436Skre 	 * of the tty output routines which use special vax
507436Skre 	 * instructions which need a 256 character trt table.
517436Skre 	 */
527436Skre 
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 	0007,0007,0007,0007,0007,0007,0007,0007
697436Skre };
707436Skre 
71146Sbill /*
7239Sbill  * Input mapping table-- if an entry is non-zero, when the
7339Sbill  * corresponding character is typed preceded by "\" the escape
7439Sbill  * sequence is replaced by the table value.  Mostly used for
7539Sbill  * upper-case only terminals.
7639Sbill  */
7739Sbill 
7839Sbill char	maptab[] ={
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,000,000,
8239Sbill 	000,000,000,000,000,000,000,000,
8339Sbill 	000,'|',000,000,000,000,000,'`',
8439Sbill 	'{','}',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,000,
8939Sbill 	000,000,000,000,000,000,000,000,
9039Sbill 	000,000,000,000,000,000,'~',000,
9139Sbill 	000,'A','B','C','D','E','F','G',
9239Sbill 	'H','I','J','K','L','M','N','O',
9339Sbill 	'P','Q','R','S','T','U','V','W',
9439Sbill 	'X','Y','Z',000,000,000,000,000,
9539Sbill };
9639Sbill 
97925Sbill short	tthiwat[16] =
98*8954Sroot    { 100,100,100,100,100,100,100,200,200,400,400,400,650,650,1300,2000 };
99925Sbill short	ttlowat[16] =
100925Sbill    {  30, 30, 30, 30, 30, 30, 30, 50, 50,120,120,120,125,125,125,125 };
101925Sbill 
10239Sbill #define	OBUFSIZ	100
10339Sbill 
10439Sbill /*
10539Sbill  * set default control characters.
10639Sbill  */
10739Sbill ttychars(tp)
1087625Ssam 	register struct tty *tp;
10939Sbill {
110174Sbill 
11139Sbill 	tun.t_intrc = CINTR;
11239Sbill 	tun.t_quitc = CQUIT;
11339Sbill 	tun.t_startc = CSTART;
11439Sbill 	tun.t_stopc = CSTOP;
11539Sbill 	tun.t_eofc = CEOT;
11639Sbill 	tun.t_brkc = CBRK;
11739Sbill 	tp->t_erase = CERASE;
11839Sbill 	tp->t_kill = CKILL;
119174Sbill /* begin local */
120208Sbill 	tlun.t_suspc = CTRL(z);
121208Sbill 	tlun.t_dsuspc = CTRL(y);
122174Sbill 	tlun.t_rprntc = CTRL(r);
123174Sbill 	tlun.t_flushc = CTRL(o);
124174Sbill 	tlun.t_werasc = CTRL(w);
125174Sbill 	tlun.t_lnextc = CTRL(v);
126174Sbill 	tp->t_local = 0;
127174Sbill 	tp->t_lstate = 0;
128174Sbill /* end local */
12939Sbill }
13039Sbill 
13139Sbill /*
132903Sbill  * Wait for output to drain, then flush input waiting.
13339Sbill  */
134903Sbill wflushtty(tp)
1355408Swnj 	register struct tty *tp;
13639Sbill {
13739Sbill 
138903Sbill 	(void) spl5();
1395622Swnj 	while (tp->t_outq.c_cc && tp->t_state&TS_CARR_ON
1405622Swnj 	    && tp->t_oproc) {		/* kludge for pty */
141903Sbill 		(*tp->t_oproc)(tp);
1425408Swnj 		tp->t_state |= TS_ASLEEP;
143903Sbill 		sleep((caddr_t)&tp->t_outq, TTOPRI);
144903Sbill 	}
1455426Swnj 	flushtty(tp, FREAD);
146903Sbill 	(void) spl0();
14739Sbill }
14839Sbill 
14939Sbill /*
150903Sbill  * flush all TTY queues
15139Sbill  */
152903Sbill flushtty(tp, rw)
1537625Ssam 	register struct tty *tp;
15439Sbill {
155903Sbill 	register s;
156903Sbill 
157903Sbill 	s = spl6();
158903Sbill 	if (rw & FREAD) {
159903Sbill 		while (getc(&tp->t_canq) >= 0)
160903Sbill 			;
161903Sbill 		wakeup((caddr_t)&tp->t_rawq);
162903Sbill 	}
163903Sbill 	if (rw & FWRITE) {
164903Sbill 		wakeup((caddr_t)&tp->t_outq);
1655408Swnj 		tp->t_state &= ~TS_TTSTOP;
1665426Swnj 		(*cdevsw[major(tp->t_dev)].d_stop)(tp, rw);
167903Sbill 		while (getc(&tp->t_outq) >= 0)
168903Sbill 			;
169903Sbill 	}
170903Sbill 	if (rw & FREAD) {
171903Sbill 		while (getc(&tp->t_rawq) >= 0)
172903Sbill 			;
173903Sbill 		tp->t_delct = 0;
174903Sbill 		tp->t_rocount = 0;		/* local */
175903Sbill 		tp->t_rocol = 0;
176903Sbill 		tp->t_lstate = 0;
177903Sbill 	}
178903Sbill 	splx(s);
17939Sbill }
18039Sbill 
181903Sbill /*
182903Sbill  * Send stop character on input overflow.
183903Sbill  */
184903Sbill ttyblock(tp)
1857625Ssam 	register struct tty *tp;
18639Sbill {
187903Sbill 	register x;
188903Sbill 	x = tp->t_rawq.c_cc + tp->t_canq.c_cc;
189903Sbill 	if (tp->t_rawq.c_cc > TTYHOG) {
190903Sbill 		flushtty(tp, FREAD|FWRITE);
1915408Swnj 		tp->t_state &= ~TS_TBLOCK;
192903Sbill 	}
193903Sbill 	if (x >= TTYHOG/2) {
194903Sbill 		if (putc(tun.t_stopc, &tp->t_outq)==0) {
1955408Swnj 			tp->t_state |= TS_TBLOCK;
196903Sbill 			tp->t_char++;
197903Sbill 			ttstart(tp);
198903Sbill 		}
199903Sbill 	}
20039Sbill }
20139Sbill 
20239Sbill /*
203903Sbill  * Restart typewriter output following a delay
204903Sbill  * timeout.
205903Sbill  * The name of the routine is passed to the timeout
206903Sbill  * subroutine and it is called during a clock interrupt.
207121Sbill  */
208903Sbill ttrstrt(tp)
2097625Ssam 	register struct tty *tp;
210121Sbill {
211121Sbill 
2123351Swnj 	if (tp == 0) {
2133351Swnj 		printf("ttrstrt: arg was 0!\n");
2143351Swnj 		return;
2153351Swnj 	}
2165408Swnj 	tp->t_state &= ~TS_TIMEOUT;
217903Sbill 	ttstart(tp);
218121Sbill }
219121Sbill 
220121Sbill /*
221903Sbill  * Start output on the typewriter. It is used from the top half
222903Sbill  * after some characters have been put on the output queue,
223903Sbill  * from the interrupt routine to transmit the next
224903Sbill  * character, and after a timeout has finished.
22539Sbill  */
226903Sbill ttstart(tp)
2277625Ssam 	register struct tty *tp;
22839Sbill {
229903Sbill 	register s;
23039Sbill 
231903Sbill 	s = spl5();
2327625Ssam 	if ((tp->t_state&(TS_TIMEOUT|TS_TTSTOP|TS_BUSY)) == 0 &&
2335622Swnj 	    tp->t_oproc)		/* kludge for pty */
234903Sbill 		(*tp->t_oproc)(tp);
235903Sbill 	splx(s);
23639Sbill }
23739Sbill 
23839Sbill /*
239903Sbill  * Common code for tty ioctls.
24039Sbill  */
2411780Sbill /*ARGSUSED*/
2427625Ssam ttioctl(tp, com, data, flag)
2437625Ssam 	register struct tty *tp;
2447625Ssam 	caddr_t data;
24539Sbill {
2468520Sroot 	int dev = tp->t_dev;
24739Sbill 	extern int nldisp;
2488556Sroot 	int s;
24939Sbill 
250903Sbill 	/*
251903Sbill 	 * If the ioctl involves modification,
252903Sbill 	 * insist on being able to write the device,
253903Sbill 	 * and hang if in the background.
254903Sbill 	 */
2557625Ssam 	switch (com) {
25639Sbill 
257915Sbill 	case TIOCSETD:
258915Sbill 	case TIOCSETP:
259915Sbill 	case TIOCSETN:
260903Sbill 	case TIOCFLUSH:
261903Sbill 	case TIOCSETC:
262903Sbill 	case TIOCSLTC:
263903Sbill 	case TIOCSPGRP:
264903Sbill 	case TIOCLBIS:
265903Sbill 	case TIOCLBIC:
266903Sbill 	case TIOCLSET:
267903Sbill 		while (tp->t_line == NTTYDISC &&
268903Sbill 		   u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp &&
269903Sbill 		   (u.u_procp->p_flag&SVFORK) == 0 &&
270903Sbill 		   u.u_signal[SIGTTOU] != SIG_IGN &&
2718556Sroot 		   u.u_signal[SIGTTOU] != SIG_HOLD) {
272903Sbill 			gsignal(u.u_procp->p_pgrp, SIGTTOU);
273903Sbill 			sleep((caddr_t)&lbolt, TTOPRI);
274903Sbill 		}
275903Sbill 		break;
276903Sbill 	}
277903Sbill 
2787625Ssam 	switch (com) {
279903Sbill 
2808556Sroot 	/* get discipline number */
28139Sbill 	case TIOCGETD:
2827625Ssam 		*(int *)data = tp->t_line;
28339Sbill 		break;
28439Sbill 
2858556Sroot 	/* set line discipline */
2867625Ssam 	case TIOCSETD: {
2877625Ssam 		register int t = *(int *)data;
2888556Sroot 		int error;
2897625Ssam 
2908556Sroot 		if (t >= nldisp)
2918556Sroot 			return (ENXIO);
2928556Sroot 		s = spl5();
29339Sbill 		if (tp->t_line)
29439Sbill 			(*linesw[tp->t_line].l_close)(tp);
29539Sbill 		if (t)
2968556Sroot 			error = (*linesw[t].l_open)(dev, tp);
2978556Sroot 		splx(s);
2988556Sroot 		if (error)
2998556Sroot 			return (error);
3008556Sroot 		tp->t_line = t;
30139Sbill 		break;
3027625Ssam 	}
30339Sbill 
3048556Sroot 	/* prevent more opens on channel */
3055614Swnj 	case TIOCEXCL:
3065614Swnj 		tp->t_state |= TS_XCLUDE;
3075614Swnj 		break;
3085614Swnj 
3095614Swnj 	case TIOCNXCL:
3105614Swnj 		tp->t_state &= ~TS_XCLUDE;
3115614Swnj 		break;
3125614Swnj 
3138556Sroot 	/* set new parameters */
31439Sbill 	case TIOCSETP:
3157625Ssam 	case TIOCSETN: {
3167625Ssam 		register struct sgttyb *sg = (struct sgttyb *)data;
3177625Ssam 		struct clist tq;
3187625Ssam 
319121Sbill 		(void) spl5();
3207625Ssam 		if (tp->t_flags&RAW || sg->sg_flags&RAW || com == TIOCSETP)
3214484Swnj 			wflushtty(tp);
3227625Ssam 		else if ((tp->t_flags&CBREAK) != (sg->sg_flags&CBREAK)) {
3237625Ssam 			if (sg->sg_flags & CBREAK) {
3244484Swnj 				catq(&tp->t_rawq, &tp->t_canq);
3254484Swnj 				tq = tp->t_rawq;
3264484Swnj 				tp->t_rawq = tp->t_canq;
3274484Swnj 				tp->t_canq = tq;
3284484Swnj 			} else {
3294484Swnj 				tp->t_local |= LPENDIN;
3304484Swnj 				ttwakeup(tp);
331174Sbill 			}
332174Sbill 		}
3337625Ssam 		tp->t_ispeed = sg->sg_ispeed;
3347625Ssam 		tp->t_ospeed = sg->sg_ospeed;
3357625Ssam 		tp->t_erase = sg->sg_erase;
3367625Ssam 		tp->t_kill = sg->sg_kill;
3377625Ssam 		tp->t_flags = sg->sg_flags;
3383941Sbugs 		if (tp->t_flags & RAW) {
3395408Swnj 			tp->t_state &= ~TS_TTSTOP;
3403941Sbugs 			ttstart(tp);
3413941Sbugs 		}
342121Sbill 		(void) spl0();
34339Sbill 		break;
3447625Ssam 	}
34539Sbill 
3468556Sroot 	/* send current parameters to user */
3477625Ssam 	case TIOCGETP: {
3487625Ssam 		register struct sgttyb *sg = (struct sgttyb *)data;
3497625Ssam 
3507625Ssam 		sg->sg_ispeed = tp->t_ispeed;
3517625Ssam 		sg->sg_ospeed = tp->t_ospeed;
3527625Ssam 		sg->sg_erase = tp->t_erase;
3537625Ssam 		sg->sg_kill = tp->t_kill;
3547625Ssam 		sg->sg_flags = tp->t_flags;
35539Sbill 		break;
3567625Ssam 	}
35739Sbill 
3588556Sroot 	/* hang up line on last close */
35939Sbill 	case TIOCHPCL:
3605408Swnj 		tp->t_state |= TS_HUPCLS;
36139Sbill 		break;
36239Sbill 
3633942Sbugs 	case TIOCFLUSH: {
3647625Ssam 		register int flags = *(int *)data;
3657625Ssam 
3667625Ssam 		if (flags == 0)
3673942Sbugs 			flags = FREAD|FWRITE;
3687625Ssam 		else
3697625Ssam 			flags &= FREAD|FWRITE;
3703942Sbugs 		flushtty(tp, flags);
37139Sbill 		break;
3723944Sbugs 	}
37339Sbill 
3747625Ssam 	case FIONBIO:
3757625Ssam 		if (*(int *)data)
3765408Swnj 			tp->t_state |= TS_NBIO;
3775408Swnj 		else
3785408Swnj 			tp->t_state &= ~TS_NBIO;
3795408Swnj 		break;
3805408Swnj 
3817625Ssam 	case FIOASYNC:
3827625Ssam 		if (*(int *)data)
3836216Swnj 			tp->t_state |= TS_ASYNC;
3846216Swnj 		else
3856216Swnj 			tp->t_state &= ~TS_ASYNC;
3866216Swnj 		break;
3876216Swnj 
3888556Sroot 	/* set and fetch special characters */
38939Sbill 	case TIOCSETC:
3907625Ssam 		bcopy(data, (caddr_t)&tun, sizeof (struct tchars));
39139Sbill 		break;
39239Sbill 
39339Sbill 	case TIOCGETC:
3947625Ssam 		bcopy((caddr_t)&tun, data, sizeof (struct tchars));
39539Sbill 		break;
39639Sbill 
3978556Sroot 	/* set/get local special characters */
398174Sbill 	case TIOCSLTC:
3997625Ssam 		bcopy(data, (caddr_t)&tlun, sizeof (struct ltchars));
400174Sbill 		break;
401174Sbill 
402174Sbill 	case TIOCGLTC:
4037625Ssam 		bcopy((caddr_t)&tlun, data, sizeof (struct ltchars));
404174Sbill 		break;
405174Sbill 
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 
4208556Sroot 	/* Modify local mode word */
421174Sbill 	case TIOCLBIS:
4227625Ssam 		tp->t_local |= *(int *)data;
423174Sbill 		break;
424174Sbill 
425174Sbill 	case TIOCLBIC:
4267625Ssam 		tp->t_local &= ~(*(int *)data);
427174Sbill 		break;
428174Sbill 
429174Sbill 	case TIOCLSET:
4307625Ssam 		tp->t_local = *(int *)data;
431174Sbill 		break;
432174Sbill 
433174Sbill 	case TIOCLGET:
4347625Ssam 		*(int *)data = tp->t_local;
435174Sbill 		break;
436174Sbill 
4378589Sroot 	case TIOCSTOP:
4388589Sroot 		s = spl5();
4395573Swnj 		if ((tp->t_state & TS_TTSTOP) == 0) {
4405573Swnj 			tp->t_state |= TS_TTSTOP;
4415573Swnj 			(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
4425573Swnj 		}
4437625Ssam 		splx(s);
4445573Swnj 		break;
4455573Swnj 
4468589Sroot 	case TIOCSTART:
4478589Sroot 		s = spl5();
4485573Swnj 		if ((tp->t_state & TS_TTSTOP) || (tp->t_local & LFLUSHO)) {
4495573Swnj 			tp->t_state &= ~TS_TTSTOP;
4505573Swnj 			tp->t_local &= ~LFLUSHO;
4515573Swnj 			ttstart(tp);
4525573Swnj 		}
4537625Ssam 		splx(s);
4545573Swnj 		break;
4555573Swnj 
45639Sbill 	default:
4578556Sroot 		return (-1);
45839Sbill 	}
4598556Sroot 	return (0);
46039Sbill }
4614484Swnj 
4624484Swnj ttnread(tp)
4634484Swnj 	struct tty *tp;
4644484Swnj {
4654484Swnj 	int nread = 0;
4664484Swnj 
4674484Swnj 	if (tp->t_local & LPENDIN)
4684484Swnj 		ttypend(tp);
4694484Swnj 	nread = tp->t_canq.c_cc;
4704484Swnj 	if (tp->t_flags & (RAW|CBREAK))
4714484Swnj 		nread += tp->t_rawq.c_cc;
4724484Swnj 	return (nread);
4734484Swnj }
4744484Swnj 
4755408Swnj ttselect(dev, rw)
4764484Swnj 	dev_t dev;
4775408Swnj 	int rw;
4784484Swnj {
4794484Swnj 	register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)];
4804484Swnj 	int nread;
4815408Swnj 	int s = spl5();
4824484Swnj 
4835408Swnj 	switch (rw) {
4844484Swnj 
4854484Swnj 	case FREAD:
4864484Swnj 		nread = ttnread(tp);
4874484Swnj 		if (nread > 0)
4885408Swnj 			goto win;
4894938Swnj 		if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait)
4905408Swnj 			tp->t_state |= TS_RCOLL;
4914484Swnj 		else
4924484Swnj 			tp->t_rsel = u.u_procp;
4935408Swnj 		break;
4944484Swnj 
4955408Swnj 	case FWRITE:
4965408Swnj 		if (tp->t_outq.c_cc <= TTLOWAT(tp))
4975408Swnj 			goto win;
4985408Swnj 		if (tp->t_wsel && tp->t_wsel->p_wchan == (caddr_t)&selwait)
4995408Swnj 			tp->t_state |= TS_WCOLL;
5005408Swnj 		else
5015408Swnj 			tp->t_wsel = u.u_procp;
5025408Swnj 		break;
5034484Swnj 	}
5045408Swnj 	splx(s);
5055408Swnj 	return (0);
5065408Swnj win:
5075408Swnj 	splx(s);
5085408Swnj 	return (1);
5094484Swnj }
5107436Skre 
5117502Sroot #define	OBUFSIZ	100
5127502Sroot 
5137502Sroot /*
5147502Sroot  * routine called on opens while tp->t_line == NTTYDISC
5157502Sroot  * establishes a process group for distribution of
5167502Sroot  * quits and interrupts from the tty.
5177502Sroot  * (actually, pp->p_pgrp can't be 0 when this routine
5187502Sroot  * is called since NTTYDISC is not the default discipline)
5197502Sroot  */
5207502Sroot ttyopen(dev, tp)
5217625Ssam 	dev_t dev;
5227625Ssam 	register struct tty *tp;
5237502Sroot {
5247502Sroot 	register struct proc *pp;
5257502Sroot 
5267502Sroot 	pp = u.u_procp;
5277502Sroot 	tp->t_dev = dev;
5287625Ssam 	if (pp->p_pgrp == 0) {
5297502Sroot 		u.u_ttyp = tp;
5307502Sroot 		u.u_ttyd = dev;
5317502Sroot 		if (tp->t_pgrp == 0)
5327502Sroot 			tp->t_pgrp = pp->p_pid;
5337502Sroot 		pp->p_pgrp = tp->t_pgrp;
5347502Sroot 	}
5357502Sroot 	tp->t_state &= ~TS_WOPEN;
5367502Sroot 	tp->t_state |= TS_ISOPEN;
5377502Sroot 	if (tp->t_line != NTTYDISC)
5387502Sroot 		wflushtty(tp);
5398556Sroot 	return (0);
5407502Sroot }
5417502Sroot 
5427502Sroot /*
5437502Sroot  * clean tp on last close
5447502Sroot  */
5457502Sroot ttyclose(tp)
5467625Ssam 	register struct tty *tp;
5477502Sroot {
5487502Sroot 
5497502Sroot 	if (tp->t_line) {
5507502Sroot 		wflushtty(tp);
5517502Sroot 		tp->t_line = 0;
5527502Sroot 		return;
5537502Sroot 	}
5547502Sroot 	tp->t_pgrp = 0;
5557502Sroot 	wflushtty(tp);
5567502Sroot 	tp->t_state = 0;
5577502Sroot }
5587502Sroot 
5597502Sroot /*
5607502Sroot  * reinput pending characters after state switch
5617502Sroot  * call at spl5().
5627502Sroot  */
5637502Sroot ttypend(tp)
5647625Ssam 	register struct tty *tp;
5657502Sroot {
5667502Sroot 	struct clist tq;
5677502Sroot 	register c;
5687502Sroot 
5697502Sroot 	tp->t_local &= ~LPENDIN;
5707502Sroot 	tp->t_lstate |= LSTYPEN;
5717502Sroot 	tq = tp->t_rawq;
5727502Sroot 	tp->t_rawq.c_cc = 0;
5737502Sroot 	tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0;
5747502Sroot 	while ((c = getc(&tq)) >= 0)
5757502Sroot 		ttyinput(c, tp);
5767502Sroot 	tp->t_lstate &= ~LSTYPEN;
5777502Sroot }
5787502Sroot 
5797502Sroot /*
5807502Sroot  * Place a character on raw TTY input queue, putting in delimiters
5817502Sroot  * and waking up top half as needed.
5827502Sroot  * Also echo if required.
5837502Sroot  * The arguments are the character and the appropriate
5847502Sroot  * tty structure.
5857502Sroot  */
5867502Sroot ttyinput(c, tp)
5877625Ssam 	register c;
5887625Ssam 	register struct tty *tp;
5897502Sroot {
5907502Sroot 	register int t_flags;
5917502Sroot 	int i;
5927502Sroot 
5937502Sroot 	if (tp->t_local&LPENDIN)
5947502Sroot 		ttypend(tp);
5957502Sroot 	tk_nin++;
5967502Sroot 	c &= 0377;
5977502Sroot 	t_flags = tp->t_flags;
5987502Sroot 	if (t_flags&TANDEM)
5997502Sroot 		ttyblock(tp);
6007502Sroot 	if ((t_flags&RAW)==0) {
6017502Sroot 		if ((tp->t_lstate&LSTYPEN) == 0)
6027502Sroot 			c &= 0177;
6037502Sroot 	/* check for literal nexting very first */
6047502Sroot 		if (tp->t_lstate&LSLNCH) {
6057502Sroot 			c |= 0200;
6067502Sroot 			tp->t_lstate &= ~LSLNCH;
6077502Sroot 		}
6087502Sroot 		if (tp->t_line == NTTYDISC && c==tlun.t_lnextc) {
6097502Sroot 			if (tp->t_flags&ECHO)
6107502Sroot 				ttyout("^\b", tp);
6117502Sroot 			tp->t_lstate |= LSLNCH;
6127502Sroot 	/* check for output control functions */
6137502Sroot 		} else if (c==tun.t_stopc) {
6147502Sroot 			if ((tp->t_state&TS_TTSTOP)==0) {
6157502Sroot 				tp->t_state |= TS_TTSTOP;
6167502Sroot 				(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
6177502Sroot 				return;
6187502Sroot 			}
6197502Sroot 			if (c!=tun.t_startc)
6207502Sroot 				return;
6217502Sroot 		} else if (c==tun.t_startc) {
6227502Sroot 			tp->t_state &= ~TS_TTSTOP;
6237502Sroot 			tp->t_local &= ~LFLUSHO;
6247502Sroot 			ttstart(tp);
6257502Sroot 			return;
6267502Sroot 		} else if (tp->t_line == NTTYDISC && c==tlun.t_flushc) {
6277502Sroot 			if (tp->t_local & LFLUSHO)
6287502Sroot 				tp->t_local &= ~LFLUSHO;
6297502Sroot 			else {
6307502Sroot 				flushtty(tp, FWRITE);
6317502Sroot 				ttyecho(c, tp);
6327502Sroot 				if (tp->t_rawq.c_cc+tp->t_canq.c_cc)
6337502Sroot 					ttyretype(tp);
6347502Sroot 				tp->t_local |= LFLUSHO;
6357502Sroot 			}
6367502Sroot 			ttstart(tp);
6377502Sroot 			return;
6387502Sroot 		} else if (c==tun.t_intrc || c==tun.t_quitc ||
6397502Sroot 		    (tp->t_line == NTTYDISC && c==tlun.t_suspc)) {
6407502Sroot 			if ((tp->t_local & LNOFLSH) == 0)
6417502Sroot 				flushtty(tp,
6427502Sroot 				    c==tlun.t_suspc ? FREAD : FREAD|FWRITE);
6437502Sroot 			ttyecho(c, tp);
6447502Sroot 			c = c==tun.t_intrc ? SIGINT :
6457502Sroot 				((c==tun.t_quitc) ? SIGQUIT : SIGTSTP);
6467502Sroot 			ttsignal(tp, c);
6477502Sroot 	/* check for buffer editing functions - cooked mode */
6487502Sroot 		} else if ((t_flags&CBREAK) == 0) {
6497502Sroot 			if ((tp->t_lstate&LSQUOT) &&
6507502Sroot 			    (c==tp->t_erase||c==tp->t_kill)) {
6517502Sroot 				ttyrub(unputc(&tp->t_rawq), tp);
6527502Sroot 				c |= 0200;
6537502Sroot 			}
6547502Sroot 			if (c==tp->t_erase) {
6557502Sroot 				if (tp->t_rawq.c_cc)
6567502Sroot 					ttyrub(unputc(&tp->t_rawq), tp);
6577502Sroot 			} else if (c==tp->t_kill) {
6587502Sroot 				if (tp->t_local&LCRTKIL &&
6597502Sroot 				    tp->t_rawq.c_cc == tp->t_rocount) {
6607502Sroot 					while (tp->t_rawq.c_cc)
6617502Sroot 						ttyrub(unputc(&tp->t_rawq), tp);
6627502Sroot 				} else {
6637502Sroot 					ttyecho(c, tp);
6647502Sroot 					ttyecho('\n', tp);
6657502Sroot 					while (getc(&tp->t_rawq) > 0)
6667502Sroot 						;
6677502Sroot 					tp->t_rocount = 0;
6687502Sroot 				}
6697502Sroot 				tp->t_lstate = 0;
6707502Sroot 			} else if (tp->t_line == NTTYDISC && c==tlun.t_werasc) {
6717502Sroot 				if (tp->t_rawq.c_cc == 0)
6727502Sroot 					goto out;
6737502Sroot 				do {
6747502Sroot 					c = unputc(&tp->t_rawq);
6757502Sroot 					if (c != ' ' && c != '\t')
6767502Sroot 						goto erasenb;
6777502Sroot 					ttyrub(c, tp);
6787502Sroot 				} while (tp->t_rawq.c_cc);
6797502Sroot 				goto out;
6807502Sroot 			    erasenb:
6817502Sroot 				do {
6827502Sroot 					ttyrub(c, tp);
6837502Sroot 					if (tp->t_rawq.c_cc == 0)
6847502Sroot 						goto out;
6857502Sroot 					c = unputc(&tp->t_rawq);
6867502Sroot 				} while (c != ' ' && c != '\t');
6877502Sroot 				(void) putc(c, &tp->t_rawq);
6887502Sroot 			} else if (tp->t_line == NTTYDISC && c==tlun.t_rprntc) {
6897502Sroot 				ttyretype(tp);
6907502Sroot 	/* check for cooked mode input buffer overflow */
6917502Sroot 			} else if (tp->t_rawq.c_cc+tp->t_canq.c_cc >= TTYHOG) {
6927502Sroot 				;
6937502Sroot 	/* put data char in q for user and wakeup if a break char */
6947502Sroot 			} else if (putc(c, &tp->t_rawq) >= 0) {
6957502Sroot 				if (tp->t_rawq.c_cc+tp->t_canq.c_cc==TTYHOG
6967502Sroot 				    && tp->t_line == NTTYDISC)
6977502Sroot 					(void) ttyoutput(CTRL(g), tp);
6987502Sroot 				if (!ttbreakc(c, tp)) {
6997502Sroot 					if (tp->t_rocount++ == 0)
7007502Sroot 						tp->t_rocol = tp->t_col;
7017502Sroot 				} else {
7027502Sroot 					tp->t_rocount = 0;
7037502Sroot 					catq(&tp->t_rawq, &tp->t_canq);
7047502Sroot 					/* IF (TP->T_CHAN) (VOID) SDATA(TP->T_CHAN); */
7057502Sroot 					ttwakeup(tp);
7067502Sroot 				}
7077502Sroot 				tp->t_lstate &= ~LSQUOT;
7087502Sroot 				if (c == '\\')
7097502Sroot 					tp->t_lstate |= LSQUOT;
7107502Sroot 				if (tp->t_lstate&LSERASE) {
7117502Sroot 					tp->t_lstate &= ~LSERASE;
7127502Sroot 					(void) ttyoutput('/', tp);
7137502Sroot 				}
7147502Sroot 				i = tp->t_col;
7157502Sroot 				ttyecho(c, tp);
7167502Sroot 				if (c==tun.t_eofc && tp->t_flags&ECHO) {
7177502Sroot 					i = MIN(2, tp->t_col - i);
7187502Sroot 					while (i > 0) {
7197502Sroot 						(void) ttyoutput('\b', tp);
7207502Sroot 						i--;
7217502Sroot 					}
7227502Sroot 				}
7237502Sroot 			}
7247502Sroot 	/* CBREAK mode */
7257502Sroot 		} else if (tp->t_rawq.c_cc > TTYHOG) {
7267502Sroot 			if (tp->t_outq.c_cc < TTHIWAT(tp) &&
7277502Sroot 			    tp->t_line == NTTYDISC)
7287502Sroot 				(void) ttyoutput(CTRL(g), tp);
7297502Sroot 		} else if (putc(c, &tp->t_rawq) >= 0) {
7307502Sroot 			ttwakeup(tp);
7317502Sroot 			ttyecho(c, tp);
7327502Sroot 		}
7337502Sroot 	/* RAW mode */
7347502Sroot 	} else if (tp->t_rawq.c_cc > TTYHOG)
7357502Sroot 		flushtty(tp, FREAD|FWRITE);
7367502Sroot 	else {
7377502Sroot 		if (putc(c, &tp->t_rawq) >= 0)
7387502Sroot 			ttwakeup(tp);
7397502Sroot 		ttyecho(c, tp);
7407502Sroot 	}
7417502Sroot out:
7427502Sroot 	if (tp->t_local & LDECCTQ && tp->t_state & TS_TTSTOP &&
7437502Sroot 	    tun.t_startc != tun.t_stopc)
7447502Sroot 		return;
7457502Sroot 	tp->t_state &= ~TS_TTSTOP;
7467502Sroot 	tp->t_local &= ~LFLUSHO;
7477502Sroot 	ttstart(tp);
7487502Sroot }
7497502Sroot 
7507502Sroot /*
7517502Sroot  * put character on TTY output queue, adding delays,
7527502Sroot  * expanding tabs, and handling the CR/NL bit.
7537502Sroot  * It is called both from the top half for output, and from
7547502Sroot  * interrupt level for echoing.
7557502Sroot  * The arguments are the character and the tty structure.
7567502Sroot  * Returns < 0 if putc succeeds, otherwise returns char to resend
7577502Sroot  * Must be recursive.
7587502Sroot  */
7597502Sroot ttyoutput(c, tp)
7607502Sroot 	register c;
7617502Sroot 	register struct tty *tp;
7627502Sroot {
7637502Sroot 	register char *colp;
7647502Sroot 	register ctype;
7657502Sroot 
7667502Sroot 	if (tp->t_flags&RAW || tp->t_local&LLITOUT) {
7677502Sroot 		if (tp->t_local&LFLUSHO)
7687502Sroot 			return (-1);
7697502Sroot 		if (putc(c, &tp->t_outq))
7707625Ssam 			return (c);
7717502Sroot 		tk_nout++;
7727502Sroot 		return (-1);
7737502Sroot 	}
7747502Sroot 	/*
7757502Sroot 	 * Ignore EOT in normal mode to avoid hanging up
7767502Sroot 	 * certain terminals.
7777502Sroot 	 */
7787502Sroot 	c &= 0177;
7797502Sroot 	if (c==CEOT && (tp->t_flags&CBREAK)==0)
7807502Sroot 		return (-1);
7817502Sroot 	/*
7827502Sroot 	 * Turn tabs to spaces as required
7837502Sroot 	 */
7847502Sroot 	if (c=='\t' && (tp->t_flags&TBDELAY)==XTABS) {
7857502Sroot 		register int s;
7867502Sroot 
7877502Sroot 		c = 8 - (tp->t_col&7);
7887502Sroot 		if ((tp->t_local&LFLUSHO) == 0) {
7897502Sroot 			s = spl5();		/* don't interrupt tabs */
7907502Sroot 			c -= b_to_q("        ", c, &tp->t_outq);
7917502Sroot 			tk_nout += c;
7927502Sroot 			splx(s);
7937502Sroot 		}
7947502Sroot 		tp->t_col += c;
7957502Sroot 		return (c ? -1 : '\t');
7967502Sroot 	}
7977502Sroot 	tk_nout++;
7987502Sroot 	/*
7997502Sroot 	 * for upper-case-only terminals,
8007502Sroot 	 * generate escapes.
8017502Sroot 	 */
8027502Sroot 	if (tp->t_flags&LCASE) {
8037502Sroot 		colp = "({)}!|^~'`";
8047625Ssam 		while (*colp++)
8057625Ssam 			if (c == *colp++) {
8067502Sroot 				if (ttyoutput('\\', tp) >= 0)
8077502Sroot 					return (c);
8087502Sroot 				c = colp[-2];
8097502Sroot 				break;
8107502Sroot 			}
8117502Sroot 		if ('A'<=c && c<='Z') {
8127502Sroot 			if (ttyoutput('\\', tp) >= 0)
8137502Sroot 				return (c);
8147502Sroot 		} else if ('a'<=c && c<='z')
8157502Sroot 			c += 'A' - 'a';
8167502Sroot 	}
8177502Sroot 	/*
8187502Sroot 	 * turn <nl> to <cr><lf> if desired.
8197502Sroot 	 */
8207502Sroot 	if (c=='\n' && tp->t_flags&CRMOD)
8217502Sroot 		if (ttyoutput('\r', tp) >= 0)
8227502Sroot 			return (c);
8237502Sroot 	if (c=='~' && tp->t_local&LTILDE)
8247502Sroot 		c = '`';
8257502Sroot 	if ((tp->t_local&LFLUSHO) == 0 && putc(c, &tp->t_outq))
8267502Sroot 		return (c);
8277502Sroot 	/*
8287502Sroot 	 * Calculate delays.
8297502Sroot 	 * The numbers here represent clock ticks
8307502Sroot 	 * and are not necessarily optimal for all terminals.
8317502Sroot 	 * The delays are indicated by characters above 0200.
8327502Sroot 	 * In raw mode there are no delays and the
8337502Sroot 	 * transmission path is 8 bits wide.
8347502Sroot 	 */
8357502Sroot 	colp = &tp->t_col;
8367502Sroot 	ctype = partab[c];
8377502Sroot 	c = 0;
8387502Sroot 	switch (ctype&077) {
8397502Sroot 
8407502Sroot 	case ORDINARY:
8417502Sroot 		(*colp)++;
8427502Sroot 
8437502Sroot 	case CONTROL:
8447502Sroot 		break;
8457502Sroot 
8467502Sroot 	case BACKSPACE:
8477502Sroot 		if (*colp)
8487502Sroot 			(*colp)--;
8497502Sroot 		break;
8507502Sroot 
8517502Sroot 	case NEWLINE:
8527502Sroot 		ctype = (tp->t_flags >> 8) & 03;
8537625Ssam 		if (ctype == 1) { /* tty 37 */
8547502Sroot 			if (*colp)
8557502Sroot 				c = max(((unsigned)*colp>>4) + 3, (unsigned)6);
8567502Sroot 		} else
8577625Ssam 		if (ctype == 2) { /* vt05 */
8587502Sroot 			c = 6;
8597502Sroot 		}
8607502Sroot 		*colp = 0;
8617502Sroot 		break;
8627502Sroot 
8637502Sroot 	case TAB:
8647502Sroot 		ctype = (tp->t_flags >> 10) & 03;
8657625Ssam 		if (ctype == 1) { /* tty 37 */
8667502Sroot 			c = 1 - (*colp | ~07);
8677625Ssam 			if (c < 5)
8687502Sroot 				c = 0;
8697502Sroot 		}
8707502Sroot 		*colp |= 07;
8717502Sroot 		(*colp)++;
8727502Sroot 		break;
8737502Sroot 
8747502Sroot 	case VTAB:
8757625Ssam 		if (tp->t_flags & VTDELAY) /* tty 37 */
8767502Sroot 			c = 0177;
8777502Sroot 		break;
8787502Sroot 
8797502Sroot 	case RETURN:
8807502Sroot 		ctype = (tp->t_flags >> 12) & 03;
8817625Ssam 		if (ctype == 1) { /* tn 300 */
8827502Sroot 			c = 5;
8837625Ssam 		} else if (ctype == 2) { /* ti 700 */
8847502Sroot 			c = 10;
8857625Ssam 		} else if (ctype == 3) { /* concept 100 */
8867502Sroot 			int i;
8877502Sroot 			if ((i = *colp) >= 0)
8887502Sroot 				for (; i<9; i++)
8897502Sroot 					(void) putc(0177, &tp->t_outq);
8907502Sroot 		}
8917502Sroot 		*colp = 0;
8927502Sroot 	}
8937625Ssam 	if (c && (tp->t_local&LFLUSHO) == 0)
8947502Sroot 		(void) putc(c|0200, &tp->t_outq);
8957502Sroot 	return (-1);
8967502Sroot }
8977502Sroot 
8987502Sroot /*
8997502Sroot  * Called from device's read routine after it has
9007502Sroot  * calculated the tty-structure given as argument.
9017502Sroot  */
9027722Swnj ttread(tp, uio)
9037625Ssam 	register struct tty *tp;
9047722Swnj 	struct uio *uio;
9057502Sroot {
9067502Sroot 	register struct clist *qp;
9077502Sroot 	register c, first;
9088520Sroot 	int error = 0;
9097502Sroot 
9107502Sroot 	if ((tp->t_state&TS_CARR_ON)==0)
9118520Sroot 		return (EIO);
9127502Sroot loop:
9137502Sroot 	(void) spl5();
9147502Sroot 	if (tp->t_local&LPENDIN)
9157502Sroot 		ttypend(tp);
9167502Sroot 	(void) spl0();
9177502Sroot 	while (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) {
9187502Sroot 		if (u.u_signal[SIGTTIN] == SIG_IGN ||
9197502Sroot 		    u.u_signal[SIGTTIN] == SIG_HOLD ||
9207502Sroot /*
9217502Sroot 		    (u.u_procp->p_flag&SDETACH) ||
9227502Sroot */
9237502Sroot 		    u.u_procp->p_flag&SVFORK)
9248520Sroot 			return (EIO);
9257502Sroot 		gsignal(u.u_procp->p_pgrp, SIGTTIN);
9267502Sroot 		sleep((caddr_t)&lbolt, TTIPRI);
9277502Sroot 	}
9287502Sroot 	if (tp->t_flags&RAW) {
9297502Sroot 		(void) spl5();
9307502Sroot 		if (tp->t_rawq.c_cc <= 0) {
9317502Sroot 			if ((tp->t_state&TS_CARR_ON)==0 ||
9327502Sroot 			    (tp->t_state&TS_NBIO)) {
9337502Sroot 				(void) spl0();
9348520Sroot 				return (EWOULDBLOCK);
9357502Sroot 			}
9367502Sroot 			sleep((caddr_t)&tp->t_rawq, TTIPRI);
9377502Sroot 			(void) spl0();
9387502Sroot 			goto loop;
9397502Sroot 		}
9407502Sroot 		(void) spl0();
9417722Swnj 		while (tp->t_rawq.c_cc && uio->uio_iovcnt) {
9428520Sroot 			error = passuc(getc(&tp->t_rawq), uio);
9438520Sroot 			if (error)
9447722Swnj 				break;
9457722Swnj 		}
9468520Sroot 		return (error);
9477502Sroot 	} else {
9487502Sroot 		qp = tp->t_flags & CBREAK ? &tp->t_rawq : &tp->t_canq;
9497502Sroot 		(void) spl5();
9507502Sroot 		if (qp->c_cc <= 0) {
9517502Sroot 			if ((tp->t_state&TS_CARR_ON)==0 ||
9527502Sroot 			    (tp->t_state&TS_NBIO)) {
9537502Sroot 				(void) spl0();
9548520Sroot 				return (EWOULDBLOCK);
9557502Sroot 			}
9567502Sroot 			sleep((caddr_t)&tp->t_rawq, TTIPRI);
9577502Sroot 			(void) spl0();
9587502Sroot 			goto loop;
9597502Sroot 		}
9607502Sroot 		(void) spl0();
9617502Sroot 		first = 1;
9627502Sroot 		while ((c = getc(qp)) >= 0) {
9637502Sroot 			if (tp->t_flags&CRMOD && c == '\r')
9647502Sroot 				c = '\n';
9657502Sroot 			if (tp->t_flags&LCASE && c <= 0177)
9667502Sroot 				if (tp->t_lstate&LSBKSL) {
9677502Sroot 					if (maptab[c])
9687502Sroot 						c = maptab[c];
9697502Sroot 					tp->t_lstate &= ~LSBKSL;
9707502Sroot 				} else if (c >= 'A' && c <= 'Z')
9717502Sroot 					c += 'a' - 'A';
9727502Sroot 				else if (c == '\\') {
9737502Sroot 					tp->t_lstate |= LSBKSL;
9747502Sroot 					continue;
9757502Sroot 				}
9767658Ssam 			if (tp->t_line == NTTYDISC && c == tlun.t_dsuspc) {
9777502Sroot 				ttsignal(tp, SIGTSTP);
9787502Sroot 				if (first) {
9797502Sroot 					sleep((caddr_t)&lbolt, TTIPRI);
9807502Sroot 					goto loop;
9817502Sroot 				}
9827502Sroot 				break;
9837502Sroot 			}
9847502Sroot 			if (c == tun.t_eofc && (tp->t_flags&CBREAK)==0)
9857502Sroot 				break;
9868520Sroot 			error = passuc(c & 0177, uio);
9878520Sroot 			if (error)
9887502Sroot 				break;
9897722Swnj 			if (uio->uio_iovcnt == 0)
9907722Swnj 				break;
9917502Sroot 			if ((tp->t_flags&CBREAK)==0 && ttbreakc(c, tp))
9927502Sroot 				break;
9937502Sroot 			first = 0;
9947502Sroot 		}
9957502Sroot 		tp->t_lstate &= ~LSBKSL;
9967502Sroot 	}
9977502Sroot 	if (tp->t_state&TS_TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) {
9987502Sroot 		if (putc(tun.t_startc, &tp->t_outq)==0) {
9997502Sroot 			tp->t_state &= ~TS_TBLOCK;
10007502Sroot 			ttstart(tp);
10017502Sroot 		}
10027502Sroot 		tp->t_char = 0;
10037502Sroot 	}
10048520Sroot 	return (error);
10057502Sroot }
10067502Sroot 
10077502Sroot /*
10087502Sroot  * Called from the device's write routine after it has
10097502Sroot  * calculated the tty-structure given as argument.
10107502Sroot  */
10117822Sroot ttwrite(tp, uio)
10127625Ssam 	register struct tty *tp;
10137822Sroot 	struct uio *uio;
10147502Sroot {
10157502Sroot #ifdef vax
10167502Sroot 	/*
10177502Sroot 	 * THE POSITIONING OF CP, CC, AND CE ARE CRITICAL
10187502Sroot 	 * AND MUST NOT BE CHANGED WITHOUT PATCHING
10197502Sroot 	 * THE 'ASM' INLINES BELOW.  WATCH OUT.
10207502Sroot 	 */
10217502Sroot #endif
10227502Sroot 	register char *cp;
10237502Sroot 	register int cc, ce;
10247502Sroot 	register i;
10257502Sroot 	char obuf[OBUFSIZ];
10267502Sroot 	register c;
10277502Sroot 	int hiwat = TTHIWAT(tp);
10287822Sroot 	int cnt = uio->uio_resid;
10298520Sroot 	int error = 0;
10307502Sroot 
10317502Sroot 	if ((tp->t_state&TS_CARR_ON)==0)
10328520Sroot 		return (EIO);
10337502Sroot loop:
10347502Sroot 	while (u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp &&
10357502Sroot 	    (tp->t_local&LTOSTOP) && (u.u_procp->p_flag&SVFORK)==0 &&
10367502Sroot 	    u.u_signal[SIGTTOU] != SIG_IGN &&
10377502Sroot 	    u.u_signal[SIGTTOU] != SIG_HOLD
10387502Sroot /*
10397502Sroot 					     &&
10407502Sroot 	    (u.u_procp->p_flag&SDETACH)==0) {
10417502Sroot */
10427502Sroot 	    ) {
10437502Sroot 		gsignal(u.u_procp->p_pgrp, SIGTTOU);
10447502Sroot 		sleep((caddr_t)&lbolt, TTIPRI);
10457502Sroot 	}
10467822Sroot 	while (uio->uio_resid > 0) {
10477822Sroot 		cc = uio->uio_iov->iov_len;
10487822Sroot 		if (cc == 0) {
10497822Sroot 			uio->uio_iovcnt--;
10507822Sroot 			uio->uio_iov++;
10517822Sroot 			if (uio->uio_iovcnt < 0)
10527822Sroot 				panic("ttwrite");
10537822Sroot 			continue;
10547822Sroot 		}
10557822Sroot 		if (cc > OBUFSIZ)
10567822Sroot 			cc = OBUFSIZ;
10577502Sroot 		cp = obuf;
10588520Sroot 		error = uiomove(cp, cc, UIO_WRITE, uio);
10598520Sroot 		if (error)
10607502Sroot 			break;
10617502Sroot 		if (tp->t_outq.c_cc > hiwat)
10627502Sroot 			goto ovhiwat;
10637502Sroot 		if (tp->t_local&LFLUSHO)
10647502Sroot 			continue;
10657502Sroot 		if (tp->t_flags&LCASE || tp->t_local&LTILDE) {
10667502Sroot 			while (cc) {
10677502Sroot 				c = *cp++;
10687502Sroot 				tp->t_rocount = 0;
10697625Ssam 				while ((c = ttyoutput(c, tp)) >= 0) {
10707502Sroot 					/* out of clists, wait a bit */
10717502Sroot 					ttstart(tp);
10727502Sroot 					sleep((caddr_t)&lbolt, TTOPRI);
10737502Sroot 					tp->t_rocount = 0;
10747502Sroot 				}
10757502Sroot 				--cc;
10767502Sroot 				if (tp->t_outq.c_cc > hiwat)
10777502Sroot 					goto ovhiwat;
10787502Sroot 			}
10797502Sroot 			continue;
10807502Sroot 		}
10817502Sroot 		while (cc) {
10827502Sroot 			if (tp->t_flags&RAW || tp->t_local&LLITOUT)
10837502Sroot 				ce = cc;
10847502Sroot 			else {
10857502Sroot #ifdef vax
10867502Sroot 				asm("	scanc	r9,(r10),_partab,$077");
10877502Sroot 				asm("	subl3	r0,r9,r8");
10887502Sroot #else
10897502Sroot 				ce=0;
10907625Ssam 				while (((partab[*(unsigned char *)(cp+ce)]&077)==0)&&(ce<cc))
10917502Sroot 					ce++;
10927502Sroot #endif
10937502Sroot 				if (ce==0) {
10947502Sroot 					tp->t_rocount = 0;
10957502Sroot 					if (ttyoutput(*cp, tp) >= 0) {
10967502Sroot 						ttstart(tp);
10977502Sroot 						sleep((caddr_t)&lbolt, TTOPRI);
10987502Sroot 						continue;
10997502Sroot 					}
11007502Sroot 					cp++;
11017502Sroot 					cc--;
11027502Sroot 					if (tp->t_outq.c_cc > hiwat)
11037502Sroot 						goto ovhiwat;
11047502Sroot 				}
11057502Sroot 			}
11067502Sroot 			tp->t_rocount = 0;
11077502Sroot 			i=b_to_q(cp,ce,&tp->t_outq);
11087502Sroot 			ce-=i;
11097502Sroot 			tk_nout+=ce;
11107502Sroot 			tp->t_col+=ce;
11117502Sroot 			cp+=ce;
11127502Sroot 			cc-=ce;
11137502Sroot 			if (i) {
11147502Sroot 				ttstart(tp);
11157502Sroot 				sleep((caddr_t)&lbolt, TTOPRI);
11167502Sroot 			}
11177502Sroot 			if (ce || tp->t_outq.c_cc > hiwat)
11187502Sroot 				goto ovhiwat;
11197502Sroot 		}
11207502Sroot 	}
11217502Sroot 	ttstart(tp);
11228520Sroot 	return (error);
11237502Sroot 
11247502Sroot ovhiwat:
11257502Sroot 	(void) spl5();
11267822Sroot 	uio->uio_iov->iov_base -= cc;
11277822Sroot 	uio->uio_iov->iov_len += cc;
11287822Sroot 	uio->uio_resid += cc;
11297822Sroot 	uio->uio_offset -= cc;
11307502Sroot 	if (tp->t_outq.c_cc <= hiwat) {
11317502Sroot 		(void) spl0();
11327502Sroot 		goto loop;
11337502Sroot 	}
11347502Sroot 	ttstart(tp);
11357502Sroot 	if (tp->t_state & TS_NBIO) {
11367822Sroot 		if (uio->uio_resid == cnt)
11378520Sroot 			return (EWOULDBLOCK);
11388520Sroot 		return (0);
11397502Sroot 	}
11407502Sroot 	tp->t_state |= TS_ASLEEP;
11417502Sroot 	sleep((caddr_t)&tp->t_outq, TTOPRI);
11427502Sroot 	(void) spl0();
11437502Sroot 	goto loop;
11447502Sroot }
11457502Sroot 
11467502Sroot /*
11477502Sroot  * Rubout one character from the rawq of tp
11487502Sroot  * as cleanly as possible.
11497502Sroot  */
11507502Sroot ttyrub(c, tp)
11517625Ssam 	register c;
11527625Ssam 	register struct tty *tp;
11537502Sroot {
11547502Sroot 	register char *cp;
11557502Sroot 	register int savecol;
11567502Sroot 	int s;
11577502Sroot 	char *nextc();
11587502Sroot 
11597502Sroot 	if ((tp->t_flags&ECHO)==0)
11607502Sroot 		return;
11617502Sroot 	tp->t_local &= ~LFLUSHO;
11627502Sroot 	c &= 0377;
11637502Sroot 	if (tp->t_local&LCRTBS) {
11647502Sroot 		if (tp->t_rocount == 0) {
11657502Sroot 			/*
11667502Sroot 			 * Screwed by ttwrite; retype
11677502Sroot 			 */
11687502Sroot 			ttyretype(tp);
11697502Sroot 			return;
11707502Sroot 		}
11717502Sroot 		if (c==('\t'|0200) || c==('\n'|0200))
11727502Sroot 			ttyrubo(tp, 2);
11737625Ssam 		else switch (partab[c&=0177] & 0177) {
11747502Sroot 
11757502Sroot 		case ORDINARY:
11767502Sroot 			if (tp->t_flags&LCASE && c >= 'A' && c <= 'Z')
11777502Sroot 				ttyrubo(tp, 2);
11787502Sroot 			else
11797502Sroot 				ttyrubo(tp, 1);
11807502Sroot 			break;
11817502Sroot 
11827502Sroot 		case VTAB:
11837502Sroot 		case BACKSPACE:
11847502Sroot 		case CONTROL:
11857502Sroot 		case RETURN:
11867502Sroot 			if (tp->t_local & LCTLECH)
11877502Sroot 				ttyrubo(tp, 2);
11887502Sroot 			break;
11897502Sroot 
11907502Sroot 		case TAB:
11917502Sroot 			if (tp->t_rocount < tp->t_rawq.c_cc) {
11927502Sroot 				ttyretype(tp);
11937502Sroot 				return;
11947502Sroot 			}
11957502Sroot 			s = spl5();
11967502Sroot 			savecol = tp->t_col;
11977502Sroot 			tp->t_lstate |= LSCNTTB;
11987502Sroot 			tp->t_local |= LFLUSHO;
11997502Sroot 			tp->t_col = tp->t_rocol;
12007502Sroot 			for (cp = tp->t_rawq.c_cf; cp; cp = nextc(&tp->t_rawq, cp))
12017502Sroot 				ttyecho(*cp, tp);
12027502Sroot 			tp->t_local &= ~LFLUSHO;
12037502Sroot 			tp->t_lstate &= ~LSCNTTB;
12047502Sroot 			splx(s);
12057502Sroot 			/*
12067502Sroot 			 * savecol will now be length of the tab
12077502Sroot 			 */
12087502Sroot 			savecol -= tp->t_col;
12097502Sroot 			tp->t_col += savecol;
12107502Sroot 			if (savecol > 8)
12117502Sroot 				savecol = 8;		/* overflow screw */
12127502Sroot 			while (--savecol >= 0)
12137502Sroot 				(void) ttyoutput('\b', tp);
12147502Sroot 			break;
12157502Sroot 
12167502Sroot 		default:
12177502Sroot 			panic("ttyrub");
12187502Sroot 		}
12197502Sroot 	} else if (tp->t_local&LPRTERA) {
12207502Sroot 		if ((tp->t_lstate&LSERASE) == 0) {
12217502Sroot 			(void) ttyoutput('\\', tp);
12227502Sroot 			tp->t_lstate |= LSERASE;
12237502Sroot 		}
12247502Sroot 		ttyecho(c, tp);
12257502Sroot 	} else
12267502Sroot 		ttyecho(tp->t_erase, tp);
12277502Sroot 	tp->t_rocount--;
12287502Sroot }
12297502Sroot 
12307502Sroot /*
12317502Sroot  * Crt back over cnt chars perhaps
12327502Sroot  * erasing them.
12337502Sroot  */
12347502Sroot ttyrubo(tp, cnt)
12357625Ssam 	register struct tty *tp;
12367625Ssam 	int cnt;
12377502Sroot {
12387502Sroot 
12397502Sroot 	while (--cnt >= 0)
12407502Sroot 		ttyout(tp->t_local&LCRTERA ? "\b \b" : "\b", tp);
12417502Sroot }
12427502Sroot 
12437502Sroot /*
12447502Sroot  * Reprint the rawq line.
12457502Sroot  * We assume c_cc has already been checked.
12467502Sroot  */
12477502Sroot ttyretype(tp)
12487625Ssam 	register struct tty *tp;
12497502Sroot {
12507502Sroot 	register char *cp;
12517502Sroot 	char *nextc();
12527502Sroot 	int s;
12537502Sroot 
12547502Sroot 	if (tlun.t_rprntc != 0377)
12557502Sroot 		ttyecho(tlun.t_rprntc, tp);
12567502Sroot 	(void) ttyoutput('\n', tp);
12577502Sroot 	s = spl5();
12587502Sroot 	for (cp = tp->t_canq.c_cf; cp; cp = nextc(&tp->t_canq, cp))
12597502Sroot 		ttyecho(*cp, tp);
12607502Sroot 	for (cp = tp->t_rawq.c_cf; cp; cp = nextc(&tp->t_rawq, cp))
12617502Sroot 		ttyecho(*cp, tp);
12627502Sroot 	tp->t_lstate &= ~LSERASE;
12637502Sroot 	splx(s);
12647502Sroot 	tp->t_rocount = tp->t_rawq.c_cc;
12657502Sroot 	tp->t_rocol = 0;
12667502Sroot }
12677502Sroot 
12687502Sroot /*
12697502Sroot  * Echo a typed character to the terminal
12707502Sroot  */
12717502Sroot ttyecho(c, tp)
12727625Ssam 	register c;
12737625Ssam 	register struct tty *tp;
12747502Sroot {
12757502Sroot 
12767502Sroot 	if ((tp->t_lstate & LSCNTTB) == 0)
12777502Sroot 		tp->t_local &= ~LFLUSHO;
12787502Sroot 	if ((tp->t_flags&ECHO) == 0)
12797502Sroot 		return;
12807502Sroot 	c &= 0377;
12817502Sroot 	if (tp->t_flags&RAW) {
12827502Sroot 		(void) ttyoutput(c, tp);
12837502Sroot 		return;
12847502Sroot 	}
12857502Sroot 	if (c == '\r' && tp->t_flags&CRMOD)
12867502Sroot 		c = '\n';
12877502Sroot 	if (tp->t_local&LCTLECH) {
12887502Sroot 		if ((c&0177) <= 037 && c!='\t' && c!='\n' || (c&0177)==0177) {
12897502Sroot 			(void) ttyoutput('^', tp);
12907502Sroot 			c &= 0177;
12917502Sroot 			if (c == 0177)
12927502Sroot 				c = '?';
12937502Sroot 			else if (tp->t_flags&LCASE)
12947502Sroot 				c += 'a' - 1;
12957502Sroot 			else
12967502Sroot 				c += 'A' - 1;
12977502Sroot 		}
12987502Sroot 	}
12997502Sroot 	if ((tp->t_flags&LCASE) && (c >= 'A' && c <= 'Z'))
13007502Sroot 		c += 'a' - 'A';
13017502Sroot 	(void) ttyoutput(c & 0177, tp);
13027502Sroot }
13037502Sroot 
13047502Sroot /*
13057502Sroot  * Is c a break char for tp?
13067502Sroot  */
13077502Sroot ttbreakc(c, tp)
13087625Ssam 	register c;
13097625Ssam 	register struct tty *tp;
13107502Sroot {
13117502Sroot 	return (c == '\n' || c == tun.t_eofc || c == tun.t_brkc ||
13127502Sroot 		c == '\r' && (tp->t_flags&CRMOD));
13137502Sroot }
13147502Sroot 
13157502Sroot /*
13167502Sroot  * send string cp to tp
13177502Sroot  */
13187502Sroot ttyout(cp, tp)
13197625Ssam 	register char *cp;
13207625Ssam 	register struct tty *tp;
13217502Sroot {
13227502Sroot 	register char c;
13237502Sroot 
13247502Sroot 	while (c = *cp++)
13257502Sroot 		(void) ttyoutput(c, tp);
13267502Sroot }
13277502Sroot 
13287502Sroot ttwakeup(tp)
13297502Sroot 	struct tty *tp;
13307502Sroot {
13317502Sroot 
13327502Sroot 	if (tp->t_rsel) {
13337502Sroot 		selwakeup(tp->t_rsel, tp->t_state&TS_RCOLL);
13347502Sroot 		tp->t_state &= ~TS_RCOLL;
13357502Sroot 		tp->t_rsel = 0;
13367502Sroot 	}
13377502Sroot 	wakeup((caddr_t)&tp->t_rawq);
13387502Sroot }
13397502Sroot 
13407502Sroot ttsignal(tp, signo)
13417502Sroot 	struct tty *tp;
13427502Sroot 	int signo;
13437502Sroot {
13447502Sroot 
13457502Sroot 	gsignal(tp->t_pgrp, signo);
13467502Sroot }
1347