xref: /csrg-svn/sys/kern/tty.c (revision 24392)
123387Smckusick /*
223387Smckusick  * Copyright (c) 1982 Regents of the University of California.
323387Smckusick  * All rights reserved.  The Berkeley software License Agreement
423387Smckusick  * specifies the terms and conditions for redistribution.
523387Smckusick  *
6*24392Skarels  *	@(#)tty.c	6.21 (Berkeley) 08/22/85
723387Smckusick  */
839Sbill 
99760Ssam #include "../machine/reg.h"
109760Ssam 
1117095Sbloom #include "param.h"
1217095Sbloom #include "systm.h"
1317095Sbloom #include "dir.h"
1417095Sbloom #include "user.h"
1517095Sbloom #include "ioctl.h"
1617095Sbloom #include "tty.h"
1717095Sbloom #include "proc.h"
1817095Sbloom #include "inode.h"
1917095Sbloom #include "file.h"
2017095Sbloom #include "conf.h"
2117095Sbloom #include "buf.h"
2217095Sbloom #include "dk.h"
2317095Sbloom #include "uio.h"
2417095Sbloom #include "kernel.h"
2539Sbill 
267436Skre /*
277436Skre  * Table giving parity for characters and indicating
287436Skre  * character classes to tty driver.  In particular,
297436Skre  * if the low 6 bits are 0, then the character needs
307436Skre  * no special processing on output.
317436Skre  */
3239Sbill 
337436Skre char partab[] = {
347436Skre 	0001,0201,0201,0001,0201,0001,0001,0201,
357436Skre 	0202,0004,0003,0201,0005,0206,0201,0001,
367436Skre 	0201,0001,0001,0201,0001,0201,0201,0001,
377436Skre 	0001,0201,0201,0001,0201,0001,0001,0201,
387436Skre 	0200,0000,0000,0200,0000,0200,0200,0000,
397436Skre 	0000,0200,0200,0000,0200,0000,0000,0200,
407436Skre 	0000,0200,0200,0000,0200,0000,0000,0200,
417436Skre 	0200,0000,0000,0200,0000,0200,0200,0000,
427436Skre 	0200,0000,0000,0200,0000,0200,0200,0000,
437436Skre 	0000,0200,0200,0000,0200,0000,0000,0200,
447436Skre 	0000,0200,0200,0000,0200,0000,0000,0200,
457436Skre 	0200,0000,0000,0200,0000,0200,0200,0000,
467436Skre 	0000,0200,0200,0000,0200,0000,0000,0200,
477436Skre 	0200,0000,0000,0200,0000,0200,0200,0000,
487436Skre 	0200,0000,0000,0200,0000,0200,0200,0000,
497436Skre 	0000,0200,0200,0000,0200,0000,0000,0201,
507436Skre 
517436Skre 	/*
527436Skre 	 * 7 bit ascii ends with the last character above,
537436Skre 	 * but we contine through all 256 codes for the sake
547436Skre 	 * of the tty output routines which use special vax
557436Skre 	 * instructions which need a 256 character trt table.
567436Skre 	 */
577436Skre 
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 	0007,0007,0007,0007,0007,0007,0007,0007,
707436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
717436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
727436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
737436Skre 	0007,0007,0007,0007,0007,0007,0007,0007
747436Skre };
757436Skre 
76146Sbill /*
7739Sbill  * Input mapping table-- if an entry is non-zero, when the
7839Sbill  * corresponding character is typed preceded by "\" the escape
7939Sbill  * sequence is replaced by the table value.  Mostly used for
8039Sbill  * upper-case only terminals.
8139Sbill  */
8239Sbill char	maptab[] ={
8339Sbill 	000,000,000,000,000,000,000,000,
8439Sbill 	000,000,000,000,000,000,000,000,
8539Sbill 	000,000,000,000,000,000,000,000,
8639Sbill 	000,000,000,000,000,000,000,000,
8739Sbill 	000,'|',000,000,000,000,000,'`',
8839Sbill 	'{','}',000,000,000,000,000,000,
8939Sbill 	000,000,000,000,000,000,000,000,
9039Sbill 	000,000,000,000,000,000,000,000,
9139Sbill 	000,000,000,000,000,000,000,000,
9239Sbill 	000,000,000,000,000,000,000,000,
9339Sbill 	000,000,000,000,000,000,000,000,
9439Sbill 	000,000,000,000,000,000,'~',000,
9539Sbill 	000,'A','B','C','D','E','F','G',
9639Sbill 	'H','I','J','K','L','M','N','O',
9739Sbill 	'P','Q','R','S','T','U','V','W',
9839Sbill 	'X','Y','Z',000,000,000,000,000,
9939Sbill };
10039Sbill 
101925Sbill short	tthiwat[16] =
1028954Sroot    { 100,100,100,100,100,100,100,200,200,400,400,400,650,650,1300,2000 };
103925Sbill short	ttlowat[16] =
104925Sbill    {  30, 30, 30, 30, 30, 30, 30, 50, 50,120,120,120,125,125,125,125 };
105925Sbill 
1069578Ssam struct	ttychars ttydefaults = {
1079578Ssam 	CERASE,	CKILL,	CINTR,	CQUIT,	CSTART,	CSTOP,	CEOF,
1089578Ssam 	CBRK,	CSUSP,	CDSUSP, CRPRNT, CFLUSH, CWERASE,CLNEXT
1099578Ssam };
11039Sbill 
11139Sbill ttychars(tp)
1129578Ssam 	struct tty *tp;
11339Sbill {
114174Sbill 
1159578Ssam 	tp->t_chars = ttydefaults;
11639Sbill }
11739Sbill 
11839Sbill /*
119903Sbill  * Wait for output to drain, then flush input waiting.
12039Sbill  */
12112752Ssam ttywflush(tp)
1225408Swnj 	register struct tty *tp;
12339Sbill {
12439Sbill 
12512752Ssam 	ttywait(tp);
12612752Ssam 	ttyflush(tp, FREAD);
12712752Ssam }
12812752Ssam 
12912752Ssam ttywait(tp)
13012752Ssam 	register struct tty *tp;
13112752Ssam {
13217545Skarels 	register int s = spltty();
13312752Ssam 
13413809Ssam 	while ((tp->t_outq.c_cc || tp->t_state&TS_BUSY) &&
13513809Ssam 	    tp->t_state&TS_CARR_ON && tp->t_oproc) {	/* kludge for pty */
136903Sbill 		(*tp->t_oproc)(tp);
1375408Swnj 		tp->t_state |= TS_ASLEEP;
138903Sbill 		sleep((caddr_t)&tp->t_outq, TTOPRI);
139903Sbill 	}
1409859Ssam 	splx(s);
14139Sbill }
14239Sbill 
14339Sbill /*
1449578Ssam  * Flush all TTY queues
14539Sbill  */
14612752Ssam ttyflush(tp, rw)
1477625Ssam 	register struct tty *tp;
14839Sbill {
149903Sbill 	register s;
150903Sbill 
15117545Skarels 	s = spltty();
152903Sbill 	if (rw & FREAD) {
153903Sbill 		while (getc(&tp->t_canq) >= 0)
154903Sbill 			;
155903Sbill 		wakeup((caddr_t)&tp->t_rawq);
156903Sbill 	}
157903Sbill 	if (rw & FWRITE) {
158903Sbill 		wakeup((caddr_t)&tp->t_outq);
1595408Swnj 		tp->t_state &= ~TS_TTSTOP;
1605426Swnj 		(*cdevsw[major(tp->t_dev)].d_stop)(tp, rw);
161903Sbill 		while (getc(&tp->t_outq) >= 0)
162903Sbill 			;
163903Sbill 	}
164903Sbill 	if (rw & FREAD) {
165903Sbill 		while (getc(&tp->t_rawq) >= 0)
166903Sbill 			;
1679578Ssam 		tp->t_rocount = 0;
168903Sbill 		tp->t_rocol = 0;
1699578Ssam 		tp->t_state &= ~TS_LOCAL;
170903Sbill 	}
171903Sbill 	splx(s);
17239Sbill }
17339Sbill 
174903Sbill /*
175903Sbill  * Send stop character on input overflow.
176903Sbill  */
177903Sbill ttyblock(tp)
1787625Ssam 	register struct tty *tp;
17939Sbill {
180903Sbill 	register x;
1819578Ssam 
182903Sbill 	x = tp->t_rawq.c_cc + tp->t_canq.c_cc;
183903Sbill 	if (tp->t_rawq.c_cc > TTYHOG) {
18412752Ssam 		ttyflush(tp, FREAD|FWRITE);
1855408Swnj 		tp->t_state &= ~TS_TBLOCK;
186903Sbill 	}
18715118Skarels 	/*
18815118Skarels 	 * Block further input iff:
18915118Skarels 	 * Current input > threshold AND input is available to user program
19015118Skarels 	 */
19116055Skarels 	if (x >= TTYHOG/2 &&
19216055Skarels 	    ((tp->t_flags & (RAW|CBREAK)) || (tp->t_canq.c_cc > 0))) {
19315118Skarels 		if (putc(tp->t_stopc, &tp->t_outq)==0) {
19415118Skarels 			tp->t_state |= TS_TBLOCK;
19515118Skarels 			ttstart(tp);
19615118Skarels 		}
197903Sbill 	}
19839Sbill }
19939Sbill 
20039Sbill /*
201903Sbill  * Restart typewriter output following a delay
202903Sbill  * timeout.
203903Sbill  * The name of the routine is passed to the timeout
204903Sbill  * subroutine and it is called during a clock interrupt.
205121Sbill  */
206903Sbill ttrstrt(tp)
2077625Ssam 	register struct tty *tp;
208121Sbill {
209121Sbill 
2109578Ssam 	if (tp == 0)
2119578Ssam 		panic("ttrstrt");
2125408Swnj 	tp->t_state &= ~TS_TIMEOUT;
213903Sbill 	ttstart(tp);
214121Sbill }
215121Sbill 
216121Sbill /*
217903Sbill  * Start output on the typewriter. It is used from the top half
218903Sbill  * after some characters have been put on the output queue,
219903Sbill  * from the interrupt routine to transmit the next
220903Sbill  * character, and after a timeout has finished.
22139Sbill  */
222903Sbill ttstart(tp)
2237625Ssam 	register struct tty *tp;
22439Sbill {
225903Sbill 	register s;
22639Sbill 
22717545Skarels 	s = spltty();
2289578Ssam 	if ((tp->t_state & (TS_TIMEOUT|TS_TTSTOP|TS_BUSY)) == 0 &&
2295622Swnj 	    tp->t_oproc)		/* kludge for pty */
230903Sbill 		(*tp->t_oproc)(tp);
231903Sbill 	splx(s);
23239Sbill }
23339Sbill 
23439Sbill /*
235903Sbill  * Common code for tty ioctls.
23639Sbill  */
2371780Sbill /*ARGSUSED*/
2387625Ssam ttioctl(tp, com, data, flag)
2397625Ssam 	register struct tty *tp;
2407625Ssam 	caddr_t data;
24139Sbill {
2428520Sroot 	int dev = tp->t_dev;
24339Sbill 	extern int nldisp;
2448556Sroot 	int s;
24512752Ssam 	register int newflags;
24639Sbill 
247903Sbill 	/*
248903Sbill 	 * If the ioctl involves modification,
24917545Skarels 	 * hang if in the background.
250903Sbill 	 */
2517625Ssam 	switch (com) {
25239Sbill 
253915Sbill 	case TIOCSETD:
254915Sbill 	case TIOCSETP:
255915Sbill 	case TIOCSETN:
256903Sbill 	case TIOCFLUSH:
257903Sbill 	case TIOCSETC:
258903Sbill 	case TIOCSLTC:
259903Sbill 	case TIOCSPGRP:
260903Sbill 	case TIOCLBIS:
261903Sbill 	case TIOCLBIC:
262903Sbill 	case TIOCLSET:
2639325Ssam 	case TIOCSTI:
26417598Sbloom 	case TIOCSWINSZ:
265903Sbill 		while (tp->t_line == NTTYDISC &&
266903Sbill 		   u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp &&
267903Sbill 		   (u.u_procp->p_flag&SVFORK) == 0 &&
268*24392Skarels 		   !(u.u_procp->p_sigignore & sigmask(SIGTTOU)) &&
269*24392Skarels 		   !(u.u_procp->p_sigmask & sigmask(SIGTTOU))) {
270903Sbill 			gsignal(u.u_procp->p_pgrp, SIGTTOU);
271903Sbill 			sleep((caddr_t)&lbolt, TTOPRI);
272903Sbill 		}
273903Sbill 		break;
274903Sbill 	}
275903Sbill 
2769578Ssam 	/*
2779578Ssam 	 * Process the ioctl.
2789578Ssam 	 */
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;
2899578Ssam 		int error = 0;
2907625Ssam 
29115078Skarels 		if ((unsigned) t >= nldisp)
29210851Ssam 			return (ENXIO);
29317545Skarels 		s = spltty();
29439Sbill 		if (tp->t_line)
29539Sbill 			(*linesw[tp->t_line].l_close)(tp);
29639Sbill 		if (t)
2978556Sroot 			error = (*linesw[t].l_open)(dev, tp);
29810851Ssam 		if (error) {
29910851Ssam 			if (tp->t_line)
30010851Ssam 				(void) (*linesw[tp->t_line].l_open)(dev, tp);
30110851Ssam 			splx(s);
3028556Sroot 			return (error);
30310851Ssam 		}
3048556Sroot 		tp->t_line = t;
30518650Sbloom 		splx(s);
30639Sbill 		break;
3077625Ssam 	}
30839Sbill 
3098556Sroot 	/* prevent more opens on channel */
3105614Swnj 	case TIOCEXCL:
3115614Swnj 		tp->t_state |= TS_XCLUDE;
3125614Swnj 		break;
3135614Swnj 
3145614Swnj 	case TIOCNXCL:
3155614Swnj 		tp->t_state &= ~TS_XCLUDE;
3165614Swnj 		break;
3175614Swnj 
3188556Sroot 	/* hang up line on last close */
31939Sbill 	case TIOCHPCL:
3205408Swnj 		tp->t_state |= TS_HUPCLS;
32139Sbill 		break;
32239Sbill 
3233942Sbugs 	case TIOCFLUSH: {
3247625Ssam 		register int flags = *(int *)data;
3257625Ssam 
3267625Ssam 		if (flags == 0)
3273942Sbugs 			flags = FREAD|FWRITE;
3287625Ssam 		else
3297625Ssam 			flags &= FREAD|FWRITE;
33012752Ssam 		ttyflush(tp, flags);
33139Sbill 		break;
3323944Sbugs 	}
33339Sbill 
3348556Sroot 	/* return number of characters immediately available */
3357625Ssam 	case FIONREAD:
3367625Ssam 		*(off_t *)data = ttnread(tp);
337174Sbill 		break;
338174Sbill 
33913077Ssam 	case TIOCOUTQ:
34013077Ssam 		*(int *)data = tp->t_outq.c_cc;
34113077Ssam 		break;
34213077Ssam 
3438589Sroot 	case TIOCSTOP:
34417545Skarels 		s = spltty();
3459578Ssam 		if ((tp->t_state&TS_TTSTOP) == 0) {
3465573Swnj 			tp->t_state |= TS_TTSTOP;
3475573Swnj 			(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
3485573Swnj 		}
3497625Ssam 		splx(s);
3505573Swnj 		break;
3515573Swnj 
3528589Sroot 	case TIOCSTART:
35317545Skarels 		s = spltty();
3549578Ssam 		if ((tp->t_state&TS_TTSTOP) || (tp->t_flags&FLUSHO)) {
3555573Swnj 			tp->t_state &= ~TS_TTSTOP;
3569578Ssam 			tp->t_flags &= ~FLUSHO;
3575573Swnj 			ttstart(tp);
3585573Swnj 		}
3597625Ssam 		splx(s);
3605573Swnj 		break;
3615573Swnj 
3629325Ssam 	/*
3639325Ssam 	 * Simulate typing of a character at the terminal.
3649325Ssam 	 */
3659325Ssam 	case TIOCSTI:
36617183Smckusick 		if (u.u_uid && (flag & FREAD) == 0)
36717183Smckusick 			return (EPERM);
3689325Ssam 		if (u.u_uid && u.u_ttyp != tp)
3699325Ssam 			return (EACCES);
3709578Ssam 		(*linesw[tp->t_line].l_rint)(*(char *)data, tp);
3719325Ssam 		break;
3729325Ssam 
37312752Ssam 	case TIOCSETP:
37412752Ssam 	case TIOCSETN: {
37512752Ssam 		register struct sgttyb *sg = (struct sgttyb *)data;
37612752Ssam 
37712752Ssam 		tp->t_erase = sg->sg_erase;
37812752Ssam 		tp->t_kill = sg->sg_kill;
37912752Ssam 		tp->t_ispeed = sg->sg_ispeed;
38012752Ssam 		tp->t_ospeed = sg->sg_ospeed;
38112752Ssam 		newflags = (tp->t_flags&0xffff0000) | (sg->sg_flags&0xffff);
38217545Skarels 		s = spltty();
38312752Ssam 		if (tp->t_flags&RAW || newflags&RAW || com == TIOCSETP) {
38412752Ssam 			ttywait(tp);
38512752Ssam 			ttyflush(tp, FREAD);
38612752Ssam 		} else if ((tp->t_flags&CBREAK) != (newflags&CBREAK)) {
38712752Ssam 			if (newflags&CBREAK) {
38812752Ssam 				struct clist tq;
38912752Ssam 
39012752Ssam 				catq(&tp->t_rawq, &tp->t_canq);
39112752Ssam 				tq = tp->t_rawq;
39212752Ssam 				tp->t_rawq = tp->t_canq;
39312752Ssam 				tp->t_canq = tq;
39412752Ssam 			} else {
39512752Ssam 				tp->t_flags |= PENDIN;
39613801Ssam 				newflags |= PENDIN;
39712752Ssam 				ttwakeup(tp);
39812752Ssam 			}
39912752Ssam 		}
40012752Ssam 		tp->t_flags = newflags;
40112752Ssam 		if (tp->t_flags&RAW) {
40212752Ssam 			tp->t_state &= ~TS_TTSTOP;
40312752Ssam 			ttstart(tp);
40412752Ssam 		}
40512752Ssam 		splx(s);
40612752Ssam 		break;
40712752Ssam 	}
40812752Ssam 
40912752Ssam 	/* send current parameters to user */
41012752Ssam 	case TIOCGETP: {
41112752Ssam 		register struct sgttyb *sg = (struct sgttyb *)data;
41212752Ssam 
41312752Ssam 		sg->sg_ispeed = tp->t_ispeed;
41412752Ssam 		sg->sg_ospeed = tp->t_ospeed;
41512752Ssam 		sg->sg_erase = tp->t_erase;
41612752Ssam 		sg->sg_kill = tp->t_kill;
41712752Ssam 		sg->sg_flags = tp->t_flags;
41812752Ssam 		break;
41912752Ssam 	}
42012752Ssam 
42112752Ssam 	case FIONBIO:
42212752Ssam 		if (*(int *)data)
42312752Ssam 			tp->t_state |= TS_NBIO;
42412752Ssam 		else
42512752Ssam 			tp->t_state &= ~TS_NBIO;
42612752Ssam 		break;
42712752Ssam 
42812752Ssam 	case FIOASYNC:
42912752Ssam 		if (*(int *)data)
43012752Ssam 			tp->t_state |= TS_ASYNC;
43112752Ssam 		else
43212752Ssam 			tp->t_state &= ~TS_ASYNC;
43312752Ssam 		break;
43412752Ssam 
43513077Ssam 	case TIOCGETC:
43613077Ssam 		bcopy((caddr_t)&tp->t_intrc, data, sizeof (struct tchars));
43713077Ssam 		break;
43813077Ssam 
43913077Ssam 	case TIOCSETC:
44013077Ssam 		bcopy(data, (caddr_t)&tp->t_intrc, sizeof (struct tchars));
44113077Ssam 		break;
44213077Ssam 
44312752Ssam 	/* set/get local special characters */
44412752Ssam 	case TIOCSLTC:
44512752Ssam 		bcopy(data, (caddr_t)&tp->t_suspc, sizeof (struct ltchars));
44612752Ssam 		break;
44712752Ssam 
44812752Ssam 	case TIOCGLTC:
44912752Ssam 		bcopy((caddr_t)&tp->t_suspc, data, sizeof (struct ltchars));
45012752Ssam 		break;
45112752Ssam 
45212752Ssam 	/*
45312752Ssam 	 * Modify local mode word.
45412752Ssam 	 */
45512752Ssam 	case TIOCLBIS:
45612752Ssam 		tp->t_flags |= *(int *)data << 16;
45712752Ssam 		break;
45812752Ssam 
45912752Ssam 	case TIOCLBIC:
46012752Ssam 		tp->t_flags &= ~(*(int *)data << 16);
46112752Ssam 		break;
46212752Ssam 
46312752Ssam 	case TIOCLSET:
46412752Ssam 		tp->t_flags &= 0xffff;
46512752Ssam 		tp->t_flags |= *(int *)data << 16;
46612752Ssam 		break;
46712752Ssam 
46812752Ssam 	case TIOCLGET:
46915720Skarels 		*(int *)data = ((unsigned) tp->t_flags) >> 16;
47012752Ssam 		break;
47112752Ssam 
47217545Skarels 	/*
47317932Skarels 	 * Allow SPGRP only if tty is open for reading.
47417598Sbloom 	 * Quick check: if we can find a process in the new pgrp,
47517598Sbloom 	 * this user must own that process.
47617598Sbloom 	 * SHOULD VERIFY THAT PGRP IS IN USE AND IS THIS USER'S.
47717545Skarels 	 */
47818650Sbloom 	case TIOCSPGRP: {
47917545Skarels 		struct proc *p;
48017545Skarels 		int pgrp = *(int *)data;
48117545Skarels 
48217545Skarels 		if (u.u_uid && (flag & FREAD) == 0)
48317545Skarels 			return (EPERM);
48417598Sbloom 		p = pfind(pgrp);
48517598Sbloom 		if (p && p->p_pgrp == pgrp &&
48617598Sbloom 		    p->p_uid != u.u_uid && u.u_uid && !inferior(p))
48717598Sbloom 			return (EPERM);
48817545Skarels 		tp->t_pgrp = pgrp;
48912752Ssam 		break;
49018650Sbloom 	}
49112752Ssam 
49212752Ssam 	case TIOCGPGRP:
49312752Ssam 		*(int *)data = tp->t_pgrp;
49412752Ssam 		break;
49512752Ssam 
49617598Sbloom 	case TIOCSWINSZ:
49718650Sbloom 		if (bcmp((caddr_t)&tp->t_winsize, data,
49818650Sbloom 		    sizeof (struct winsize))) {
49917598Sbloom 			tp->t_winsize = *(struct winsize *)data;
50017598Sbloom 			gsignal(tp->t_pgrp, SIGWINCH);
50117598Sbloom 		}
50217598Sbloom 		break;
50317598Sbloom 
50417598Sbloom 	case TIOCGWINSZ:
50517598Sbloom 		*(struct winsize *)data = tp->t_winsize;
50617598Sbloom 		break;
50717598Sbloom 
50839Sbill 	default:
5098556Sroot 		return (-1);
51039Sbill 	}
5118556Sroot 	return (0);
51239Sbill }
5134484Swnj 
5144484Swnj ttnread(tp)
5154484Swnj 	struct tty *tp;
5164484Swnj {
5174484Swnj 	int nread = 0;
5184484Swnj 
5199578Ssam 	if (tp->t_flags & PENDIN)
5204484Swnj 		ttypend(tp);
5214484Swnj 	nread = tp->t_canq.c_cc;
5224484Swnj 	if (tp->t_flags & (RAW|CBREAK))
5234484Swnj 		nread += tp->t_rawq.c_cc;
5244484Swnj 	return (nread);
5254484Swnj }
5264484Swnj 
5275408Swnj ttselect(dev, rw)
5284484Swnj 	dev_t dev;
5295408Swnj 	int rw;
5304484Swnj {
5314484Swnj 	register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)];
5324484Swnj 	int nread;
53317545Skarels 	int s = spltty();
5344484Swnj 
5355408Swnj 	switch (rw) {
5364484Swnj 
5374484Swnj 	case FREAD:
5384484Swnj 		nread = ttnread(tp);
53921776Sbloom 		if ((nread > 0) || ((tp->t_state & TS_CARR_ON) == 0))
5405408Swnj 			goto win;
5414938Swnj 		if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait)
5425408Swnj 			tp->t_state |= TS_RCOLL;
5434484Swnj 		else
5444484Swnj 			tp->t_rsel = u.u_procp;
5455408Swnj 		break;
5464484Swnj 
5475408Swnj 	case FWRITE:
5485408Swnj 		if (tp->t_outq.c_cc <= TTLOWAT(tp))
5495408Swnj 			goto win;
5505408Swnj 		if (tp->t_wsel && tp->t_wsel->p_wchan == (caddr_t)&selwait)
5515408Swnj 			tp->t_state |= TS_WCOLL;
5525408Swnj 		else
5535408Swnj 			tp->t_wsel = u.u_procp;
5545408Swnj 		break;
5554484Swnj 	}
5565408Swnj 	splx(s);
5575408Swnj 	return (0);
5585408Swnj win:
5595408Swnj 	splx(s);
5605408Swnj 	return (1);
5614484Swnj }
5627436Skre 
5637502Sroot /*
5649578Ssam  * Establish a process group for distribution of
5657502Sroot  * quits and interrupts from the tty.
5667502Sroot  */
5677502Sroot ttyopen(dev, tp)
5687625Ssam 	dev_t dev;
5697625Ssam 	register struct tty *tp;
5707502Sroot {
5717502Sroot 	register struct proc *pp;
5727502Sroot 
5737502Sroot 	pp = u.u_procp;
5747502Sroot 	tp->t_dev = dev;
5757625Ssam 	if (pp->p_pgrp == 0) {
5767502Sroot 		u.u_ttyp = tp;
5777502Sroot 		u.u_ttyd = dev;
5787502Sroot 		if (tp->t_pgrp == 0)
5797502Sroot 			tp->t_pgrp = pp->p_pid;
5807502Sroot 		pp->p_pgrp = tp->t_pgrp;
5817502Sroot 	}
5827502Sroot 	tp->t_state &= ~TS_WOPEN;
58317545Skarels 	if ((tp->t_state & TS_ISOPEN) == 0) {
58417545Skarels 		tp->t_state |= TS_ISOPEN;
58517598Sbloom 		bzero((caddr_t)&tp->t_winsize, sizeof(tp->t_winsize));
58617545Skarels 		if (tp->t_line != NTTYDISC)
58717545Skarels 			ttywflush(tp);
58817545Skarels 	}
5898556Sroot 	return (0);
5907502Sroot }
5917502Sroot 
5927502Sroot /*
5937502Sroot  * clean tp on last close
5947502Sroot  */
5957502Sroot ttyclose(tp)
5967625Ssam 	register struct tty *tp;
5977502Sroot {
5987502Sroot 
5997502Sroot 	if (tp->t_line) {
60012752Ssam 		ttywflush(tp);
6017502Sroot 		tp->t_line = 0;
6027502Sroot 		return;
6037502Sroot 	}
6047502Sroot 	tp->t_pgrp = 0;
60512752Ssam 	ttywflush(tp);
6067502Sroot 	tp->t_state = 0;
6077502Sroot }
6087502Sroot 
6097502Sroot /*
6107502Sroot  * reinput pending characters after state switch
61117545Skarels  * call at spltty().
6127502Sroot  */
6137502Sroot ttypend(tp)
6147625Ssam 	register struct tty *tp;
6157502Sroot {
6167502Sroot 	struct clist tq;
6177502Sroot 	register c;
6187502Sroot 
6199578Ssam 	tp->t_flags &= ~PENDIN;
6209578Ssam 	tp->t_state |= TS_TYPEN;
6217502Sroot 	tq = tp->t_rawq;
6227502Sroot 	tp->t_rawq.c_cc = 0;
6237502Sroot 	tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0;
6247502Sroot 	while ((c = getc(&tq)) >= 0)
6257502Sroot 		ttyinput(c, tp);
6269578Ssam 	tp->t_state &= ~TS_TYPEN;
6277502Sroot }
6287502Sroot 
6297502Sroot /*
6309578Ssam  * Place a character on raw TTY input queue,
6319578Ssam  * putting in delimiters and waking up top
6329578Ssam  * half as needed.  Also echo if required.
6339578Ssam  * The arguments are the character and the
6349578Ssam  * appropriate tty structure.
6357502Sroot  */
6367502Sroot ttyinput(c, tp)
6377625Ssam 	register c;
6387625Ssam 	register struct tty *tp;
6397502Sroot {
6409578Ssam 	register int t_flags = tp->t_flags;
6417502Sroot 	int i;
6427502Sroot 
6439578Ssam 	/*
6449578Ssam 	 * If input is pending take it first.
6459578Ssam 	 */
6469578Ssam 	if (t_flags&PENDIN)
6477502Sroot 		ttypend(tp);
6487502Sroot 	tk_nin++;
6497502Sroot 	c &= 0377;
6509578Ssam 
6519578Ssam 	/*
6529578Ssam 	 * In tandem mode, check high water mark.
6539578Ssam 	 */
6547502Sroot 	if (t_flags&TANDEM)
6557502Sroot 		ttyblock(tp);
6569578Ssam 
6579578Ssam 	if (t_flags&RAW) {
6589578Ssam 		/*
6599578Ssam 		 * Raw mode, just put character
6609578Ssam 		 * in input q w/o interpretation.
6619578Ssam 		 */
6629578Ssam 		if (tp->t_rawq.c_cc > TTYHOG)
66312752Ssam 			ttyflush(tp, FREAD|FWRITE);
6649578Ssam 		else {
6659578Ssam 			if (putc(c, &tp->t_rawq) >= 0)
6669578Ssam 				ttwakeup(tp);
6679578Ssam 			ttyecho(c, tp);
6687502Sroot 		}
6699578Ssam 		goto endcase;
6709578Ssam 	}
6719578Ssam 
6729578Ssam 	/*
6739578Ssam 	 * Ignore any high bit added during
6749578Ssam 	 * previous ttyinput processing.
6759578Ssam 	 */
67624273Slepreau 	if ((tp->t_state&TS_TYPEN) == 0 && (t_flags&PASS8) == 0)
6779578Ssam 		c &= 0177;
6789578Ssam 	/*
6799578Ssam 	 * Check for literal nexting very first
6809578Ssam 	 */
6819578Ssam 	if (tp->t_state&TS_LNCH) {
6829578Ssam 		c |= 0200;
6839578Ssam 		tp->t_state &= ~TS_LNCH;
6849578Ssam 	}
6859578Ssam 
6869578Ssam 	/*
6879578Ssam 	 * Scan for special characters.  This code
6889578Ssam 	 * is really just a big case statement with
6899578Ssam 	 * non-constant cases.  The bottom of the
6909578Ssam 	 * case statement is labeled ``endcase'', so goto
6919578Ssam 	 * it after a case match, or similar.
6929578Ssam 	 */
6939578Ssam 	if (tp->t_line == NTTYDISC) {
6949578Ssam 		if (c == tp->t_lnextc) {
69521776Sbloom 			if (t_flags&ECHO)
6967502Sroot 				ttyout("^\b", tp);
6979578Ssam 			tp->t_state |= TS_LNCH;
6989578Ssam 			goto endcase;
6999578Ssam 		}
7009578Ssam 		if (c == tp->t_flushc) {
70121776Sbloom 			if (t_flags&FLUSHO)
7029578Ssam 				tp->t_flags &= ~FLUSHO;
7037502Sroot 			else {
70412752Ssam 				ttyflush(tp, FWRITE);
7057502Sroot 				ttyecho(c, tp);
7069578Ssam 				if (tp->t_rawq.c_cc + tp->t_canq.c_cc)
7077502Sroot 					ttyretype(tp);
7089578Ssam 				tp->t_flags |= FLUSHO;
7097502Sroot 			}
7109578Ssam 			goto startoutput;
7119578Ssam 		}
7129578Ssam 		if (c == tp->t_suspc) {
71321776Sbloom 			if ((t_flags&NOFLSH) == 0)
71412752Ssam 				ttyflush(tp, FREAD);
7159578Ssam 			ttyecho(c, tp);
7169578Ssam 			gsignal(tp->t_pgrp, SIGTSTP);
7179578Ssam 			goto endcase;
7189578Ssam 		}
7199578Ssam 	}
7209578Ssam 
7219578Ssam 	/*
7229578Ssam 	 * Handle start/stop characters.
7239578Ssam 	 */
7249578Ssam 	if (c == tp->t_stopc) {
7259578Ssam 		if ((tp->t_state&TS_TTSTOP) == 0) {
7269578Ssam 			tp->t_state |= TS_TTSTOP;
7279578Ssam 			(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
7287502Sroot 			return;
7299578Ssam 		}
7309578Ssam 		if (c != tp->t_startc)
7319578Ssam 			return;
7329578Ssam 		goto endcase;
7339578Ssam 	}
7349578Ssam 	if (c == tp->t_startc)
7359578Ssam 		goto restartoutput;
7369578Ssam 
7379578Ssam 	/*
7389578Ssam 	 * Look for interrupt/quit chars.
7399578Ssam 	 */
7409578Ssam 	if (c == tp->t_intrc || c == tp->t_quitc) {
74121776Sbloom 		if ((t_flags&NOFLSH) == 0)
74212752Ssam 			ttyflush(tp, FREAD|FWRITE);
7439578Ssam 		ttyecho(c, tp);
7449578Ssam 		gsignal(tp->t_pgrp, c == tp->t_intrc ? SIGINT : SIGQUIT);
7459578Ssam 		goto endcase;
7469578Ssam 	}
7479578Ssam 
74823165Sbloom 	if (tp->t_flags & LCASE && c <= 0177) {
74923165Sbloom 		if (tp->t_state&TS_BKSL) {
75023165Sbloom 			ttyrub(unputc(&tp->t_rawq), tp);
75123165Sbloom 			if (maptab[c])
75223165Sbloom 				c = maptab[c];
75323165Sbloom 			c |= 0200;
75423165Sbloom 			tp->t_state &= ~(TS_BKSL|TS_QUOT);
75523165Sbloom 		} else if (c >= 'A' && c <= 'Z')
75623165Sbloom 			c += 'a' - 'A';
75723165Sbloom 		else if (c == '\\')
75823165Sbloom 			tp->t_state |= TS_BKSL;
75923165Sbloom 	}
76023165Sbloom 
7619578Ssam 	/*
7629578Ssam 	 * Cbreak mode, don't process line editing
7639578Ssam 	 * characters; check high water mark for wakeup.
7649578Ssam 	 */
7659578Ssam 	if (t_flags&CBREAK) {
7669578Ssam 		if (tp->t_rawq.c_cc > TTYHOG) {
7677502Sroot 			if (tp->t_outq.c_cc < TTHIWAT(tp) &&
7687502Sroot 			    tp->t_line == NTTYDISC)
7697502Sroot 				(void) ttyoutput(CTRL(g), tp);
7707502Sroot 		} else if (putc(c, &tp->t_rawq) >= 0) {
7717502Sroot 			ttwakeup(tp);
7727502Sroot 			ttyecho(c, tp);
7737502Sroot 		}
7749578Ssam 		goto endcase;
7759578Ssam 	}
7769578Ssam 
7779578Ssam 	/*
7789578Ssam 	 * From here on down cooked mode character
7799578Ssam 	 * processing takes place.
7809578Ssam 	 */
7819578Ssam 	if ((tp->t_state&TS_QUOT) &&
7829578Ssam 	    (c == tp->t_erase || c == tp->t_kill)) {
7839578Ssam 		ttyrub(unputc(&tp->t_rawq), tp);
7849578Ssam 		c |= 0200;
7859578Ssam 	}
7869578Ssam 	if (c == tp->t_erase) {
7879578Ssam 		if (tp->t_rawq.c_cc)
7889578Ssam 			ttyrub(unputc(&tp->t_rawq), tp);
7899578Ssam 		goto endcase;
7909578Ssam 	}
7919578Ssam 	if (c == tp->t_kill) {
79221776Sbloom 		if (t_flags&CRTKIL &&
7939578Ssam 		    tp->t_rawq.c_cc == tp->t_rocount) {
7949578Ssam 			while (tp->t_rawq.c_cc)
7959578Ssam 				ttyrub(unputc(&tp->t_rawq), tp);
7969578Ssam 		} else {
7979578Ssam 			ttyecho(c, tp);
7989578Ssam 			ttyecho('\n', tp);
7999578Ssam 			while (getc(&tp->t_rawq) > 0)
8009578Ssam 				;
8019578Ssam 			tp->t_rocount = 0;
8029578Ssam 		}
8039578Ssam 		tp->t_state &= ~TS_LOCAL;
8049578Ssam 		goto endcase;
8059578Ssam 	}
8069578Ssam 
8079578Ssam 	/*
8089578Ssam 	 * New line discipline,
8099578Ssam 	 * check word erase/reprint line.
8109578Ssam 	 */
8119578Ssam 	if (tp->t_line == NTTYDISC) {
8129578Ssam 		if (c == tp->t_werasc) {
8139578Ssam 			if (tp->t_rawq.c_cc == 0)
8149578Ssam 				goto endcase;
8159578Ssam 			do {
8169578Ssam 				c = unputc(&tp->t_rawq);
8179578Ssam 				if (c != ' ' && c != '\t')
8189578Ssam 					goto erasenb;
8199578Ssam 				ttyrub(c, tp);
8209578Ssam 			} while (tp->t_rawq.c_cc);
8219578Ssam 			goto endcase;
8229578Ssam 	erasenb:
8239578Ssam 			do {
8249578Ssam 				ttyrub(c, tp);
8259578Ssam 				if (tp->t_rawq.c_cc == 0)
8269578Ssam 					goto endcase;
8279578Ssam 				c = unputc(&tp->t_rawq);
8289578Ssam 			} while (c != ' ' && c != '\t');
8299578Ssam 			(void) putc(c, &tp->t_rawq);
8309578Ssam 			goto endcase;
8319578Ssam 		}
8329578Ssam 		if (c == tp->t_rprntc) {
8339578Ssam 			ttyretype(tp);
8349578Ssam 			goto endcase;
8359578Ssam 		}
8369578Ssam 	}
8379578Ssam 
8389578Ssam 	/*
8399578Ssam 	 * Check for input buffer overflow
8409578Ssam 	 */
84110391Ssam 	if (tp->t_rawq.c_cc+tp->t_canq.c_cc >= TTYHOG) {
84210391Ssam 		if (tp->t_line == NTTYDISC)
84310391Ssam 			(void) ttyoutput(CTRL(g), tp);
8449578Ssam 		goto endcase;
84510391Ssam 	}
8469578Ssam 
8479578Ssam 	/*
8489578Ssam 	 * Put data char in q for user and
8499578Ssam 	 * wakeup on seeing a line delimiter.
8509578Ssam 	 */
8519578Ssam 	if (putc(c, &tp->t_rawq) >= 0) {
8529578Ssam 		if (ttbreakc(c, tp)) {
8539578Ssam 			tp->t_rocount = 0;
8549578Ssam 			catq(&tp->t_rawq, &tp->t_canq);
8557502Sroot 			ttwakeup(tp);
8569578Ssam 		} else if (tp->t_rocount++ == 0)
8579578Ssam 			tp->t_rocol = tp->t_col;
8589578Ssam 		tp->t_state &= ~TS_QUOT;
8599578Ssam 		if (c == '\\')
8609578Ssam 			tp->t_state |= TS_QUOT;
8619578Ssam 		if (tp->t_state&TS_ERASE) {
8629578Ssam 			tp->t_state &= ~TS_ERASE;
8639578Ssam 			(void) ttyoutput('/', tp);
8649578Ssam 		}
8659578Ssam 		i = tp->t_col;
8667502Sroot 		ttyecho(c, tp);
86721776Sbloom 		if (c == tp->t_eofc && t_flags&ECHO) {
8689578Ssam 			i = MIN(2, tp->t_col - i);
8699578Ssam 			while (i > 0) {
8709578Ssam 				(void) ttyoutput('\b', tp);
8719578Ssam 				i--;
8729578Ssam 			}
8739578Ssam 		}
8747502Sroot 	}
8759578Ssam endcase:
8769578Ssam 	/*
8779578Ssam 	 * If DEC-style start/stop is enabled don't restart
8789578Ssam 	 * output until seeing the start character.
8799578Ssam 	 */
88021776Sbloom 	if (t_flags&DECCTQ && tp->t_state&TS_TTSTOP &&
8819578Ssam 	    tp->t_startc != tp->t_stopc)
8827502Sroot 		return;
8839578Ssam restartoutput:
8847502Sroot 	tp->t_state &= ~TS_TTSTOP;
8859578Ssam 	tp->t_flags &= ~FLUSHO;
8869578Ssam startoutput:
8877502Sroot 	ttstart(tp);
8887502Sroot }
8897502Sroot 
8907502Sroot /*
8919578Ssam  * Put character on TTY output queue, adding delays,
8927502Sroot  * expanding tabs, and handling the CR/NL bit.
8939578Ssam  * This is called both from the top half for output,
8949578Ssam  * and from interrupt level for echoing.
8957502Sroot  * The arguments are the character and the tty structure.
8967502Sroot  * Returns < 0 if putc succeeds, otherwise returns char to resend
8977502Sroot  * Must be recursive.
8987502Sroot  */
8997502Sroot ttyoutput(c, tp)
9007502Sroot 	register c;
9017502Sroot 	register struct tty *tp;
9027502Sroot {
9037502Sroot 	register char *colp;
9047502Sroot 	register ctype;
9057502Sroot 
9069578Ssam 	if (tp->t_flags & (RAW|LITOUT)) {
9079578Ssam 		if (tp->t_flags&FLUSHO)
9087502Sroot 			return (-1);
9097502Sroot 		if (putc(c, &tp->t_outq))
9107625Ssam 			return (c);
9117502Sroot 		tk_nout++;
9127502Sroot 		return (-1);
9137502Sroot 	}
9149578Ssam 
9157502Sroot 	/*
9169578Ssam 	 * Ignore EOT in normal mode to avoid
9179578Ssam 	 * hanging up certain terminals.
9187502Sroot 	 */
9197502Sroot 	c &= 0177;
9209578Ssam 	if (c == CEOT && (tp->t_flags&CBREAK) == 0)
9217502Sroot 		return (-1);
9227502Sroot 	/*
9237502Sroot 	 * Turn tabs to spaces as required
9247502Sroot 	 */
9259578Ssam 	if (c == '\t' && (tp->t_flags&TBDELAY) == XTABS) {
9267502Sroot 		register int s;
9277502Sroot 
9287502Sroot 		c = 8 - (tp->t_col&7);
9299578Ssam 		if ((tp->t_flags&FLUSHO) == 0) {
93017545Skarels 			s = spltty();		/* don't interrupt tabs */
9317502Sroot 			c -= b_to_q("        ", c, &tp->t_outq);
9327502Sroot 			tk_nout += c;
9337502Sroot 			splx(s);
9347502Sroot 		}
9357502Sroot 		tp->t_col += c;
9367502Sroot 		return (c ? -1 : '\t');
9377502Sroot 	}
9387502Sroot 	tk_nout++;
9397502Sroot 	/*
9407502Sroot 	 * for upper-case-only terminals,
9417502Sroot 	 * generate escapes.
9427502Sroot 	 */
9437502Sroot 	if (tp->t_flags&LCASE) {
9447502Sroot 		colp = "({)}!|^~'`";
9457625Ssam 		while (*colp++)
9467625Ssam 			if (c == *colp++) {
9477502Sroot 				if (ttyoutput('\\', tp) >= 0)
9487502Sroot 					return (c);
9497502Sroot 				c = colp[-2];
9507502Sroot 				break;
9517502Sroot 			}
9529578Ssam 		if ('A' <= c && c <= 'Z') {
9537502Sroot 			if (ttyoutput('\\', tp) >= 0)
9547502Sroot 				return (c);
9559578Ssam 		} else if ('a' <= c && c <= 'z')
9567502Sroot 			c += 'A' - 'a';
9577502Sroot 	}
9589578Ssam 
9597502Sroot 	/*
9607502Sroot 	 * turn <nl> to <cr><lf> if desired.
9617502Sroot 	 */
9629578Ssam 	if (c == '\n' && tp->t_flags&CRMOD)
9637502Sroot 		if (ttyoutput('\r', tp) >= 0)
9647502Sroot 			return (c);
9659578Ssam 	if (c == '~' && tp->t_flags&TILDE)
9667502Sroot 		c = '`';
9679578Ssam 	if ((tp->t_flags&FLUSHO) == 0 && putc(c, &tp->t_outq))
9687502Sroot 		return (c);
9697502Sroot 	/*
9707502Sroot 	 * Calculate delays.
9717502Sroot 	 * The numbers here represent clock ticks
9727502Sroot 	 * and are not necessarily optimal for all terminals.
9737502Sroot 	 * The delays are indicated by characters above 0200.
9747502Sroot 	 * In raw mode there are no delays and the
9757502Sroot 	 * transmission path is 8 bits wide.
9769578Ssam 	 *
9779578Ssam 	 * SHOULD JUST ALLOW USER TO SPECIFY DELAYS
9787502Sroot 	 */
9797502Sroot 	colp = &tp->t_col;
9807502Sroot 	ctype = partab[c];
9817502Sroot 	c = 0;
9827502Sroot 	switch (ctype&077) {
9837502Sroot 
9847502Sroot 	case ORDINARY:
9857502Sroot 		(*colp)++;
9867502Sroot 
9877502Sroot 	case CONTROL:
9887502Sroot 		break;
9897502Sroot 
9907502Sroot 	case BACKSPACE:
9917502Sroot 		if (*colp)
9927502Sroot 			(*colp)--;
9937502Sroot 		break;
9947502Sroot 
99513821Ssam 	/*
99613821Ssam 	 * This macro is close enough to the correct thing;
99713821Ssam 	 * it should be replaced by real user settable delays
99813821Ssam 	 * in any event...
99913821Ssam 	 */
100013821Ssam #define	mstohz(ms)	(((ms) * hz) >> 10)
10017502Sroot 	case NEWLINE:
10027502Sroot 		ctype = (tp->t_flags >> 8) & 03;
10037625Ssam 		if (ctype == 1) { /* tty 37 */
100412752Ssam 			if (*colp > 0)
100513863Ssam 				c = max((((unsigned)*colp) >> 4) + 3,
100613863Ssam 				    (unsigned)6);
10079578Ssam 		} else if (ctype == 2) /* vt05 */
100813821Ssam 			c = mstohz(100);
10097502Sroot 		*colp = 0;
10107502Sroot 		break;
10117502Sroot 
10127502Sroot 	case TAB:
10137502Sroot 		ctype = (tp->t_flags >> 10) & 03;
10147625Ssam 		if (ctype == 1) { /* tty 37 */
10157502Sroot 			c = 1 - (*colp | ~07);
10167625Ssam 			if (c < 5)
10177502Sroot 				c = 0;
10187502Sroot 		}
10197502Sroot 		*colp |= 07;
10207502Sroot 		(*colp)++;
10217502Sroot 		break;
10227502Sroot 
10237502Sroot 	case VTAB:
10249578Ssam 		if (tp->t_flags&VTDELAY) /* tty 37 */
10257502Sroot 			c = 0177;
10267502Sroot 		break;
10277502Sroot 
10287502Sroot 	case RETURN:
10297502Sroot 		ctype = (tp->t_flags >> 12) & 03;
10309578Ssam 		if (ctype == 1) /* tn 300 */
103113821Ssam 			c = mstohz(83);
10329578Ssam 		else if (ctype == 2) /* ti 700 */
103313821Ssam 			c = mstohz(166);
10349578Ssam 		else if (ctype == 3) { /* concept 100 */
10357502Sroot 			int i;
10369578Ssam 
10377502Sroot 			if ((i = *colp) >= 0)
10389578Ssam 				for (; i < 9; i++)
10397502Sroot 					(void) putc(0177, &tp->t_outq);
10407502Sroot 		}
10417502Sroot 		*colp = 0;
10427502Sroot 	}
10439578Ssam 	if (c && (tp->t_flags&FLUSHO) == 0)
10447502Sroot 		(void) putc(c|0200, &tp->t_outq);
10457502Sroot 	return (-1);
10467502Sroot }
104713821Ssam #undef mstohz
10487502Sroot 
10497502Sroot /*
10507502Sroot  * Called from device's read routine after it has
10517502Sroot  * calculated the tty-structure given as argument.
10527502Sroot  */
10537722Swnj ttread(tp, uio)
10547625Ssam 	register struct tty *tp;
10557722Swnj 	struct uio *uio;
10567502Sroot {
10577502Sroot 	register struct clist *qp;
10589578Ssam 	register c, t_flags;
10599859Ssam 	int s, first, error = 0;
10607502Sroot 
10617502Sroot loop:
10629578Ssam 	/*
10639578Ssam 	 * Take any pending input first.
10649578Ssam 	 */
106517545Skarels 	s = spltty();
10669578Ssam 	if (tp->t_flags&PENDIN)
10677502Sroot 		ttypend(tp);
10689859Ssam 	splx(s);
10699578Ssam 
107023165Sbloom 	if ((tp->t_state&TS_CARR_ON)==0)
107123165Sbloom 		return (EIO);
107223165Sbloom 
10739578Ssam 	/*
10749578Ssam 	 * Hang process if it's in the background.
10759578Ssam 	 */
107623165Sbloom 	if (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) {
1077*24392Skarels 		if ((u.u_procp->p_sigignore & sigmask(SIGTTIN)) ||
1078*24392Skarels 		   (u.u_procp->p_sigmask & sigmask(SIGTTIN)) ||
10797502Sroot 		    u.u_procp->p_flag&SVFORK)
10808520Sroot 			return (EIO);
10817502Sroot 		gsignal(u.u_procp->p_pgrp, SIGTTIN);
10827502Sroot 		sleep((caddr_t)&lbolt, TTIPRI);
108323165Sbloom 		goto loop;
10847502Sroot 	}
10859578Ssam 	t_flags = tp->t_flags;
10869578Ssam 
10879578Ssam 	/*
10889578Ssam 	 * In raw mode take characters directly from the
10899578Ssam 	 * raw queue w/o processing.  Interlock against
10909578Ssam 	 * device interrupts when interrogating rawq.
10919578Ssam 	 */
10929578Ssam 	if (t_flags&RAW) {
109317545Skarels 		s = spltty();
10947502Sroot 		if (tp->t_rawq.c_cc <= 0) {
10959578Ssam 			if ((tp->t_state&TS_CARR_ON) == 0 ||
10967502Sroot 			    (tp->t_state&TS_NBIO)) {
10979859Ssam 				splx(s);
109815094Skarels 				return (EWOULDBLOCK);
10997502Sroot 			}
11007502Sroot 			sleep((caddr_t)&tp->t_rawq, TTIPRI);
11019859Ssam 			splx(s);
11027502Sroot 			goto loop;
11037502Sroot 		}
11049859Ssam 		splx(s);
110514938Smckusick  		while (!error && tp->t_rawq.c_cc && uio->uio_resid)
110614938Smckusick  			error = ureadc(getc(&tp->t_rawq), uio);
11079859Ssam 		goto checktandem;
11089578Ssam 	}
11099578Ssam 
11109578Ssam 	/*
11119578Ssam 	 * In cbreak mode use the rawq, otherwise
11129578Ssam 	 * take characters from the canonicalized q.
11139578Ssam 	 */
11149578Ssam 	qp = t_flags&CBREAK ? &tp->t_rawq : &tp->t_canq;
11159578Ssam 
11169578Ssam 	/*
11179578Ssam 	 * No input, sleep on rawq awaiting hardware
11189578Ssam 	 * receipt and notification.
11199578Ssam 	 */
112017545Skarels 	s = spltty();
11219578Ssam 	if (qp->c_cc <= 0) {
11229578Ssam 		if ((tp->t_state&TS_CARR_ON) == 0 ||
11239578Ssam 		    (tp->t_state&TS_NBIO)) {
11249859Ssam 			splx(s);
11259578Ssam 			return (EWOULDBLOCK);
11267502Sroot 		}
11279578Ssam 		sleep((caddr_t)&tp->t_rawq, TTIPRI);
11289859Ssam 		splx(s);
11299578Ssam 		goto loop;
11309578Ssam 	}
11319859Ssam 	splx(s);
11329578Ssam 
11339578Ssam 	/*
11349578Ssam 	 * Input present, perform input mapping
11359578Ssam 	 * and processing (we're not in raw mode).
11369578Ssam 	 */
11379578Ssam 	first = 1;
11389578Ssam 	while ((c = getc(qp)) >= 0) {
11399578Ssam 		if (t_flags&CRMOD && c == '\r')
11409578Ssam 			c = '\n';
11419578Ssam 		/*
11429578Ssam 		 * Check for delayed suspend character.
11439578Ssam 		 */
11449578Ssam 		if (tp->t_line == NTTYDISC && c == tp->t_dsuspc) {
11459578Ssam 			gsignal(tp->t_pgrp, SIGTSTP);
11469578Ssam 			if (first) {
11479578Ssam 				sleep((caddr_t)&lbolt, TTIPRI);
11489578Ssam 				goto loop;
11499578Ssam 			}
11509578Ssam 			break;
11517502Sroot 		}
11529578Ssam 		/*
11539578Ssam 		 * Interpret EOF only in cooked mode.
11549578Ssam 		 */
11559578Ssam 		if (c == tp->t_eofc && (t_flags&CBREAK) == 0)
11569578Ssam 			break;
11579578Ssam 		/*
11589578Ssam 		 * Give user character.
11599578Ssam 		 */
116024273Slepreau  		error = ureadc(t_flags&PASS8 ? c : c & 0177, uio);
11619578Ssam 		if (error)
11629578Ssam 			break;
116314938Smckusick  		if (uio->uio_resid == 0)
11649578Ssam 			break;
11659578Ssam 		/*
11669578Ssam 		 * In cooked mode check for a "break character"
11679578Ssam 		 * marking the end of a "line of input".
11689578Ssam 		 */
11699578Ssam 		if ((t_flags&CBREAK) == 0 && ttbreakc(c, tp))
11709578Ssam 			break;
11719578Ssam 		first = 0;
11727502Sroot 	}
11739578Ssam 
11749859Ssam checktandem:
11759578Ssam 	/*
11769578Ssam 	 * Look to unblock output now that (presumably)
11779578Ssam 	 * the input queue has gone down.
11789578Ssam 	 */
11799859Ssam 	if (tp->t_state&TS_TBLOCK && tp->t_rawq.c_cc < TTYHOG/5)
11809578Ssam 		if (putc(tp->t_startc, &tp->t_outq) == 0) {
11817502Sroot 			tp->t_state &= ~TS_TBLOCK;
11827502Sroot 			ttstart(tp);
11837502Sroot 		}
11848520Sroot 	return (error);
11857502Sroot }
11867502Sroot 
11877502Sroot /*
11887502Sroot  * Called from the device's write routine after it has
11897502Sroot  * calculated the tty-structure given as argument.
11907502Sroot  */
11917822Sroot ttwrite(tp, uio)
11927625Ssam 	register struct tty *tp;
11939578Ssam 	register struct uio *uio;
11947502Sroot {
11957502Sroot 	register char *cp;
11969578Ssam 	register int cc, ce, c;
11979578Ssam 	int i, hiwat, cnt, error, s;
11987502Sroot 	char obuf[OBUFSIZ];
11997502Sroot 
12009578Ssam 	hiwat = TTHIWAT(tp);
12019578Ssam 	cnt = uio->uio_resid;
12029578Ssam 	error = 0;
12037502Sroot loop:
120421776Sbloom 	if ((tp->t_state&TS_CARR_ON) == 0)
120521776Sbloom 		return (EIO);
12069578Ssam 	/*
12079578Ssam 	 * Hang the process if it's in the background.
12089578Ssam 	 */
120921776Sbloom 	if (u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp &&
12109578Ssam 	    (tp->t_flags&TOSTOP) && (u.u_procp->p_flag&SVFORK)==0 &&
1211*24392Skarels 	    !(u.u_procp->p_sigignore & sigmask(SIGTTOU)) &&
1212*24392Skarels 	    !(u.u_procp->p_sigmask & sigmask(SIGTTOU))) {
12137502Sroot 		gsignal(u.u_procp->p_pgrp, SIGTTOU);
12147502Sroot 		sleep((caddr_t)&lbolt, TTIPRI);
121521776Sbloom 		goto loop;
12167502Sroot 	}
12179578Ssam 
12189578Ssam 	/*
12199578Ssam 	 * Process the user's data in at most OBUFSIZ
12209578Ssam 	 * chunks.  Perform lower case simulation and
12219578Ssam 	 * similar hacks.  Keep track of high water
12229578Ssam 	 * mark, sleep on overflow awaiting device aid
12239578Ssam 	 * in acquiring new space.
12249578Ssam 	 */
12257822Sroot 	while (uio->uio_resid > 0) {
12269578Ssam 		/*
12279578Ssam 		 * Grab a hunk of data from the user.
12289578Ssam 		 */
12297822Sroot 		cc = uio->uio_iov->iov_len;
12307822Sroot 		if (cc == 0) {
12317822Sroot 			uio->uio_iovcnt--;
12327822Sroot 			uio->uio_iov++;
123321776Sbloom 			if (uio->uio_iovcnt <= 0)
12347822Sroot 				panic("ttwrite");
12357822Sroot 			continue;
12367822Sroot 		}
12377822Sroot 		if (cc > OBUFSIZ)
12387822Sroot 			cc = OBUFSIZ;
12397502Sroot 		cp = obuf;
124012752Ssam 		error = uiomove(cp, cc, UIO_WRITE, uio);
12418520Sroot 		if (error)
12427502Sroot 			break;
12437502Sroot 		if (tp->t_outq.c_cc > hiwat)
12447502Sroot 			goto ovhiwat;
12459578Ssam 		if (tp->t_flags&FLUSHO)
12467502Sroot 			continue;
12479578Ssam 		/*
12489578Ssam 		 * If we're mapping lower case or kludging tildes,
12499578Ssam 		 * then we've got to look at each character, so
12509578Ssam 		 * just feed the stuff to ttyoutput...
12519578Ssam 		 */
12529578Ssam 		if (tp->t_flags & (LCASE|TILDE)) {
12539578Ssam 			while (cc > 0) {
12547502Sroot 				c = *cp++;
12557502Sroot 				tp->t_rocount = 0;
12567625Ssam 				while ((c = ttyoutput(c, tp)) >= 0) {
12577502Sroot 					/* out of clists, wait a bit */
12587502Sroot 					ttstart(tp);
12597502Sroot 					sleep((caddr_t)&lbolt, TTOPRI);
12607502Sroot 					tp->t_rocount = 0;
126121776Sbloom 					if (cc != 0) {
126221776Sbloom 						uio->uio_iov->iov_base -= cc;
126321776Sbloom 						uio->uio_iov->iov_len += cc;
126421776Sbloom 						uio->uio_resid += cc;
126521776Sbloom 						uio->uio_offset -= cc;
126621776Sbloom 					}
126721776Sbloom 					goto loop;
12687502Sroot 				}
12697502Sroot 				--cc;
12707502Sroot 				if (tp->t_outq.c_cc > hiwat)
12717502Sroot 					goto ovhiwat;
12727502Sroot 			}
12737502Sroot 			continue;
12747502Sroot 		}
12759578Ssam 		/*
12769578Ssam 		 * If nothing fancy need be done, grab those characters we
12779578Ssam 		 * can handle without any of ttyoutput's processing and
12789578Ssam 		 * just transfer them to the output q.  For those chars
12799578Ssam 		 * which require special processing (as indicated by the
12809578Ssam 		 * bits in partab), call ttyoutput.  After processing
12819578Ssam 		 * a hunk of data, look for FLUSHO so ^O's will take effect
12829578Ssam 		 * immediately.
12839578Ssam 		 */
12849578Ssam 		while (cc > 0) {
12859578Ssam 			if (tp->t_flags & (RAW|LITOUT))
12867502Sroot 				ce = cc;
12877502Sroot 			else {
128812752Ssam 				ce = cc - scanc((unsigned)cc, (caddr_t)cp,
128912752Ssam 				   (caddr_t)partab, 077);
12909578Ssam 				/*
12919578Ssam 				 * If ce is zero, then we're processing
12929578Ssam 				 * a special character through ttyoutput.
12939578Ssam 				 */
12949578Ssam 				if (ce == 0) {
12957502Sroot 					tp->t_rocount = 0;
12967502Sroot 					if (ttyoutput(*cp, tp) >= 0) {
129721776Sbloom 					    /* no c-lists, wait a bit */
129821776Sbloom 					    ttstart(tp);
129921776Sbloom 					    sleep((caddr_t)&lbolt, TTOPRI);
130021776Sbloom 					    if (cc != 0) {
130121776Sbloom 					        uio->uio_iov->iov_base -= cc;
130221776Sbloom 					        uio->uio_iov->iov_len += cc;
130321776Sbloom 					        uio->uio_resid += cc;
130421776Sbloom 						uio->uio_offset -= cc;
130521776Sbloom 					    }
130621776Sbloom 					    goto loop;
13077502Sroot 					}
13089578Ssam 					cp++, cc--;
13099578Ssam 					if (tp->t_flags&FLUSHO ||
13109578Ssam 					    tp->t_outq.c_cc > hiwat)
13117502Sroot 						goto ovhiwat;
13129578Ssam 					continue;
13137502Sroot 				}
13147502Sroot 			}
13159578Ssam 			/*
13169578Ssam 			 * A bunch of normal characters have been found,
13179578Ssam 			 * transfer them en masse to the output queue and
13189578Ssam 			 * continue processing at the top of the loop.
13199578Ssam 			 * If there are any further characters in this
13209578Ssam 			 * <= OBUFSIZ chunk, the first should be a character
13219578Ssam 			 * requiring special handling by ttyoutput.
13229578Ssam 			 */
13237502Sroot 			tp->t_rocount = 0;
13249578Ssam 			i = b_to_q(cp, ce, &tp->t_outq);
13259578Ssam 			ce -= i;
13269578Ssam 			tp->t_col += ce;
13279578Ssam 			cp += ce, cc -= ce, tk_nout += ce;
13289578Ssam 			if (i > 0) {
13299578Ssam 				/* out of c-lists, wait a bit */
13307502Sroot 				ttstart(tp);
13317502Sroot 				sleep((caddr_t)&lbolt, TTOPRI);
133221776Sbloom 				uio->uio_iov->iov_base -= cc;
133321776Sbloom 				uio->uio_iov->iov_len += cc;
133421776Sbloom 				uio->uio_resid += cc;
133521776Sbloom 				uio->uio_offset -= cc;
133621776Sbloom 				goto loop;
13377502Sroot 			}
13389578Ssam 			if (tp->t_flags&FLUSHO || tp->t_outq.c_cc > hiwat)
13397502Sroot 				goto ovhiwat;
13407502Sroot 		}
13417502Sroot 	}
13427502Sroot 	ttstart(tp);
13438520Sroot 	return (error);
13447502Sroot 
13457502Sroot ovhiwat:
134617545Skarels 	s = spltty();
13479578Ssam 	if (cc != 0) {
13489578Ssam 		uio->uio_iov->iov_base -= cc;
13499578Ssam 		uio->uio_iov->iov_len += cc;
13509578Ssam 		uio->uio_resid += cc;
13519578Ssam 		uio->uio_offset -= cc;
13529578Ssam 	}
13539578Ssam 	/*
13549578Ssam 	 * This can only occur if FLUSHO
13559578Ssam 	 * is also set in t_flags.
13569578Ssam 	 */
13577502Sroot 	if (tp->t_outq.c_cc <= hiwat) {
13589578Ssam 		splx(s);
13597502Sroot 		goto loop;
13607502Sroot 	}
13617502Sroot 	ttstart(tp);
13629578Ssam 	if (tp->t_state&TS_NBIO) {
136317545Skarels 		splx(s);
13647822Sroot 		if (uio->uio_resid == cnt)
13658520Sroot 			return (EWOULDBLOCK);
13668520Sroot 		return (0);
13677502Sroot 	}
13687502Sroot 	tp->t_state |= TS_ASLEEP;
13697502Sroot 	sleep((caddr_t)&tp->t_outq, TTOPRI);
13709578Ssam 	splx(s);
13717502Sroot 	goto loop;
13727502Sroot }
13737502Sroot 
13747502Sroot /*
13757502Sroot  * Rubout one character from the rawq of tp
13767502Sroot  * as cleanly as possible.
13777502Sroot  */
13787502Sroot ttyrub(c, tp)
13797625Ssam 	register c;
13807625Ssam 	register struct tty *tp;
13817502Sroot {
13827502Sroot 	register char *cp;
13837502Sroot 	register int savecol;
13847502Sroot 	int s;
13857502Sroot 	char *nextc();
13867502Sroot 
13879578Ssam 	if ((tp->t_flags&ECHO) == 0)
13887502Sroot 		return;
13899578Ssam 	tp->t_flags &= ~FLUSHO;
13907502Sroot 	c &= 0377;
13919578Ssam 	if (tp->t_flags&CRTBS) {
13927502Sroot 		if (tp->t_rocount == 0) {
13937502Sroot 			/*
13947502Sroot 			 * Screwed by ttwrite; retype
13957502Sroot 			 */
13967502Sroot 			ttyretype(tp);
13977502Sroot 			return;
13987502Sroot 		}
13999578Ssam 		if (c == ('\t'|0200) || c == ('\n'|0200))
14007502Sroot 			ttyrubo(tp, 2);
14019578Ssam 		else switch (partab[c&=0177]&0177) {
14027502Sroot 
14037502Sroot 		case ORDINARY:
14047502Sroot 			if (tp->t_flags&LCASE && c >= 'A' && c <= 'Z')
14057502Sroot 				ttyrubo(tp, 2);
14067502Sroot 			else
14077502Sroot 				ttyrubo(tp, 1);
14087502Sroot 			break;
14097502Sroot 
14107502Sroot 		case VTAB:
14117502Sroot 		case BACKSPACE:
14127502Sroot 		case CONTROL:
14137502Sroot 		case RETURN:
14149578Ssam 			if (tp->t_flags&CTLECH)
14157502Sroot 				ttyrubo(tp, 2);
14167502Sroot 			break;
14177502Sroot 
14187502Sroot 		case TAB:
14197502Sroot 			if (tp->t_rocount < tp->t_rawq.c_cc) {
14207502Sroot 				ttyretype(tp);
14217502Sroot 				return;
14227502Sroot 			}
142317545Skarels 			s = spltty();
14247502Sroot 			savecol = tp->t_col;
14259578Ssam 			tp->t_state |= TS_CNTTB;
14269578Ssam 			tp->t_flags |= FLUSHO;
14277502Sroot 			tp->t_col = tp->t_rocol;
14289578Ssam 			cp = tp->t_rawq.c_cf;
14299578Ssam 			for (; cp; cp = nextc(&tp->t_rawq, cp))
14307502Sroot 				ttyecho(*cp, tp);
14319578Ssam 			tp->t_flags &= ~FLUSHO;
14329578Ssam 			tp->t_state &= ~TS_CNTTB;
14337502Sroot 			splx(s);
14347502Sroot 			/*
14357502Sroot 			 * savecol will now be length of the tab
14367502Sroot 			 */
14377502Sroot 			savecol -= tp->t_col;
14387502Sroot 			tp->t_col += savecol;
14397502Sroot 			if (savecol > 8)
14407502Sroot 				savecol = 8;		/* overflow screw */
14417502Sroot 			while (--savecol >= 0)
14427502Sroot 				(void) ttyoutput('\b', tp);
14437502Sroot 			break;
14447502Sroot 
14457502Sroot 		default:
14467502Sroot 			panic("ttyrub");
14477502Sroot 		}
14489578Ssam 	} else if (tp->t_flags&PRTERA) {
14499578Ssam 		if ((tp->t_state&TS_ERASE) == 0) {
14507502Sroot 			(void) ttyoutput('\\', tp);
14519578Ssam 			tp->t_state |= TS_ERASE;
14527502Sroot 		}
14537502Sroot 		ttyecho(c, tp);
14547502Sroot 	} else
14557502Sroot 		ttyecho(tp->t_erase, tp);
14567502Sroot 	tp->t_rocount--;
14577502Sroot }
14587502Sroot 
14597502Sroot /*
14607502Sroot  * Crt back over cnt chars perhaps
14617502Sroot  * erasing them.
14627502Sroot  */
14637502Sroot ttyrubo(tp, cnt)
14647625Ssam 	register struct tty *tp;
14657625Ssam 	int cnt;
14667502Sroot {
14679578Ssam 	register char *rubostring = tp->t_flags&CRTERA ? "\b \b" : "\b";
14687502Sroot 
14697502Sroot 	while (--cnt >= 0)
14709578Ssam 		ttyout(rubostring, tp);
14717502Sroot }
14727502Sroot 
14737502Sroot /*
14747502Sroot  * Reprint the rawq line.
14757502Sroot  * We assume c_cc has already been checked.
14767502Sroot  */
14777502Sroot ttyretype(tp)
14787625Ssam 	register struct tty *tp;
14797502Sroot {
14807502Sroot 	register char *cp;
14817502Sroot 	char *nextc();
14827502Sroot 	int s;
14837502Sroot 
14849578Ssam 	if (tp->t_rprntc != 0377)
14859578Ssam 		ttyecho(tp->t_rprntc, tp);
14867502Sroot 	(void) ttyoutput('\n', tp);
148717545Skarels 	s = spltty();
14887502Sroot 	for (cp = tp->t_canq.c_cf; cp; cp = nextc(&tp->t_canq, cp))
14897502Sroot 		ttyecho(*cp, tp);
14907502Sroot 	for (cp = tp->t_rawq.c_cf; cp; cp = nextc(&tp->t_rawq, cp))
14917502Sroot 		ttyecho(*cp, tp);
14929578Ssam 	tp->t_state &= ~TS_ERASE;
14937502Sroot 	splx(s);
14947502Sroot 	tp->t_rocount = tp->t_rawq.c_cc;
14957502Sroot 	tp->t_rocol = 0;
14967502Sroot }
14977502Sroot 
14987502Sroot /*
14997502Sroot  * Echo a typed character to the terminal
15007502Sroot  */
15017502Sroot ttyecho(c, tp)
15027625Ssam 	register c;
15037625Ssam 	register struct tty *tp;
15047502Sroot {
15057502Sroot 
15069578Ssam 	if ((tp->t_state&TS_CNTTB) == 0)
15079578Ssam 		tp->t_flags &= ~FLUSHO;
15087502Sroot 	if ((tp->t_flags&ECHO) == 0)
15097502Sroot 		return;
15107502Sroot 	c &= 0377;
15117502Sroot 	if (tp->t_flags&RAW) {
15127502Sroot 		(void) ttyoutput(c, tp);
15137502Sroot 		return;
15147502Sroot 	}
15157502Sroot 	if (c == '\r' && tp->t_flags&CRMOD)
15167502Sroot 		c = '\n';
15179578Ssam 	if (tp->t_flags&CTLECH) {
15187502Sroot 		if ((c&0177) <= 037 && c!='\t' && c!='\n' || (c&0177)==0177) {
15197502Sroot 			(void) ttyoutput('^', tp);
15207502Sroot 			c &= 0177;
15217502Sroot 			if (c == 0177)
15227502Sroot 				c = '?';
15237502Sroot 			else if (tp->t_flags&LCASE)
15247502Sroot 				c += 'a' - 1;
15257502Sroot 			else
15267502Sroot 				c += 'A' - 1;
15277502Sroot 		}
15287502Sroot 	}
15299578Ssam 	(void) ttyoutput(c&0177, tp);
15307502Sroot }
15317502Sroot 
15327502Sroot /*
15337502Sroot  * Is c a break char for tp?
15347502Sroot  */
15357502Sroot ttbreakc(c, tp)
15367625Ssam 	register c;
15377625Ssam 	register struct tty *tp;
15387502Sroot {
15399578Ssam 	return (c == '\n' || c == tp->t_eofc || c == tp->t_brkc ||
15407502Sroot 		c == '\r' && (tp->t_flags&CRMOD));
15417502Sroot }
15427502Sroot 
15437502Sroot /*
15447502Sroot  * send string cp to tp
15457502Sroot  */
15467502Sroot ttyout(cp, tp)
15477625Ssam 	register char *cp;
15487625Ssam 	register struct tty *tp;
15497502Sroot {
15507502Sroot 	register char c;
15517502Sroot 
15527502Sroot 	while (c = *cp++)
15537502Sroot 		(void) ttyoutput(c, tp);
15547502Sroot }
15557502Sroot 
15567502Sroot ttwakeup(tp)
15577502Sroot 	struct tty *tp;
15587502Sroot {
15597502Sroot 
15607502Sroot 	if (tp->t_rsel) {
15617502Sroot 		selwakeup(tp->t_rsel, tp->t_state&TS_RCOLL);
15627502Sroot 		tp->t_state &= ~TS_RCOLL;
15637502Sroot 		tp->t_rsel = 0;
15647502Sroot 	}
156512752Ssam 	if (tp->t_state & TS_ASYNC)
156612752Ssam 		gsignal(tp->t_pgrp, SIGIO);
15677502Sroot 	wakeup((caddr_t)&tp->t_rawq);
15687502Sroot }
1569