xref: /csrg-svn/sys/kern/tty.c (revision 23165)
1*23165Sbloom /*	tty.c	6.18	85/06/08	*/
239Sbill 
39760Ssam #include "../machine/reg.h"
49760Ssam 
517095Sbloom #include "param.h"
617095Sbloom #include "systm.h"
717095Sbloom #include "dir.h"
817095Sbloom #include "user.h"
917095Sbloom #include "ioctl.h"
1017095Sbloom #include "tty.h"
1117095Sbloom #include "proc.h"
1217095Sbloom #include "inode.h"
1317095Sbloom #include "file.h"
1417095Sbloom #include "conf.h"
1517095Sbloom #include "buf.h"
1617095Sbloom #include "dk.h"
1717095Sbloom #include "uio.h"
1817095Sbloom #include "kernel.h"
1939Sbill 
207436Skre /*
217436Skre  * Table giving parity for characters and indicating
227436Skre  * character classes to tty driver.  In particular,
237436Skre  * if the low 6 bits are 0, then the character needs
247436Skre  * no special processing on output.
257436Skre  */
2639Sbill 
277436Skre char partab[] = {
287436Skre 	0001,0201,0201,0001,0201,0001,0001,0201,
297436Skre 	0202,0004,0003,0201,0005,0206,0201,0001,
307436Skre 	0201,0001,0001,0201,0001,0201,0201,0001,
317436Skre 	0001,0201,0201,0001,0201,0001,0001,0201,
327436Skre 	0200,0000,0000,0200,0000,0200,0200,0000,
337436Skre 	0000,0200,0200,0000,0200,0000,0000,0200,
347436Skre 	0000,0200,0200,0000,0200,0000,0000,0200,
357436Skre 	0200,0000,0000,0200,0000,0200,0200,0000,
367436Skre 	0200,0000,0000,0200,0000,0200,0200,0000,
377436Skre 	0000,0200,0200,0000,0200,0000,0000,0200,
387436Skre 	0000,0200,0200,0000,0200,0000,0000,0200,
397436Skre 	0200,0000,0000,0200,0000,0200,0200,0000,
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,0201,
447436Skre 
457436Skre 	/*
467436Skre 	 * 7 bit ascii ends with the last character above,
477436Skre 	 * but we contine through all 256 codes for the sake
487436Skre 	 * of the tty output routines which use special vax
497436Skre 	 * instructions which need a 256 character trt table.
507436Skre 	 */
517436Skre 
527436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
537436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
547436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
557436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
567436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
577436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
587436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
597436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
607436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
617436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
627436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
637436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
647436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
657436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
667436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
677436Skre 	0007,0007,0007,0007,0007,0007,0007,0007
687436Skre };
697436Skre 
70146Sbill /*
7139Sbill  * Input mapping table-- if an entry is non-zero, when the
7239Sbill  * corresponding character is typed preceded by "\" the escape
7339Sbill  * sequence is replaced by the table value.  Mostly used for
7439Sbill  * upper-case only terminals.
7539Sbill  */
7639Sbill char	maptab[] ={
7739Sbill 	000,000,000,000,000,000,000,000,
7839Sbill 	000,000,000,000,000,000,000,000,
7939Sbill 	000,000,000,000,000,000,000,000,
8039Sbill 	000,000,000,000,000,000,000,000,
8139Sbill 	000,'|',000,000,000,000,000,'`',
8239Sbill 	'{','}',000,000,000,000,000,000,
8339Sbill 	000,000,000,000,000,000,000,000,
8439Sbill 	000,000,000,000,000,000,000,000,
8539Sbill 	000,000,000,000,000,000,000,000,
8639Sbill 	000,000,000,000,000,000,000,000,
8739Sbill 	000,000,000,000,000,000,000,000,
8839Sbill 	000,000,000,000,000,000,'~',000,
8939Sbill 	000,'A','B','C','D','E','F','G',
9039Sbill 	'H','I','J','K','L','M','N','O',
9139Sbill 	'P','Q','R','S','T','U','V','W',
9239Sbill 	'X','Y','Z',000,000,000,000,000,
9339Sbill };
9439Sbill 
95925Sbill short	tthiwat[16] =
968954Sroot    { 100,100,100,100,100,100,100,200,200,400,400,400,650,650,1300,2000 };
97925Sbill short	ttlowat[16] =
98925Sbill    {  30, 30, 30, 30, 30, 30, 30, 50, 50,120,120,120,125,125,125,125 };
99925Sbill 
1009578Ssam struct	ttychars ttydefaults = {
1019578Ssam 	CERASE,	CKILL,	CINTR,	CQUIT,	CSTART,	CSTOP,	CEOF,
1029578Ssam 	CBRK,	CSUSP,	CDSUSP, CRPRNT, CFLUSH, CWERASE,CLNEXT
1039578Ssam };
10439Sbill 
10539Sbill ttychars(tp)
1069578Ssam 	struct tty *tp;
10739Sbill {
108174Sbill 
1099578Ssam 	tp->t_chars = ttydefaults;
11039Sbill }
11139Sbill 
11239Sbill /*
113903Sbill  * Wait for output to drain, then flush input waiting.
11439Sbill  */
11512752Ssam ttywflush(tp)
1165408Swnj 	register struct tty *tp;
11739Sbill {
11839Sbill 
11912752Ssam 	ttywait(tp);
12012752Ssam 	ttyflush(tp, FREAD);
12112752Ssam }
12212752Ssam 
12312752Ssam ttywait(tp)
12412752Ssam 	register struct tty *tp;
12512752Ssam {
12617545Skarels 	register int s = spltty();
12712752Ssam 
12813809Ssam 	while ((tp->t_outq.c_cc || tp->t_state&TS_BUSY) &&
12913809Ssam 	    tp->t_state&TS_CARR_ON && tp->t_oproc) {	/* kludge for pty */
130903Sbill 		(*tp->t_oproc)(tp);
1315408Swnj 		tp->t_state |= TS_ASLEEP;
132903Sbill 		sleep((caddr_t)&tp->t_outq, TTOPRI);
133903Sbill 	}
1349859Ssam 	splx(s);
13539Sbill }
13639Sbill 
13739Sbill /*
1389578Ssam  * Flush all TTY queues
13939Sbill  */
14012752Ssam ttyflush(tp, rw)
1417625Ssam 	register struct tty *tp;
14239Sbill {
143903Sbill 	register s;
144903Sbill 
14517545Skarels 	s = spltty();
146903Sbill 	if (rw & FREAD) {
147903Sbill 		while (getc(&tp->t_canq) >= 0)
148903Sbill 			;
149903Sbill 		wakeup((caddr_t)&tp->t_rawq);
150903Sbill 	}
151903Sbill 	if (rw & FWRITE) {
152903Sbill 		wakeup((caddr_t)&tp->t_outq);
1535408Swnj 		tp->t_state &= ~TS_TTSTOP;
1545426Swnj 		(*cdevsw[major(tp->t_dev)].d_stop)(tp, rw);
155903Sbill 		while (getc(&tp->t_outq) >= 0)
156903Sbill 			;
157903Sbill 	}
158903Sbill 	if (rw & FREAD) {
159903Sbill 		while (getc(&tp->t_rawq) >= 0)
160903Sbill 			;
1619578Ssam 		tp->t_rocount = 0;
162903Sbill 		tp->t_rocol = 0;
1639578Ssam 		tp->t_state &= ~TS_LOCAL;
164903Sbill 	}
165903Sbill 	splx(s);
16639Sbill }
16739Sbill 
168903Sbill /*
169903Sbill  * Send stop character on input overflow.
170903Sbill  */
171903Sbill ttyblock(tp)
1727625Ssam 	register struct tty *tp;
17339Sbill {
174903Sbill 	register x;
1759578Ssam 
176903Sbill 	x = tp->t_rawq.c_cc + tp->t_canq.c_cc;
177903Sbill 	if (tp->t_rawq.c_cc > TTYHOG) {
17812752Ssam 		ttyflush(tp, FREAD|FWRITE);
1795408Swnj 		tp->t_state &= ~TS_TBLOCK;
180903Sbill 	}
18115118Skarels 	/*
18215118Skarels 	 * Block further input iff:
18315118Skarels 	 * Current input > threshold AND input is available to user program
18415118Skarels 	 */
18516055Skarels 	if (x >= TTYHOG/2 &&
18616055Skarels 	    ((tp->t_flags & (RAW|CBREAK)) || (tp->t_canq.c_cc > 0))) {
18715118Skarels 		if (putc(tp->t_stopc, &tp->t_outq)==0) {
18815118Skarels 			tp->t_state |= TS_TBLOCK;
18915118Skarels 			ttstart(tp);
19015118Skarels 		}
191903Sbill 	}
19239Sbill }
19339Sbill 
19439Sbill /*
195903Sbill  * Restart typewriter output following a delay
196903Sbill  * timeout.
197903Sbill  * The name of the routine is passed to the timeout
198903Sbill  * subroutine and it is called during a clock interrupt.
199121Sbill  */
200903Sbill ttrstrt(tp)
2017625Ssam 	register struct tty *tp;
202121Sbill {
203121Sbill 
2049578Ssam 	if (tp == 0)
2059578Ssam 		panic("ttrstrt");
2065408Swnj 	tp->t_state &= ~TS_TIMEOUT;
207903Sbill 	ttstart(tp);
208121Sbill }
209121Sbill 
210121Sbill /*
211903Sbill  * Start output on the typewriter. It is used from the top half
212903Sbill  * after some characters have been put on the output queue,
213903Sbill  * from the interrupt routine to transmit the next
214903Sbill  * character, and after a timeout has finished.
21539Sbill  */
216903Sbill ttstart(tp)
2177625Ssam 	register struct tty *tp;
21839Sbill {
219903Sbill 	register s;
22039Sbill 
22117545Skarels 	s = spltty();
2229578Ssam 	if ((tp->t_state & (TS_TIMEOUT|TS_TTSTOP|TS_BUSY)) == 0 &&
2235622Swnj 	    tp->t_oproc)		/* kludge for pty */
224903Sbill 		(*tp->t_oproc)(tp);
225903Sbill 	splx(s);
22639Sbill }
22739Sbill 
22839Sbill /*
229903Sbill  * Common code for tty ioctls.
23039Sbill  */
2311780Sbill /*ARGSUSED*/
2327625Ssam ttioctl(tp, com, data, flag)
2337625Ssam 	register struct tty *tp;
2347625Ssam 	caddr_t data;
23539Sbill {
2368520Sroot 	int dev = tp->t_dev;
23739Sbill 	extern int nldisp;
2388556Sroot 	int s;
23912752Ssam 	register int newflags;
24039Sbill 
241903Sbill 	/*
242903Sbill 	 * If the ioctl involves modification,
24317545Skarels 	 * hang if in the background.
244903Sbill 	 */
2457625Ssam 	switch (com) {
24639Sbill 
247915Sbill 	case TIOCSETD:
248915Sbill 	case TIOCSETP:
249915Sbill 	case TIOCSETN:
250903Sbill 	case TIOCFLUSH:
251903Sbill 	case TIOCSETC:
252903Sbill 	case TIOCSLTC:
253903Sbill 	case TIOCSPGRP:
254903Sbill 	case TIOCLBIS:
255903Sbill 	case TIOCLBIC:
256903Sbill 	case TIOCLSET:
2579325Ssam 	case TIOCSTI:
25817598Sbloom 	case TIOCSWINSZ:
25915078Skarels #define bit(a) (1<<(a-1))
260903Sbill 		while (tp->t_line == NTTYDISC &&
261903Sbill 		   u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp &&
262903Sbill 		   (u.u_procp->p_flag&SVFORK) == 0 &&
26315078Skarels 		   !(u.u_procp->p_sigignore & bit(SIGTTOU)) &&
26415078Skarels 		   !(u.u_procp->p_sigmask & bit(SIGTTOU))) {
265903Sbill 			gsignal(u.u_procp->p_pgrp, SIGTTOU);
266903Sbill 			sleep((caddr_t)&lbolt, TTOPRI);
267903Sbill 		}
268903Sbill 		break;
269903Sbill 	}
27015078Skarels #undef	bit
271903Sbill 
2729578Ssam 	/*
2739578Ssam 	 * Process the ioctl.
2749578Ssam 	 */
2757625Ssam 	switch (com) {
276903Sbill 
2778556Sroot 	/* get discipline number */
27839Sbill 	case TIOCGETD:
2797625Ssam 		*(int *)data = tp->t_line;
28039Sbill 		break;
28139Sbill 
2828556Sroot 	/* set line discipline */
2837625Ssam 	case TIOCSETD: {
2847625Ssam 		register int t = *(int *)data;
2859578Ssam 		int error = 0;
2867625Ssam 
28715078Skarels 		if ((unsigned) t >= nldisp)
28810851Ssam 			return (ENXIO);
28917545Skarels 		s = spltty();
29039Sbill 		if (tp->t_line)
29139Sbill 			(*linesw[tp->t_line].l_close)(tp);
29239Sbill 		if (t)
2938556Sroot 			error = (*linesw[t].l_open)(dev, tp);
29410851Ssam 		if (error) {
29510851Ssam 			if (tp->t_line)
29610851Ssam 				(void) (*linesw[tp->t_line].l_open)(dev, tp);
29710851Ssam 			splx(s);
2988556Sroot 			return (error);
29910851Ssam 		}
3008556Sroot 		tp->t_line = t;
30118650Sbloom 		splx(s);
30239Sbill 		break;
3037625Ssam 	}
30439Sbill 
3058556Sroot 	/* prevent more opens on channel */
3065614Swnj 	case TIOCEXCL:
3075614Swnj 		tp->t_state |= TS_XCLUDE;
3085614Swnj 		break;
3095614Swnj 
3105614Swnj 	case TIOCNXCL:
3115614Swnj 		tp->t_state &= ~TS_XCLUDE;
3125614Swnj 		break;
3135614Swnj 
3148556Sroot 	/* hang up line on last close */
31539Sbill 	case TIOCHPCL:
3165408Swnj 		tp->t_state |= TS_HUPCLS;
31739Sbill 		break;
31839Sbill 
3193942Sbugs 	case TIOCFLUSH: {
3207625Ssam 		register int flags = *(int *)data;
3217625Ssam 
3227625Ssam 		if (flags == 0)
3233942Sbugs 			flags = FREAD|FWRITE;
3247625Ssam 		else
3257625Ssam 			flags &= FREAD|FWRITE;
32612752Ssam 		ttyflush(tp, flags);
32739Sbill 		break;
3283944Sbugs 	}
32939Sbill 
3308556Sroot 	/* return number of characters immediately available */
3317625Ssam 	case FIONREAD:
3327625Ssam 		*(off_t *)data = ttnread(tp);
333174Sbill 		break;
334174Sbill 
33513077Ssam 	case TIOCOUTQ:
33613077Ssam 		*(int *)data = tp->t_outq.c_cc;
33713077Ssam 		break;
33813077Ssam 
3398589Sroot 	case TIOCSTOP:
34017545Skarels 		s = spltty();
3419578Ssam 		if ((tp->t_state&TS_TTSTOP) == 0) {
3425573Swnj 			tp->t_state |= TS_TTSTOP;
3435573Swnj 			(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
3445573Swnj 		}
3457625Ssam 		splx(s);
3465573Swnj 		break;
3475573Swnj 
3488589Sroot 	case TIOCSTART:
34917545Skarels 		s = spltty();
3509578Ssam 		if ((tp->t_state&TS_TTSTOP) || (tp->t_flags&FLUSHO)) {
3515573Swnj 			tp->t_state &= ~TS_TTSTOP;
3529578Ssam 			tp->t_flags &= ~FLUSHO;
3535573Swnj 			ttstart(tp);
3545573Swnj 		}
3557625Ssam 		splx(s);
3565573Swnj 		break;
3575573Swnj 
3589325Ssam 	/*
3599325Ssam 	 * Simulate typing of a character at the terminal.
3609325Ssam 	 */
3619325Ssam 	case TIOCSTI:
36217183Smckusick 		if (u.u_uid && (flag & FREAD) == 0)
36317183Smckusick 			return (EPERM);
3649325Ssam 		if (u.u_uid && u.u_ttyp != tp)
3659325Ssam 			return (EACCES);
3669578Ssam 		(*linesw[tp->t_line].l_rint)(*(char *)data, tp);
3679325Ssam 		break;
3689325Ssam 
36912752Ssam 	case TIOCSETP:
37012752Ssam 	case TIOCSETN: {
37112752Ssam 		register struct sgttyb *sg = (struct sgttyb *)data;
37212752Ssam 
37312752Ssam 		tp->t_erase = sg->sg_erase;
37412752Ssam 		tp->t_kill = sg->sg_kill;
37512752Ssam 		tp->t_ispeed = sg->sg_ispeed;
37612752Ssam 		tp->t_ospeed = sg->sg_ospeed;
37712752Ssam 		newflags = (tp->t_flags&0xffff0000) | (sg->sg_flags&0xffff);
37817545Skarels 		s = spltty();
37912752Ssam 		if (tp->t_flags&RAW || newflags&RAW || com == TIOCSETP) {
38012752Ssam 			ttywait(tp);
38112752Ssam 			ttyflush(tp, FREAD);
38212752Ssam 		} else if ((tp->t_flags&CBREAK) != (newflags&CBREAK)) {
38312752Ssam 			if (newflags&CBREAK) {
38412752Ssam 				struct clist tq;
38512752Ssam 
38612752Ssam 				catq(&tp->t_rawq, &tp->t_canq);
38712752Ssam 				tq = tp->t_rawq;
38812752Ssam 				tp->t_rawq = tp->t_canq;
38912752Ssam 				tp->t_canq = tq;
39012752Ssam 			} else {
39112752Ssam 				tp->t_flags |= PENDIN;
39213801Ssam 				newflags |= PENDIN;
39312752Ssam 				ttwakeup(tp);
39412752Ssam 			}
39512752Ssam 		}
39612752Ssam 		tp->t_flags = newflags;
39712752Ssam 		if (tp->t_flags&RAW) {
39812752Ssam 			tp->t_state &= ~TS_TTSTOP;
39912752Ssam 			ttstart(tp);
40012752Ssam 		}
40112752Ssam 		splx(s);
40212752Ssam 		break;
40312752Ssam 	}
40412752Ssam 
40512752Ssam 	/* send current parameters to user */
40612752Ssam 	case TIOCGETP: {
40712752Ssam 		register struct sgttyb *sg = (struct sgttyb *)data;
40812752Ssam 
40912752Ssam 		sg->sg_ispeed = tp->t_ispeed;
41012752Ssam 		sg->sg_ospeed = tp->t_ospeed;
41112752Ssam 		sg->sg_erase = tp->t_erase;
41212752Ssam 		sg->sg_kill = tp->t_kill;
41312752Ssam 		sg->sg_flags = tp->t_flags;
41412752Ssam 		break;
41512752Ssam 	}
41612752Ssam 
41712752Ssam 	case FIONBIO:
41812752Ssam 		if (*(int *)data)
41912752Ssam 			tp->t_state |= TS_NBIO;
42012752Ssam 		else
42112752Ssam 			tp->t_state &= ~TS_NBIO;
42212752Ssam 		break;
42312752Ssam 
42412752Ssam 	case FIOASYNC:
42512752Ssam 		if (*(int *)data)
42612752Ssam 			tp->t_state |= TS_ASYNC;
42712752Ssam 		else
42812752Ssam 			tp->t_state &= ~TS_ASYNC;
42912752Ssam 		break;
43012752Ssam 
43113077Ssam 	case TIOCGETC:
43213077Ssam 		bcopy((caddr_t)&tp->t_intrc, data, sizeof (struct tchars));
43313077Ssam 		break;
43413077Ssam 
43513077Ssam 	case TIOCSETC:
43613077Ssam 		bcopy(data, (caddr_t)&tp->t_intrc, sizeof (struct tchars));
43713077Ssam 		break;
43813077Ssam 
43912752Ssam 	/* set/get local special characters */
44012752Ssam 	case TIOCSLTC:
44112752Ssam 		bcopy(data, (caddr_t)&tp->t_suspc, sizeof (struct ltchars));
44212752Ssam 		break;
44312752Ssam 
44412752Ssam 	case TIOCGLTC:
44512752Ssam 		bcopy((caddr_t)&tp->t_suspc, data, sizeof (struct ltchars));
44612752Ssam 		break;
44712752Ssam 
44812752Ssam 	/*
44912752Ssam 	 * Modify local mode word.
45012752Ssam 	 */
45112752Ssam 	case TIOCLBIS:
45212752Ssam 		tp->t_flags |= *(int *)data << 16;
45312752Ssam 		break;
45412752Ssam 
45512752Ssam 	case TIOCLBIC:
45612752Ssam 		tp->t_flags &= ~(*(int *)data << 16);
45712752Ssam 		break;
45812752Ssam 
45912752Ssam 	case TIOCLSET:
46012752Ssam 		tp->t_flags &= 0xffff;
46112752Ssam 		tp->t_flags |= *(int *)data << 16;
46212752Ssam 		break;
46312752Ssam 
46412752Ssam 	case TIOCLGET:
46515720Skarels 		*(int *)data = ((unsigned) tp->t_flags) >> 16;
46612752Ssam 		break;
46712752Ssam 
46817545Skarels 	/*
46917932Skarels 	 * Allow SPGRP only if tty is open for reading.
47017598Sbloom 	 * Quick check: if we can find a process in the new pgrp,
47117598Sbloom 	 * this user must own that process.
47217598Sbloom 	 * SHOULD VERIFY THAT PGRP IS IN USE AND IS THIS USER'S.
47317545Skarels 	 */
47418650Sbloom 	case TIOCSPGRP: {
47517545Skarels 		struct proc *p;
47617545Skarels 		int pgrp = *(int *)data;
47717545Skarels 
47817545Skarels 		if (u.u_uid && (flag & FREAD) == 0)
47917545Skarels 			return (EPERM);
48017598Sbloom 		p = pfind(pgrp);
48117598Sbloom 		if (p && p->p_pgrp == pgrp &&
48217598Sbloom 		    p->p_uid != u.u_uid && u.u_uid && !inferior(p))
48317598Sbloom 			return (EPERM);
48417545Skarels 		tp->t_pgrp = pgrp;
48512752Ssam 		break;
48618650Sbloom 	}
48712752Ssam 
48812752Ssam 	case TIOCGPGRP:
48912752Ssam 		*(int *)data = tp->t_pgrp;
49012752Ssam 		break;
49112752Ssam 
49217598Sbloom 	case TIOCSWINSZ:
49318650Sbloom 		if (bcmp((caddr_t)&tp->t_winsize, data,
49418650Sbloom 		    sizeof (struct winsize))) {
49517598Sbloom 			tp->t_winsize = *(struct winsize *)data;
49617598Sbloom 			gsignal(tp->t_pgrp, SIGWINCH);
49717598Sbloom 		}
49817598Sbloom 		break;
49917598Sbloom 
50017598Sbloom 	case TIOCGWINSZ:
50117598Sbloom 		*(struct winsize *)data = tp->t_winsize;
50217598Sbloom 		break;
50317598Sbloom 
50439Sbill 	default:
5058556Sroot 		return (-1);
50639Sbill 	}
5078556Sroot 	return (0);
50839Sbill }
5094484Swnj 
5104484Swnj ttnread(tp)
5114484Swnj 	struct tty *tp;
5124484Swnj {
5134484Swnj 	int nread = 0;
5144484Swnj 
5159578Ssam 	if (tp->t_flags & PENDIN)
5164484Swnj 		ttypend(tp);
5174484Swnj 	nread = tp->t_canq.c_cc;
5184484Swnj 	if (tp->t_flags & (RAW|CBREAK))
5194484Swnj 		nread += tp->t_rawq.c_cc;
5204484Swnj 	return (nread);
5214484Swnj }
5224484Swnj 
5235408Swnj ttselect(dev, rw)
5244484Swnj 	dev_t dev;
5255408Swnj 	int rw;
5264484Swnj {
5274484Swnj 	register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)];
5284484Swnj 	int nread;
52917545Skarels 	int s = spltty();
5304484Swnj 
5315408Swnj 	switch (rw) {
5324484Swnj 
5334484Swnj 	case FREAD:
5344484Swnj 		nread = ttnread(tp);
53521776Sbloom 		if ((nread > 0) || ((tp->t_state & TS_CARR_ON) == 0))
5365408Swnj 			goto win;
5374938Swnj 		if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait)
5385408Swnj 			tp->t_state |= TS_RCOLL;
5394484Swnj 		else
5404484Swnj 			tp->t_rsel = u.u_procp;
5415408Swnj 		break;
5424484Swnj 
5435408Swnj 	case FWRITE:
5445408Swnj 		if (tp->t_outq.c_cc <= TTLOWAT(tp))
5455408Swnj 			goto win;
5465408Swnj 		if (tp->t_wsel && tp->t_wsel->p_wchan == (caddr_t)&selwait)
5475408Swnj 			tp->t_state |= TS_WCOLL;
5485408Swnj 		else
5495408Swnj 			tp->t_wsel = u.u_procp;
5505408Swnj 		break;
5514484Swnj 	}
5525408Swnj 	splx(s);
5535408Swnj 	return (0);
5545408Swnj win:
5555408Swnj 	splx(s);
5565408Swnj 	return (1);
5574484Swnj }
5587436Skre 
5597502Sroot /*
5609578Ssam  * Establish a process group for distribution of
5617502Sroot  * quits and interrupts from the tty.
5627502Sroot  */
5637502Sroot ttyopen(dev, tp)
5647625Ssam 	dev_t dev;
5657625Ssam 	register struct tty *tp;
5667502Sroot {
5677502Sroot 	register struct proc *pp;
5687502Sroot 
5697502Sroot 	pp = u.u_procp;
5707502Sroot 	tp->t_dev = dev;
5717625Ssam 	if (pp->p_pgrp == 0) {
5727502Sroot 		u.u_ttyp = tp;
5737502Sroot 		u.u_ttyd = dev;
5747502Sroot 		if (tp->t_pgrp == 0)
5757502Sroot 			tp->t_pgrp = pp->p_pid;
5767502Sroot 		pp->p_pgrp = tp->t_pgrp;
5777502Sroot 	}
5787502Sroot 	tp->t_state &= ~TS_WOPEN;
57917545Skarels 	if ((tp->t_state & TS_ISOPEN) == 0) {
58017545Skarels 		tp->t_state |= TS_ISOPEN;
58117598Sbloom 		bzero((caddr_t)&tp->t_winsize, sizeof(tp->t_winsize));
58217545Skarels 		if (tp->t_line != NTTYDISC)
58317545Skarels 			ttywflush(tp);
58417545Skarels 	}
5858556Sroot 	return (0);
5867502Sroot }
5877502Sroot 
5887502Sroot /*
5897502Sroot  * clean tp on last close
5907502Sroot  */
5917502Sroot ttyclose(tp)
5927625Ssam 	register struct tty *tp;
5937502Sroot {
5947502Sroot 
5957502Sroot 	if (tp->t_line) {
59612752Ssam 		ttywflush(tp);
5977502Sroot 		tp->t_line = 0;
5987502Sroot 		return;
5997502Sroot 	}
6007502Sroot 	tp->t_pgrp = 0;
60112752Ssam 	ttywflush(tp);
6027502Sroot 	tp->t_state = 0;
6037502Sroot }
6047502Sroot 
6057502Sroot /*
6067502Sroot  * reinput pending characters after state switch
60717545Skarels  * call at spltty().
6087502Sroot  */
6097502Sroot ttypend(tp)
6107625Ssam 	register struct tty *tp;
6117502Sroot {
6127502Sroot 	struct clist tq;
6137502Sroot 	register c;
6147502Sroot 
6159578Ssam 	tp->t_flags &= ~PENDIN;
6169578Ssam 	tp->t_state |= TS_TYPEN;
6177502Sroot 	tq = tp->t_rawq;
6187502Sroot 	tp->t_rawq.c_cc = 0;
6197502Sroot 	tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0;
6207502Sroot 	while ((c = getc(&tq)) >= 0)
6217502Sroot 		ttyinput(c, tp);
6229578Ssam 	tp->t_state &= ~TS_TYPEN;
6237502Sroot }
6247502Sroot 
6257502Sroot /*
6269578Ssam  * Place a character on raw TTY input queue,
6279578Ssam  * putting in delimiters and waking up top
6289578Ssam  * half as needed.  Also echo if required.
6299578Ssam  * The arguments are the character and the
6309578Ssam  * appropriate tty structure.
6317502Sroot  */
6327502Sroot ttyinput(c, tp)
6337625Ssam 	register c;
6347625Ssam 	register struct tty *tp;
6357502Sroot {
6369578Ssam 	register int t_flags = tp->t_flags;
6377502Sroot 	int i;
6387502Sroot 
6399578Ssam 	/*
6409578Ssam 	 * If input is pending take it first.
6419578Ssam 	 */
6429578Ssam 	if (t_flags&PENDIN)
6437502Sroot 		ttypend(tp);
6447502Sroot 	tk_nin++;
6457502Sroot 	c &= 0377;
6469578Ssam 
6479578Ssam 	/*
6489578Ssam 	 * In tandem mode, check high water mark.
6499578Ssam 	 */
6507502Sroot 	if (t_flags&TANDEM)
6517502Sroot 		ttyblock(tp);
6529578Ssam 
6539578Ssam 	if (t_flags&RAW) {
6549578Ssam 		/*
6559578Ssam 		 * Raw mode, just put character
6569578Ssam 		 * in input q w/o interpretation.
6579578Ssam 		 */
6589578Ssam 		if (tp->t_rawq.c_cc > TTYHOG)
65912752Ssam 			ttyflush(tp, FREAD|FWRITE);
6609578Ssam 		else {
6619578Ssam 			if (putc(c, &tp->t_rawq) >= 0)
6629578Ssam 				ttwakeup(tp);
6639578Ssam 			ttyecho(c, tp);
6647502Sroot 		}
6659578Ssam 		goto endcase;
6669578Ssam 	}
6679578Ssam 
6689578Ssam 	/*
6699578Ssam 	 * Ignore any high bit added during
6709578Ssam 	 * previous ttyinput processing.
6719578Ssam 	 */
6729578Ssam 	if ((tp->t_state&TS_TYPEN) == 0)
6739578Ssam 		c &= 0177;
6749578Ssam 	/*
6759578Ssam 	 * Check for literal nexting very first
6769578Ssam 	 */
6779578Ssam 	if (tp->t_state&TS_LNCH) {
6789578Ssam 		c |= 0200;
6799578Ssam 		tp->t_state &= ~TS_LNCH;
6809578Ssam 	}
6819578Ssam 
6829578Ssam 	/*
6839578Ssam 	 * Scan for special characters.  This code
6849578Ssam 	 * is really just a big case statement with
6859578Ssam 	 * non-constant cases.  The bottom of the
6869578Ssam 	 * case statement is labeled ``endcase'', so goto
6879578Ssam 	 * it after a case match, or similar.
6889578Ssam 	 */
6899578Ssam 	if (tp->t_line == NTTYDISC) {
6909578Ssam 		if (c == tp->t_lnextc) {
69121776Sbloom 			if (t_flags&ECHO)
6927502Sroot 				ttyout("^\b", tp);
6939578Ssam 			tp->t_state |= TS_LNCH;
6949578Ssam 			goto endcase;
6959578Ssam 		}
6969578Ssam 		if (c == tp->t_flushc) {
69721776Sbloom 			if (t_flags&FLUSHO)
6989578Ssam 				tp->t_flags &= ~FLUSHO;
6997502Sroot 			else {
70012752Ssam 				ttyflush(tp, FWRITE);
7017502Sroot 				ttyecho(c, tp);
7029578Ssam 				if (tp->t_rawq.c_cc + tp->t_canq.c_cc)
7037502Sroot 					ttyretype(tp);
7049578Ssam 				tp->t_flags |= FLUSHO;
7057502Sroot 			}
7069578Ssam 			goto startoutput;
7079578Ssam 		}
7089578Ssam 		if (c == tp->t_suspc) {
70921776Sbloom 			if ((t_flags&NOFLSH) == 0)
71012752Ssam 				ttyflush(tp, FREAD);
7119578Ssam 			ttyecho(c, tp);
7129578Ssam 			gsignal(tp->t_pgrp, SIGTSTP);
7139578Ssam 			goto endcase;
7149578Ssam 		}
7159578Ssam 	}
7169578Ssam 
7179578Ssam 	/*
7189578Ssam 	 * Handle start/stop characters.
7199578Ssam 	 */
7209578Ssam 	if (c == tp->t_stopc) {
7219578Ssam 		if ((tp->t_state&TS_TTSTOP) == 0) {
7229578Ssam 			tp->t_state |= TS_TTSTOP;
7239578Ssam 			(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
7247502Sroot 			return;
7259578Ssam 		}
7269578Ssam 		if (c != tp->t_startc)
7279578Ssam 			return;
7289578Ssam 		goto endcase;
7299578Ssam 	}
7309578Ssam 	if (c == tp->t_startc)
7319578Ssam 		goto restartoutput;
7329578Ssam 
7339578Ssam 	/*
7349578Ssam 	 * Look for interrupt/quit chars.
7359578Ssam 	 */
7369578Ssam 	if (c == tp->t_intrc || c == tp->t_quitc) {
73721776Sbloom 		if ((t_flags&NOFLSH) == 0)
73812752Ssam 			ttyflush(tp, FREAD|FWRITE);
7399578Ssam 		ttyecho(c, tp);
7409578Ssam 		gsignal(tp->t_pgrp, c == tp->t_intrc ? SIGINT : SIGQUIT);
7419578Ssam 		goto endcase;
7429578Ssam 	}
7439578Ssam 
744*23165Sbloom 	if (tp->t_flags & LCASE && c <= 0177) {
745*23165Sbloom 		if (tp->t_state&TS_BKSL) {
746*23165Sbloom 			ttyrub(unputc(&tp->t_rawq), tp);
747*23165Sbloom 			if (maptab[c])
748*23165Sbloom 				c = maptab[c];
749*23165Sbloom 			c |= 0200;
750*23165Sbloom 			tp->t_state &= ~(TS_BKSL|TS_QUOT);
751*23165Sbloom 		} else if (c >= 'A' && c <= 'Z')
752*23165Sbloom 			c += 'a' - 'A';
753*23165Sbloom 		else if (c == '\\')
754*23165Sbloom 			tp->t_state |= TS_BKSL;
755*23165Sbloom 	}
756*23165Sbloom 
7579578Ssam 	/*
7589578Ssam 	 * Cbreak mode, don't process line editing
7599578Ssam 	 * characters; check high water mark for wakeup.
7609578Ssam 	 */
7619578Ssam 	if (t_flags&CBREAK) {
7629578Ssam 		if (tp->t_rawq.c_cc > TTYHOG) {
7637502Sroot 			if (tp->t_outq.c_cc < TTHIWAT(tp) &&
7647502Sroot 			    tp->t_line == NTTYDISC)
7657502Sroot 				(void) ttyoutput(CTRL(g), tp);
7667502Sroot 		} else if (putc(c, &tp->t_rawq) >= 0) {
7677502Sroot 			ttwakeup(tp);
7687502Sroot 			ttyecho(c, tp);
7697502Sroot 		}
7709578Ssam 		goto endcase;
7719578Ssam 	}
7729578Ssam 
7739578Ssam 	/*
7749578Ssam 	 * From here on down cooked mode character
7759578Ssam 	 * processing takes place.
7769578Ssam 	 */
7779578Ssam 	if ((tp->t_state&TS_QUOT) &&
7789578Ssam 	    (c == tp->t_erase || c == tp->t_kill)) {
7799578Ssam 		ttyrub(unputc(&tp->t_rawq), tp);
7809578Ssam 		c |= 0200;
7819578Ssam 	}
7829578Ssam 	if (c == tp->t_erase) {
7839578Ssam 		if (tp->t_rawq.c_cc)
7849578Ssam 			ttyrub(unputc(&tp->t_rawq), tp);
7859578Ssam 		goto endcase;
7869578Ssam 	}
7879578Ssam 	if (c == tp->t_kill) {
78821776Sbloom 		if (t_flags&CRTKIL &&
7899578Ssam 		    tp->t_rawq.c_cc == tp->t_rocount) {
7909578Ssam 			while (tp->t_rawq.c_cc)
7919578Ssam 				ttyrub(unputc(&tp->t_rawq), tp);
7929578Ssam 		} else {
7939578Ssam 			ttyecho(c, tp);
7949578Ssam 			ttyecho('\n', tp);
7959578Ssam 			while (getc(&tp->t_rawq) > 0)
7969578Ssam 				;
7979578Ssam 			tp->t_rocount = 0;
7989578Ssam 		}
7999578Ssam 		tp->t_state &= ~TS_LOCAL;
8009578Ssam 		goto endcase;
8019578Ssam 	}
8029578Ssam 
8039578Ssam 	/*
8049578Ssam 	 * New line discipline,
8059578Ssam 	 * check word erase/reprint line.
8069578Ssam 	 */
8079578Ssam 	if (tp->t_line == NTTYDISC) {
8089578Ssam 		if (c == tp->t_werasc) {
8099578Ssam 			if (tp->t_rawq.c_cc == 0)
8109578Ssam 				goto endcase;
8119578Ssam 			do {
8129578Ssam 				c = unputc(&tp->t_rawq);
8139578Ssam 				if (c != ' ' && c != '\t')
8149578Ssam 					goto erasenb;
8159578Ssam 				ttyrub(c, tp);
8169578Ssam 			} while (tp->t_rawq.c_cc);
8179578Ssam 			goto endcase;
8189578Ssam 	erasenb:
8199578Ssam 			do {
8209578Ssam 				ttyrub(c, tp);
8219578Ssam 				if (tp->t_rawq.c_cc == 0)
8229578Ssam 					goto endcase;
8239578Ssam 				c = unputc(&tp->t_rawq);
8249578Ssam 			} while (c != ' ' && c != '\t');
8259578Ssam 			(void) putc(c, &tp->t_rawq);
8269578Ssam 			goto endcase;
8279578Ssam 		}
8289578Ssam 		if (c == tp->t_rprntc) {
8299578Ssam 			ttyretype(tp);
8309578Ssam 			goto endcase;
8319578Ssam 		}
8329578Ssam 	}
8339578Ssam 
8349578Ssam 	/*
8359578Ssam 	 * Check for input buffer overflow
8369578Ssam 	 */
83710391Ssam 	if (tp->t_rawq.c_cc+tp->t_canq.c_cc >= TTYHOG) {
83810391Ssam 		if (tp->t_line == NTTYDISC)
83910391Ssam 			(void) ttyoutput(CTRL(g), tp);
8409578Ssam 		goto endcase;
84110391Ssam 	}
8429578Ssam 
8439578Ssam 	/*
8449578Ssam 	 * Put data char in q for user and
8459578Ssam 	 * wakeup on seeing a line delimiter.
8469578Ssam 	 */
8479578Ssam 	if (putc(c, &tp->t_rawq) >= 0) {
8489578Ssam 		if (ttbreakc(c, tp)) {
8499578Ssam 			tp->t_rocount = 0;
8509578Ssam 			catq(&tp->t_rawq, &tp->t_canq);
8517502Sroot 			ttwakeup(tp);
8529578Ssam 		} else if (tp->t_rocount++ == 0)
8539578Ssam 			tp->t_rocol = tp->t_col;
8549578Ssam 		tp->t_state &= ~TS_QUOT;
8559578Ssam 		if (c == '\\')
8569578Ssam 			tp->t_state |= TS_QUOT;
8579578Ssam 		if (tp->t_state&TS_ERASE) {
8589578Ssam 			tp->t_state &= ~TS_ERASE;
8599578Ssam 			(void) ttyoutput('/', tp);
8609578Ssam 		}
8619578Ssam 		i = tp->t_col;
8627502Sroot 		ttyecho(c, tp);
86321776Sbloom 		if (c == tp->t_eofc && t_flags&ECHO) {
8649578Ssam 			i = MIN(2, tp->t_col - i);
8659578Ssam 			while (i > 0) {
8669578Ssam 				(void) ttyoutput('\b', tp);
8679578Ssam 				i--;
8689578Ssam 			}
8699578Ssam 		}
8707502Sroot 	}
8719578Ssam endcase:
8729578Ssam 	/*
8739578Ssam 	 * If DEC-style start/stop is enabled don't restart
8749578Ssam 	 * output until seeing the start character.
8759578Ssam 	 */
87621776Sbloom 	if (t_flags&DECCTQ && tp->t_state&TS_TTSTOP &&
8779578Ssam 	    tp->t_startc != tp->t_stopc)
8787502Sroot 		return;
8799578Ssam restartoutput:
8807502Sroot 	tp->t_state &= ~TS_TTSTOP;
8819578Ssam 	tp->t_flags &= ~FLUSHO;
8829578Ssam startoutput:
8837502Sroot 	ttstart(tp);
8847502Sroot }
8857502Sroot 
8867502Sroot /*
8879578Ssam  * Put character on TTY output queue, adding delays,
8887502Sroot  * expanding tabs, and handling the CR/NL bit.
8899578Ssam  * This is called both from the top half for output,
8909578Ssam  * and from interrupt level for echoing.
8917502Sroot  * The arguments are the character and the tty structure.
8927502Sroot  * Returns < 0 if putc succeeds, otherwise returns char to resend
8937502Sroot  * Must be recursive.
8947502Sroot  */
8957502Sroot ttyoutput(c, tp)
8967502Sroot 	register c;
8977502Sroot 	register struct tty *tp;
8987502Sroot {
8997502Sroot 	register char *colp;
9007502Sroot 	register ctype;
9017502Sroot 
9029578Ssam 	if (tp->t_flags & (RAW|LITOUT)) {
9039578Ssam 		if (tp->t_flags&FLUSHO)
9047502Sroot 			return (-1);
9057502Sroot 		if (putc(c, &tp->t_outq))
9067625Ssam 			return (c);
9077502Sroot 		tk_nout++;
9087502Sroot 		return (-1);
9097502Sroot 	}
9109578Ssam 
9117502Sroot 	/*
9129578Ssam 	 * Ignore EOT in normal mode to avoid
9139578Ssam 	 * hanging up certain terminals.
9147502Sroot 	 */
9157502Sroot 	c &= 0177;
9169578Ssam 	if (c == CEOT && (tp->t_flags&CBREAK) == 0)
9177502Sroot 		return (-1);
9187502Sroot 	/*
9197502Sroot 	 * Turn tabs to spaces as required
9207502Sroot 	 */
9219578Ssam 	if (c == '\t' && (tp->t_flags&TBDELAY) == XTABS) {
9227502Sroot 		register int s;
9237502Sroot 
9247502Sroot 		c = 8 - (tp->t_col&7);
9259578Ssam 		if ((tp->t_flags&FLUSHO) == 0) {
92617545Skarels 			s = spltty();		/* don't interrupt tabs */
9277502Sroot 			c -= b_to_q("        ", c, &tp->t_outq);
9287502Sroot 			tk_nout += c;
9297502Sroot 			splx(s);
9307502Sroot 		}
9317502Sroot 		tp->t_col += c;
9327502Sroot 		return (c ? -1 : '\t');
9337502Sroot 	}
9347502Sroot 	tk_nout++;
9357502Sroot 	/*
9367502Sroot 	 * for upper-case-only terminals,
9377502Sroot 	 * generate escapes.
9387502Sroot 	 */
9397502Sroot 	if (tp->t_flags&LCASE) {
9407502Sroot 		colp = "({)}!|^~'`";
9417625Ssam 		while (*colp++)
9427625Ssam 			if (c == *colp++) {
9437502Sroot 				if (ttyoutput('\\', tp) >= 0)
9447502Sroot 					return (c);
9457502Sroot 				c = colp[-2];
9467502Sroot 				break;
9477502Sroot 			}
9489578Ssam 		if ('A' <= c && c <= 'Z') {
9497502Sroot 			if (ttyoutput('\\', tp) >= 0)
9507502Sroot 				return (c);
9519578Ssam 		} else if ('a' <= c && c <= 'z')
9527502Sroot 			c += 'A' - 'a';
9537502Sroot 	}
9549578Ssam 
9557502Sroot 	/*
9567502Sroot 	 * turn <nl> to <cr><lf> if desired.
9577502Sroot 	 */
9589578Ssam 	if (c == '\n' && tp->t_flags&CRMOD)
9597502Sroot 		if (ttyoutput('\r', tp) >= 0)
9607502Sroot 			return (c);
9619578Ssam 	if (c == '~' && tp->t_flags&TILDE)
9627502Sroot 		c = '`';
9639578Ssam 	if ((tp->t_flags&FLUSHO) == 0 && putc(c, &tp->t_outq))
9647502Sroot 		return (c);
9657502Sroot 	/*
9667502Sroot 	 * Calculate delays.
9677502Sroot 	 * The numbers here represent clock ticks
9687502Sroot 	 * and are not necessarily optimal for all terminals.
9697502Sroot 	 * The delays are indicated by characters above 0200.
9707502Sroot 	 * In raw mode there are no delays and the
9717502Sroot 	 * transmission path is 8 bits wide.
9729578Ssam 	 *
9739578Ssam 	 * SHOULD JUST ALLOW USER TO SPECIFY DELAYS
9747502Sroot 	 */
9757502Sroot 	colp = &tp->t_col;
9767502Sroot 	ctype = partab[c];
9777502Sroot 	c = 0;
9787502Sroot 	switch (ctype&077) {
9797502Sroot 
9807502Sroot 	case ORDINARY:
9817502Sroot 		(*colp)++;
9827502Sroot 
9837502Sroot 	case CONTROL:
9847502Sroot 		break;
9857502Sroot 
9867502Sroot 	case BACKSPACE:
9877502Sroot 		if (*colp)
9887502Sroot 			(*colp)--;
9897502Sroot 		break;
9907502Sroot 
99113821Ssam 	/*
99213821Ssam 	 * This macro is close enough to the correct thing;
99313821Ssam 	 * it should be replaced by real user settable delays
99413821Ssam 	 * in any event...
99513821Ssam 	 */
99613821Ssam #define	mstohz(ms)	(((ms) * hz) >> 10)
9977502Sroot 	case NEWLINE:
9987502Sroot 		ctype = (tp->t_flags >> 8) & 03;
9997625Ssam 		if (ctype == 1) { /* tty 37 */
100012752Ssam 			if (*colp > 0)
100113863Ssam 				c = max((((unsigned)*colp) >> 4) + 3,
100213863Ssam 				    (unsigned)6);
10039578Ssam 		} else if (ctype == 2) /* vt05 */
100413821Ssam 			c = mstohz(100);
10057502Sroot 		*colp = 0;
10067502Sroot 		break;
10077502Sroot 
10087502Sroot 	case TAB:
10097502Sroot 		ctype = (tp->t_flags >> 10) & 03;
10107625Ssam 		if (ctype == 1) { /* tty 37 */
10117502Sroot 			c = 1 - (*colp | ~07);
10127625Ssam 			if (c < 5)
10137502Sroot 				c = 0;
10147502Sroot 		}
10157502Sroot 		*colp |= 07;
10167502Sroot 		(*colp)++;
10177502Sroot 		break;
10187502Sroot 
10197502Sroot 	case VTAB:
10209578Ssam 		if (tp->t_flags&VTDELAY) /* tty 37 */
10217502Sroot 			c = 0177;
10227502Sroot 		break;
10237502Sroot 
10247502Sroot 	case RETURN:
10257502Sroot 		ctype = (tp->t_flags >> 12) & 03;
10269578Ssam 		if (ctype == 1) /* tn 300 */
102713821Ssam 			c = mstohz(83);
10289578Ssam 		else if (ctype == 2) /* ti 700 */
102913821Ssam 			c = mstohz(166);
10309578Ssam 		else if (ctype == 3) { /* concept 100 */
10317502Sroot 			int i;
10329578Ssam 
10337502Sroot 			if ((i = *colp) >= 0)
10349578Ssam 				for (; i < 9; i++)
10357502Sroot 					(void) putc(0177, &tp->t_outq);
10367502Sroot 		}
10377502Sroot 		*colp = 0;
10387502Sroot 	}
10399578Ssam 	if (c && (tp->t_flags&FLUSHO) == 0)
10407502Sroot 		(void) putc(c|0200, &tp->t_outq);
10417502Sroot 	return (-1);
10427502Sroot }
104313821Ssam #undef mstohz
10447502Sroot 
10457502Sroot /*
10467502Sroot  * Called from device's read routine after it has
10477502Sroot  * calculated the tty-structure given as argument.
10487502Sroot  */
10497722Swnj ttread(tp, uio)
10507625Ssam 	register struct tty *tp;
10517722Swnj 	struct uio *uio;
10527502Sroot {
10537502Sroot 	register struct clist *qp;
10549578Ssam 	register c, t_flags;
10559859Ssam 	int s, first, error = 0;
10567502Sroot 
10577502Sroot loop:
10589578Ssam 	/*
10599578Ssam 	 * Take any pending input first.
10609578Ssam 	 */
106117545Skarels 	s = spltty();
10629578Ssam 	if (tp->t_flags&PENDIN)
10637502Sroot 		ttypend(tp);
10649859Ssam 	splx(s);
10659578Ssam 
1066*23165Sbloom 	if ((tp->t_state&TS_CARR_ON)==0)
1067*23165Sbloom 		return (EIO);
1068*23165Sbloom 
10699578Ssam 	/*
10709578Ssam 	 * Hang process if it's in the background.
10719578Ssam 	 */
107215141Skarels #define bit(a) (1<<(a-1))
1073*23165Sbloom 	if (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) {
107415141Skarels 		if ((u.u_procp->p_sigignore & bit(SIGTTIN)) ||
107515141Skarels 		   (u.u_procp->p_sigmask & bit(SIGTTIN)) ||
10767502Sroot 		    u.u_procp->p_flag&SVFORK)
10778520Sroot 			return (EIO);
10787502Sroot 		gsignal(u.u_procp->p_pgrp, SIGTTIN);
10797502Sroot 		sleep((caddr_t)&lbolt, TTIPRI);
1080*23165Sbloom 		goto loop;
10817502Sroot 	}
10829578Ssam 	t_flags = tp->t_flags;
108315141Skarels #undef	bit
10849578Ssam 
10859578Ssam 	/*
10869578Ssam 	 * In raw mode take characters directly from the
10879578Ssam 	 * raw queue w/o processing.  Interlock against
10889578Ssam 	 * device interrupts when interrogating rawq.
10899578Ssam 	 */
10909578Ssam 	if (t_flags&RAW) {
109117545Skarels 		s = spltty();
10927502Sroot 		if (tp->t_rawq.c_cc <= 0) {
10939578Ssam 			if ((tp->t_state&TS_CARR_ON) == 0 ||
10947502Sroot 			    (tp->t_state&TS_NBIO)) {
10959859Ssam 				splx(s);
109615094Skarels 				return (EWOULDBLOCK);
10977502Sroot 			}
10987502Sroot 			sleep((caddr_t)&tp->t_rawq, TTIPRI);
10999859Ssam 			splx(s);
11007502Sroot 			goto loop;
11017502Sroot 		}
11029859Ssam 		splx(s);
110314938Smckusick  		while (!error && tp->t_rawq.c_cc && uio->uio_resid)
110414938Smckusick  			error = ureadc(getc(&tp->t_rawq), uio);
11059859Ssam 		goto checktandem;
11069578Ssam 	}
11079578Ssam 
11089578Ssam 	/*
11099578Ssam 	 * In cbreak mode use the rawq, otherwise
11109578Ssam 	 * take characters from the canonicalized q.
11119578Ssam 	 */
11129578Ssam 	qp = t_flags&CBREAK ? &tp->t_rawq : &tp->t_canq;
11139578Ssam 
11149578Ssam 	/*
11159578Ssam 	 * No input, sleep on rawq awaiting hardware
11169578Ssam 	 * receipt and notification.
11179578Ssam 	 */
111817545Skarels 	s = spltty();
11199578Ssam 	if (qp->c_cc <= 0) {
11209578Ssam 		if ((tp->t_state&TS_CARR_ON) == 0 ||
11219578Ssam 		    (tp->t_state&TS_NBIO)) {
11229859Ssam 			splx(s);
11239578Ssam 			return (EWOULDBLOCK);
11247502Sroot 		}
11259578Ssam 		sleep((caddr_t)&tp->t_rawq, TTIPRI);
11269859Ssam 		splx(s);
11279578Ssam 		goto loop;
11289578Ssam 	}
11299859Ssam 	splx(s);
11309578Ssam 
11319578Ssam 	/*
11329578Ssam 	 * Input present, perform input mapping
11339578Ssam 	 * and processing (we're not in raw mode).
11349578Ssam 	 */
11359578Ssam 	first = 1;
11369578Ssam 	while ((c = getc(qp)) >= 0) {
11379578Ssam 		if (t_flags&CRMOD && c == '\r')
11389578Ssam 			c = '\n';
11399578Ssam 		/*
11409578Ssam 		 * Check for delayed suspend character.
11419578Ssam 		 */
11429578Ssam 		if (tp->t_line == NTTYDISC && c == tp->t_dsuspc) {
11439578Ssam 			gsignal(tp->t_pgrp, SIGTSTP);
11449578Ssam 			if (first) {
11459578Ssam 				sleep((caddr_t)&lbolt, TTIPRI);
11469578Ssam 				goto loop;
11479578Ssam 			}
11489578Ssam 			break;
11497502Sroot 		}
11509578Ssam 		/*
11519578Ssam 		 * Interpret EOF only in cooked mode.
11529578Ssam 		 */
11539578Ssam 		if (c == tp->t_eofc && (t_flags&CBREAK) == 0)
11549578Ssam 			break;
11559578Ssam 		/*
11569578Ssam 		 * Give user character.
11579578Ssam 		 */
115814938Smckusick  		error = ureadc(c & 0177, uio);
11599578Ssam 		if (error)
11609578Ssam 			break;
116114938Smckusick  		if (uio->uio_resid == 0)
11629578Ssam 			break;
11639578Ssam 		/*
11649578Ssam 		 * In cooked mode check for a "break character"
11659578Ssam 		 * marking the end of a "line of input".
11669578Ssam 		 */
11679578Ssam 		if ((t_flags&CBREAK) == 0 && ttbreakc(c, tp))
11689578Ssam 			break;
11699578Ssam 		first = 0;
11707502Sroot 	}
11719578Ssam 
11729859Ssam checktandem:
11739578Ssam 	/*
11749578Ssam 	 * Look to unblock output now that (presumably)
11759578Ssam 	 * the input queue has gone down.
11769578Ssam 	 */
11779859Ssam 	if (tp->t_state&TS_TBLOCK && tp->t_rawq.c_cc < TTYHOG/5)
11789578Ssam 		if (putc(tp->t_startc, &tp->t_outq) == 0) {
11797502Sroot 			tp->t_state &= ~TS_TBLOCK;
11807502Sroot 			ttstart(tp);
11817502Sroot 		}
11828520Sroot 	return (error);
11837502Sroot }
11847502Sroot 
11857502Sroot /*
11867502Sroot  * Called from the device's write routine after it has
11877502Sroot  * calculated the tty-structure given as argument.
11887502Sroot  */
11897822Sroot ttwrite(tp, uio)
11907625Ssam 	register struct tty *tp;
11919578Ssam 	register struct uio *uio;
11927502Sroot {
11937502Sroot 	register char *cp;
11949578Ssam 	register int cc, ce, c;
11959578Ssam 	int i, hiwat, cnt, error, s;
11967502Sroot 	char obuf[OBUFSIZ];
11977502Sroot 
11989578Ssam 	hiwat = TTHIWAT(tp);
11999578Ssam 	cnt = uio->uio_resid;
12009578Ssam 	error = 0;
12017502Sroot loop:
120221776Sbloom 	if ((tp->t_state&TS_CARR_ON) == 0)
120321776Sbloom 		return (EIO);
12049578Ssam 	/*
12059578Ssam 	 * Hang the process if it's in the background.
12069578Ssam 	 */
120715141Skarels #define bit(a) (1<<(a-1))
120821776Sbloom 	if (u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp &&
12099578Ssam 	    (tp->t_flags&TOSTOP) && (u.u_procp->p_flag&SVFORK)==0 &&
121015141Skarels 	    !(u.u_procp->p_sigignore & bit(SIGTTOU)) &&
121121776Sbloom 	    !(u.u_procp->p_sigmask & bit(SIGTTOU))) {
12127502Sroot 		gsignal(u.u_procp->p_pgrp, SIGTTOU);
12137502Sroot 		sleep((caddr_t)&lbolt, TTIPRI);
121421776Sbloom 		goto loop;
12157502Sroot 	}
121615141Skarels #undef	bit
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