xref: /csrg-svn/sys/kern/tty.c (revision 8556)
1*8556Sroot /*	tty.c	4.31	82/10/17	*/
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] =
98925Sbill    { 100,100,100,100,100,100,100,200,200,400,400,400,650,650,650,650 };
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;
248*8556Sroot 	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 &&
271*8556Sroot 		   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 
280*8556Sroot 	/* get discipline number */
28139Sbill 	case TIOCGETD:
2827625Ssam 		*(int *)data = tp->t_line;
28339Sbill 		break;
28439Sbill 
285*8556Sroot 	/* set line discipline */
2867625Ssam 	case TIOCSETD: {
2877625Ssam 		register int t = *(int *)data;
288*8556Sroot 		int error;
2897625Ssam 
290*8556Sroot 		if (t >= nldisp)
291*8556Sroot 			return (ENXIO);
292*8556Sroot 		s = spl5();
29339Sbill 		if (tp->t_line)
29439Sbill 			(*linesw[tp->t_line].l_close)(tp);
29539Sbill 		if (t)
296*8556Sroot 			error = (*linesw[t].l_open)(dev, tp);
297*8556Sroot 		splx(s);
298*8556Sroot 		if (error)
299*8556Sroot 			return (error);
300*8556Sroot 		tp->t_line = t;
30139Sbill 		break;
3027625Ssam 	}
30339Sbill 
304*8556Sroot 	/* 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 
313*8556Sroot 	/* 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 
346*8556Sroot 	/* 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 
358*8556Sroot 	/* 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 
388*8556Sroot 	/* 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 
397*8556Sroot 	/* 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 
406*8556Sroot 	/* return number of characters immediately available */
4077625Ssam 	case FIONREAD:
4087625Ssam 		*(off_t *)data = ttnread(tp);
409174Sbill 		break;
410174Sbill 
411*8556Sroot 	/* 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 
420*8556Sroot 	/* 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 
4377625Ssam 	case TIOCSTOP: {
4387625Ssam 		int s = spl5();
439213Sbill 
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;
4467625Ssam 	}
4475573Swnj 
4487625Ssam 	case TIOCSTART: {
4497625Ssam 		int s = spl5();
4507625Ssam 
4515573Swnj 		if ((tp->t_state & TS_TTSTOP) || (tp->t_local & LFLUSHO)) {
4525573Swnj 			tp->t_state &= ~TS_TTSTOP;
4535573Swnj 			tp->t_local &= ~LFLUSHO;
4545573Swnj 			ttstart(tp);
4555573Swnj 		}
4567625Ssam 		splx(s);
4575573Swnj 		break;
4587625Ssam 	}
4595573Swnj 
46039Sbill 	default:
461*8556Sroot 		return (-1);
46239Sbill 	}
463*8556Sroot 	return (0);
46439Sbill }
4654484Swnj 
4664484Swnj ttnread(tp)
4674484Swnj 	struct tty *tp;
4684484Swnj {
4694484Swnj 	int nread = 0;
4704484Swnj 
4714484Swnj 	if (tp->t_local & LPENDIN)
4724484Swnj 		ttypend(tp);
4734484Swnj 	nread = tp->t_canq.c_cc;
4744484Swnj 	if (tp->t_flags & (RAW|CBREAK))
4754484Swnj 		nread += tp->t_rawq.c_cc;
4764484Swnj 	return (nread);
4774484Swnj }
4784484Swnj 
4795408Swnj ttselect(dev, rw)
4804484Swnj 	dev_t dev;
4815408Swnj 	int rw;
4824484Swnj {
4834484Swnj 	register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)];
4844484Swnj 	int nread;
4855408Swnj 	int s = spl5();
4864484Swnj 
4875408Swnj 	switch (rw) {
4884484Swnj 
4894484Swnj 	case FREAD:
4904484Swnj 		nread = ttnread(tp);
4914484Swnj 		if (nread > 0)
4925408Swnj 			goto win;
4934938Swnj 		if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait)
4945408Swnj 			tp->t_state |= TS_RCOLL;
4954484Swnj 		else
4964484Swnj 			tp->t_rsel = u.u_procp;
4975408Swnj 		break;
4984484Swnj 
4995408Swnj 	case FWRITE:
5005408Swnj 		if (tp->t_outq.c_cc <= TTLOWAT(tp))
5015408Swnj 			goto win;
5025408Swnj 		if (tp->t_wsel && tp->t_wsel->p_wchan == (caddr_t)&selwait)
5035408Swnj 			tp->t_state |= TS_WCOLL;
5045408Swnj 		else
5055408Swnj 			tp->t_wsel = u.u_procp;
5065408Swnj 		break;
5074484Swnj 	}
5085408Swnj 	splx(s);
5095408Swnj 	return (0);
5105408Swnj win:
5115408Swnj 	splx(s);
5125408Swnj 	return (1);
5134484Swnj }
5147436Skre 
5157502Sroot #define	OBUFSIZ	100
5167502Sroot 
5177502Sroot /*
5187502Sroot  * routine called on opens while tp->t_line == NTTYDISC
5197502Sroot  * establishes a process group for distribution of
5207502Sroot  * quits and interrupts from the tty.
5217502Sroot  * (actually, pp->p_pgrp can't be 0 when this routine
5227502Sroot  * is called since NTTYDISC is not the default discipline)
5237502Sroot  */
5247502Sroot ttyopen(dev, tp)
5257625Ssam 	dev_t dev;
5267625Ssam 	register struct tty *tp;
5277502Sroot {
5287502Sroot 	register struct proc *pp;
5297502Sroot 
5307502Sroot 	pp = u.u_procp;
5317502Sroot 	tp->t_dev = dev;
5327625Ssam 	if (pp->p_pgrp == 0) {
5337502Sroot 		u.u_ttyp = tp;
5347502Sroot 		u.u_ttyd = dev;
5357502Sroot 		if (tp->t_pgrp == 0)
5367502Sroot 			tp->t_pgrp = pp->p_pid;
5377502Sroot 		pp->p_pgrp = tp->t_pgrp;
5387502Sroot 	}
5397502Sroot 	tp->t_state &= ~TS_WOPEN;
5407502Sroot 	tp->t_state |= TS_ISOPEN;
5417502Sroot 	if (tp->t_line != NTTYDISC)
5427502Sroot 		wflushtty(tp);
543*8556Sroot 	return (0);
5447502Sroot }
5457502Sroot 
5467502Sroot /*
5477502Sroot  * clean tp on last close
5487502Sroot  */
5497502Sroot ttyclose(tp)
5507625Ssam 	register struct tty *tp;
5517502Sroot {
5527502Sroot 
5537502Sroot 	if (tp->t_line) {
5547502Sroot 		wflushtty(tp);
5557502Sroot 		tp->t_line = 0;
5567502Sroot 		return;
5577502Sroot 	}
5587502Sroot 	tp->t_pgrp = 0;
5597502Sroot 	wflushtty(tp);
5607502Sroot 	tp->t_state = 0;
5617502Sroot }
5627502Sroot 
5637502Sroot /*
5647502Sroot  * reinput pending characters after state switch
5657502Sroot  * call at spl5().
5667502Sroot  */
5677502Sroot ttypend(tp)
5687625Ssam 	register struct tty *tp;
5697502Sroot {
5707502Sroot 	struct clist tq;
5717502Sroot 	register c;
5727502Sroot 
5737502Sroot 	tp->t_local &= ~LPENDIN;
5747502Sroot 	tp->t_lstate |= LSTYPEN;
5757502Sroot 	tq = tp->t_rawq;
5767502Sroot 	tp->t_rawq.c_cc = 0;
5777502Sroot 	tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0;
5787502Sroot 	while ((c = getc(&tq)) >= 0)
5797502Sroot 		ttyinput(c, tp);
5807502Sroot 	tp->t_lstate &= ~LSTYPEN;
5817502Sroot }
5827502Sroot 
5837502Sroot /*
5847502Sroot  * Place a character on raw TTY input queue, putting in delimiters
5857502Sroot  * and waking up top half as needed.
5867502Sroot  * Also echo if required.
5877502Sroot  * The arguments are the character and the appropriate
5887502Sroot  * tty structure.
5897502Sroot  */
5907502Sroot ttyinput(c, tp)
5917625Ssam 	register c;
5927625Ssam 	register struct tty *tp;
5937502Sroot {
5947502Sroot 	register int t_flags;
5957502Sroot 	int i;
5967502Sroot 
5977502Sroot 	if (tp->t_local&LPENDIN)
5987502Sroot 		ttypend(tp);
5997502Sroot 	tk_nin++;
6007502Sroot 	c &= 0377;
6017502Sroot 	t_flags = tp->t_flags;
6027502Sroot 	if (t_flags&TANDEM)
6037502Sroot 		ttyblock(tp);
6047502Sroot 	if ((t_flags&RAW)==0) {
6057502Sroot 		if ((tp->t_lstate&LSTYPEN) == 0)
6067502Sroot 			c &= 0177;
6077502Sroot 	/* check for literal nexting very first */
6087502Sroot 		if (tp->t_lstate&LSLNCH) {
6097502Sroot 			c |= 0200;
6107502Sroot 			tp->t_lstate &= ~LSLNCH;
6117502Sroot 		}
6127502Sroot 		if (tp->t_line == NTTYDISC && c==tlun.t_lnextc) {
6137502Sroot 			if (tp->t_flags&ECHO)
6147502Sroot 				ttyout("^\b", tp);
6157502Sroot 			tp->t_lstate |= LSLNCH;
6167502Sroot 	/* check for output control functions */
6177502Sroot 		} else if (c==tun.t_stopc) {
6187502Sroot 			if ((tp->t_state&TS_TTSTOP)==0) {
6197502Sroot 				tp->t_state |= TS_TTSTOP;
6207502Sroot 				(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
6217502Sroot 				return;
6227502Sroot 			}
6237502Sroot 			if (c!=tun.t_startc)
6247502Sroot 				return;
6257502Sroot 		} else if (c==tun.t_startc) {
6267502Sroot 			tp->t_state &= ~TS_TTSTOP;
6277502Sroot 			tp->t_local &= ~LFLUSHO;
6287502Sroot 			ttstart(tp);
6297502Sroot 			return;
6307502Sroot 		} else if (tp->t_line == NTTYDISC && c==tlun.t_flushc) {
6317502Sroot 			if (tp->t_local & LFLUSHO)
6327502Sroot 				tp->t_local &= ~LFLUSHO;
6337502Sroot 			else {
6347502Sroot 				flushtty(tp, FWRITE);
6357502Sroot 				ttyecho(c, tp);
6367502Sroot 				if (tp->t_rawq.c_cc+tp->t_canq.c_cc)
6377502Sroot 					ttyretype(tp);
6387502Sroot 				tp->t_local |= LFLUSHO;
6397502Sroot 			}
6407502Sroot 			ttstart(tp);
6417502Sroot 			return;
6427502Sroot 		} else if (c==tun.t_intrc || c==tun.t_quitc ||
6437502Sroot 		    (tp->t_line == NTTYDISC && c==tlun.t_suspc)) {
6447502Sroot 			if ((tp->t_local & LNOFLSH) == 0)
6457502Sroot 				flushtty(tp,
6467502Sroot 				    c==tlun.t_suspc ? FREAD : FREAD|FWRITE);
6477502Sroot 			ttyecho(c, tp);
6487502Sroot 			c = c==tun.t_intrc ? SIGINT :
6497502Sroot 				((c==tun.t_quitc) ? SIGQUIT : SIGTSTP);
6507502Sroot 			ttsignal(tp, c);
6517502Sroot 	/* check for buffer editing functions - cooked mode */
6527502Sroot 		} else if ((t_flags&CBREAK) == 0) {
6537502Sroot 			if ((tp->t_lstate&LSQUOT) &&
6547502Sroot 			    (c==tp->t_erase||c==tp->t_kill)) {
6557502Sroot 				ttyrub(unputc(&tp->t_rawq), tp);
6567502Sroot 				c |= 0200;
6577502Sroot 			}
6587502Sroot 			if (c==tp->t_erase) {
6597502Sroot 				if (tp->t_rawq.c_cc)
6607502Sroot 					ttyrub(unputc(&tp->t_rawq), tp);
6617502Sroot 			} else if (c==tp->t_kill) {
6627502Sroot 				if (tp->t_local&LCRTKIL &&
6637502Sroot 				    tp->t_rawq.c_cc == tp->t_rocount) {
6647502Sroot 					while (tp->t_rawq.c_cc)
6657502Sroot 						ttyrub(unputc(&tp->t_rawq), tp);
6667502Sroot 				} else {
6677502Sroot 					ttyecho(c, tp);
6687502Sroot 					ttyecho('\n', tp);
6697502Sroot 					while (getc(&tp->t_rawq) > 0)
6707502Sroot 						;
6717502Sroot 					tp->t_rocount = 0;
6727502Sroot 				}
6737502Sroot 				tp->t_lstate = 0;
6747502Sroot 			} else if (tp->t_line == NTTYDISC && c==tlun.t_werasc) {
6757502Sroot 				if (tp->t_rawq.c_cc == 0)
6767502Sroot 					goto out;
6777502Sroot 				do {
6787502Sroot 					c = unputc(&tp->t_rawq);
6797502Sroot 					if (c != ' ' && c != '\t')
6807502Sroot 						goto erasenb;
6817502Sroot 					ttyrub(c, tp);
6827502Sroot 				} while (tp->t_rawq.c_cc);
6837502Sroot 				goto out;
6847502Sroot 			    erasenb:
6857502Sroot 				do {
6867502Sroot 					ttyrub(c, tp);
6877502Sroot 					if (tp->t_rawq.c_cc == 0)
6887502Sroot 						goto out;
6897502Sroot 					c = unputc(&tp->t_rawq);
6907502Sroot 				} while (c != ' ' && c != '\t');
6917502Sroot 				(void) putc(c, &tp->t_rawq);
6927502Sroot 			} else if (tp->t_line == NTTYDISC && c==tlun.t_rprntc) {
6937502Sroot 				ttyretype(tp);
6947502Sroot 	/* check for cooked mode input buffer overflow */
6957502Sroot 			} else if (tp->t_rawq.c_cc+tp->t_canq.c_cc >= TTYHOG) {
6967502Sroot 				;
6977502Sroot 	/* put data char in q for user and wakeup if a break char */
6987502Sroot 			} else if (putc(c, &tp->t_rawq) >= 0) {
6997502Sroot 				if (tp->t_rawq.c_cc+tp->t_canq.c_cc==TTYHOG
7007502Sroot 				    && tp->t_line == NTTYDISC)
7017502Sroot 					(void) ttyoutput(CTRL(g), tp);
7027502Sroot 				if (!ttbreakc(c, tp)) {
7037502Sroot 					if (tp->t_rocount++ == 0)
7047502Sroot 						tp->t_rocol = tp->t_col;
7057502Sroot 				} else {
7067502Sroot 					tp->t_rocount = 0;
7077502Sroot 					catq(&tp->t_rawq, &tp->t_canq);
7087502Sroot 					/* IF (TP->T_CHAN) (VOID) SDATA(TP->T_CHAN); */
7097502Sroot 					ttwakeup(tp);
7107502Sroot 				}
7117502Sroot 				tp->t_lstate &= ~LSQUOT;
7127502Sroot 				if (c == '\\')
7137502Sroot 					tp->t_lstate |= LSQUOT;
7147502Sroot 				if (tp->t_lstate&LSERASE) {
7157502Sroot 					tp->t_lstate &= ~LSERASE;
7167502Sroot 					(void) ttyoutput('/', tp);
7177502Sroot 				}
7187502Sroot 				i = tp->t_col;
7197502Sroot 				ttyecho(c, tp);
7207502Sroot 				if (c==tun.t_eofc && tp->t_flags&ECHO) {
7217502Sroot 					i = MIN(2, tp->t_col - i);
7227502Sroot 					while (i > 0) {
7237502Sroot 						(void) ttyoutput('\b', tp);
7247502Sroot 						i--;
7257502Sroot 					}
7267502Sroot 				}
7277502Sroot 			}
7287502Sroot 	/* CBREAK mode */
7297502Sroot 		} else if (tp->t_rawq.c_cc > TTYHOG) {
7307502Sroot 			if (tp->t_outq.c_cc < TTHIWAT(tp) &&
7317502Sroot 			    tp->t_line == NTTYDISC)
7327502Sroot 				(void) ttyoutput(CTRL(g), tp);
7337502Sroot 		} else if (putc(c, &tp->t_rawq) >= 0) {
7347502Sroot 			ttwakeup(tp);
7357502Sroot 			ttyecho(c, tp);
7367502Sroot 		}
7377502Sroot 	/* RAW mode */
7387502Sroot 	} else if (tp->t_rawq.c_cc > TTYHOG)
7397502Sroot 		flushtty(tp, FREAD|FWRITE);
7407502Sroot 	else {
7417502Sroot 		if (putc(c, &tp->t_rawq) >= 0)
7427502Sroot 			ttwakeup(tp);
7437502Sroot 		ttyecho(c, tp);
7447502Sroot 	}
7457502Sroot out:
7467502Sroot 	if (tp->t_local & LDECCTQ && tp->t_state & TS_TTSTOP &&
7477502Sroot 	    tun.t_startc != tun.t_stopc)
7487502Sroot 		return;
7497502Sroot 	tp->t_state &= ~TS_TTSTOP;
7507502Sroot 	tp->t_local &= ~LFLUSHO;
7517502Sroot 	ttstart(tp);
7527502Sroot }
7537502Sroot 
7547502Sroot /*
7557502Sroot  * put character on TTY output queue, adding delays,
7567502Sroot  * expanding tabs, and handling the CR/NL bit.
7577502Sroot  * It is called both from the top half for output, and from
7587502Sroot  * interrupt level for echoing.
7597502Sroot  * The arguments are the character and the tty structure.
7607502Sroot  * Returns < 0 if putc succeeds, otherwise returns char to resend
7617502Sroot  * Must be recursive.
7627502Sroot  */
7637502Sroot ttyoutput(c, tp)
7647502Sroot 	register c;
7657502Sroot 	register struct tty *tp;
7667502Sroot {
7677502Sroot 	register char *colp;
7687502Sroot 	register ctype;
7697502Sroot 
7707502Sroot 	if (tp->t_flags&RAW || tp->t_local&LLITOUT) {
7717502Sroot 		if (tp->t_local&LFLUSHO)
7727502Sroot 			return (-1);
7737502Sroot 		if (putc(c, &tp->t_outq))
7747625Ssam 			return (c);
7757502Sroot 		tk_nout++;
7767502Sroot 		return (-1);
7777502Sroot 	}
7787502Sroot 	/*
7797502Sroot 	 * Ignore EOT in normal mode to avoid hanging up
7807502Sroot 	 * certain terminals.
7817502Sroot 	 */
7827502Sroot 	c &= 0177;
7837502Sroot 	if (c==CEOT && (tp->t_flags&CBREAK)==0)
7847502Sroot 		return (-1);
7857502Sroot 	/*
7867502Sroot 	 * Turn tabs to spaces as required
7877502Sroot 	 */
7887502Sroot 	if (c=='\t' && (tp->t_flags&TBDELAY)==XTABS) {
7897502Sroot 		register int s;
7907502Sroot 
7917502Sroot 		c = 8 - (tp->t_col&7);
7927502Sroot 		if ((tp->t_local&LFLUSHO) == 0) {
7937502Sroot 			s = spl5();		/* don't interrupt tabs */
7947502Sroot 			c -= b_to_q("        ", c, &tp->t_outq);
7957502Sroot 			tk_nout += c;
7967502Sroot 			splx(s);
7977502Sroot 		}
7987502Sroot 		tp->t_col += c;
7997502Sroot 		return (c ? -1 : '\t');
8007502Sroot 	}
8017502Sroot 	tk_nout++;
8027502Sroot 	/*
8037502Sroot 	 * for upper-case-only terminals,
8047502Sroot 	 * generate escapes.
8057502Sroot 	 */
8067502Sroot 	if (tp->t_flags&LCASE) {
8077502Sroot 		colp = "({)}!|^~'`";
8087625Ssam 		while (*colp++)
8097625Ssam 			if (c == *colp++) {
8107502Sroot 				if (ttyoutput('\\', tp) >= 0)
8117502Sroot 					return (c);
8127502Sroot 				c = colp[-2];
8137502Sroot 				break;
8147502Sroot 			}
8157502Sroot 		if ('A'<=c && c<='Z') {
8167502Sroot 			if (ttyoutput('\\', tp) >= 0)
8177502Sroot 				return (c);
8187502Sroot 		} else if ('a'<=c && c<='z')
8197502Sroot 			c += 'A' - 'a';
8207502Sroot 	}
8217502Sroot 	/*
8227502Sroot 	 * turn <nl> to <cr><lf> if desired.
8237502Sroot 	 */
8247502Sroot 	if (c=='\n' && tp->t_flags&CRMOD)
8257502Sroot 		if (ttyoutput('\r', tp) >= 0)
8267502Sroot 			return (c);
8277502Sroot 	if (c=='~' && tp->t_local&LTILDE)
8287502Sroot 		c = '`';
8297502Sroot 	if ((tp->t_local&LFLUSHO) == 0 && putc(c, &tp->t_outq))
8307502Sroot 		return (c);
8317502Sroot 	/*
8327502Sroot 	 * Calculate delays.
8337502Sroot 	 * The numbers here represent clock ticks
8347502Sroot 	 * and are not necessarily optimal for all terminals.
8357502Sroot 	 * The delays are indicated by characters above 0200.
8367502Sroot 	 * In raw mode there are no delays and the
8377502Sroot 	 * transmission path is 8 bits wide.
8387502Sroot 	 */
8397502Sroot 	colp = &tp->t_col;
8407502Sroot 	ctype = partab[c];
8417502Sroot 	c = 0;
8427502Sroot 	switch (ctype&077) {
8437502Sroot 
8447502Sroot 	case ORDINARY:
8457502Sroot 		(*colp)++;
8467502Sroot 
8477502Sroot 	case CONTROL:
8487502Sroot 		break;
8497502Sroot 
8507502Sroot 	case BACKSPACE:
8517502Sroot 		if (*colp)
8527502Sroot 			(*colp)--;
8537502Sroot 		break;
8547502Sroot 
8557502Sroot 	case NEWLINE:
8567502Sroot 		ctype = (tp->t_flags >> 8) & 03;
8577625Ssam 		if (ctype == 1) { /* tty 37 */
8587502Sroot 			if (*colp)
8597502Sroot 				c = max(((unsigned)*colp>>4) + 3, (unsigned)6);
8607502Sroot 		} else
8617625Ssam 		if (ctype == 2) { /* vt05 */
8627502Sroot 			c = 6;
8637502Sroot 		}
8647502Sroot 		*colp = 0;
8657502Sroot 		break;
8667502Sroot 
8677502Sroot 	case TAB:
8687502Sroot 		ctype = (tp->t_flags >> 10) & 03;
8697625Ssam 		if (ctype == 1) { /* tty 37 */
8707502Sroot 			c = 1 - (*colp | ~07);
8717625Ssam 			if (c < 5)
8727502Sroot 				c = 0;
8737502Sroot 		}
8747502Sroot 		*colp |= 07;
8757502Sroot 		(*colp)++;
8767502Sroot 		break;
8777502Sroot 
8787502Sroot 	case VTAB:
8797625Ssam 		if (tp->t_flags & VTDELAY) /* tty 37 */
8807502Sroot 			c = 0177;
8817502Sroot 		break;
8827502Sroot 
8837502Sroot 	case RETURN:
8847502Sroot 		ctype = (tp->t_flags >> 12) & 03;
8857625Ssam 		if (ctype == 1) { /* tn 300 */
8867502Sroot 			c = 5;
8877625Ssam 		} else if (ctype == 2) { /* ti 700 */
8887502Sroot 			c = 10;
8897625Ssam 		} else if (ctype == 3) { /* concept 100 */
8907502Sroot 			int i;
8917502Sroot 			if ((i = *colp) >= 0)
8927502Sroot 				for (; i<9; i++)
8937502Sroot 					(void) putc(0177, &tp->t_outq);
8947502Sroot 		}
8957502Sroot 		*colp = 0;
8967502Sroot 	}
8977625Ssam 	if (c && (tp->t_local&LFLUSHO) == 0)
8987502Sroot 		(void) putc(c|0200, &tp->t_outq);
8997502Sroot 	return (-1);
9007502Sroot }
9017502Sroot 
9027502Sroot /*
9037502Sroot  * Called from device's read routine after it has
9047502Sroot  * calculated the tty-structure given as argument.
9057502Sroot  */
9067722Swnj ttread(tp, uio)
9077625Ssam 	register struct tty *tp;
9087722Swnj 	struct uio *uio;
9097502Sroot {
9107502Sroot 	register struct clist *qp;
9117502Sroot 	register c, first;
9128520Sroot 	int error = 0;
9137502Sroot 
9147502Sroot 	if ((tp->t_state&TS_CARR_ON)==0)
9158520Sroot 		return (EIO);
9167502Sroot loop:
9177502Sroot 	(void) spl5();
9187502Sroot 	if (tp->t_local&LPENDIN)
9197502Sroot 		ttypend(tp);
9207502Sroot 	(void) spl0();
9217502Sroot 	while (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) {
9227502Sroot 		if (u.u_signal[SIGTTIN] == SIG_IGN ||
9237502Sroot 		    u.u_signal[SIGTTIN] == SIG_HOLD ||
9247502Sroot /*
9257502Sroot 		    (u.u_procp->p_flag&SDETACH) ||
9267502Sroot */
9277502Sroot 		    u.u_procp->p_flag&SVFORK)
9288520Sroot 			return (EIO);
9297502Sroot 		gsignal(u.u_procp->p_pgrp, SIGTTIN);
9307502Sroot 		sleep((caddr_t)&lbolt, TTIPRI);
9317502Sroot 	}
9327502Sroot 	if (tp->t_flags&RAW) {
9337502Sroot 		(void) spl5();
9347502Sroot 		if (tp->t_rawq.c_cc <= 0) {
9357502Sroot 			if ((tp->t_state&TS_CARR_ON)==0 ||
9367502Sroot 			    (tp->t_state&TS_NBIO)) {
9377502Sroot 				(void) spl0();
9388520Sroot 				return (EWOULDBLOCK);
9397502Sroot 			}
9407502Sroot 			sleep((caddr_t)&tp->t_rawq, TTIPRI);
9417502Sroot 			(void) spl0();
9427502Sroot 			goto loop;
9437502Sroot 		}
9447502Sroot 		(void) spl0();
9457722Swnj 		while (tp->t_rawq.c_cc && uio->uio_iovcnt) {
9468520Sroot 			error = passuc(getc(&tp->t_rawq), uio);
9478520Sroot 			if (error)
9487722Swnj 				break;
9497722Swnj 		}
9508520Sroot 		return (error);
9517502Sroot 	} else {
9527502Sroot 		qp = tp->t_flags & CBREAK ? &tp->t_rawq : &tp->t_canq;
9537502Sroot 		(void) spl5();
9547502Sroot 		if (qp->c_cc <= 0) {
9557502Sroot 			if ((tp->t_state&TS_CARR_ON)==0 ||
9567502Sroot 			    (tp->t_state&TS_NBIO)) {
9577502Sroot 				(void) spl0();
9588520Sroot 				return (EWOULDBLOCK);
9597502Sroot 			}
9607502Sroot 			sleep((caddr_t)&tp->t_rawq, TTIPRI);
9617502Sroot 			(void) spl0();
9627502Sroot 			goto loop;
9637502Sroot 		}
9647502Sroot 		(void) spl0();
9657502Sroot 		first = 1;
9667502Sroot 		while ((c = getc(qp)) >= 0) {
9677502Sroot 			if (tp->t_flags&CRMOD && c == '\r')
9687502Sroot 				c = '\n';
9697502Sroot 			if (tp->t_flags&LCASE && c <= 0177)
9707502Sroot 				if (tp->t_lstate&LSBKSL) {
9717502Sroot 					if (maptab[c])
9727502Sroot 						c = maptab[c];
9737502Sroot 					tp->t_lstate &= ~LSBKSL;
9747502Sroot 				} else if (c >= 'A' && c <= 'Z')
9757502Sroot 					c += 'a' - 'A';
9767502Sroot 				else if (c == '\\') {
9777502Sroot 					tp->t_lstate |= LSBKSL;
9787502Sroot 					continue;
9797502Sroot 				}
9807658Ssam 			if (tp->t_line == NTTYDISC && c == tlun.t_dsuspc) {
9817502Sroot 				ttsignal(tp, SIGTSTP);
9827502Sroot 				if (first) {
9837502Sroot 					sleep((caddr_t)&lbolt, TTIPRI);
9847502Sroot 					goto loop;
9857502Sroot 				}
9867502Sroot 				break;
9877502Sroot 			}
9887502Sroot 			if (c == tun.t_eofc && (tp->t_flags&CBREAK)==0)
9897502Sroot 				break;
9908520Sroot 			error = passuc(c & 0177, uio);
9918520Sroot 			if (error)
9927502Sroot 				break;
9937722Swnj 			if (uio->uio_iovcnt == 0)
9947722Swnj 				break;
9957502Sroot 			if ((tp->t_flags&CBREAK)==0 && ttbreakc(c, tp))
9967502Sroot 				break;
9977502Sroot 			first = 0;
9987502Sroot 		}
9997502Sroot 		tp->t_lstate &= ~LSBKSL;
10007502Sroot 	}
10017502Sroot 	if (tp->t_state&TS_TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) {
10027502Sroot 		if (putc(tun.t_startc, &tp->t_outq)==0) {
10037502Sroot 			tp->t_state &= ~TS_TBLOCK;
10047502Sroot 			ttstart(tp);
10057502Sroot 		}
10067502Sroot 		tp->t_char = 0;
10077502Sroot 	}
10088520Sroot 	return (error);
10097502Sroot }
10107502Sroot 
10117502Sroot /*
10127502Sroot  * Called from the device's write routine after it has
10137502Sroot  * calculated the tty-structure given as argument.
10147502Sroot  */
10157822Sroot ttwrite(tp, uio)
10167625Ssam 	register struct tty *tp;
10177822Sroot 	struct uio *uio;
10187502Sroot {
10197502Sroot #ifdef vax
10207502Sroot 	/*
10217502Sroot 	 * THE POSITIONING OF CP, CC, AND CE ARE CRITICAL
10227502Sroot 	 * AND MUST NOT BE CHANGED WITHOUT PATCHING
10237502Sroot 	 * THE 'ASM' INLINES BELOW.  WATCH OUT.
10247502Sroot 	 */
10257502Sroot #endif
10267502Sroot 	register char *cp;
10277502Sroot 	register int cc, ce;
10287502Sroot 	register i;
10297502Sroot 	char obuf[OBUFSIZ];
10307502Sroot 	register c;
10317502Sroot 	int hiwat = TTHIWAT(tp);
10327822Sroot 	int cnt = uio->uio_resid;
10338520Sroot 	int error = 0;
10347502Sroot 
10357502Sroot 	if ((tp->t_state&TS_CARR_ON)==0)
10368520Sroot 		return (EIO);
10377502Sroot loop:
10387502Sroot 	while (u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp &&
10397502Sroot 	    (tp->t_local&LTOSTOP) && (u.u_procp->p_flag&SVFORK)==0 &&
10407502Sroot 	    u.u_signal[SIGTTOU] != SIG_IGN &&
10417502Sroot 	    u.u_signal[SIGTTOU] != SIG_HOLD
10427502Sroot /*
10437502Sroot 					     &&
10447502Sroot 	    (u.u_procp->p_flag&SDETACH)==0) {
10457502Sroot */
10467502Sroot 	    ) {
10477502Sroot 		gsignal(u.u_procp->p_pgrp, SIGTTOU);
10487502Sroot 		sleep((caddr_t)&lbolt, TTIPRI);
10497502Sroot 	}
10507822Sroot 	while (uio->uio_resid > 0) {
10517822Sroot 		cc = uio->uio_iov->iov_len;
10527822Sroot 		if (cc == 0) {
10537822Sroot 			uio->uio_iovcnt--;
10547822Sroot 			uio->uio_iov++;
10557822Sroot 			if (uio->uio_iovcnt < 0)
10567822Sroot 				panic("ttwrite");
10577822Sroot 			continue;
10587822Sroot 		}
10597822Sroot 		if (cc > OBUFSIZ)
10607822Sroot 			cc = OBUFSIZ;
10617502Sroot 		cp = obuf;
10628520Sroot 		error = uiomove(cp, cc, UIO_WRITE, uio);
10638520Sroot 		if (error)
10647502Sroot 			break;
10657502Sroot 		if (tp->t_outq.c_cc > hiwat)
10667502Sroot 			goto ovhiwat;
10677502Sroot 		if (tp->t_local&LFLUSHO)
10687502Sroot 			continue;
10697502Sroot 		if (tp->t_flags&LCASE || tp->t_local&LTILDE) {
10707502Sroot 			while (cc) {
10717502Sroot 				c = *cp++;
10727502Sroot 				tp->t_rocount = 0;
10737625Ssam 				while ((c = ttyoutput(c, tp)) >= 0) {
10747502Sroot 					/* out of clists, wait a bit */
10757502Sroot 					ttstart(tp);
10767502Sroot 					sleep((caddr_t)&lbolt, TTOPRI);
10777502Sroot 					tp->t_rocount = 0;
10787502Sroot 				}
10797502Sroot 				--cc;
10807502Sroot 				if (tp->t_outq.c_cc > hiwat)
10817502Sroot 					goto ovhiwat;
10827502Sroot 			}
10837502Sroot 			continue;
10847502Sroot 		}
10857502Sroot 		while (cc) {
10867502Sroot 			if (tp->t_flags&RAW || tp->t_local&LLITOUT)
10877502Sroot 				ce = cc;
10887502Sroot 			else {
10897502Sroot #ifdef vax
10907502Sroot 				asm("	scanc	r9,(r10),_partab,$077");
10917502Sroot 				asm("	subl3	r0,r9,r8");
10927502Sroot #else
10937502Sroot 				ce=0;
10947625Ssam 				while (((partab[*(unsigned char *)(cp+ce)]&077)==0)&&(ce<cc))
10957502Sroot 					ce++;
10967502Sroot #endif
10977502Sroot 				if (ce==0) {
10987502Sroot 					tp->t_rocount = 0;
10997502Sroot 					if (ttyoutput(*cp, tp) >= 0) {
11007502Sroot 						ttstart(tp);
11017502Sroot 						sleep((caddr_t)&lbolt, TTOPRI);
11027502Sroot 						continue;
11037502Sroot 					}
11047502Sroot 					cp++;
11057502Sroot 					cc--;
11067502Sroot 					if (tp->t_outq.c_cc > hiwat)
11077502Sroot 						goto ovhiwat;
11087502Sroot 				}
11097502Sroot 			}
11107502Sroot 			tp->t_rocount = 0;
11117502Sroot 			i=b_to_q(cp,ce,&tp->t_outq);
11127502Sroot 			ce-=i;
11137502Sroot 			tk_nout+=ce;
11147502Sroot 			tp->t_col+=ce;
11157502Sroot 			cp+=ce;
11167502Sroot 			cc-=ce;
11177502Sroot 			if (i) {
11187502Sroot 				ttstart(tp);
11197502Sroot 				sleep((caddr_t)&lbolt, TTOPRI);
11207502Sroot 			}
11217502Sroot 			if (ce || tp->t_outq.c_cc > hiwat)
11227502Sroot 				goto ovhiwat;
11237502Sroot 		}
11247502Sroot 	}
11257502Sroot 	ttstart(tp);
11268520Sroot 	return (error);
11277502Sroot 
11287502Sroot ovhiwat:
11297502Sroot 	(void) spl5();
11307822Sroot 	uio->uio_iov->iov_base -= cc;
11317822Sroot 	uio->uio_iov->iov_len += cc;
11327822Sroot 	uio->uio_resid += cc;
11337822Sroot 	uio->uio_offset -= cc;
11347502Sroot 	if (tp->t_outq.c_cc <= hiwat) {
11357502Sroot 		(void) spl0();
11367502Sroot 		goto loop;
11377502Sroot 	}
11387502Sroot 	ttstart(tp);
11397502Sroot 	if (tp->t_state & TS_NBIO) {
11407822Sroot 		if (uio->uio_resid == cnt)
11418520Sroot 			return (EWOULDBLOCK);
11428520Sroot 		return (0);
11437502Sroot 	}
11447502Sroot 	tp->t_state |= TS_ASLEEP;
11457502Sroot 	sleep((caddr_t)&tp->t_outq, TTOPRI);
11467502Sroot 	(void) spl0();
11477502Sroot 	goto loop;
11487502Sroot }
11497502Sroot 
11507502Sroot /*
11517502Sroot  * Rubout one character from the rawq of tp
11527502Sroot  * as cleanly as possible.
11537502Sroot  */
11547502Sroot ttyrub(c, tp)
11557625Ssam 	register c;
11567625Ssam 	register struct tty *tp;
11577502Sroot {
11587502Sroot 	register char *cp;
11597502Sroot 	register int savecol;
11607502Sroot 	int s;
11617502Sroot 	char *nextc();
11627502Sroot 
11637502Sroot 	if ((tp->t_flags&ECHO)==0)
11647502Sroot 		return;
11657502Sroot 	tp->t_local &= ~LFLUSHO;
11667502Sroot 	c &= 0377;
11677502Sroot 	if (tp->t_local&LCRTBS) {
11687502Sroot 		if (tp->t_rocount == 0) {
11697502Sroot 			/*
11707502Sroot 			 * Screwed by ttwrite; retype
11717502Sroot 			 */
11727502Sroot 			ttyretype(tp);
11737502Sroot 			return;
11747502Sroot 		}
11757502Sroot 		if (c==('\t'|0200) || c==('\n'|0200))
11767502Sroot 			ttyrubo(tp, 2);
11777625Ssam 		else switch (partab[c&=0177] & 0177) {
11787502Sroot 
11797502Sroot 		case ORDINARY:
11807502Sroot 			if (tp->t_flags&LCASE && c >= 'A' && c <= 'Z')
11817502Sroot 				ttyrubo(tp, 2);
11827502Sroot 			else
11837502Sroot 				ttyrubo(tp, 1);
11847502Sroot 			break;
11857502Sroot 
11867502Sroot 		case VTAB:
11877502Sroot 		case BACKSPACE:
11887502Sroot 		case CONTROL:
11897502Sroot 		case RETURN:
11907502Sroot 			if (tp->t_local & LCTLECH)
11917502Sroot 				ttyrubo(tp, 2);
11927502Sroot 			break;
11937502Sroot 
11947502Sroot 		case TAB:
11957502Sroot 			if (tp->t_rocount < tp->t_rawq.c_cc) {
11967502Sroot 				ttyretype(tp);
11977502Sroot 				return;
11987502Sroot 			}
11997502Sroot 			s = spl5();
12007502Sroot 			savecol = tp->t_col;
12017502Sroot 			tp->t_lstate |= LSCNTTB;
12027502Sroot 			tp->t_local |= LFLUSHO;
12037502Sroot 			tp->t_col = tp->t_rocol;
12047502Sroot 			for (cp = tp->t_rawq.c_cf; cp; cp = nextc(&tp->t_rawq, cp))
12057502Sroot 				ttyecho(*cp, tp);
12067502Sroot 			tp->t_local &= ~LFLUSHO;
12077502Sroot 			tp->t_lstate &= ~LSCNTTB;
12087502Sroot 			splx(s);
12097502Sroot 			/*
12107502Sroot 			 * savecol will now be length of the tab
12117502Sroot 			 */
12127502Sroot 			savecol -= tp->t_col;
12137502Sroot 			tp->t_col += savecol;
12147502Sroot 			if (savecol > 8)
12157502Sroot 				savecol = 8;		/* overflow screw */
12167502Sroot 			while (--savecol >= 0)
12177502Sroot 				(void) ttyoutput('\b', tp);
12187502Sroot 			break;
12197502Sroot 
12207502Sroot 		default:
12217502Sroot 			panic("ttyrub");
12227502Sroot 		}
12237502Sroot 	} else if (tp->t_local&LPRTERA) {
12247502Sroot 		if ((tp->t_lstate&LSERASE) == 0) {
12257502Sroot 			(void) ttyoutput('\\', tp);
12267502Sroot 			tp->t_lstate |= LSERASE;
12277502Sroot 		}
12287502Sroot 		ttyecho(c, tp);
12297502Sroot 	} else
12307502Sroot 		ttyecho(tp->t_erase, tp);
12317502Sroot 	tp->t_rocount--;
12327502Sroot }
12337502Sroot 
12347502Sroot /*
12357502Sroot  * Crt back over cnt chars perhaps
12367502Sroot  * erasing them.
12377502Sroot  */
12387502Sroot ttyrubo(tp, cnt)
12397625Ssam 	register struct tty *tp;
12407625Ssam 	int cnt;
12417502Sroot {
12427502Sroot 
12437502Sroot 	while (--cnt >= 0)
12447502Sroot 		ttyout(tp->t_local&LCRTERA ? "\b \b" : "\b", tp);
12457502Sroot }
12467502Sroot 
12477502Sroot /*
12487502Sroot  * Reprint the rawq line.
12497502Sroot  * We assume c_cc has already been checked.
12507502Sroot  */
12517502Sroot ttyretype(tp)
12527625Ssam 	register struct tty *tp;
12537502Sroot {
12547502Sroot 	register char *cp;
12557502Sroot 	char *nextc();
12567502Sroot 	int s;
12577502Sroot 
12587502Sroot 	if (tlun.t_rprntc != 0377)
12597502Sroot 		ttyecho(tlun.t_rprntc, tp);
12607502Sroot 	(void) ttyoutput('\n', tp);
12617502Sroot 	s = spl5();
12627502Sroot 	for (cp = tp->t_canq.c_cf; cp; cp = nextc(&tp->t_canq, cp))
12637502Sroot 		ttyecho(*cp, tp);
12647502Sroot 	for (cp = tp->t_rawq.c_cf; cp; cp = nextc(&tp->t_rawq, cp))
12657502Sroot 		ttyecho(*cp, tp);
12667502Sroot 	tp->t_lstate &= ~LSERASE;
12677502Sroot 	splx(s);
12687502Sroot 	tp->t_rocount = tp->t_rawq.c_cc;
12697502Sroot 	tp->t_rocol = 0;
12707502Sroot }
12717502Sroot 
12727502Sroot /*
12737502Sroot  * Echo a typed character to the terminal
12747502Sroot  */
12757502Sroot ttyecho(c, tp)
12767625Ssam 	register c;
12777625Ssam 	register struct tty *tp;
12787502Sroot {
12797502Sroot 
12807502Sroot 	if ((tp->t_lstate & LSCNTTB) == 0)
12817502Sroot 		tp->t_local &= ~LFLUSHO;
12827502Sroot 	if ((tp->t_flags&ECHO) == 0)
12837502Sroot 		return;
12847502Sroot 	c &= 0377;
12857502Sroot 	if (tp->t_flags&RAW) {
12867502Sroot 		(void) ttyoutput(c, tp);
12877502Sroot 		return;
12887502Sroot 	}
12897502Sroot 	if (c == '\r' && tp->t_flags&CRMOD)
12907502Sroot 		c = '\n';
12917502Sroot 	if (tp->t_local&LCTLECH) {
12927502Sroot 		if ((c&0177) <= 037 && c!='\t' && c!='\n' || (c&0177)==0177) {
12937502Sroot 			(void) ttyoutput('^', tp);
12947502Sroot 			c &= 0177;
12957502Sroot 			if (c == 0177)
12967502Sroot 				c = '?';
12977502Sroot 			else if (tp->t_flags&LCASE)
12987502Sroot 				c += 'a' - 1;
12997502Sroot 			else
13007502Sroot 				c += 'A' - 1;
13017502Sroot 		}
13027502Sroot 	}
13037502Sroot 	if ((tp->t_flags&LCASE) && (c >= 'A' && c <= 'Z'))
13047502Sroot 		c += 'a' - 'A';
13057502Sroot 	(void) ttyoutput(c & 0177, tp);
13067502Sroot }
13077502Sroot 
13087502Sroot /*
13097502Sroot  * Is c a break char for tp?
13107502Sroot  */
13117502Sroot ttbreakc(c, tp)
13127625Ssam 	register c;
13137625Ssam 	register struct tty *tp;
13147502Sroot {
13157502Sroot 	return (c == '\n' || c == tun.t_eofc || c == tun.t_brkc ||
13167502Sroot 		c == '\r' && (tp->t_flags&CRMOD));
13177502Sroot }
13187502Sroot 
13197502Sroot /*
13207502Sroot  * send string cp to tp
13217502Sroot  */
13227502Sroot ttyout(cp, tp)
13237625Ssam 	register char *cp;
13247625Ssam 	register struct tty *tp;
13257502Sroot {
13267502Sroot 	register char c;
13277502Sroot 
13287502Sroot 	while (c = *cp++)
13297502Sroot 		(void) ttyoutput(c, tp);
13307502Sroot }
13317502Sroot 
13327502Sroot ttwakeup(tp)
13337502Sroot 	struct tty *tp;
13347502Sroot {
13357502Sroot 
13367502Sroot 	if (tp->t_rsel) {
13377502Sroot 		selwakeup(tp->t_rsel, tp->t_state&TS_RCOLL);
13387502Sroot 		tp->t_state &= ~TS_RCOLL;
13397502Sroot 		tp->t_rsel = 0;
13407502Sroot 	}
13417502Sroot 	wakeup((caddr_t)&tp->t_rawq);
13427502Sroot }
13437502Sroot 
13447502Sroot ttsignal(tp, signo)
13457502Sroot 	struct tty *tp;
13467502Sroot 	int signo;
13477502Sroot {
13487502Sroot 
13497502Sroot 	gsignal(tp->t_pgrp, signo);
13507502Sroot }
1351