xref: /csrg-svn/sys/kern/tty.c (revision 9325)
1*9325Ssam /*	tty.c	4.34	82/11/22	*/
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] =
988954Sroot    { 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:
267*9325Ssam 	case TIOCSTI:
268903Sbill 		while (tp->t_line == NTTYDISC &&
269903Sbill 		   u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp &&
270903Sbill 		   (u.u_procp->p_flag&SVFORK) == 0 &&
271903Sbill 		   u.u_signal[SIGTTOU] != SIG_IGN &&
2728556Sroot 		   u.u_signal[SIGTTOU] != SIG_HOLD) {
273903Sbill 			gsignal(u.u_procp->p_pgrp, SIGTTOU);
274903Sbill 			sleep((caddr_t)&lbolt, TTOPRI);
275903Sbill 		}
276903Sbill 		break;
277903Sbill 	}
278903Sbill 
2797625Ssam 	switch (com) {
280903Sbill 
2818556Sroot 	/* get discipline number */
28239Sbill 	case TIOCGETD:
2837625Ssam 		*(int *)data = tp->t_line;
28439Sbill 		break;
28539Sbill 
2868556Sroot 	/* set line discipline */
2877625Ssam 	case TIOCSETD: {
2887625Ssam 		register int t = *(int *)data;
2898556Sroot 		int error;
2907625Ssam 
2918556Sroot 		if (t >= nldisp)
2928556Sroot 			return (ENXIO);
2938556Sroot 		s = spl5();
29439Sbill 		if (tp->t_line)
29539Sbill 			(*linesw[tp->t_line].l_close)(tp);
29639Sbill 		if (t)
2978556Sroot 			error = (*linesw[t].l_open)(dev, tp);
2988556Sroot 		splx(s);
2998556Sroot 		if (error)
3008556Sroot 			return (error);
3018556Sroot 		tp->t_line = t;
30239Sbill 		break;
3037625Ssam 	}
30439Sbill 
3058556Sroot 	/* prevent more opens on channel */
3065614Swnj 	case TIOCEXCL:
3075614Swnj 		tp->t_state |= TS_XCLUDE;
3085614Swnj 		break;
3095614Swnj 
3105614Swnj 	case TIOCNXCL:
3115614Swnj 		tp->t_state &= ~TS_XCLUDE;
3125614Swnj 		break;
3135614Swnj 
3148556Sroot 	/* set new parameters */
31539Sbill 	case TIOCSETP:
3167625Ssam 	case TIOCSETN: {
3177625Ssam 		register struct sgttyb *sg = (struct sgttyb *)data;
3187625Ssam 		struct clist tq;
3197625Ssam 
320121Sbill 		(void) spl5();
3217625Ssam 		if (tp->t_flags&RAW || sg->sg_flags&RAW || com == TIOCSETP)
3224484Swnj 			wflushtty(tp);
3237625Ssam 		else if ((tp->t_flags&CBREAK) != (sg->sg_flags&CBREAK)) {
3247625Ssam 			if (sg->sg_flags & CBREAK) {
3254484Swnj 				catq(&tp->t_rawq, &tp->t_canq);
3264484Swnj 				tq = tp->t_rawq;
3274484Swnj 				tp->t_rawq = tp->t_canq;
3284484Swnj 				tp->t_canq = tq;
3294484Swnj 			} else {
3304484Swnj 				tp->t_local |= LPENDIN;
3314484Swnj 				ttwakeup(tp);
332174Sbill 			}
333174Sbill 		}
3347625Ssam 		tp->t_ispeed = sg->sg_ispeed;
3357625Ssam 		tp->t_ospeed = sg->sg_ospeed;
3367625Ssam 		tp->t_erase = sg->sg_erase;
3377625Ssam 		tp->t_kill = sg->sg_kill;
3387625Ssam 		tp->t_flags = sg->sg_flags;
3393941Sbugs 		if (tp->t_flags & RAW) {
3405408Swnj 			tp->t_state &= ~TS_TTSTOP;
3413941Sbugs 			ttstart(tp);
3423941Sbugs 		}
343121Sbill 		(void) spl0();
34439Sbill 		break;
3457625Ssam 	}
34639Sbill 
3478556Sroot 	/* send current parameters to user */
3487625Ssam 	case TIOCGETP: {
3497625Ssam 		register struct sgttyb *sg = (struct sgttyb *)data;
3507625Ssam 
3517625Ssam 		sg->sg_ispeed = tp->t_ispeed;
3527625Ssam 		sg->sg_ospeed = tp->t_ospeed;
3537625Ssam 		sg->sg_erase = tp->t_erase;
3547625Ssam 		sg->sg_kill = tp->t_kill;
3557625Ssam 		sg->sg_flags = tp->t_flags;
35639Sbill 		break;
3577625Ssam 	}
35839Sbill 
3598556Sroot 	/* hang up line on last close */
36039Sbill 	case TIOCHPCL:
3615408Swnj 		tp->t_state |= TS_HUPCLS;
36239Sbill 		break;
36339Sbill 
3643942Sbugs 	case TIOCFLUSH: {
3657625Ssam 		register int flags = *(int *)data;
3667625Ssam 
3677625Ssam 		if (flags == 0)
3683942Sbugs 			flags = FREAD|FWRITE;
3697625Ssam 		else
3707625Ssam 			flags &= FREAD|FWRITE;
3713942Sbugs 		flushtty(tp, flags);
37239Sbill 		break;
3733944Sbugs 	}
37439Sbill 
3757625Ssam 	case FIONBIO:
3767625Ssam 		if (*(int *)data)
3775408Swnj 			tp->t_state |= TS_NBIO;
3785408Swnj 		else
3795408Swnj 			tp->t_state &= ~TS_NBIO;
3805408Swnj 		break;
3815408Swnj 
3827625Ssam 	case FIOASYNC:
3837625Ssam 		if (*(int *)data)
3846216Swnj 			tp->t_state |= TS_ASYNC;
3856216Swnj 		else
3866216Swnj 			tp->t_state &= ~TS_ASYNC;
3876216Swnj 		break;
3886216Swnj 
3898556Sroot 	/* set and fetch special characters */
39039Sbill 	case TIOCSETC:
3917625Ssam 		bcopy(data, (caddr_t)&tun, sizeof (struct tchars));
39239Sbill 		break;
39339Sbill 
39439Sbill 	case TIOCGETC:
3957625Ssam 		bcopy((caddr_t)&tun, data, sizeof (struct tchars));
39639Sbill 		break;
39739Sbill 
3988556Sroot 	/* set/get local special characters */
399174Sbill 	case TIOCSLTC:
4007625Ssam 		bcopy(data, (caddr_t)&tlun, sizeof (struct ltchars));
401174Sbill 		break;
402174Sbill 
403174Sbill 	case TIOCGLTC:
4047625Ssam 		bcopy((caddr_t)&tlun, data, sizeof (struct ltchars));
405174Sbill 		break;
406174Sbill 
4078556Sroot 	/* return number of characters immediately available */
4087625Ssam 	case FIONREAD:
4097625Ssam 		*(off_t *)data = ttnread(tp);
410174Sbill 		break;
411174Sbill 
4128556Sroot 	/* should allow SPGRP and GPGRP only if tty open for reading */
413174Sbill 	case TIOCSPGRP:
4147625Ssam 		tp->t_pgrp = *(int *)data;
415174Sbill 		break;
416174Sbill 
417174Sbill 	case TIOCGPGRP:
4187625Ssam 		*(int *)data = tp->t_pgrp;
419174Sbill 		break;
420174Sbill 
4218556Sroot 	/* Modify local mode word */
422174Sbill 	case TIOCLBIS:
4237625Ssam 		tp->t_local |= *(int *)data;
424174Sbill 		break;
425174Sbill 
426174Sbill 	case TIOCLBIC:
4277625Ssam 		tp->t_local &= ~(*(int *)data);
428174Sbill 		break;
429174Sbill 
430174Sbill 	case TIOCLSET:
4317625Ssam 		tp->t_local = *(int *)data;
432174Sbill 		break;
433174Sbill 
434174Sbill 	case TIOCLGET:
4357625Ssam 		*(int *)data = tp->t_local;
436174Sbill 		break;
437174Sbill 
4388589Sroot 	case TIOCSTOP:
4398589Sroot 		s = spl5();
4405573Swnj 		if ((tp->t_state & TS_TTSTOP) == 0) {
4415573Swnj 			tp->t_state |= TS_TTSTOP;
4425573Swnj 			(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
4435573Swnj 		}
4447625Ssam 		splx(s);
4455573Swnj 		break;
4465573Swnj 
4478589Sroot 	case TIOCSTART:
4488589Sroot 		s = spl5();
4495573Swnj 		if ((tp->t_state & TS_TTSTOP) || (tp->t_local & LFLUSHO)) {
4505573Swnj 			tp->t_state &= ~TS_TTSTOP;
4515573Swnj 			tp->t_local &= ~LFLUSHO;
4525573Swnj 			ttstart(tp);
4535573Swnj 		}
4547625Ssam 		splx(s);
4555573Swnj 		break;
4565573Swnj 
457*9325Ssam 	/*
458*9325Ssam 	 * Simulate typing of a character at the terminal.
459*9325Ssam 	 */
460*9325Ssam 	case TIOCSTI:
461*9325Ssam 		if (u.u_uid && u.u_ttyp != tp)
462*9325Ssam 			return (EACCES);
463*9325Ssam 		else
464*9325Ssam 			(*linesw[tp->t_line].l_rint)(*(char *)data, tp);
465*9325Ssam 		break;
466*9325Ssam 
46739Sbill 	default:
4688556Sroot 		return (-1);
46939Sbill 	}
4708556Sroot 	return (0);
47139Sbill }
4724484Swnj 
4734484Swnj ttnread(tp)
4744484Swnj 	struct tty *tp;
4754484Swnj {
4764484Swnj 	int nread = 0;
4774484Swnj 
4784484Swnj 	if (tp->t_local & LPENDIN)
4794484Swnj 		ttypend(tp);
4804484Swnj 	nread = tp->t_canq.c_cc;
4814484Swnj 	if (tp->t_flags & (RAW|CBREAK))
4824484Swnj 		nread += tp->t_rawq.c_cc;
4834484Swnj 	return (nread);
4844484Swnj }
4854484Swnj 
4865408Swnj ttselect(dev, rw)
4874484Swnj 	dev_t dev;
4885408Swnj 	int rw;
4894484Swnj {
4904484Swnj 	register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)];
4914484Swnj 	int nread;
4925408Swnj 	int s = spl5();
4934484Swnj 
4945408Swnj 	switch (rw) {
4954484Swnj 
4964484Swnj 	case FREAD:
4974484Swnj 		nread = ttnread(tp);
4984484Swnj 		if (nread > 0)
4995408Swnj 			goto win;
5004938Swnj 		if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait)
5015408Swnj 			tp->t_state |= TS_RCOLL;
5024484Swnj 		else
5034484Swnj 			tp->t_rsel = u.u_procp;
5045408Swnj 		break;
5054484Swnj 
5065408Swnj 	case FWRITE:
5075408Swnj 		if (tp->t_outq.c_cc <= TTLOWAT(tp))
5085408Swnj 			goto win;
5095408Swnj 		if (tp->t_wsel && tp->t_wsel->p_wchan == (caddr_t)&selwait)
5105408Swnj 			tp->t_state |= TS_WCOLL;
5115408Swnj 		else
5125408Swnj 			tp->t_wsel = u.u_procp;
5135408Swnj 		break;
5144484Swnj 	}
5155408Swnj 	splx(s);
5165408Swnj 	return (0);
5175408Swnj win:
5185408Swnj 	splx(s);
5195408Swnj 	return (1);
5204484Swnj }
5217436Skre 
5227502Sroot #define	OBUFSIZ	100
5237502Sroot 
5247502Sroot /*
5257502Sroot  * routine called on opens while tp->t_line == NTTYDISC
5267502Sroot  * establishes a process group for distribution of
5277502Sroot  * quits and interrupts from the tty.
5287502Sroot  * (actually, pp->p_pgrp can't be 0 when this routine
5297502Sroot  * is called since NTTYDISC is not the default discipline)
5307502Sroot  */
5317502Sroot ttyopen(dev, tp)
5327625Ssam 	dev_t dev;
5337625Ssam 	register struct tty *tp;
5347502Sroot {
5357502Sroot 	register struct proc *pp;
5367502Sroot 
5377502Sroot 	pp = u.u_procp;
5387502Sroot 	tp->t_dev = dev;
5397625Ssam 	if (pp->p_pgrp == 0) {
5407502Sroot 		u.u_ttyp = tp;
5417502Sroot 		u.u_ttyd = dev;
5427502Sroot 		if (tp->t_pgrp == 0)
5437502Sroot 			tp->t_pgrp = pp->p_pid;
5447502Sroot 		pp->p_pgrp = tp->t_pgrp;
5457502Sroot 	}
5467502Sroot 	tp->t_state &= ~TS_WOPEN;
5477502Sroot 	tp->t_state |= TS_ISOPEN;
5487502Sroot 	if (tp->t_line != NTTYDISC)
5497502Sroot 		wflushtty(tp);
5508556Sroot 	return (0);
5517502Sroot }
5527502Sroot 
5537502Sroot /*
5547502Sroot  * clean tp on last close
5557502Sroot  */
5567502Sroot ttyclose(tp)
5577625Ssam 	register struct tty *tp;
5587502Sroot {
5597502Sroot 
5607502Sroot 	if (tp->t_line) {
5617502Sroot 		wflushtty(tp);
5627502Sroot 		tp->t_line = 0;
5637502Sroot 		return;
5647502Sroot 	}
5657502Sroot 	tp->t_pgrp = 0;
5667502Sroot 	wflushtty(tp);
5677502Sroot 	tp->t_state = 0;
5687502Sroot }
5697502Sroot 
5707502Sroot /*
5717502Sroot  * reinput pending characters after state switch
5727502Sroot  * call at spl5().
5737502Sroot  */
5747502Sroot ttypend(tp)
5757625Ssam 	register struct tty *tp;
5767502Sroot {
5777502Sroot 	struct clist tq;
5787502Sroot 	register c;
5797502Sroot 
5807502Sroot 	tp->t_local &= ~LPENDIN;
5817502Sroot 	tp->t_lstate |= LSTYPEN;
5827502Sroot 	tq = tp->t_rawq;
5837502Sroot 	tp->t_rawq.c_cc = 0;
5847502Sroot 	tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0;
5857502Sroot 	while ((c = getc(&tq)) >= 0)
5867502Sroot 		ttyinput(c, tp);
5877502Sroot 	tp->t_lstate &= ~LSTYPEN;
5887502Sroot }
5897502Sroot 
5907502Sroot /*
5917502Sroot  * Place a character on raw TTY input queue, putting in delimiters
5927502Sroot  * and waking up top half as needed.
5937502Sroot  * Also echo if required.
5947502Sroot  * The arguments are the character and the appropriate
5957502Sroot  * tty structure.
5967502Sroot  */
5977502Sroot ttyinput(c, tp)
5987625Ssam 	register c;
5997625Ssam 	register struct tty *tp;
6007502Sroot {
6017502Sroot 	register int t_flags;
6027502Sroot 	int i;
6037502Sroot 
6047502Sroot 	if (tp->t_local&LPENDIN)
6057502Sroot 		ttypend(tp);
6067502Sroot 	tk_nin++;
6077502Sroot 	c &= 0377;
6087502Sroot 	t_flags = tp->t_flags;
6097502Sroot 	if (t_flags&TANDEM)
6107502Sroot 		ttyblock(tp);
6117502Sroot 	if ((t_flags&RAW)==0) {
6127502Sroot 		if ((tp->t_lstate&LSTYPEN) == 0)
6137502Sroot 			c &= 0177;
6147502Sroot 	/* check for literal nexting very first */
6157502Sroot 		if (tp->t_lstate&LSLNCH) {
6167502Sroot 			c |= 0200;
6177502Sroot 			tp->t_lstate &= ~LSLNCH;
6187502Sroot 		}
6197502Sroot 		if (tp->t_line == NTTYDISC && c==tlun.t_lnextc) {
6207502Sroot 			if (tp->t_flags&ECHO)
6217502Sroot 				ttyout("^\b", tp);
6227502Sroot 			tp->t_lstate |= LSLNCH;
6237502Sroot 	/* check for output control functions */
6247502Sroot 		} else if (c==tun.t_stopc) {
6257502Sroot 			if ((tp->t_state&TS_TTSTOP)==0) {
6267502Sroot 				tp->t_state |= TS_TTSTOP;
6277502Sroot 				(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
6287502Sroot 				return;
6297502Sroot 			}
6307502Sroot 			if (c!=tun.t_startc)
6317502Sroot 				return;
6327502Sroot 		} else if (c==tun.t_startc) {
6337502Sroot 			tp->t_state &= ~TS_TTSTOP;
6347502Sroot 			tp->t_local &= ~LFLUSHO;
6357502Sroot 			ttstart(tp);
6367502Sroot 			return;
6377502Sroot 		} else if (tp->t_line == NTTYDISC && c==tlun.t_flushc) {
6387502Sroot 			if (tp->t_local & LFLUSHO)
6397502Sroot 				tp->t_local &= ~LFLUSHO;
6407502Sroot 			else {
6417502Sroot 				flushtty(tp, FWRITE);
6427502Sroot 				ttyecho(c, tp);
6437502Sroot 				if (tp->t_rawq.c_cc+tp->t_canq.c_cc)
6447502Sroot 					ttyretype(tp);
6457502Sroot 				tp->t_local |= LFLUSHO;
6467502Sroot 			}
6477502Sroot 			ttstart(tp);
6487502Sroot 			return;
6497502Sroot 		} else if (c==tun.t_intrc || c==tun.t_quitc ||
6507502Sroot 		    (tp->t_line == NTTYDISC && c==tlun.t_suspc)) {
6517502Sroot 			if ((tp->t_local & LNOFLSH) == 0)
6527502Sroot 				flushtty(tp,
6537502Sroot 				    c==tlun.t_suspc ? FREAD : FREAD|FWRITE);
6547502Sroot 			ttyecho(c, tp);
6557502Sroot 			c = c==tun.t_intrc ? SIGINT :
6567502Sroot 				((c==tun.t_quitc) ? SIGQUIT : SIGTSTP);
6577502Sroot 			ttsignal(tp, c);
6587502Sroot 	/* check for buffer editing functions - cooked mode */
6597502Sroot 		} else if ((t_flags&CBREAK) == 0) {
6607502Sroot 			if ((tp->t_lstate&LSQUOT) &&
6617502Sroot 			    (c==tp->t_erase||c==tp->t_kill)) {
6627502Sroot 				ttyrub(unputc(&tp->t_rawq), tp);
6637502Sroot 				c |= 0200;
6647502Sroot 			}
6657502Sroot 			if (c==tp->t_erase) {
6667502Sroot 				if (tp->t_rawq.c_cc)
6677502Sroot 					ttyrub(unputc(&tp->t_rawq), tp);
6687502Sroot 			} else if (c==tp->t_kill) {
6697502Sroot 				if (tp->t_local&LCRTKIL &&
6707502Sroot 				    tp->t_rawq.c_cc == tp->t_rocount) {
6717502Sroot 					while (tp->t_rawq.c_cc)
6727502Sroot 						ttyrub(unputc(&tp->t_rawq), tp);
6737502Sroot 				} else {
6747502Sroot 					ttyecho(c, tp);
6757502Sroot 					ttyecho('\n', tp);
6767502Sroot 					while (getc(&tp->t_rawq) > 0)
6777502Sroot 						;
6787502Sroot 					tp->t_rocount = 0;
6797502Sroot 				}
6807502Sroot 				tp->t_lstate = 0;
6817502Sroot 			} else if (tp->t_line == NTTYDISC && c==tlun.t_werasc) {
6827502Sroot 				if (tp->t_rawq.c_cc == 0)
6837502Sroot 					goto out;
6847502Sroot 				do {
6857502Sroot 					c = unputc(&tp->t_rawq);
6867502Sroot 					if (c != ' ' && c != '\t')
6877502Sroot 						goto erasenb;
6887502Sroot 					ttyrub(c, tp);
6897502Sroot 				} while (tp->t_rawq.c_cc);
6907502Sroot 				goto out;
6917502Sroot 			    erasenb:
6927502Sroot 				do {
6937502Sroot 					ttyrub(c, tp);
6947502Sroot 					if (tp->t_rawq.c_cc == 0)
6957502Sroot 						goto out;
6967502Sroot 					c = unputc(&tp->t_rawq);
6977502Sroot 				} while (c != ' ' && c != '\t');
6987502Sroot 				(void) putc(c, &tp->t_rawq);
6997502Sroot 			} else if (tp->t_line == NTTYDISC && c==tlun.t_rprntc) {
7007502Sroot 				ttyretype(tp);
7017502Sroot 	/* check for cooked mode input buffer overflow */
7027502Sroot 			} else if (tp->t_rawq.c_cc+tp->t_canq.c_cc >= TTYHOG) {
7037502Sroot 				;
7047502Sroot 	/* put data char in q for user and wakeup if a break char */
7057502Sroot 			} else if (putc(c, &tp->t_rawq) >= 0) {
7067502Sroot 				if (tp->t_rawq.c_cc+tp->t_canq.c_cc==TTYHOG
7077502Sroot 				    && tp->t_line == NTTYDISC)
7087502Sroot 					(void) ttyoutput(CTRL(g), tp);
7097502Sroot 				if (!ttbreakc(c, tp)) {
7107502Sroot 					if (tp->t_rocount++ == 0)
7117502Sroot 						tp->t_rocol = tp->t_col;
7127502Sroot 				} else {
7137502Sroot 					tp->t_rocount = 0;
7147502Sroot 					catq(&tp->t_rawq, &tp->t_canq);
7157502Sroot 					/* IF (TP->T_CHAN) (VOID) SDATA(TP->T_CHAN); */
7167502Sroot 					ttwakeup(tp);
7177502Sroot 				}
7187502Sroot 				tp->t_lstate &= ~LSQUOT;
7197502Sroot 				if (c == '\\')
7207502Sroot 					tp->t_lstate |= LSQUOT;
7217502Sroot 				if (tp->t_lstate&LSERASE) {
7227502Sroot 					tp->t_lstate &= ~LSERASE;
7237502Sroot 					(void) ttyoutput('/', tp);
7247502Sroot 				}
7257502Sroot 				i = tp->t_col;
7267502Sroot 				ttyecho(c, tp);
7277502Sroot 				if (c==tun.t_eofc && tp->t_flags&ECHO) {
7287502Sroot 					i = MIN(2, tp->t_col - i);
7297502Sroot 					while (i > 0) {
7307502Sroot 						(void) ttyoutput('\b', tp);
7317502Sroot 						i--;
7327502Sroot 					}
7337502Sroot 				}
7347502Sroot 			}
7357502Sroot 	/* CBREAK mode */
7367502Sroot 		} else if (tp->t_rawq.c_cc > TTYHOG) {
7377502Sroot 			if (tp->t_outq.c_cc < TTHIWAT(tp) &&
7387502Sroot 			    tp->t_line == NTTYDISC)
7397502Sroot 				(void) ttyoutput(CTRL(g), tp);
7407502Sroot 		} else if (putc(c, &tp->t_rawq) >= 0) {
7417502Sroot 			ttwakeup(tp);
7427502Sroot 			ttyecho(c, tp);
7437502Sroot 		}
7447502Sroot 	/* RAW mode */
7457502Sroot 	} else if (tp->t_rawq.c_cc > TTYHOG)
7467502Sroot 		flushtty(tp, FREAD|FWRITE);
7477502Sroot 	else {
7487502Sroot 		if (putc(c, &tp->t_rawq) >= 0)
7497502Sroot 			ttwakeup(tp);
7507502Sroot 		ttyecho(c, tp);
7517502Sroot 	}
7527502Sroot out:
7537502Sroot 	if (tp->t_local & LDECCTQ && tp->t_state & TS_TTSTOP &&
7547502Sroot 	    tun.t_startc != tun.t_stopc)
7557502Sroot 		return;
7567502Sroot 	tp->t_state &= ~TS_TTSTOP;
7577502Sroot 	tp->t_local &= ~LFLUSHO;
7587502Sroot 	ttstart(tp);
7597502Sroot }
7607502Sroot 
7617502Sroot /*
7627502Sroot  * put character on TTY output queue, adding delays,
7637502Sroot  * expanding tabs, and handling the CR/NL bit.
7647502Sroot  * It is called both from the top half for output, and from
7657502Sroot  * interrupt level for echoing.
7667502Sroot  * The arguments are the character and the tty structure.
7677502Sroot  * Returns < 0 if putc succeeds, otherwise returns char to resend
7687502Sroot  * Must be recursive.
7697502Sroot  */
7707502Sroot ttyoutput(c, tp)
7717502Sroot 	register c;
7727502Sroot 	register struct tty *tp;
7737502Sroot {
7747502Sroot 	register char *colp;
7757502Sroot 	register ctype;
7767502Sroot 
7777502Sroot 	if (tp->t_flags&RAW || tp->t_local&LLITOUT) {
7787502Sroot 		if (tp->t_local&LFLUSHO)
7797502Sroot 			return (-1);
7807502Sroot 		if (putc(c, &tp->t_outq))
7817625Ssam 			return (c);
7827502Sroot 		tk_nout++;
7837502Sroot 		return (-1);
7847502Sroot 	}
7857502Sroot 	/*
7867502Sroot 	 * Ignore EOT in normal mode to avoid hanging up
7877502Sroot 	 * certain terminals.
7887502Sroot 	 */
7897502Sroot 	c &= 0177;
7907502Sroot 	if (c==CEOT && (tp->t_flags&CBREAK)==0)
7917502Sroot 		return (-1);
7927502Sroot 	/*
7937502Sroot 	 * Turn tabs to spaces as required
7947502Sroot 	 */
7957502Sroot 	if (c=='\t' && (tp->t_flags&TBDELAY)==XTABS) {
7967502Sroot 		register int s;
7977502Sroot 
7987502Sroot 		c = 8 - (tp->t_col&7);
7997502Sroot 		if ((tp->t_local&LFLUSHO) == 0) {
8007502Sroot 			s = spl5();		/* don't interrupt tabs */
8017502Sroot 			c -= b_to_q("        ", c, &tp->t_outq);
8027502Sroot 			tk_nout += c;
8037502Sroot 			splx(s);
8047502Sroot 		}
8057502Sroot 		tp->t_col += c;
8067502Sroot 		return (c ? -1 : '\t');
8077502Sroot 	}
8087502Sroot 	tk_nout++;
8097502Sroot 	/*
8107502Sroot 	 * for upper-case-only terminals,
8117502Sroot 	 * generate escapes.
8127502Sroot 	 */
8137502Sroot 	if (tp->t_flags&LCASE) {
8147502Sroot 		colp = "({)}!|^~'`";
8157625Ssam 		while (*colp++)
8167625Ssam 			if (c == *colp++) {
8177502Sroot 				if (ttyoutput('\\', tp) >= 0)
8187502Sroot 					return (c);
8197502Sroot 				c = colp[-2];
8207502Sroot 				break;
8217502Sroot 			}
8227502Sroot 		if ('A'<=c && c<='Z') {
8237502Sroot 			if (ttyoutput('\\', tp) >= 0)
8247502Sroot 				return (c);
8257502Sroot 		} else if ('a'<=c && c<='z')
8267502Sroot 			c += 'A' - 'a';
8277502Sroot 	}
8287502Sroot 	/*
8297502Sroot 	 * turn <nl> to <cr><lf> if desired.
8307502Sroot 	 */
8317502Sroot 	if (c=='\n' && tp->t_flags&CRMOD)
8327502Sroot 		if (ttyoutput('\r', tp) >= 0)
8337502Sroot 			return (c);
8347502Sroot 	if (c=='~' && tp->t_local&LTILDE)
8357502Sroot 		c = '`';
8367502Sroot 	if ((tp->t_local&LFLUSHO) == 0 && putc(c, &tp->t_outq))
8377502Sroot 		return (c);
8387502Sroot 	/*
8397502Sroot 	 * Calculate delays.
8407502Sroot 	 * The numbers here represent clock ticks
8417502Sroot 	 * and are not necessarily optimal for all terminals.
8427502Sroot 	 * The delays are indicated by characters above 0200.
8437502Sroot 	 * In raw mode there are no delays and the
8447502Sroot 	 * transmission path is 8 bits wide.
8457502Sroot 	 */
8467502Sroot 	colp = &tp->t_col;
8477502Sroot 	ctype = partab[c];
8487502Sroot 	c = 0;
8497502Sroot 	switch (ctype&077) {
8507502Sroot 
8517502Sroot 	case ORDINARY:
8527502Sroot 		(*colp)++;
8537502Sroot 
8547502Sroot 	case CONTROL:
8557502Sroot 		break;
8567502Sroot 
8577502Sroot 	case BACKSPACE:
8587502Sroot 		if (*colp)
8597502Sroot 			(*colp)--;
8607502Sroot 		break;
8617502Sroot 
8627502Sroot 	case NEWLINE:
8637502Sroot 		ctype = (tp->t_flags >> 8) & 03;
8647625Ssam 		if (ctype == 1) { /* tty 37 */
8657502Sroot 			if (*colp)
8667502Sroot 				c = max(((unsigned)*colp>>4) + 3, (unsigned)6);
8677502Sroot 		} else
8687625Ssam 		if (ctype == 2) { /* vt05 */
8697502Sroot 			c = 6;
8707502Sroot 		}
8717502Sroot 		*colp = 0;
8727502Sroot 		break;
8737502Sroot 
8747502Sroot 	case TAB:
8757502Sroot 		ctype = (tp->t_flags >> 10) & 03;
8767625Ssam 		if (ctype == 1) { /* tty 37 */
8777502Sroot 			c = 1 - (*colp | ~07);
8787625Ssam 			if (c < 5)
8797502Sroot 				c = 0;
8807502Sroot 		}
8817502Sroot 		*colp |= 07;
8827502Sroot 		(*colp)++;
8837502Sroot 		break;
8847502Sroot 
8857502Sroot 	case VTAB:
8867625Ssam 		if (tp->t_flags & VTDELAY) /* tty 37 */
8877502Sroot 			c = 0177;
8887502Sroot 		break;
8897502Sroot 
8907502Sroot 	case RETURN:
8917502Sroot 		ctype = (tp->t_flags >> 12) & 03;
8927625Ssam 		if (ctype == 1) { /* tn 300 */
8937502Sroot 			c = 5;
8947625Ssam 		} else if (ctype == 2) { /* ti 700 */
8957502Sroot 			c = 10;
8967625Ssam 		} else if (ctype == 3) { /* concept 100 */
8977502Sroot 			int i;
8987502Sroot 			if ((i = *colp) >= 0)
8997502Sroot 				for (; i<9; i++)
9007502Sroot 					(void) putc(0177, &tp->t_outq);
9017502Sroot 		}
9027502Sroot 		*colp = 0;
9037502Sroot 	}
9047625Ssam 	if (c && (tp->t_local&LFLUSHO) == 0)
9057502Sroot 		(void) putc(c|0200, &tp->t_outq);
9067502Sroot 	return (-1);
9077502Sroot }
9087502Sroot 
9097502Sroot /*
9107502Sroot  * Called from device's read routine after it has
9117502Sroot  * calculated the tty-structure given as argument.
9127502Sroot  */
9137722Swnj ttread(tp, uio)
9147625Ssam 	register struct tty *tp;
9157722Swnj 	struct uio *uio;
9167502Sroot {
9177502Sroot 	register struct clist *qp;
9187502Sroot 	register c, first;
9198520Sroot 	int error = 0;
9207502Sroot 
9217502Sroot 	if ((tp->t_state&TS_CARR_ON)==0)
9228520Sroot 		return (EIO);
9237502Sroot loop:
9247502Sroot 	(void) spl5();
9257502Sroot 	if (tp->t_local&LPENDIN)
9267502Sroot 		ttypend(tp);
9277502Sroot 	(void) spl0();
9287502Sroot 	while (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) {
9297502Sroot 		if (u.u_signal[SIGTTIN] == SIG_IGN ||
9307502Sroot 		    u.u_signal[SIGTTIN] == SIG_HOLD ||
9317502Sroot /*
9327502Sroot 		    (u.u_procp->p_flag&SDETACH) ||
9337502Sroot */
9347502Sroot 		    u.u_procp->p_flag&SVFORK)
9358520Sroot 			return (EIO);
9367502Sroot 		gsignal(u.u_procp->p_pgrp, SIGTTIN);
9377502Sroot 		sleep((caddr_t)&lbolt, TTIPRI);
9387502Sroot 	}
9397502Sroot 	if (tp->t_flags&RAW) {
9407502Sroot 		(void) spl5();
9417502Sroot 		if (tp->t_rawq.c_cc <= 0) {
9427502Sroot 			if ((tp->t_state&TS_CARR_ON)==0 ||
9437502Sroot 			    (tp->t_state&TS_NBIO)) {
9447502Sroot 				(void) spl0();
9458520Sroot 				return (EWOULDBLOCK);
9467502Sroot 			}
9477502Sroot 			sleep((caddr_t)&tp->t_rawq, TTIPRI);
9487502Sroot 			(void) spl0();
9497502Sroot 			goto loop;
9507502Sroot 		}
9517502Sroot 		(void) spl0();
9527722Swnj 		while (tp->t_rawq.c_cc && uio->uio_iovcnt) {
9538520Sroot 			error = passuc(getc(&tp->t_rawq), uio);
9548520Sroot 			if (error)
9557722Swnj 				break;
9567722Swnj 		}
9578520Sroot 		return (error);
9587502Sroot 	} else {
9597502Sroot 		qp = tp->t_flags & CBREAK ? &tp->t_rawq : &tp->t_canq;
9607502Sroot 		(void) spl5();
9617502Sroot 		if (qp->c_cc <= 0) {
9627502Sroot 			if ((tp->t_state&TS_CARR_ON)==0 ||
9637502Sroot 			    (tp->t_state&TS_NBIO)) {
9647502Sroot 				(void) spl0();
9658520Sroot 				return (EWOULDBLOCK);
9667502Sroot 			}
9677502Sroot 			sleep((caddr_t)&tp->t_rawq, TTIPRI);
9687502Sroot 			(void) spl0();
9697502Sroot 			goto loop;
9707502Sroot 		}
9717502Sroot 		(void) spl0();
9727502Sroot 		first = 1;
9737502Sroot 		while ((c = getc(qp)) >= 0) {
9747502Sroot 			if (tp->t_flags&CRMOD && c == '\r')
9757502Sroot 				c = '\n';
9767502Sroot 			if (tp->t_flags&LCASE && c <= 0177)
9777502Sroot 				if (tp->t_lstate&LSBKSL) {
9787502Sroot 					if (maptab[c])
9797502Sroot 						c = maptab[c];
9807502Sroot 					tp->t_lstate &= ~LSBKSL;
9817502Sroot 				} else if (c >= 'A' && c <= 'Z')
9827502Sroot 					c += 'a' - 'A';
9837502Sroot 				else if (c == '\\') {
9847502Sroot 					tp->t_lstate |= LSBKSL;
9857502Sroot 					continue;
9867502Sroot 				}
9877658Ssam 			if (tp->t_line == NTTYDISC && c == tlun.t_dsuspc) {
9887502Sroot 				ttsignal(tp, SIGTSTP);
9897502Sroot 				if (first) {
9907502Sroot 					sleep((caddr_t)&lbolt, TTIPRI);
9917502Sroot 					goto loop;
9927502Sroot 				}
9937502Sroot 				break;
9947502Sroot 			}
9957502Sroot 			if (c == tun.t_eofc && (tp->t_flags&CBREAK)==0)
9967502Sroot 				break;
9978520Sroot 			error = passuc(c & 0177, uio);
9988520Sroot 			if (error)
9997502Sroot 				break;
10007722Swnj 			if (uio->uio_iovcnt == 0)
10017722Swnj 				break;
10027502Sroot 			if ((tp->t_flags&CBREAK)==0 && ttbreakc(c, tp))
10037502Sroot 				break;
10047502Sroot 			first = 0;
10057502Sroot 		}
10067502Sroot 		tp->t_lstate &= ~LSBKSL;
10077502Sroot 	}
10087502Sroot 	if (tp->t_state&TS_TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) {
10097502Sroot 		if (putc(tun.t_startc, &tp->t_outq)==0) {
10107502Sroot 			tp->t_state &= ~TS_TBLOCK;
10117502Sroot 			ttstart(tp);
10127502Sroot 		}
10137502Sroot 		tp->t_char = 0;
10147502Sroot 	}
10158520Sroot 	return (error);
10167502Sroot }
10177502Sroot 
10187502Sroot /*
10197502Sroot  * Called from the device's write routine after it has
10207502Sroot  * calculated the tty-structure given as argument.
10217502Sroot  */
10227822Sroot ttwrite(tp, uio)
10237625Ssam 	register struct tty *tp;
10247822Sroot 	struct uio *uio;
10257502Sroot {
10267502Sroot #ifdef vax
10277502Sroot 	/*
10287502Sroot 	 * THE POSITIONING OF CP, CC, AND CE ARE CRITICAL
10297502Sroot 	 * AND MUST NOT BE CHANGED WITHOUT PATCHING
10307502Sroot 	 * THE 'ASM' INLINES BELOW.  WATCH OUT.
10317502Sroot 	 */
10327502Sroot #endif
10337502Sroot 	register char *cp;
10347502Sroot 	register int cc, ce;
10357502Sroot 	register i;
10367502Sroot 	char obuf[OBUFSIZ];
10377502Sroot 	register c;
10387502Sroot 	int hiwat = TTHIWAT(tp);
10397822Sroot 	int cnt = uio->uio_resid;
10408520Sroot 	int error = 0;
10417502Sroot 
10427502Sroot 	if ((tp->t_state&TS_CARR_ON)==0)
10438520Sroot 		return (EIO);
10447502Sroot loop:
10457502Sroot 	while (u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp &&
10467502Sroot 	    (tp->t_local&LTOSTOP) && (u.u_procp->p_flag&SVFORK)==0 &&
10477502Sroot 	    u.u_signal[SIGTTOU] != SIG_IGN &&
10487502Sroot 	    u.u_signal[SIGTTOU] != SIG_HOLD
10497502Sroot /*
10507502Sroot 					     &&
10517502Sroot 	    (u.u_procp->p_flag&SDETACH)==0) {
10527502Sroot */
10537502Sroot 	    ) {
10547502Sroot 		gsignal(u.u_procp->p_pgrp, SIGTTOU);
10557502Sroot 		sleep((caddr_t)&lbolt, TTIPRI);
10567502Sroot 	}
10577822Sroot 	while (uio->uio_resid > 0) {
10587822Sroot 		cc = uio->uio_iov->iov_len;
10597822Sroot 		if (cc == 0) {
10607822Sroot 			uio->uio_iovcnt--;
10617822Sroot 			uio->uio_iov++;
10627822Sroot 			if (uio->uio_iovcnt < 0)
10637822Sroot 				panic("ttwrite");
10647822Sroot 			continue;
10657822Sroot 		}
10667822Sroot 		if (cc > OBUFSIZ)
10677822Sroot 			cc = OBUFSIZ;
10687502Sroot 		cp = obuf;
10698520Sroot 		error = uiomove(cp, cc, UIO_WRITE, uio);
10708520Sroot 		if (error)
10717502Sroot 			break;
10727502Sroot 		if (tp->t_outq.c_cc > hiwat)
10737502Sroot 			goto ovhiwat;
10747502Sroot 		if (tp->t_local&LFLUSHO)
10757502Sroot 			continue;
10767502Sroot 		if (tp->t_flags&LCASE || tp->t_local&LTILDE) {
10777502Sroot 			while (cc) {
10787502Sroot 				c = *cp++;
10797502Sroot 				tp->t_rocount = 0;
10807625Ssam 				while ((c = ttyoutput(c, tp)) >= 0) {
10817502Sroot 					/* out of clists, wait a bit */
10827502Sroot 					ttstart(tp);
10837502Sroot 					sleep((caddr_t)&lbolt, TTOPRI);
10847502Sroot 					tp->t_rocount = 0;
10857502Sroot 				}
10867502Sroot 				--cc;
10877502Sroot 				if (tp->t_outq.c_cc > hiwat)
10887502Sroot 					goto ovhiwat;
10897502Sroot 			}
10907502Sroot 			continue;
10917502Sroot 		}
10927502Sroot 		while (cc) {
10937502Sroot 			if (tp->t_flags&RAW || tp->t_local&LLITOUT)
10947502Sroot 				ce = cc;
10957502Sroot 			else {
10967502Sroot #ifdef vax
10977502Sroot 				asm("	scanc	r9,(r10),_partab,$077");
10987502Sroot 				asm("	subl3	r0,r9,r8");
10997502Sroot #else
11007502Sroot 				ce=0;
11017625Ssam 				while (((partab[*(unsigned char *)(cp+ce)]&077)==0)&&(ce<cc))
11027502Sroot 					ce++;
11037502Sroot #endif
11047502Sroot 				if (ce==0) {
11057502Sroot 					tp->t_rocount = 0;
11067502Sroot 					if (ttyoutput(*cp, tp) >= 0) {
11077502Sroot 						ttstart(tp);
11087502Sroot 						sleep((caddr_t)&lbolt, TTOPRI);
11097502Sroot 						continue;
11107502Sroot 					}
11117502Sroot 					cp++;
11127502Sroot 					cc--;
11137502Sroot 					if (tp->t_outq.c_cc > hiwat)
11147502Sroot 						goto ovhiwat;
11157502Sroot 				}
11167502Sroot 			}
11177502Sroot 			tp->t_rocount = 0;
11187502Sroot 			i=b_to_q(cp,ce,&tp->t_outq);
11197502Sroot 			ce-=i;
11207502Sroot 			tk_nout+=ce;
11217502Sroot 			tp->t_col+=ce;
11227502Sroot 			cp+=ce;
11237502Sroot 			cc-=ce;
11247502Sroot 			if (i) {
11257502Sroot 				ttstart(tp);
11267502Sroot 				sleep((caddr_t)&lbolt, TTOPRI);
11277502Sroot 			}
11287502Sroot 			if (ce || tp->t_outq.c_cc > hiwat)
11297502Sroot 				goto ovhiwat;
11307502Sroot 		}
11317502Sroot 	}
11327502Sroot 	ttstart(tp);
11338520Sroot 	return (error);
11347502Sroot 
11357502Sroot ovhiwat:
11367502Sroot 	(void) spl5();
11377822Sroot 	uio->uio_iov->iov_base -= cc;
11387822Sroot 	uio->uio_iov->iov_len += cc;
11397822Sroot 	uio->uio_resid += cc;
11407822Sroot 	uio->uio_offset -= cc;
11417502Sroot 	if (tp->t_outq.c_cc <= hiwat) {
11427502Sroot 		(void) spl0();
11437502Sroot 		goto loop;
11447502Sroot 	}
11457502Sroot 	ttstart(tp);
11467502Sroot 	if (tp->t_state & TS_NBIO) {
11477822Sroot 		if (uio->uio_resid == cnt)
11488520Sroot 			return (EWOULDBLOCK);
11498520Sroot 		return (0);
11507502Sroot 	}
11517502Sroot 	tp->t_state |= TS_ASLEEP;
11527502Sroot 	sleep((caddr_t)&tp->t_outq, TTOPRI);
11537502Sroot 	(void) spl0();
11547502Sroot 	goto loop;
11557502Sroot }
11567502Sroot 
11577502Sroot /*
11587502Sroot  * Rubout one character from the rawq of tp
11597502Sroot  * as cleanly as possible.
11607502Sroot  */
11617502Sroot ttyrub(c, tp)
11627625Ssam 	register c;
11637625Ssam 	register struct tty *tp;
11647502Sroot {
11657502Sroot 	register char *cp;
11667502Sroot 	register int savecol;
11677502Sroot 	int s;
11687502Sroot 	char *nextc();
11697502Sroot 
11707502Sroot 	if ((tp->t_flags&ECHO)==0)
11717502Sroot 		return;
11727502Sroot 	tp->t_local &= ~LFLUSHO;
11737502Sroot 	c &= 0377;
11747502Sroot 	if (tp->t_local&LCRTBS) {
11757502Sroot 		if (tp->t_rocount == 0) {
11767502Sroot 			/*
11777502Sroot 			 * Screwed by ttwrite; retype
11787502Sroot 			 */
11797502Sroot 			ttyretype(tp);
11807502Sroot 			return;
11817502Sroot 		}
11827502Sroot 		if (c==('\t'|0200) || c==('\n'|0200))
11837502Sroot 			ttyrubo(tp, 2);
11847625Ssam 		else switch (partab[c&=0177] & 0177) {
11857502Sroot 
11867502Sroot 		case ORDINARY:
11877502Sroot 			if (tp->t_flags&LCASE && c >= 'A' && c <= 'Z')
11887502Sroot 				ttyrubo(tp, 2);
11897502Sroot 			else
11907502Sroot 				ttyrubo(tp, 1);
11917502Sroot 			break;
11927502Sroot 
11937502Sroot 		case VTAB:
11947502Sroot 		case BACKSPACE:
11957502Sroot 		case CONTROL:
11967502Sroot 		case RETURN:
11977502Sroot 			if (tp->t_local & LCTLECH)
11987502Sroot 				ttyrubo(tp, 2);
11997502Sroot 			break;
12007502Sroot 
12017502Sroot 		case TAB:
12027502Sroot 			if (tp->t_rocount < tp->t_rawq.c_cc) {
12037502Sroot 				ttyretype(tp);
12047502Sroot 				return;
12057502Sroot 			}
12067502Sroot 			s = spl5();
12077502Sroot 			savecol = tp->t_col;
12087502Sroot 			tp->t_lstate |= LSCNTTB;
12097502Sroot 			tp->t_local |= LFLUSHO;
12107502Sroot 			tp->t_col = tp->t_rocol;
12117502Sroot 			for (cp = tp->t_rawq.c_cf; cp; cp = nextc(&tp->t_rawq, cp))
12127502Sroot 				ttyecho(*cp, tp);
12137502Sroot 			tp->t_local &= ~LFLUSHO;
12147502Sroot 			tp->t_lstate &= ~LSCNTTB;
12157502Sroot 			splx(s);
12167502Sroot 			/*
12177502Sroot 			 * savecol will now be length of the tab
12187502Sroot 			 */
12197502Sroot 			savecol -= tp->t_col;
12207502Sroot 			tp->t_col += savecol;
12217502Sroot 			if (savecol > 8)
12227502Sroot 				savecol = 8;		/* overflow screw */
12237502Sroot 			while (--savecol >= 0)
12247502Sroot 				(void) ttyoutput('\b', tp);
12257502Sroot 			break;
12267502Sroot 
12277502Sroot 		default:
12287502Sroot 			panic("ttyrub");
12297502Sroot 		}
12307502Sroot 	} else if (tp->t_local&LPRTERA) {
12317502Sroot 		if ((tp->t_lstate&LSERASE) == 0) {
12327502Sroot 			(void) ttyoutput('\\', tp);
12337502Sroot 			tp->t_lstate |= LSERASE;
12347502Sroot 		}
12357502Sroot 		ttyecho(c, tp);
12367502Sroot 	} else
12377502Sroot 		ttyecho(tp->t_erase, tp);
12387502Sroot 	tp->t_rocount--;
12397502Sroot }
12407502Sroot 
12417502Sroot /*
12427502Sroot  * Crt back over cnt chars perhaps
12437502Sroot  * erasing them.
12447502Sroot  */
12457502Sroot ttyrubo(tp, cnt)
12467625Ssam 	register struct tty *tp;
12477625Ssam 	int cnt;
12487502Sroot {
12497502Sroot 
12507502Sroot 	while (--cnt >= 0)
12517502Sroot 		ttyout(tp->t_local&LCRTERA ? "\b \b" : "\b", tp);
12527502Sroot }
12537502Sroot 
12547502Sroot /*
12557502Sroot  * Reprint the rawq line.
12567502Sroot  * We assume c_cc has already been checked.
12577502Sroot  */
12587502Sroot ttyretype(tp)
12597625Ssam 	register struct tty *tp;
12607502Sroot {
12617502Sroot 	register char *cp;
12627502Sroot 	char *nextc();
12637502Sroot 	int s;
12647502Sroot 
12657502Sroot 	if (tlun.t_rprntc != 0377)
12667502Sroot 		ttyecho(tlun.t_rprntc, tp);
12677502Sroot 	(void) ttyoutput('\n', tp);
12687502Sroot 	s = spl5();
12697502Sroot 	for (cp = tp->t_canq.c_cf; cp; cp = nextc(&tp->t_canq, cp))
12707502Sroot 		ttyecho(*cp, tp);
12717502Sroot 	for (cp = tp->t_rawq.c_cf; cp; cp = nextc(&tp->t_rawq, cp))
12727502Sroot 		ttyecho(*cp, tp);
12737502Sroot 	tp->t_lstate &= ~LSERASE;
12747502Sroot 	splx(s);
12757502Sroot 	tp->t_rocount = tp->t_rawq.c_cc;
12767502Sroot 	tp->t_rocol = 0;
12777502Sroot }
12787502Sroot 
12797502Sroot /*
12807502Sroot  * Echo a typed character to the terminal
12817502Sroot  */
12827502Sroot ttyecho(c, tp)
12837625Ssam 	register c;
12847625Ssam 	register struct tty *tp;
12857502Sroot {
12867502Sroot 
12877502Sroot 	if ((tp->t_lstate & LSCNTTB) == 0)
12887502Sroot 		tp->t_local &= ~LFLUSHO;
12897502Sroot 	if ((tp->t_flags&ECHO) == 0)
12907502Sroot 		return;
12917502Sroot 	c &= 0377;
12927502Sroot 	if (tp->t_flags&RAW) {
12937502Sroot 		(void) ttyoutput(c, tp);
12947502Sroot 		return;
12957502Sroot 	}
12967502Sroot 	if (c == '\r' && tp->t_flags&CRMOD)
12977502Sroot 		c = '\n';
12987502Sroot 	if (tp->t_local&LCTLECH) {
12997502Sroot 		if ((c&0177) <= 037 && c!='\t' && c!='\n' || (c&0177)==0177) {
13007502Sroot 			(void) ttyoutput('^', tp);
13017502Sroot 			c &= 0177;
13027502Sroot 			if (c == 0177)
13037502Sroot 				c = '?';
13047502Sroot 			else if (tp->t_flags&LCASE)
13057502Sroot 				c += 'a' - 1;
13067502Sroot 			else
13077502Sroot 				c += 'A' - 1;
13087502Sroot 		}
13097502Sroot 	}
13107502Sroot 	if ((tp->t_flags&LCASE) && (c >= 'A' && c <= 'Z'))
13117502Sroot 		c += 'a' - 'A';
13127502Sroot 	(void) ttyoutput(c & 0177, tp);
13137502Sroot }
13147502Sroot 
13157502Sroot /*
13167502Sroot  * Is c a break char for tp?
13177502Sroot  */
13187502Sroot ttbreakc(c, tp)
13197625Ssam 	register c;
13207625Ssam 	register struct tty *tp;
13217502Sroot {
13227502Sroot 	return (c == '\n' || c == tun.t_eofc || c == tun.t_brkc ||
13237502Sroot 		c == '\r' && (tp->t_flags&CRMOD));
13247502Sroot }
13257502Sroot 
13267502Sroot /*
13277502Sroot  * send string cp to tp
13287502Sroot  */
13297502Sroot ttyout(cp, tp)
13307625Ssam 	register char *cp;
13317625Ssam 	register struct tty *tp;
13327502Sroot {
13337502Sroot 	register char c;
13347502Sroot 
13357502Sroot 	while (c = *cp++)
13367502Sroot 		(void) ttyoutput(c, tp);
13377502Sroot }
13387502Sroot 
13397502Sroot ttwakeup(tp)
13407502Sroot 	struct tty *tp;
13417502Sroot {
13427502Sroot 
13437502Sroot 	if (tp->t_rsel) {
13447502Sroot 		selwakeup(tp->t_rsel, tp->t_state&TS_RCOLL);
13457502Sroot 		tp->t_state &= ~TS_RCOLL;
13467502Sroot 		tp->t_rsel = 0;
13477502Sroot 	}
13487502Sroot 	wakeup((caddr_t)&tp->t_rawq);
13497502Sroot }
13507502Sroot 
13517502Sroot ttsignal(tp, signo)
13527502Sroot 	struct tty *tp;
13537502Sroot 	int signo;
13547502Sroot {
13557502Sroot 
13567502Sroot 	gsignal(tp->t_pgrp, signo);
13577502Sroot }
1358