xref: /csrg-svn/sys/kern/tty.c (revision 30534)
123387Smckusick /*
229107Smckusick  * Copyright (c) 1982, 1986 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*30534Skarels  *	@(#)tty.c	7.4 (Berkeley) 02/19/87
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"
2229946Skarels #include "dkstat.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 
111*30534Skarels extern struct tty *constty;		/* temporary virtual console */
112*30534Skarels 
11339Sbill ttychars(tp)
1149578Ssam 	struct tty *tp;
11539Sbill {
116174Sbill 
1179578Ssam 	tp->t_chars = ttydefaults;
11839Sbill }
11939Sbill 
12039Sbill /*
121903Sbill  * Wait for output to drain, then flush input waiting.
12239Sbill  */
12312752Ssam ttywflush(tp)
1245408Swnj 	register struct tty *tp;
12539Sbill {
12639Sbill 
12712752Ssam 	ttywait(tp);
12812752Ssam 	ttyflush(tp, FREAD);
12912752Ssam }
13012752Ssam 
13112752Ssam ttywait(tp)
13212752Ssam 	register struct tty *tp;
13312752Ssam {
13417545Skarels 	register int s = spltty();
13512752Ssam 
13613809Ssam 	while ((tp->t_outq.c_cc || tp->t_state&TS_BUSY) &&
13725391Skarels 	    tp->t_state&TS_CARR_ON) {
138903Sbill 		(*tp->t_oproc)(tp);
1395408Swnj 		tp->t_state |= TS_ASLEEP;
140903Sbill 		sleep((caddr_t)&tp->t_outq, TTOPRI);
141903Sbill 	}
1429859Ssam 	splx(s);
14339Sbill }
14439Sbill 
14539Sbill /*
1469578Ssam  * Flush all TTY queues
14739Sbill  */
14812752Ssam ttyflush(tp, rw)
1497625Ssam 	register struct tty *tp;
15039Sbill {
151903Sbill 	register s;
152903Sbill 
15317545Skarels 	s = spltty();
154903Sbill 	if (rw & FREAD) {
155903Sbill 		while (getc(&tp->t_canq) >= 0)
156903Sbill 			;
157903Sbill 		wakeup((caddr_t)&tp->t_rawq);
158903Sbill 	}
159903Sbill 	if (rw & FWRITE) {
160903Sbill 		wakeup((caddr_t)&tp->t_outq);
1615408Swnj 		tp->t_state &= ~TS_TTSTOP;
1625426Swnj 		(*cdevsw[major(tp->t_dev)].d_stop)(tp, rw);
163903Sbill 		while (getc(&tp->t_outq) >= 0)
164903Sbill 			;
165903Sbill 	}
166903Sbill 	if (rw & FREAD) {
167903Sbill 		while (getc(&tp->t_rawq) >= 0)
168903Sbill 			;
1699578Ssam 		tp->t_rocount = 0;
170903Sbill 		tp->t_rocol = 0;
1719578Ssam 		tp->t_state &= ~TS_LOCAL;
172903Sbill 	}
173903Sbill 	splx(s);
17439Sbill }
17539Sbill 
176903Sbill /*
177903Sbill  * Send stop character on input overflow.
178903Sbill  */
179903Sbill ttyblock(tp)
1807625Ssam 	register struct tty *tp;
18139Sbill {
182903Sbill 	register x;
1839578Ssam 
184903Sbill 	x = tp->t_rawq.c_cc + tp->t_canq.c_cc;
185903Sbill 	if (tp->t_rawq.c_cc > TTYHOG) {
18612752Ssam 		ttyflush(tp, FREAD|FWRITE);
1875408Swnj 		tp->t_state &= ~TS_TBLOCK;
188903Sbill 	}
18915118Skarels 	/*
19015118Skarels 	 * Block further input iff:
19115118Skarels 	 * Current input > threshold AND input is available to user program
19215118Skarels 	 */
19316055Skarels 	if (x >= TTYHOG/2 &&
19416055Skarels 	    ((tp->t_flags & (RAW|CBREAK)) || (tp->t_canq.c_cc > 0))) {
19515118Skarels 		if (putc(tp->t_stopc, &tp->t_outq)==0) {
19615118Skarels 			tp->t_state |= TS_TBLOCK;
19715118Skarels 			ttstart(tp);
19815118Skarels 		}
199903Sbill 	}
20039Sbill }
20139Sbill 
20239Sbill /*
203903Sbill  * Restart typewriter output following a delay
204903Sbill  * timeout.
205903Sbill  * The name of the routine is passed to the timeout
206903Sbill  * subroutine and it is called during a clock interrupt.
207121Sbill  */
208903Sbill ttrstrt(tp)
2097625Ssam 	register struct tty *tp;
210121Sbill {
211121Sbill 
2129578Ssam 	if (tp == 0)
2139578Ssam 		panic("ttrstrt");
2145408Swnj 	tp->t_state &= ~TS_TIMEOUT;
215903Sbill 	ttstart(tp);
216121Sbill }
217121Sbill 
218121Sbill /*
219903Sbill  * Start output on the typewriter. It is used from the top half
220903Sbill  * after some characters have been put on the output queue,
221903Sbill  * from the interrupt routine to transmit the next
222903Sbill  * character, and after a timeout has finished.
22339Sbill  */
224903Sbill ttstart(tp)
2257625Ssam 	register struct tty *tp;
22639Sbill {
227903Sbill 	register s;
22839Sbill 
22917545Skarels 	s = spltty();
2309578Ssam 	if ((tp->t_state & (TS_TIMEOUT|TS_TTSTOP|TS_BUSY)) == 0 &&
2315622Swnj 	    tp->t_oproc)		/* kludge for pty */
232903Sbill 		(*tp->t_oproc)(tp);
233903Sbill 	splx(s);
23439Sbill }
23539Sbill 
23639Sbill /*
237903Sbill  * Common code for tty ioctls.
23839Sbill  */
2391780Sbill /*ARGSUSED*/
2407625Ssam ttioctl(tp, com, data, flag)
2417625Ssam 	register struct tty *tp;
2427625Ssam 	caddr_t data;
24339Sbill {
2448520Sroot 	int dev = tp->t_dev;
24539Sbill 	extern int nldisp;
2468556Sroot 	int s;
24712752Ssam 	register int newflags;
24839Sbill 
249*30534Skarels 
250903Sbill 	/*
251903Sbill 	 * If the ioctl involves modification,
25217545Skarels 	 * hang if in the background.
253903Sbill 	 */
2547625Ssam 	switch (com) {
25539Sbill 
256915Sbill 	case TIOCSETD:
257915Sbill 	case TIOCSETP:
258915Sbill 	case TIOCSETN:
259903Sbill 	case TIOCFLUSH:
260903Sbill 	case TIOCSETC:
261903Sbill 	case TIOCSLTC:
262903Sbill 	case TIOCSPGRP:
263903Sbill 	case TIOCLBIS:
264903Sbill 	case TIOCLBIC:
265903Sbill 	case TIOCLSET:
2669325Ssam 	case TIOCSTI:
26717598Sbloom 	case TIOCSWINSZ:
268903Sbill 		while (tp->t_line == NTTYDISC &&
269903Sbill 		   u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp &&
270903Sbill 		   (u.u_procp->p_flag&SVFORK) == 0 &&
27124392Skarels 		   !(u.u_procp->p_sigignore & sigmask(SIGTTOU)) &&
27224392Skarels 		   !(u.u_procp->p_sigmask & sigmask(SIGTTOU))) {
273903Sbill 			gsignal(u.u_procp->p_pgrp, SIGTTOU);
274903Sbill 			sleep((caddr_t)&lbolt, TTOPRI);
275903Sbill 		}
276903Sbill 		break;
277903Sbill 	}
278903Sbill 
2799578Ssam 	/*
2809578Ssam 	 * Process the ioctl.
2819578Ssam 	 */
2827625Ssam 	switch (com) {
283903Sbill 
2848556Sroot 	/* get discipline number */
28539Sbill 	case TIOCGETD:
2867625Ssam 		*(int *)data = tp->t_line;
28739Sbill 		break;
28839Sbill 
2898556Sroot 	/* set line discipline */
2907625Ssam 	case TIOCSETD: {
2917625Ssam 		register int t = *(int *)data;
2929578Ssam 		int error = 0;
2937625Ssam 
29415078Skarels 		if ((unsigned) t >= nldisp)
29510851Ssam 			return (ENXIO);
29625584Skarels 		if (t != tp->t_line) {
29725584Skarels 			s = spltty();
29825584Skarels 			(*linesw[tp->t_line].l_close)(tp);
29925584Skarels 			error = (*linesw[t].l_open)(dev, tp);
30025584Skarels 			if (error) {
30125584Skarels 				(void) (*linesw[tp->t_line].l_open)(dev, tp);
30225584Skarels 				splx(s);
30325584Skarels 				return (error);
30425584Skarels 			}
30525584Skarels 			tp->t_line = t;
30610851Ssam 			splx(s);
30710851Ssam 		}
30839Sbill 		break;
3097625Ssam 	}
31039Sbill 
3118556Sroot 	/* prevent more opens on channel */
3125614Swnj 	case TIOCEXCL:
3135614Swnj 		tp->t_state |= TS_XCLUDE;
3145614Swnj 		break;
3155614Swnj 
3165614Swnj 	case TIOCNXCL:
3175614Swnj 		tp->t_state &= ~TS_XCLUDE;
3185614Swnj 		break;
3195614Swnj 
3208556Sroot 	/* hang up line on last close */
32139Sbill 	case TIOCHPCL:
3225408Swnj 		tp->t_state |= TS_HUPCLS;
32339Sbill 		break;
32439Sbill 
3253942Sbugs 	case TIOCFLUSH: {
3267625Ssam 		register int flags = *(int *)data;
3277625Ssam 
3287625Ssam 		if (flags == 0)
3293942Sbugs 			flags = FREAD|FWRITE;
3307625Ssam 		else
3317625Ssam 			flags &= FREAD|FWRITE;
33212752Ssam 		ttyflush(tp, flags);
33339Sbill 		break;
3343944Sbugs 	}
33539Sbill 
3368556Sroot 	/* return number of characters immediately available */
3377625Ssam 	case FIONREAD:
3387625Ssam 		*(off_t *)data = ttnread(tp);
339174Sbill 		break;
340174Sbill 
34113077Ssam 	case TIOCOUTQ:
34213077Ssam 		*(int *)data = tp->t_outq.c_cc;
34313077Ssam 		break;
34413077Ssam 
3458589Sroot 	case TIOCSTOP:
34617545Skarels 		s = spltty();
3479578Ssam 		if ((tp->t_state&TS_TTSTOP) == 0) {
3485573Swnj 			tp->t_state |= TS_TTSTOP;
3495573Swnj 			(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
3505573Swnj 		}
3517625Ssam 		splx(s);
3525573Swnj 		break;
3535573Swnj 
3548589Sroot 	case TIOCSTART:
35517545Skarels 		s = spltty();
3569578Ssam 		if ((tp->t_state&TS_TTSTOP) || (tp->t_flags&FLUSHO)) {
3575573Swnj 			tp->t_state &= ~TS_TTSTOP;
3589578Ssam 			tp->t_flags &= ~FLUSHO;
3595573Swnj 			ttstart(tp);
3605573Swnj 		}
3617625Ssam 		splx(s);
3625573Swnj 		break;
3635573Swnj 
3649325Ssam 	/*
3659325Ssam 	 * Simulate typing of a character at the terminal.
3669325Ssam 	 */
3679325Ssam 	case TIOCSTI:
36817183Smckusick 		if (u.u_uid && (flag & FREAD) == 0)
36917183Smckusick 			return (EPERM);
3709325Ssam 		if (u.u_uid && u.u_ttyp != tp)
3719325Ssam 			return (EACCES);
3729578Ssam 		(*linesw[tp->t_line].l_rint)(*(char *)data, tp);
3739325Ssam 		break;
3749325Ssam 
37512752Ssam 	case TIOCSETP:
37612752Ssam 	case TIOCSETN: {
37712752Ssam 		register struct sgttyb *sg = (struct sgttyb *)data;
37812752Ssam 
37912752Ssam 		tp->t_erase = sg->sg_erase;
38012752Ssam 		tp->t_kill = sg->sg_kill;
38112752Ssam 		tp->t_ispeed = sg->sg_ispeed;
38212752Ssam 		tp->t_ospeed = sg->sg_ospeed;
38312752Ssam 		newflags = (tp->t_flags&0xffff0000) | (sg->sg_flags&0xffff);
38417545Skarels 		s = spltty();
38512752Ssam 		if (tp->t_flags&RAW || newflags&RAW || com == TIOCSETP) {
38612752Ssam 			ttywait(tp);
38712752Ssam 			ttyflush(tp, FREAD);
38812752Ssam 		} else if ((tp->t_flags&CBREAK) != (newflags&CBREAK)) {
38912752Ssam 			if (newflags&CBREAK) {
39012752Ssam 				struct clist tq;
39112752Ssam 
39212752Ssam 				catq(&tp->t_rawq, &tp->t_canq);
39312752Ssam 				tq = tp->t_rawq;
39412752Ssam 				tp->t_rawq = tp->t_canq;
39512752Ssam 				tp->t_canq = tq;
39612752Ssam 			} else {
39712752Ssam 				tp->t_flags |= PENDIN;
39813801Ssam 				newflags |= PENDIN;
39912752Ssam 				ttwakeup(tp);
40012752Ssam 			}
40112752Ssam 		}
40212752Ssam 		tp->t_flags = newflags;
40312752Ssam 		if (tp->t_flags&RAW) {
40412752Ssam 			tp->t_state &= ~TS_TTSTOP;
40512752Ssam 			ttstart(tp);
40612752Ssam 		}
40712752Ssam 		splx(s);
40812752Ssam 		break;
40912752Ssam 	}
41012752Ssam 
41112752Ssam 	/* send current parameters to user */
41212752Ssam 	case TIOCGETP: {
41312752Ssam 		register struct sgttyb *sg = (struct sgttyb *)data;
41412752Ssam 
41512752Ssam 		sg->sg_ispeed = tp->t_ispeed;
41612752Ssam 		sg->sg_ospeed = tp->t_ospeed;
41712752Ssam 		sg->sg_erase = tp->t_erase;
41812752Ssam 		sg->sg_kill = tp->t_kill;
41912752Ssam 		sg->sg_flags = tp->t_flags;
42012752Ssam 		break;
42112752Ssam 	}
42212752Ssam 
42312752Ssam 	case FIONBIO:
42412752Ssam 		if (*(int *)data)
42512752Ssam 			tp->t_state |= TS_NBIO;
42612752Ssam 		else
42712752Ssam 			tp->t_state &= ~TS_NBIO;
42812752Ssam 		break;
42912752Ssam 
43012752Ssam 	case FIOASYNC:
43112752Ssam 		if (*(int *)data)
43212752Ssam 			tp->t_state |= TS_ASYNC;
43312752Ssam 		else
43412752Ssam 			tp->t_state &= ~TS_ASYNC;
43512752Ssam 		break;
43612752Ssam 
43713077Ssam 	case TIOCGETC:
43813077Ssam 		bcopy((caddr_t)&tp->t_intrc, data, sizeof (struct tchars));
43913077Ssam 		break;
44013077Ssam 
44113077Ssam 	case TIOCSETC:
44213077Ssam 		bcopy(data, (caddr_t)&tp->t_intrc, sizeof (struct tchars));
44313077Ssam 		break;
44413077Ssam 
44512752Ssam 	/* set/get local special characters */
44612752Ssam 	case TIOCSLTC:
44712752Ssam 		bcopy(data, (caddr_t)&tp->t_suspc, sizeof (struct ltchars));
44812752Ssam 		break;
44912752Ssam 
45012752Ssam 	case TIOCGLTC:
45112752Ssam 		bcopy((caddr_t)&tp->t_suspc, data, sizeof (struct ltchars));
45212752Ssam 		break;
45312752Ssam 
45412752Ssam 	/*
45512752Ssam 	 * Modify local mode word.
45612752Ssam 	 */
45712752Ssam 	case TIOCLBIS:
45812752Ssam 		tp->t_flags |= *(int *)data << 16;
45912752Ssam 		break;
46012752Ssam 
46112752Ssam 	case TIOCLBIC:
46212752Ssam 		tp->t_flags &= ~(*(int *)data << 16);
46312752Ssam 		break;
46412752Ssam 
46512752Ssam 	case TIOCLSET:
46612752Ssam 		tp->t_flags &= 0xffff;
46712752Ssam 		tp->t_flags |= *(int *)data << 16;
46812752Ssam 		break;
46912752Ssam 
47012752Ssam 	case TIOCLGET:
47129946Skarels 		*(int *)data = ((unsigned)tp->t_flags) >> 16;
47212752Ssam 		break;
47312752Ssam 
47417545Skarels 	/*
47517932Skarels 	 * Allow SPGRP only if tty is open for reading.
47617598Sbloom 	 * Quick check: if we can find a process in the new pgrp,
47717598Sbloom 	 * this user must own that process.
47817598Sbloom 	 * SHOULD VERIFY THAT PGRP IS IN USE AND IS THIS USER'S.
47917545Skarels 	 */
48018650Sbloom 	case TIOCSPGRP: {
48117545Skarels 		struct proc *p;
48217545Skarels 		int pgrp = *(int *)data;
48317545Skarels 
48417545Skarels 		if (u.u_uid && (flag & FREAD) == 0)
48517545Skarels 			return (EPERM);
48617598Sbloom 		p = pfind(pgrp);
48717598Sbloom 		if (p && p->p_pgrp == pgrp &&
48817598Sbloom 		    p->p_uid != u.u_uid && u.u_uid && !inferior(p))
48917598Sbloom 			return (EPERM);
49017545Skarels 		tp->t_pgrp = pgrp;
49112752Ssam 		break;
49218650Sbloom 	}
49312752Ssam 
49412752Ssam 	case TIOCGPGRP:
49512752Ssam 		*(int *)data = tp->t_pgrp;
49612752Ssam 		break;
49712752Ssam 
49817598Sbloom 	case TIOCSWINSZ:
49918650Sbloom 		if (bcmp((caddr_t)&tp->t_winsize, data,
50018650Sbloom 		    sizeof (struct winsize))) {
50117598Sbloom 			tp->t_winsize = *(struct winsize *)data;
50217598Sbloom 			gsignal(tp->t_pgrp, SIGWINCH);
50317598Sbloom 		}
50417598Sbloom 		break;
50517598Sbloom 
50617598Sbloom 	case TIOCGWINSZ:
50717598Sbloom 		*(struct winsize *)data = tp->t_winsize;
50817598Sbloom 		break;
50917598Sbloom 
510*30534Skarels 	case TIOCCONS:
511*30534Skarels 		if (*(int *)data) {
512*30534Skarels 			if (constty != NULL)
513*30534Skarels 				return (EBUSY);
514*30534Skarels #ifndef	UCONSOLE
515*30534Skarels 			if (!suser())
516*30534Skarels 				return (EPERM);
517*30534Skarels #endif
518*30534Skarels 			constty = tp;
519*30534Skarels 		} else if (tp == constty)
520*30534Skarels 			constty == NULL;
521*30534Skarels 		break;
522*30534Skarels 
52339Sbill 	default:
5248556Sroot 		return (-1);
52539Sbill 	}
5268556Sroot 	return (0);
52739Sbill }
5284484Swnj 
5294484Swnj ttnread(tp)
5304484Swnj 	struct tty *tp;
5314484Swnj {
5324484Swnj 	int nread = 0;
5334484Swnj 
5349578Ssam 	if (tp->t_flags & PENDIN)
5354484Swnj 		ttypend(tp);
5364484Swnj 	nread = tp->t_canq.c_cc;
5374484Swnj 	if (tp->t_flags & (RAW|CBREAK))
5384484Swnj 		nread += tp->t_rawq.c_cc;
5394484Swnj 	return (nread);
5404484Swnj }
5414484Swnj 
5425408Swnj ttselect(dev, rw)
5434484Swnj 	dev_t dev;
5445408Swnj 	int rw;
5454484Swnj {
5464484Swnj 	register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)];
5474484Swnj 	int nread;
54817545Skarels 	int s = spltty();
5494484Swnj 
5505408Swnj 	switch (rw) {
5514484Swnj 
5524484Swnj 	case FREAD:
5534484Swnj 		nread = ttnread(tp);
55429946Skarels 		if (nread > 0 || (tp->t_state & TS_CARR_ON) == 0)
5555408Swnj 			goto win;
5564938Swnj 		if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait)
5575408Swnj 			tp->t_state |= TS_RCOLL;
5584484Swnj 		else
5594484Swnj 			tp->t_rsel = u.u_procp;
5605408Swnj 		break;
5614484Swnj 
5625408Swnj 	case FWRITE:
5635408Swnj 		if (tp->t_outq.c_cc <= TTLOWAT(tp))
5645408Swnj 			goto win;
5655408Swnj 		if (tp->t_wsel && tp->t_wsel->p_wchan == (caddr_t)&selwait)
5665408Swnj 			tp->t_state |= TS_WCOLL;
5675408Swnj 		else
5685408Swnj 			tp->t_wsel = u.u_procp;
5695408Swnj 		break;
5704484Swnj 	}
5715408Swnj 	splx(s);
5725408Swnj 	return (0);
5735408Swnj win:
5745408Swnj 	splx(s);
5755408Swnj 	return (1);
5764484Swnj }
5777436Skre 
5787502Sroot /*
57925391Skarels  * Initial open of tty, or (re)entry to line discipline.
5809578Ssam  * Establish a process group for distribution of
5817502Sroot  * quits and interrupts from the tty.
5827502Sroot  */
5837502Sroot ttyopen(dev, tp)
5847625Ssam 	dev_t dev;
5857625Ssam 	register struct tty *tp;
5867502Sroot {
5877502Sroot 	register struct proc *pp;
5887502Sroot 
5897502Sroot 	pp = u.u_procp;
5907502Sroot 	tp->t_dev = dev;
5917625Ssam 	if (pp->p_pgrp == 0) {
5927502Sroot 		u.u_ttyp = tp;
5937502Sroot 		u.u_ttyd = dev;
5947502Sroot 		if (tp->t_pgrp == 0)
5957502Sroot 			tp->t_pgrp = pp->p_pid;
5967502Sroot 		pp->p_pgrp = tp->t_pgrp;
5977502Sroot 	}
5987502Sroot 	tp->t_state &= ~TS_WOPEN;
59917545Skarels 	if ((tp->t_state & TS_ISOPEN) == 0) {
60017545Skarels 		tp->t_state |= TS_ISOPEN;
60117598Sbloom 		bzero((caddr_t)&tp->t_winsize, sizeof(tp->t_winsize));
60217545Skarels 		if (tp->t_line != NTTYDISC)
60317545Skarels 			ttywflush(tp);
60417545Skarels 	}
6058556Sroot 	return (0);
6067502Sroot }
6077502Sroot 
6087502Sroot /*
60925391Skarels  * "close" a line discipline
61025391Skarels  */
61125391Skarels ttylclose(tp)
61225391Skarels 	register struct tty *tp;
61325391Skarels {
61425391Skarels 
61525391Skarels 	ttywflush(tp);
61625391Skarels 	tp->t_line = 0;
61725391Skarels }
61825391Skarels 
61925391Skarels /*
6207502Sroot  * clean tp on last close
6217502Sroot  */
6227502Sroot ttyclose(tp)
6237625Ssam 	register struct tty *tp;
6247502Sroot {
6257502Sroot 
626*30534Skarels 	if (constty == tp)
627*30534Skarels 		constty = NULL;
62825391Skarels 	ttyflush(tp, FREAD|FWRITE);
6297502Sroot 	tp->t_pgrp = 0;
6307502Sroot 	tp->t_state = 0;
6317502Sroot }
6327502Sroot 
6337502Sroot /*
63425391Skarels  * Handle modem control transition on a tty.
63525391Skarels  * Flag indicates new state of carrier.
63625391Skarels  * Returns 0 if the line should be turned off, otherwise 1.
63725391Skarels  */
63825391Skarels ttymodem(tp, flag)
63925391Skarels 	register struct tty *tp;
64025391Skarels {
64125391Skarels 
64225391Skarels 	if ((tp->t_state&TS_WOPEN) == 0 && (tp->t_flags & MDMBUF)) {
64325391Skarels 		/*
64425391Skarels 		 * MDMBUF: do flow control according to carrier flag
64525391Skarels 		 */
64625391Skarels 		if (flag) {
64725391Skarels 			tp->t_state &= ~TS_TTSTOP;
64825391Skarels 			ttstart(tp);
64925391Skarels 		} else if ((tp->t_state&TS_TTSTOP) == 0) {
65025391Skarels 			tp->t_state |= TS_TTSTOP;
65125391Skarels 			(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
65225391Skarels 		}
65325391Skarels 	} else if (flag == 0) {
65425391Skarels 		/*
65525391Skarels 		 * Lost carrier.
65625391Skarels 		 */
65725391Skarels 		tp->t_state &= ~TS_CARR_ON;
65825391Skarels 		if (tp->t_state & TS_ISOPEN) {
65925391Skarels 			if ((tp->t_flags & NOHANG) == 0) {
66025391Skarels 				gsignal(tp->t_pgrp, SIGHUP);
66125391Skarels 				gsignal(tp->t_pgrp, SIGCONT);
66225391Skarels 				ttyflush(tp, FREAD|FWRITE);
66325391Skarels 				return (0);
66425391Skarels 			}
66525391Skarels 		}
66625391Skarels 	} else {
66725391Skarels 		/*
66825391Skarels 		 * Carrier now on.
66925391Skarels 		 */
67025391Skarels 		tp->t_state |= TS_CARR_ON;
67125391Skarels 		wakeup((caddr_t)&tp->t_rawq);
67225391Skarels 	}
67325391Skarels 	return (1);
67425391Skarels }
67525391Skarels 
67625391Skarels /*
67725404Skarels  * Default modem control routine (for other line disciplines).
67825404Skarels  * Return argument flag, to turn off device on carrier drop.
67925404Skarels  */
68025415Skarels nullmodem(tp, flag)
68125415Skarels 	register struct tty *tp;
68225404Skarels 	int flag;
68325404Skarels {
68425404Skarels 
68525404Skarels 	if (flag)
68625404Skarels 		tp->t_state |= TS_CARR_ON;
68725404Skarels 	else
68825404Skarels 		tp->t_state &= ~TS_CARR_ON;
68925404Skarels 	return (flag);
69025404Skarels }
69125404Skarels 
69225404Skarels /*
6937502Sroot  * reinput pending characters after state switch
69417545Skarels  * call at spltty().
6957502Sroot  */
6967502Sroot ttypend(tp)
6977625Ssam 	register struct tty *tp;
6987502Sroot {
6997502Sroot 	struct clist tq;
7007502Sroot 	register c;
7017502Sroot 
7029578Ssam 	tp->t_flags &= ~PENDIN;
7039578Ssam 	tp->t_state |= TS_TYPEN;
7047502Sroot 	tq = tp->t_rawq;
7057502Sroot 	tp->t_rawq.c_cc = 0;
7067502Sroot 	tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0;
7077502Sroot 	while ((c = getc(&tq)) >= 0)
7087502Sroot 		ttyinput(c, tp);
7099578Ssam 	tp->t_state &= ~TS_TYPEN;
7107502Sroot }
7117502Sroot 
7127502Sroot /*
7139578Ssam  * Place a character on raw TTY input queue,
7149578Ssam  * putting in delimiters and waking up top
7159578Ssam  * half as needed.  Also echo if required.
7169578Ssam  * The arguments are the character and the
7179578Ssam  * appropriate tty structure.
7187502Sroot  */
7197502Sroot ttyinput(c, tp)
7207625Ssam 	register c;
7217625Ssam 	register struct tty *tp;
7227502Sroot {
7239578Ssam 	register int t_flags = tp->t_flags;
7247502Sroot 	int i;
7257502Sroot 
7269578Ssam 	/*
7279578Ssam 	 * If input is pending take it first.
7289578Ssam 	 */
7299578Ssam 	if (t_flags&PENDIN)
7307502Sroot 		ttypend(tp);
7317502Sroot 	tk_nin++;
7327502Sroot 	c &= 0377;
7339578Ssam 
7349578Ssam 	/*
7359578Ssam 	 * In tandem mode, check high water mark.
7369578Ssam 	 */
7377502Sroot 	if (t_flags&TANDEM)
7387502Sroot 		ttyblock(tp);
7399578Ssam 
7409578Ssam 	if (t_flags&RAW) {
7419578Ssam 		/*
7429578Ssam 		 * Raw mode, just put character
7439578Ssam 		 * in input q w/o interpretation.
7449578Ssam 		 */
7459578Ssam 		if (tp->t_rawq.c_cc > TTYHOG)
74612752Ssam 			ttyflush(tp, FREAD|FWRITE);
7479578Ssam 		else {
7489578Ssam 			if (putc(c, &tp->t_rawq) >= 0)
7499578Ssam 				ttwakeup(tp);
7509578Ssam 			ttyecho(c, tp);
7517502Sroot 		}
7529578Ssam 		goto endcase;
7539578Ssam 	}
7549578Ssam 
7559578Ssam 	/*
7569578Ssam 	 * Ignore any high bit added during
7579578Ssam 	 * previous ttyinput processing.
7589578Ssam 	 */
75924273Slepreau 	if ((tp->t_state&TS_TYPEN) == 0 && (t_flags&PASS8) == 0)
7609578Ssam 		c &= 0177;
7619578Ssam 	/*
7629578Ssam 	 * Check for literal nexting very first
7639578Ssam 	 */
7649578Ssam 	if (tp->t_state&TS_LNCH) {
7659578Ssam 		c |= 0200;
7669578Ssam 		tp->t_state &= ~TS_LNCH;
7679578Ssam 	}
7689578Ssam 
7699578Ssam 	/*
7709578Ssam 	 * Scan for special characters.  This code
7719578Ssam 	 * is really just a big case statement with
7729578Ssam 	 * non-constant cases.  The bottom of the
7739578Ssam 	 * case statement is labeled ``endcase'', so goto
7749578Ssam 	 * it after a case match, or similar.
7759578Ssam 	 */
7769578Ssam 	if (tp->t_line == NTTYDISC) {
7779578Ssam 		if (c == tp->t_lnextc) {
77821776Sbloom 			if (t_flags&ECHO)
7797502Sroot 				ttyout("^\b", tp);
7809578Ssam 			tp->t_state |= TS_LNCH;
7819578Ssam 			goto endcase;
7829578Ssam 		}
7839578Ssam 		if (c == tp->t_flushc) {
78421776Sbloom 			if (t_flags&FLUSHO)
7859578Ssam 				tp->t_flags &= ~FLUSHO;
7867502Sroot 			else {
78712752Ssam 				ttyflush(tp, FWRITE);
7887502Sroot 				ttyecho(c, tp);
7899578Ssam 				if (tp->t_rawq.c_cc + tp->t_canq.c_cc)
7907502Sroot 					ttyretype(tp);
7919578Ssam 				tp->t_flags |= FLUSHO;
7927502Sroot 			}
7939578Ssam 			goto startoutput;
7949578Ssam 		}
7959578Ssam 		if (c == tp->t_suspc) {
79621776Sbloom 			if ((t_flags&NOFLSH) == 0)
79712752Ssam 				ttyflush(tp, FREAD);
7989578Ssam 			ttyecho(c, tp);
7999578Ssam 			gsignal(tp->t_pgrp, SIGTSTP);
8009578Ssam 			goto endcase;
8019578Ssam 		}
8029578Ssam 	}
8039578Ssam 
8049578Ssam 	/*
8059578Ssam 	 * Handle start/stop characters.
8069578Ssam 	 */
8079578Ssam 	if (c == tp->t_stopc) {
8089578Ssam 		if ((tp->t_state&TS_TTSTOP) == 0) {
8099578Ssam 			tp->t_state |= TS_TTSTOP;
8109578Ssam 			(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
8117502Sroot 			return;
8129578Ssam 		}
8139578Ssam 		if (c != tp->t_startc)
8149578Ssam 			return;
8159578Ssam 		goto endcase;
8169578Ssam 	}
8179578Ssam 	if (c == tp->t_startc)
8189578Ssam 		goto restartoutput;
8199578Ssam 
8209578Ssam 	/*
8219578Ssam 	 * Look for interrupt/quit chars.
8229578Ssam 	 */
8239578Ssam 	if (c == tp->t_intrc || c == tp->t_quitc) {
82421776Sbloom 		if ((t_flags&NOFLSH) == 0)
82512752Ssam 			ttyflush(tp, FREAD|FWRITE);
8269578Ssam 		ttyecho(c, tp);
8279578Ssam 		gsignal(tp->t_pgrp, c == tp->t_intrc ? SIGINT : SIGQUIT);
8289578Ssam 		goto endcase;
8299578Ssam 	}
8309578Ssam 
83123165Sbloom 	if (tp->t_flags & LCASE && c <= 0177) {
83223165Sbloom 		if (tp->t_state&TS_BKSL) {
83323165Sbloom 			ttyrub(unputc(&tp->t_rawq), tp);
83423165Sbloom 			if (maptab[c])
83523165Sbloom 				c = maptab[c];
83623165Sbloom 			c |= 0200;
83723165Sbloom 			tp->t_state &= ~(TS_BKSL|TS_QUOT);
83823165Sbloom 		} else if (c >= 'A' && c <= 'Z')
83923165Sbloom 			c += 'a' - 'A';
84023165Sbloom 		else if (c == '\\')
84123165Sbloom 			tp->t_state |= TS_BKSL;
84223165Sbloom 	}
84323165Sbloom 
8449578Ssam 	/*
8459578Ssam 	 * Cbreak mode, don't process line editing
8469578Ssam 	 * characters; check high water mark for wakeup.
8479578Ssam 	 */
8489578Ssam 	if (t_flags&CBREAK) {
8499578Ssam 		if (tp->t_rawq.c_cc > TTYHOG) {
8507502Sroot 			if (tp->t_outq.c_cc < TTHIWAT(tp) &&
8517502Sroot 			    tp->t_line == NTTYDISC)
8527502Sroot 				(void) ttyoutput(CTRL(g), tp);
8537502Sroot 		} else if (putc(c, &tp->t_rawq) >= 0) {
8547502Sroot 			ttwakeup(tp);
8557502Sroot 			ttyecho(c, tp);
8567502Sroot 		}
8579578Ssam 		goto endcase;
8589578Ssam 	}
8599578Ssam 
8609578Ssam 	/*
8619578Ssam 	 * From here on down cooked mode character
8629578Ssam 	 * processing takes place.
8639578Ssam 	 */
8649578Ssam 	if ((tp->t_state&TS_QUOT) &&
8659578Ssam 	    (c == tp->t_erase || c == tp->t_kill)) {
8669578Ssam 		ttyrub(unputc(&tp->t_rawq), tp);
8679578Ssam 		c |= 0200;
8689578Ssam 	}
8699578Ssam 	if (c == tp->t_erase) {
8709578Ssam 		if (tp->t_rawq.c_cc)
8719578Ssam 			ttyrub(unputc(&tp->t_rawq), tp);
8729578Ssam 		goto endcase;
8739578Ssam 	}
8749578Ssam 	if (c == tp->t_kill) {
87521776Sbloom 		if (t_flags&CRTKIL &&
8769578Ssam 		    tp->t_rawq.c_cc == tp->t_rocount) {
8779578Ssam 			while (tp->t_rawq.c_cc)
8789578Ssam 				ttyrub(unputc(&tp->t_rawq), tp);
8799578Ssam 		} else {
8809578Ssam 			ttyecho(c, tp);
8819578Ssam 			ttyecho('\n', tp);
8829578Ssam 			while (getc(&tp->t_rawq) > 0)
8839578Ssam 				;
8849578Ssam 			tp->t_rocount = 0;
8859578Ssam 		}
8869578Ssam 		tp->t_state &= ~TS_LOCAL;
8879578Ssam 		goto endcase;
8889578Ssam 	}
8899578Ssam 
8909578Ssam 	/*
8919578Ssam 	 * New line discipline,
8929578Ssam 	 * check word erase/reprint line.
8939578Ssam 	 */
8949578Ssam 	if (tp->t_line == NTTYDISC) {
8959578Ssam 		if (c == tp->t_werasc) {
8969578Ssam 			if (tp->t_rawq.c_cc == 0)
8979578Ssam 				goto endcase;
8989578Ssam 			do {
8999578Ssam 				c = unputc(&tp->t_rawq);
9009578Ssam 				if (c != ' ' && c != '\t')
9019578Ssam 					goto erasenb;
9029578Ssam 				ttyrub(c, tp);
9039578Ssam 			} while (tp->t_rawq.c_cc);
9049578Ssam 			goto endcase;
9059578Ssam 	erasenb:
9069578Ssam 			do {
9079578Ssam 				ttyrub(c, tp);
9089578Ssam 				if (tp->t_rawq.c_cc == 0)
9099578Ssam 					goto endcase;
9109578Ssam 				c = unputc(&tp->t_rawq);
9119578Ssam 			} while (c != ' ' && c != '\t');
9129578Ssam 			(void) putc(c, &tp->t_rawq);
9139578Ssam 			goto endcase;
9149578Ssam 		}
9159578Ssam 		if (c == tp->t_rprntc) {
9169578Ssam 			ttyretype(tp);
9179578Ssam 			goto endcase;
9189578Ssam 		}
9199578Ssam 	}
9209578Ssam 
9219578Ssam 	/*
9229578Ssam 	 * Check for input buffer overflow
9239578Ssam 	 */
92410391Ssam 	if (tp->t_rawq.c_cc+tp->t_canq.c_cc >= TTYHOG) {
92510391Ssam 		if (tp->t_line == NTTYDISC)
92610391Ssam 			(void) ttyoutput(CTRL(g), tp);
9279578Ssam 		goto endcase;
92810391Ssam 	}
9299578Ssam 
9309578Ssam 	/*
9319578Ssam 	 * Put data char in q for user and
9329578Ssam 	 * wakeup on seeing a line delimiter.
9339578Ssam 	 */
9349578Ssam 	if (putc(c, &tp->t_rawq) >= 0) {
9359578Ssam 		if (ttbreakc(c, tp)) {
9369578Ssam 			tp->t_rocount = 0;
9379578Ssam 			catq(&tp->t_rawq, &tp->t_canq);
9387502Sroot 			ttwakeup(tp);
9399578Ssam 		} else if (tp->t_rocount++ == 0)
9409578Ssam 			tp->t_rocol = tp->t_col;
9419578Ssam 		tp->t_state &= ~TS_QUOT;
9429578Ssam 		if (c == '\\')
9439578Ssam 			tp->t_state |= TS_QUOT;
9449578Ssam 		if (tp->t_state&TS_ERASE) {
9459578Ssam 			tp->t_state &= ~TS_ERASE;
9469578Ssam 			(void) ttyoutput('/', tp);
9479578Ssam 		}
9489578Ssam 		i = tp->t_col;
9497502Sroot 		ttyecho(c, tp);
95021776Sbloom 		if (c == tp->t_eofc && t_flags&ECHO) {
9519578Ssam 			i = MIN(2, tp->t_col - i);
9529578Ssam 			while (i > 0) {
9539578Ssam 				(void) ttyoutput('\b', tp);
9549578Ssam 				i--;
9559578Ssam 			}
9569578Ssam 		}
9577502Sroot 	}
9589578Ssam endcase:
9599578Ssam 	/*
9609578Ssam 	 * If DEC-style start/stop is enabled don't restart
9619578Ssam 	 * output until seeing the start character.
9629578Ssam 	 */
96321776Sbloom 	if (t_flags&DECCTQ && tp->t_state&TS_TTSTOP &&
9649578Ssam 	    tp->t_startc != tp->t_stopc)
9657502Sroot 		return;
9669578Ssam restartoutput:
9677502Sroot 	tp->t_state &= ~TS_TTSTOP;
9689578Ssam 	tp->t_flags &= ~FLUSHO;
9699578Ssam startoutput:
9707502Sroot 	ttstart(tp);
9717502Sroot }
9727502Sroot 
9737502Sroot /*
9749578Ssam  * Put character on TTY output queue, adding delays,
9757502Sroot  * expanding tabs, and handling the CR/NL bit.
9769578Ssam  * This is called both from the top half for output,
9779578Ssam  * and from interrupt level for echoing.
9787502Sroot  * The arguments are the character and the tty structure.
9797502Sroot  * Returns < 0 if putc succeeds, otherwise returns char to resend
9807502Sroot  * Must be recursive.
9817502Sroot  */
9827502Sroot ttyoutput(c, tp)
9837502Sroot 	register c;
9847502Sroot 	register struct tty *tp;
9857502Sroot {
9867502Sroot 	register char *colp;
9877502Sroot 	register ctype;
9887502Sroot 
9899578Ssam 	if (tp->t_flags & (RAW|LITOUT)) {
9909578Ssam 		if (tp->t_flags&FLUSHO)
9917502Sroot 			return (-1);
9927502Sroot 		if (putc(c, &tp->t_outq))
9937625Ssam 			return (c);
9947502Sroot 		tk_nout++;
9957502Sroot 		return (-1);
9967502Sroot 	}
9979578Ssam 
9987502Sroot 	/*
9999578Ssam 	 * Ignore EOT in normal mode to avoid
10009578Ssam 	 * hanging up certain terminals.
10017502Sroot 	 */
10027502Sroot 	c &= 0177;
10039578Ssam 	if (c == CEOT && (tp->t_flags&CBREAK) == 0)
10047502Sroot 		return (-1);
10057502Sroot 	/*
10067502Sroot 	 * Turn tabs to spaces as required
10077502Sroot 	 */
10089578Ssam 	if (c == '\t' && (tp->t_flags&TBDELAY) == XTABS) {
10097502Sroot 		register int s;
10107502Sroot 
10117502Sroot 		c = 8 - (tp->t_col&7);
10129578Ssam 		if ((tp->t_flags&FLUSHO) == 0) {
101317545Skarels 			s = spltty();		/* don't interrupt tabs */
10147502Sroot 			c -= b_to_q("        ", c, &tp->t_outq);
10157502Sroot 			tk_nout += c;
10167502Sroot 			splx(s);
10177502Sroot 		}
10187502Sroot 		tp->t_col += c;
10197502Sroot 		return (c ? -1 : '\t');
10207502Sroot 	}
10217502Sroot 	tk_nout++;
10227502Sroot 	/*
10237502Sroot 	 * for upper-case-only terminals,
10247502Sroot 	 * generate escapes.
10257502Sroot 	 */
10267502Sroot 	if (tp->t_flags&LCASE) {
10277502Sroot 		colp = "({)}!|^~'`";
10287625Ssam 		while (*colp++)
10297625Ssam 			if (c == *colp++) {
10307502Sroot 				if (ttyoutput('\\', tp) >= 0)
10317502Sroot 					return (c);
10327502Sroot 				c = colp[-2];
10337502Sroot 				break;
10347502Sroot 			}
10359578Ssam 		if ('A' <= c && c <= 'Z') {
10367502Sroot 			if (ttyoutput('\\', tp) >= 0)
10377502Sroot 				return (c);
10389578Ssam 		} else if ('a' <= c && c <= 'z')
10397502Sroot 			c += 'A' - 'a';
10407502Sroot 	}
10419578Ssam 
10427502Sroot 	/*
10437502Sroot 	 * turn <nl> to <cr><lf> if desired.
10447502Sroot 	 */
10459578Ssam 	if (c == '\n' && tp->t_flags&CRMOD)
10467502Sroot 		if (ttyoutput('\r', tp) >= 0)
10477502Sroot 			return (c);
10489578Ssam 	if (c == '~' && tp->t_flags&TILDE)
10497502Sroot 		c = '`';
10509578Ssam 	if ((tp->t_flags&FLUSHO) == 0 && putc(c, &tp->t_outq))
10517502Sroot 		return (c);
10527502Sroot 	/*
10537502Sroot 	 * Calculate delays.
10547502Sroot 	 * The numbers here represent clock ticks
10557502Sroot 	 * and are not necessarily optimal for all terminals.
10567502Sroot 	 * The delays are indicated by characters above 0200.
10577502Sroot 	 * In raw mode there are no delays and the
10587502Sroot 	 * transmission path is 8 bits wide.
10599578Ssam 	 *
10609578Ssam 	 * SHOULD JUST ALLOW USER TO SPECIFY DELAYS
10617502Sroot 	 */
10627502Sroot 	colp = &tp->t_col;
10637502Sroot 	ctype = partab[c];
10647502Sroot 	c = 0;
10657502Sroot 	switch (ctype&077) {
10667502Sroot 
10677502Sroot 	case ORDINARY:
10687502Sroot 		(*colp)++;
10697502Sroot 
10707502Sroot 	case CONTROL:
10717502Sroot 		break;
10727502Sroot 
10737502Sroot 	case BACKSPACE:
10747502Sroot 		if (*colp)
10757502Sroot 			(*colp)--;
10767502Sroot 		break;
10777502Sroot 
107813821Ssam 	/*
107913821Ssam 	 * This macro is close enough to the correct thing;
108013821Ssam 	 * it should be replaced by real user settable delays
108113821Ssam 	 * in any event...
108213821Ssam 	 */
108313821Ssam #define	mstohz(ms)	(((ms) * hz) >> 10)
10847502Sroot 	case NEWLINE:
10857502Sroot 		ctype = (tp->t_flags >> 8) & 03;
10867625Ssam 		if (ctype == 1) { /* tty 37 */
108726357Skarels 			if (*colp > 0) {
108826357Skarels 				c = (((unsigned)*colp) >> 4) + 3;
108926357Skarels 				if ((unsigned)c > 6)
109026357Skarels 					c = 6;
109126357Skarels 			}
10929578Ssam 		} else if (ctype == 2) /* vt05 */
109313821Ssam 			c = mstohz(100);
10947502Sroot 		*colp = 0;
10957502Sroot 		break;
10967502Sroot 
10977502Sroot 	case TAB:
10987502Sroot 		ctype = (tp->t_flags >> 10) & 03;
10997625Ssam 		if (ctype == 1) { /* tty 37 */
11007502Sroot 			c = 1 - (*colp | ~07);
11017625Ssam 			if (c < 5)
11027502Sroot 				c = 0;
11037502Sroot 		}
11047502Sroot 		*colp |= 07;
11057502Sroot 		(*colp)++;
11067502Sroot 		break;
11077502Sroot 
11087502Sroot 	case VTAB:
11099578Ssam 		if (tp->t_flags&VTDELAY) /* tty 37 */
11107502Sroot 			c = 0177;
11117502Sroot 		break;
11127502Sroot 
11137502Sroot 	case RETURN:
11147502Sroot 		ctype = (tp->t_flags >> 12) & 03;
11159578Ssam 		if (ctype == 1) /* tn 300 */
111613821Ssam 			c = mstohz(83);
11179578Ssam 		else if (ctype == 2) /* ti 700 */
111813821Ssam 			c = mstohz(166);
11199578Ssam 		else if (ctype == 3) { /* concept 100 */
11207502Sroot 			int i;
11219578Ssam 
11227502Sroot 			if ((i = *colp) >= 0)
11239578Ssam 				for (; i < 9; i++)
11247502Sroot 					(void) putc(0177, &tp->t_outq);
11257502Sroot 		}
11267502Sroot 		*colp = 0;
11277502Sroot 	}
11289578Ssam 	if (c && (tp->t_flags&FLUSHO) == 0)
11297502Sroot 		(void) putc(c|0200, &tp->t_outq);
11307502Sroot 	return (-1);
11317502Sroot }
113213821Ssam #undef mstohz
11337502Sroot 
11347502Sroot /*
11357502Sroot  * Called from device's read routine after it has
11367502Sroot  * calculated the tty-structure given as argument.
11377502Sroot  */
11387722Swnj ttread(tp, uio)
11397625Ssam 	register struct tty *tp;
11407722Swnj 	struct uio *uio;
11417502Sroot {
11427502Sroot 	register struct clist *qp;
11439578Ssam 	register c, t_flags;
11449859Ssam 	int s, first, error = 0;
11457502Sroot 
11467502Sroot loop:
11479578Ssam 	/*
11489578Ssam 	 * Take any pending input first.
11499578Ssam 	 */
115017545Skarels 	s = spltty();
11519578Ssam 	if (tp->t_flags&PENDIN)
11527502Sroot 		ttypend(tp);
11539859Ssam 	splx(s);
11549578Ssam 
115523165Sbloom 	if ((tp->t_state&TS_CARR_ON)==0)
115623165Sbloom 		return (EIO);
115723165Sbloom 
11589578Ssam 	/*
11599578Ssam 	 * Hang process if it's in the background.
11609578Ssam 	 */
116123165Sbloom 	if (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) {
116224392Skarels 		if ((u.u_procp->p_sigignore & sigmask(SIGTTIN)) ||
116324392Skarels 		   (u.u_procp->p_sigmask & sigmask(SIGTTIN)) ||
11647502Sroot 		    u.u_procp->p_flag&SVFORK)
11658520Sroot 			return (EIO);
11667502Sroot 		gsignal(u.u_procp->p_pgrp, SIGTTIN);
11677502Sroot 		sleep((caddr_t)&lbolt, TTIPRI);
116823165Sbloom 		goto loop;
11697502Sroot 	}
11709578Ssam 	t_flags = tp->t_flags;
11719578Ssam 
11729578Ssam 	/*
11739578Ssam 	 * In raw mode take characters directly from the
11749578Ssam 	 * raw queue w/o processing.  Interlock against
11759578Ssam 	 * device interrupts when interrogating rawq.
11769578Ssam 	 */
11779578Ssam 	if (t_flags&RAW) {
117817545Skarels 		s = spltty();
11797502Sroot 		if (tp->t_rawq.c_cc <= 0) {
11809578Ssam 			if ((tp->t_state&TS_CARR_ON) == 0 ||
11817502Sroot 			    (tp->t_state&TS_NBIO)) {
11829859Ssam 				splx(s);
118315094Skarels 				return (EWOULDBLOCK);
11847502Sroot 			}
11857502Sroot 			sleep((caddr_t)&tp->t_rawq, TTIPRI);
11869859Ssam 			splx(s);
11877502Sroot 			goto loop;
11887502Sroot 		}
11899859Ssam 		splx(s);
119014938Smckusick  		while (!error && tp->t_rawq.c_cc && uio->uio_resid)
119114938Smckusick  			error = ureadc(getc(&tp->t_rawq), uio);
11929859Ssam 		goto checktandem;
11939578Ssam 	}
11949578Ssam 
11959578Ssam 	/*
11969578Ssam 	 * In cbreak mode use the rawq, otherwise
11979578Ssam 	 * take characters from the canonicalized q.
11989578Ssam 	 */
11999578Ssam 	qp = t_flags&CBREAK ? &tp->t_rawq : &tp->t_canq;
12009578Ssam 
12019578Ssam 	/*
12029578Ssam 	 * No input, sleep on rawq awaiting hardware
12039578Ssam 	 * receipt and notification.
12049578Ssam 	 */
120517545Skarels 	s = spltty();
12069578Ssam 	if (qp->c_cc <= 0) {
12079578Ssam 		if ((tp->t_state&TS_CARR_ON) == 0 ||
12089578Ssam 		    (tp->t_state&TS_NBIO)) {
12099859Ssam 			splx(s);
12109578Ssam 			return (EWOULDBLOCK);
12117502Sroot 		}
12129578Ssam 		sleep((caddr_t)&tp->t_rawq, TTIPRI);
12139859Ssam 		splx(s);
12149578Ssam 		goto loop;
12159578Ssam 	}
12169859Ssam 	splx(s);
12179578Ssam 
12189578Ssam 	/*
12199578Ssam 	 * Input present, perform input mapping
12209578Ssam 	 * and processing (we're not in raw mode).
12219578Ssam 	 */
12229578Ssam 	first = 1;
12239578Ssam 	while ((c = getc(qp)) >= 0) {
12249578Ssam 		if (t_flags&CRMOD && c == '\r')
12259578Ssam 			c = '\n';
12269578Ssam 		/*
12279578Ssam 		 * Check for delayed suspend character.
12289578Ssam 		 */
12299578Ssam 		if (tp->t_line == NTTYDISC && c == tp->t_dsuspc) {
12309578Ssam 			gsignal(tp->t_pgrp, SIGTSTP);
12319578Ssam 			if (first) {
12329578Ssam 				sleep((caddr_t)&lbolt, TTIPRI);
12339578Ssam 				goto loop;
12349578Ssam 			}
12359578Ssam 			break;
12367502Sroot 		}
12379578Ssam 		/*
12389578Ssam 		 * Interpret EOF only in cooked mode.
12399578Ssam 		 */
12409578Ssam 		if (c == tp->t_eofc && (t_flags&CBREAK) == 0)
12419578Ssam 			break;
12429578Ssam 		/*
12439578Ssam 		 * Give user character.
12449578Ssam 		 */
124524273Slepreau  		error = ureadc(t_flags&PASS8 ? c : c & 0177, uio);
12469578Ssam 		if (error)
12479578Ssam 			break;
124814938Smckusick  		if (uio->uio_resid == 0)
12499578Ssam 			break;
12509578Ssam 		/*
12519578Ssam 		 * In cooked mode check for a "break character"
12529578Ssam 		 * marking the end of a "line of input".
12539578Ssam 		 */
12549578Ssam 		if ((t_flags&CBREAK) == 0 && ttbreakc(c, tp))
12559578Ssam 			break;
12569578Ssam 		first = 0;
12577502Sroot 	}
12589578Ssam 
12599859Ssam checktandem:
12609578Ssam 	/*
12619578Ssam 	 * Look to unblock output now that (presumably)
12629578Ssam 	 * the input queue has gone down.
12639578Ssam 	 */
12649859Ssam 	if (tp->t_state&TS_TBLOCK && tp->t_rawq.c_cc < TTYHOG/5)
12659578Ssam 		if (putc(tp->t_startc, &tp->t_outq) == 0) {
12667502Sroot 			tp->t_state &= ~TS_TBLOCK;
12677502Sroot 			ttstart(tp);
12687502Sroot 		}
12698520Sroot 	return (error);
12707502Sroot }
12717502Sroot 
12727502Sroot /*
127325391Skarels  * Check the output queue on tp for space for a kernel message
127425391Skarels  * (from uprintf/tprintf).  Allow some space over the normal
127525391Skarels  * hiwater mark so we don't lose messages due to normal flow
127625391Skarels  * control, but don't let the tty run amok.
127725391Skarels  */
127825391Skarels ttycheckoutq(tp, wait)
127925391Skarels 	register struct tty *tp;
128025391Skarels 	int wait;
128125391Skarels {
128225391Skarels 	int hiwat, s;
128325391Skarels 
128425391Skarels 	hiwat = TTHIWAT(tp);
128525391Skarels 	s = spltty();
128625391Skarels 	if (tp->t_outq.c_cc > hiwat + 200)
128729946Skarels 		while (tp->t_outq.c_cc > hiwat) {
128829946Skarels 			ttstart(tp);
128929946Skarels 			if (wait == 0) {
129029946Skarels 				splx(s);
129129946Skarels 				return (0);
129229946Skarels 			}
129329946Skarels 			tp->t_state |= TS_ASLEEP;
129429946Skarels 			sleep((caddr_t)&tp->t_outq, TTOPRI);
129525391Skarels 		}
129625391Skarels 	splx(s);
129725391Skarels 	return (1);
129825391Skarels }
129925391Skarels 
130025391Skarels /*
13017502Sroot  * Called from the device's write routine after it has
13027502Sroot  * calculated the tty-structure given as argument.
13037502Sroot  */
13047822Sroot ttwrite(tp, uio)
13057625Ssam 	register struct tty *tp;
13069578Ssam 	register struct uio *uio;
13077502Sroot {
13087502Sroot 	register char *cp;
13099578Ssam 	register int cc, ce, c;
13109578Ssam 	int i, hiwat, cnt, error, s;
13117502Sroot 	char obuf[OBUFSIZ];
13127502Sroot 
13139578Ssam 	hiwat = TTHIWAT(tp);
13149578Ssam 	cnt = uio->uio_resid;
13159578Ssam 	error = 0;
13167502Sroot loop:
131721776Sbloom 	if ((tp->t_state&TS_CARR_ON) == 0)
131821776Sbloom 		return (EIO);
13199578Ssam 	/*
13209578Ssam 	 * Hang the process if it's in the background.
13219578Ssam 	 */
132221776Sbloom 	if (u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp &&
13239578Ssam 	    (tp->t_flags&TOSTOP) && (u.u_procp->p_flag&SVFORK)==0 &&
132424392Skarels 	    !(u.u_procp->p_sigignore & sigmask(SIGTTOU)) &&
132524392Skarels 	    !(u.u_procp->p_sigmask & sigmask(SIGTTOU))) {
13267502Sroot 		gsignal(u.u_procp->p_pgrp, SIGTTOU);
13277502Sroot 		sleep((caddr_t)&lbolt, TTIPRI);
132821776Sbloom 		goto loop;
13297502Sroot 	}
13309578Ssam 
13319578Ssam 	/*
13329578Ssam 	 * Process the user's data in at most OBUFSIZ
13339578Ssam 	 * chunks.  Perform lower case simulation and
13349578Ssam 	 * similar hacks.  Keep track of high water
13359578Ssam 	 * mark, sleep on overflow awaiting device aid
13369578Ssam 	 * in acquiring new space.
13379578Ssam 	 */
13387822Sroot 	while (uio->uio_resid > 0) {
13399578Ssam 		/*
13409578Ssam 		 * Grab a hunk of data from the user.
13419578Ssam 		 */
13427822Sroot 		cc = uio->uio_iov->iov_len;
13437822Sroot 		if (cc == 0) {
13447822Sroot 			uio->uio_iovcnt--;
13457822Sroot 			uio->uio_iov++;
134621776Sbloom 			if (uio->uio_iovcnt <= 0)
13477822Sroot 				panic("ttwrite");
13487822Sroot 			continue;
13497822Sroot 		}
13507822Sroot 		if (cc > OBUFSIZ)
13517822Sroot 			cc = OBUFSIZ;
13527502Sroot 		cp = obuf;
135312752Ssam 		error = uiomove(cp, cc, UIO_WRITE, uio);
13548520Sroot 		if (error)
13557502Sroot 			break;
13567502Sroot 		if (tp->t_outq.c_cc > hiwat)
13577502Sroot 			goto ovhiwat;
13589578Ssam 		if (tp->t_flags&FLUSHO)
13597502Sroot 			continue;
13609578Ssam 		/*
13619578Ssam 		 * If we're mapping lower case or kludging tildes,
13629578Ssam 		 * then we've got to look at each character, so
13639578Ssam 		 * just feed the stuff to ttyoutput...
13649578Ssam 		 */
13659578Ssam 		if (tp->t_flags & (LCASE|TILDE)) {
13669578Ssam 			while (cc > 0) {
13677502Sroot 				c = *cp++;
13687502Sroot 				tp->t_rocount = 0;
13697625Ssam 				while ((c = ttyoutput(c, tp)) >= 0) {
13707502Sroot 					/* out of clists, wait a bit */
13717502Sroot 					ttstart(tp);
13727502Sroot 					sleep((caddr_t)&lbolt, TTOPRI);
13737502Sroot 					tp->t_rocount = 0;
137421776Sbloom 					if (cc != 0) {
137521776Sbloom 						uio->uio_iov->iov_base -= cc;
137621776Sbloom 						uio->uio_iov->iov_len += cc;
137721776Sbloom 						uio->uio_resid += cc;
137821776Sbloom 						uio->uio_offset -= cc;
137921776Sbloom 					}
138021776Sbloom 					goto loop;
13817502Sroot 				}
13827502Sroot 				--cc;
13837502Sroot 				if (tp->t_outq.c_cc > hiwat)
13847502Sroot 					goto ovhiwat;
13857502Sroot 			}
13867502Sroot 			continue;
13877502Sroot 		}
13889578Ssam 		/*
13899578Ssam 		 * If nothing fancy need be done, grab those characters we
13909578Ssam 		 * can handle without any of ttyoutput's processing and
13919578Ssam 		 * just transfer them to the output q.  For those chars
13929578Ssam 		 * which require special processing (as indicated by the
13939578Ssam 		 * bits in partab), call ttyoutput.  After processing
13949578Ssam 		 * a hunk of data, look for FLUSHO so ^O's will take effect
13959578Ssam 		 * immediately.
13969578Ssam 		 */
13979578Ssam 		while (cc > 0) {
13989578Ssam 			if (tp->t_flags & (RAW|LITOUT))
13997502Sroot 				ce = cc;
14007502Sroot 			else {
140112752Ssam 				ce = cc - scanc((unsigned)cc, (caddr_t)cp,
140212752Ssam 				   (caddr_t)partab, 077);
14039578Ssam 				/*
14049578Ssam 				 * If ce is zero, then we're processing
14059578Ssam 				 * a special character through ttyoutput.
14069578Ssam 				 */
14079578Ssam 				if (ce == 0) {
14087502Sroot 					tp->t_rocount = 0;
14097502Sroot 					if (ttyoutput(*cp, tp) >= 0) {
141021776Sbloom 					    /* no c-lists, wait a bit */
141121776Sbloom 					    ttstart(tp);
141221776Sbloom 					    sleep((caddr_t)&lbolt, TTOPRI);
141321776Sbloom 					    if (cc != 0) {
141421776Sbloom 					        uio->uio_iov->iov_base -= cc;
141521776Sbloom 					        uio->uio_iov->iov_len += cc;
141621776Sbloom 					        uio->uio_resid += cc;
141721776Sbloom 						uio->uio_offset -= cc;
141821776Sbloom 					    }
141921776Sbloom 					    goto loop;
14207502Sroot 					}
14219578Ssam 					cp++, cc--;
14229578Ssam 					if (tp->t_flags&FLUSHO ||
14239578Ssam 					    tp->t_outq.c_cc > hiwat)
14247502Sroot 						goto ovhiwat;
14259578Ssam 					continue;
14267502Sroot 				}
14277502Sroot 			}
14289578Ssam 			/*
14299578Ssam 			 * A bunch of normal characters have been found,
14309578Ssam 			 * transfer them en masse to the output queue and
14319578Ssam 			 * continue processing at the top of the loop.
14329578Ssam 			 * If there are any further characters in this
14339578Ssam 			 * <= OBUFSIZ chunk, the first should be a character
14349578Ssam 			 * requiring special handling by ttyoutput.
14359578Ssam 			 */
14367502Sroot 			tp->t_rocount = 0;
14379578Ssam 			i = b_to_q(cp, ce, &tp->t_outq);
14389578Ssam 			ce -= i;
14399578Ssam 			tp->t_col += ce;
14409578Ssam 			cp += ce, cc -= ce, tk_nout += ce;
14419578Ssam 			if (i > 0) {
14429578Ssam 				/* out of c-lists, wait a bit */
14437502Sroot 				ttstart(tp);
14447502Sroot 				sleep((caddr_t)&lbolt, TTOPRI);
144521776Sbloom 				uio->uio_iov->iov_base -= cc;
144621776Sbloom 				uio->uio_iov->iov_len += cc;
144721776Sbloom 				uio->uio_resid += cc;
144821776Sbloom 				uio->uio_offset -= cc;
144921776Sbloom 				goto loop;
14507502Sroot 			}
14519578Ssam 			if (tp->t_flags&FLUSHO || tp->t_outq.c_cc > hiwat)
14527502Sroot 				goto ovhiwat;
14537502Sroot 		}
14547502Sroot 	}
14557502Sroot 	ttstart(tp);
14568520Sroot 	return (error);
14577502Sroot 
14587502Sroot ovhiwat:
145917545Skarels 	s = spltty();
14609578Ssam 	if (cc != 0) {
14619578Ssam 		uio->uio_iov->iov_base -= cc;
14629578Ssam 		uio->uio_iov->iov_len += cc;
14639578Ssam 		uio->uio_resid += cc;
14649578Ssam 		uio->uio_offset -= cc;
14659578Ssam 	}
14669578Ssam 	/*
14679578Ssam 	 * This can only occur if FLUSHO
14689578Ssam 	 * is also set in t_flags.
14699578Ssam 	 */
14707502Sroot 	if (tp->t_outq.c_cc <= hiwat) {
14719578Ssam 		splx(s);
14727502Sroot 		goto loop;
14737502Sroot 	}
14747502Sroot 	ttstart(tp);
14759578Ssam 	if (tp->t_state&TS_NBIO) {
147617545Skarels 		splx(s);
14777822Sroot 		if (uio->uio_resid == cnt)
14788520Sroot 			return (EWOULDBLOCK);
14798520Sroot 		return (0);
14807502Sroot 	}
14817502Sroot 	tp->t_state |= TS_ASLEEP;
14827502Sroot 	sleep((caddr_t)&tp->t_outq, TTOPRI);
14839578Ssam 	splx(s);
14847502Sroot 	goto loop;
14857502Sroot }
14867502Sroot 
14877502Sroot /*
14887502Sroot  * Rubout one character from the rawq of tp
14897502Sroot  * as cleanly as possible.
14907502Sroot  */
14917502Sroot ttyrub(c, tp)
14927625Ssam 	register c;
14937625Ssam 	register struct tty *tp;
14947502Sroot {
14957502Sroot 	register char *cp;
14967502Sroot 	register int savecol;
14977502Sroot 	int s;
14987502Sroot 	char *nextc();
14997502Sroot 
15009578Ssam 	if ((tp->t_flags&ECHO) == 0)
15017502Sroot 		return;
15029578Ssam 	tp->t_flags &= ~FLUSHO;
15037502Sroot 	c &= 0377;
15049578Ssam 	if (tp->t_flags&CRTBS) {
15057502Sroot 		if (tp->t_rocount == 0) {
15067502Sroot 			/*
15077502Sroot 			 * Screwed by ttwrite; retype
15087502Sroot 			 */
15097502Sroot 			ttyretype(tp);
15107502Sroot 			return;
15117502Sroot 		}
15129578Ssam 		if (c == ('\t'|0200) || c == ('\n'|0200))
15137502Sroot 			ttyrubo(tp, 2);
15149578Ssam 		else switch (partab[c&=0177]&0177) {
15157502Sroot 
15167502Sroot 		case ORDINARY:
15177502Sroot 			if (tp->t_flags&LCASE && c >= 'A' && c <= 'Z')
15187502Sroot 				ttyrubo(tp, 2);
15197502Sroot 			else
15207502Sroot 				ttyrubo(tp, 1);
15217502Sroot 			break;
15227502Sroot 
15237502Sroot 		case VTAB:
15247502Sroot 		case BACKSPACE:
15257502Sroot 		case CONTROL:
15267502Sroot 		case RETURN:
15279578Ssam 			if (tp->t_flags&CTLECH)
15287502Sroot 				ttyrubo(tp, 2);
15297502Sroot 			break;
15307502Sroot 
15317502Sroot 		case TAB:
15327502Sroot 			if (tp->t_rocount < tp->t_rawq.c_cc) {
15337502Sroot 				ttyretype(tp);
15347502Sroot 				return;
15357502Sroot 			}
153617545Skarels 			s = spltty();
15377502Sroot 			savecol = tp->t_col;
15389578Ssam 			tp->t_state |= TS_CNTTB;
15399578Ssam 			tp->t_flags |= FLUSHO;
15407502Sroot 			tp->t_col = tp->t_rocol;
15419578Ssam 			cp = tp->t_rawq.c_cf;
15429578Ssam 			for (; cp; cp = nextc(&tp->t_rawq, cp))
15437502Sroot 				ttyecho(*cp, tp);
15449578Ssam 			tp->t_flags &= ~FLUSHO;
15459578Ssam 			tp->t_state &= ~TS_CNTTB;
15467502Sroot 			splx(s);
15477502Sroot 			/*
15487502Sroot 			 * savecol will now be length of the tab
15497502Sroot 			 */
15507502Sroot 			savecol -= tp->t_col;
15517502Sroot 			tp->t_col += savecol;
15527502Sroot 			if (savecol > 8)
15537502Sroot 				savecol = 8;		/* overflow screw */
15547502Sroot 			while (--savecol >= 0)
15557502Sroot 				(void) ttyoutput('\b', tp);
15567502Sroot 			break;
15577502Sroot 
15587502Sroot 		default:
15597502Sroot 			panic("ttyrub");
15607502Sroot 		}
15619578Ssam 	} else if (tp->t_flags&PRTERA) {
15629578Ssam 		if ((tp->t_state&TS_ERASE) == 0) {
15637502Sroot 			(void) ttyoutput('\\', tp);
15649578Ssam 			tp->t_state |= TS_ERASE;
15657502Sroot 		}
15667502Sroot 		ttyecho(c, tp);
15677502Sroot 	} else
15687502Sroot 		ttyecho(tp->t_erase, tp);
15697502Sroot 	tp->t_rocount--;
15707502Sroot }
15717502Sroot 
15727502Sroot /*
15737502Sroot  * Crt back over cnt chars perhaps
15747502Sroot  * erasing them.
15757502Sroot  */
15767502Sroot ttyrubo(tp, cnt)
15777625Ssam 	register struct tty *tp;
15787625Ssam 	int cnt;
15797502Sroot {
15809578Ssam 	register char *rubostring = tp->t_flags&CRTERA ? "\b \b" : "\b";
15817502Sroot 
15827502Sroot 	while (--cnt >= 0)
15839578Ssam 		ttyout(rubostring, tp);
15847502Sroot }
15857502Sroot 
15867502Sroot /*
15877502Sroot  * Reprint the rawq line.
15887502Sroot  * We assume c_cc has already been checked.
15897502Sroot  */
15907502Sroot ttyretype(tp)
15917625Ssam 	register struct tty *tp;
15927502Sroot {
15937502Sroot 	register char *cp;
15947502Sroot 	char *nextc();
15957502Sroot 	int s;
15967502Sroot 
15979578Ssam 	if (tp->t_rprntc != 0377)
15989578Ssam 		ttyecho(tp->t_rprntc, tp);
15997502Sroot 	(void) ttyoutput('\n', tp);
160017545Skarels 	s = spltty();
16017502Sroot 	for (cp = tp->t_canq.c_cf; cp; cp = nextc(&tp->t_canq, cp))
16027502Sroot 		ttyecho(*cp, tp);
16037502Sroot 	for (cp = tp->t_rawq.c_cf; cp; cp = nextc(&tp->t_rawq, cp))
16047502Sroot 		ttyecho(*cp, tp);
16059578Ssam 	tp->t_state &= ~TS_ERASE;
16067502Sroot 	splx(s);
16077502Sroot 	tp->t_rocount = tp->t_rawq.c_cc;
16087502Sroot 	tp->t_rocol = 0;
16097502Sroot }
16107502Sroot 
16117502Sroot /*
16127502Sroot  * Echo a typed character to the terminal
16137502Sroot  */
16147502Sroot ttyecho(c, tp)
16157625Ssam 	register c;
16167625Ssam 	register struct tty *tp;
16177502Sroot {
16187502Sroot 
16199578Ssam 	if ((tp->t_state&TS_CNTTB) == 0)
16209578Ssam 		tp->t_flags &= ~FLUSHO;
16217502Sroot 	if ((tp->t_flags&ECHO) == 0)
16227502Sroot 		return;
16237502Sroot 	c &= 0377;
16247502Sroot 	if (tp->t_flags&RAW) {
16257502Sroot 		(void) ttyoutput(c, tp);
16267502Sroot 		return;
16277502Sroot 	}
16287502Sroot 	if (c == '\r' && tp->t_flags&CRMOD)
16297502Sroot 		c = '\n';
16309578Ssam 	if (tp->t_flags&CTLECH) {
16317502Sroot 		if ((c&0177) <= 037 && c!='\t' && c!='\n' || (c&0177)==0177) {
16327502Sroot 			(void) ttyoutput('^', tp);
16337502Sroot 			c &= 0177;
16347502Sroot 			if (c == 0177)
16357502Sroot 				c = '?';
16367502Sroot 			else if (tp->t_flags&LCASE)
16377502Sroot 				c += 'a' - 1;
16387502Sroot 			else
16397502Sroot 				c += 'A' - 1;
16407502Sroot 		}
16417502Sroot 	}
16429578Ssam 	(void) ttyoutput(c&0177, tp);
16437502Sroot }
16447502Sroot 
16457502Sroot /*
16467502Sroot  * Is c a break char for tp?
16477502Sroot  */
16487502Sroot ttbreakc(c, tp)
16497625Ssam 	register c;
16507625Ssam 	register struct tty *tp;
16517502Sroot {
16529578Ssam 	return (c == '\n' || c == tp->t_eofc || c == tp->t_brkc ||
16537502Sroot 		c == '\r' && (tp->t_flags&CRMOD));
16547502Sroot }
16557502Sroot 
16567502Sroot /*
16577502Sroot  * send string cp to tp
16587502Sroot  */
16597502Sroot ttyout(cp, tp)
16607625Ssam 	register char *cp;
16617625Ssam 	register struct tty *tp;
16627502Sroot {
16637502Sroot 	register char c;
16647502Sroot 
16657502Sroot 	while (c = *cp++)
16667502Sroot 		(void) ttyoutput(c, tp);
16677502Sroot }
16687502Sroot 
16697502Sroot ttwakeup(tp)
16707502Sroot 	struct tty *tp;
16717502Sroot {
16727502Sroot 
16737502Sroot 	if (tp->t_rsel) {
16747502Sroot 		selwakeup(tp->t_rsel, tp->t_state&TS_RCOLL);
16757502Sroot 		tp->t_state &= ~TS_RCOLL;
16767502Sroot 		tp->t_rsel = 0;
16777502Sroot 	}
167812752Ssam 	if (tp->t_state & TS_ASYNC)
167912752Ssam 		gsignal(tp->t_pgrp, SIGIO);
16807502Sroot 	wakeup((caddr_t)&tp->t_rawq);
16817502Sroot }
1682