xref: /csrg-svn/sys/kern/tty.c (revision 34492)
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*34492Skarels  *	@(#)tty.c	7.12 (Berkeley) 05/26/88
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 "file.h"
1917095Sbloom #include "conf.h"
2029946Skarels #include "dkstat.h"
2117095Sbloom #include "uio.h"
2217095Sbloom #include "kernel.h"
2339Sbill 
247436Skre /*
257436Skre  * Table giving parity for characters and indicating
267436Skre  * character classes to tty driver.  In particular,
277436Skre  * if the low 6 bits are 0, then the character needs
287436Skre  * no special processing on output.
297436Skre  */
3039Sbill 
317436Skre char partab[] = {
327436Skre 	0001,0201,0201,0001,0201,0001,0001,0201,
337436Skre 	0202,0004,0003,0201,0005,0206,0201,0001,
347436Skre 	0201,0001,0001,0201,0001,0201,0201,0001,
357436Skre 	0001,0201,0201,0001,0201,0001,0001,0201,
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 	0200,0000,0000,0200,0000,0200,0200,0000,
417436Skre 	0000,0200,0200,0000,0200,0000,0000,0200,
427436Skre 	0000,0200,0200,0000,0200,0000,0000,0200,
437436Skre 	0200,0000,0000,0200,0000,0200,0200,0000,
447436Skre 	0000,0200,0200,0000,0200,0000,0000,0200,
457436Skre 	0200,0000,0000,0200,0000,0200,0200,0000,
467436Skre 	0200,0000,0000,0200,0000,0200,0200,0000,
477436Skre 	0000,0200,0200,0000,0200,0000,0000,0201,
487436Skre 
497436Skre 	/*
507436Skre 	 * 7 bit ascii ends with the last character above,
517436Skre 	 * but we contine through all 256 codes for the sake
527436Skre 	 * of the tty output routines which use special vax
537436Skre 	 * instructions which need a 256 character trt table.
547436Skre 	 */
557436Skre 
567436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
577436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
587436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
597436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
607436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
617436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
627436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
637436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
647436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
657436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
667436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
677436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
687436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
697436Skre 	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 };
737436Skre 
74146Sbill /*
7539Sbill  * Input mapping table-- if an entry is non-zero, when the
7639Sbill  * corresponding character is typed preceded by "\" the escape
7739Sbill  * sequence is replaced by the table value.  Mostly used for
7839Sbill  * upper-case only terminals.
7939Sbill  */
8039Sbill char	maptab[] ={
8139Sbill 	000,000,000,000,000,000,000,000,
8239Sbill 	000,000,000,000,000,000,000,000,
8339Sbill 	000,000,000,000,000,000,000,000,
8439Sbill 	000,000,000,000,000,000,000,000,
8539Sbill 	000,'|',000,000,000,000,000,'`',
8639Sbill 	'{','}',000,000,000,000,000,000,
8739Sbill 	000,000,000,000,000,000,000,000,
8839Sbill 	000,000,000,000,000,000,000,000,
8939Sbill 	000,000,000,000,000,000,000,000,
9039Sbill 	000,000,000,000,000,000,000,000,
9139Sbill 	000,000,000,000,000,000,000,000,
9239Sbill 	000,000,000,000,000,000,'~',000,
9339Sbill 	000,'A','B','C','D','E','F','G',
9439Sbill 	'H','I','J','K','L','M','N','O',
9539Sbill 	'P','Q','R','S','T','U','V','W',
9639Sbill 	'X','Y','Z',000,000,000,000,000,
9739Sbill };
9839Sbill 
99925Sbill short	tthiwat[16] =
1008954Sroot    { 100,100,100,100,100,100,100,200,200,400,400,400,650,650,1300,2000 };
101925Sbill short	ttlowat[16] =
102925Sbill    {  30, 30, 30, 30, 30, 30, 30, 50, 50,120,120,120,125,125,125,125 };
103925Sbill 
104*34492Skarels struct	ttychars ttydefaults = {
105*34492Skarels 	CERASE,	CKILL,	CINTR,	CQUIT,	CSTART,	CSTOP,	CEOF,
106*34492Skarels 	CBRK,	CSUSP,	CDSUSP, CRPRNT, CFLUSH, CWERASE,CLNEXT
107*34492Skarels };
108*34492Skarels 
10930534Skarels extern struct tty *constty;		/* temporary virtual console */
11030534Skarels 
11139Sbill ttychars(tp)
1129578Ssam 	struct tty *tp;
11339Sbill {
114*34492Skarels 
115*34492Skarels 	tp->t_chars = ttydefaults;
11639Sbill }
11739Sbill 
11839Sbill /*
119903Sbill  * Wait for output to drain, then flush input waiting.
12039Sbill  */
12112752Ssam ttywflush(tp)
1225408Swnj 	register struct tty *tp;
12339Sbill {
12439Sbill 
12512752Ssam 	ttywait(tp);
12612752Ssam 	ttyflush(tp, FREAD);
12712752Ssam }
12812752Ssam 
12912752Ssam ttywait(tp)
13012752Ssam 	register struct tty *tp;
13112752Ssam {
13217545Skarels 	register int s = spltty();
13312752Ssam 
13413809Ssam 	while ((tp->t_outq.c_cc || tp->t_state&TS_BUSY) &&
13532336Smckusick 	    tp->t_state&TS_CARR_ON && tp->t_oproc) {
136903Sbill 		(*tp->t_oproc)(tp);
1375408Swnj 		tp->t_state |= TS_ASLEEP;
138903Sbill 		sleep((caddr_t)&tp->t_outq, TTOPRI);
139903Sbill 	}
1409859Ssam 	splx(s);
14139Sbill }
14239Sbill 
14339Sbill /*
1449578Ssam  * Flush all TTY queues
14539Sbill  */
14612752Ssam ttyflush(tp, rw)
1477625Ssam 	register struct tty *tp;
14839Sbill {
149903Sbill 	register s;
150903Sbill 
15117545Skarels 	s = spltty();
152903Sbill 	if (rw & FREAD) {
153903Sbill 		while (getc(&tp->t_canq) >= 0)
154903Sbill 			;
155903Sbill 		wakeup((caddr_t)&tp->t_rawq);
156903Sbill 	}
157903Sbill 	if (rw & FWRITE) {
158903Sbill 		wakeup((caddr_t)&tp->t_outq);
1595408Swnj 		tp->t_state &= ~TS_TTSTOP;
1605426Swnj 		(*cdevsw[major(tp->t_dev)].d_stop)(tp, rw);
161903Sbill 		while (getc(&tp->t_outq) >= 0)
162903Sbill 			;
163903Sbill 	}
164903Sbill 	if (rw & FREAD) {
165903Sbill 		while (getc(&tp->t_rawq) >= 0)
166903Sbill 			;
1679578Ssam 		tp->t_rocount = 0;
168903Sbill 		tp->t_rocol = 0;
1699578Ssam 		tp->t_state &= ~TS_LOCAL;
170903Sbill 	}
171903Sbill 	splx(s);
17239Sbill }
17339Sbill 
174903Sbill /*
175903Sbill  * Send stop character on input overflow.
176903Sbill  */
177903Sbill ttyblock(tp)
1787625Ssam 	register struct tty *tp;
17939Sbill {
180903Sbill 	register x;
1819578Ssam 
182903Sbill 	x = tp->t_rawq.c_cc + tp->t_canq.c_cc;
183903Sbill 	if (tp->t_rawq.c_cc > TTYHOG) {
18412752Ssam 		ttyflush(tp, FREAD|FWRITE);
1855408Swnj 		tp->t_state &= ~TS_TBLOCK;
186903Sbill 	}
18715118Skarels 	/*
18815118Skarels 	 * Block further input iff:
18915118Skarels 	 * Current input > threshold AND input is available to user program
19015118Skarels 	 */
19116055Skarels 	if (x >= TTYHOG/2 &&
192*34492Skarels 	    ((tp->t_flags & (RAW|CBREAK)) || (tp->t_canq.c_cc > 0))) {
193*34492Skarels 		if (putc(tp->t_stopc, &tp->t_outq)==0) {
19415118Skarels 			tp->t_state |= TS_TBLOCK;
19515118Skarels 			ttstart(tp);
19615118Skarels 		}
197903Sbill 	}
19839Sbill }
19939Sbill 
20039Sbill /*
201903Sbill  * Restart typewriter output following a delay
202903Sbill  * timeout.
203903Sbill  * The name of the routine is passed to the timeout
204903Sbill  * subroutine and it is called during a clock interrupt.
205121Sbill  */
206903Sbill ttrstrt(tp)
2077625Ssam 	register struct tty *tp;
208121Sbill {
209121Sbill 
2109578Ssam 	if (tp == 0)
2119578Ssam 		panic("ttrstrt");
2125408Swnj 	tp->t_state &= ~TS_TIMEOUT;
213903Sbill 	ttstart(tp);
214121Sbill }
215121Sbill 
216121Sbill /*
217903Sbill  * Start output on the typewriter. It is used from the top half
218903Sbill  * after some characters have been put on the output queue,
219903Sbill  * from the interrupt routine to transmit the next
220903Sbill  * character, and after a timeout has finished.
22139Sbill  */
222903Sbill ttstart(tp)
2237625Ssam 	register struct tty *tp;
22439Sbill {
22539Sbill 
22632067Skarels 	if (tp->t_oproc)		/* kludge for pty */
227903Sbill 		(*tp->t_oproc)(tp);
22839Sbill }
22939Sbill 
23039Sbill /*
231903Sbill  * Common code for tty ioctls.
23239Sbill  */
2331780Sbill /*ARGSUSED*/
2347625Ssam ttioctl(tp, com, data, flag)
2357625Ssam 	register struct tty *tp;
2367625Ssam 	caddr_t data;
23739Sbill {
238*34492Skarels 	int dev = tp->t_dev;
23939Sbill 	extern int nldisp;
2408556Sroot 	int s;
241*34492Skarels 	register int newflags;
24239Sbill 
24330534Skarels 
244903Sbill 	/*
245903Sbill 	 * If the ioctl involves modification,
24617545Skarels 	 * hang if in the background.
247903Sbill 	 */
2487625Ssam 	switch (com) {
24939Sbill 
250*34492Skarels 	case TIOCSETD:
251*34492Skarels 	case TIOCSETP:
252*34492Skarels 	case TIOCSETN:
253903Sbill 	case TIOCFLUSH:
254*34492Skarels 	case TIOCSETC:
255*34492Skarels 	case TIOCSLTC:
256903Sbill 	case TIOCSPGRP:
257*34492Skarels 	case TIOCLBIS:
258*34492Skarels 	case TIOCLBIC:
259*34492Skarels 	case TIOCLSET:
2609325Ssam 	case TIOCSTI:
26117598Sbloom 	case TIOCSWINSZ:
262*34492Skarels 		while (tp->t_line == NTTYDISC &&
263903Sbill 		   u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp &&
264903Sbill 		   (u.u_procp->p_flag&SVFORK) == 0 &&
26524392Skarels 		   !(u.u_procp->p_sigignore & sigmask(SIGTTOU)) &&
26624392Skarels 		   !(u.u_procp->p_sigmask & sigmask(SIGTTOU))) {
267903Sbill 			gsignal(u.u_procp->p_pgrp, SIGTTOU);
268903Sbill 			sleep((caddr_t)&lbolt, TTOPRI);
269903Sbill 		}
270903Sbill 		break;
271903Sbill 	}
272903Sbill 
2739578Ssam 	/*
2749578Ssam 	 * Process the ioctl.
2759578Ssam 	 */
2767625Ssam 	switch (com) {
277903Sbill 
2788556Sroot 	/* get discipline number */
27939Sbill 	case TIOCGETD:
2807625Ssam 		*(int *)data = tp->t_line;
28139Sbill 		break;
28239Sbill 
2838556Sroot 	/* set line discipline */
2847625Ssam 	case TIOCSETD: {
2857625Ssam 		register int t = *(int *)data;
2869578Ssam 		int error = 0;
2877625Ssam 
28815078Skarels 		if ((unsigned) t >= nldisp)
28910851Ssam 			return (ENXIO);
29025584Skarels 		if (t != tp->t_line) {
29125584Skarels 			s = spltty();
29225584Skarels 			(*linesw[tp->t_line].l_close)(tp);
29325584Skarels 			error = (*linesw[t].l_open)(dev, tp);
29425584Skarels 			if (error) {
295*34492Skarels 				(void) (*linesw[tp->t_line].l_open)(dev, tp);
29625584Skarels 				splx(s);
29725584Skarels 				return (error);
29825584Skarels 			}
29925584Skarels 			tp->t_line = t;
30010851Ssam 			splx(s);
30110851Ssam 		}
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 
314*34492Skarels 	/* hang up line on last close */
31539Sbill 	case TIOCHPCL:
316*34492Skarels 		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();
350*34492Skarels 		if ((tp->t_state&TS_TTSTOP) || (tp->t_flags&FLUSHO)) {
3515573Swnj 			tp->t_state &= ~TS_TTSTOP;
352*34492Skarels 			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 
369*34492Skarels 	case TIOCSETP:
370*34492Skarels 	case TIOCSETN: {
371*34492Skarels 		register struct sgttyb *sg = (struct sgttyb *)data;
37212752Ssam 
373*34492Skarels 		tp->t_erase = sg->sg_erase;
374*34492Skarels 		tp->t_kill = sg->sg_kill;
375*34492Skarels 		tp->t_ispeed = sg->sg_ispeed;
376*34492Skarels 		tp->t_ospeed = sg->sg_ospeed;
377*34492Skarels 		newflags = (tp->t_flags&0xffff0000) | (sg->sg_flags&0xffff);
37817545Skarels 		s = spltty();
379*34492Skarels 		if (tp->t_flags&RAW || newflags&RAW || com == TIOCSETP) {
380*34492Skarels 			ttywait(tp);
381*34492Skarels 			ttyflush(tp, FREAD);
382*34492Skarels 		} else if ((tp->t_flags&CBREAK) != (newflags&CBREAK)) {
383*34492Skarels 			if (newflags&CBREAK) {
384*34492Skarels 				struct clist tq;
38512752Ssam 
386*34492Skarels 				catq(&tp->t_rawq, &tp->t_canq);
387*34492Skarels 				tq = tp->t_rawq;
388*34492Skarels 				tp->t_rawq = tp->t_canq;
389*34492Skarels 				tp->t_canq = tq;
390*34492Skarels 			} else {
391*34492Skarels 				tp->t_flags |= PENDIN;
392*34492Skarels 				newflags |= PENDIN;
393*34492Skarels 				ttwakeup(tp);
394*34492Skarels 			}
39512752Ssam 		}
396*34492Skarels 		tp->t_flags = newflags;
397*34492Skarels 		if (tp->t_flags&RAW) {
398*34492Skarels 			tp->t_state &= ~TS_TTSTOP;
399*34492Skarels 			ttstart(tp);
40012752Ssam 		}
40112752Ssam 		splx(s);
40212752Ssam 		break;
40312752Ssam 	}
40412752Ssam 
405*34492Skarels 	/* send current parameters to user */
406*34492Skarels 	case TIOCGETP: {
407*34492Skarels 		register struct sgttyb *sg = (struct sgttyb *)data;
408*34492Skarels 
409*34492Skarels 		sg->sg_ispeed = tp->t_ispeed;
410*34492Skarels 		sg->sg_ospeed = tp->t_ospeed;
411*34492Skarels 		sg->sg_erase = tp->t_erase;
412*34492Skarels 		sg->sg_kill = tp->t_kill;
413*34492Skarels 		sg->sg_flags = tp->t_flags;
41412752Ssam 		break;
415*34492Skarels 	}
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 
431*34492Skarels 	case TIOCGETC:
432*34492Skarels 		bcopy((caddr_t)&tp->t_intrc, data, sizeof (struct tchars));
433*34492Skarels 		break;
43413077Ssam 
435*34492Skarels 	case TIOCSETC:
436*34492Skarels 		bcopy(data, (caddr_t)&tp->t_intrc, sizeof (struct tchars));
437*34492Skarels 		break;
438*34492Skarels 
439*34492Skarels 	/* set/get local special characters */
440*34492Skarels 	case TIOCSLTC:
441*34492Skarels 		bcopy(data, (caddr_t)&tp->t_suspc, sizeof (struct ltchars));
442*34492Skarels 		break;
443*34492Skarels 
444*34492Skarels 	case TIOCGLTC:
445*34492Skarels 		bcopy((caddr_t)&tp->t_suspc, data, sizeof (struct ltchars));
446*34492Skarels 		break;
447*34492Skarels 
44812752Ssam 	/*
449*34492Skarels 	 * Modify local mode word.
450*34492Skarels 	 */
451*34492Skarels 	case TIOCLBIS:
452*34492Skarels 		tp->t_flags |= *(int *)data << 16;
453*34492Skarels 		break;
454*34492Skarels 
455*34492Skarels 	case TIOCLBIC:
456*34492Skarels 		tp->t_flags &= ~(*(int *)data << 16);
457*34492Skarels 		break;
458*34492Skarels 
459*34492Skarels 	case TIOCLSET:
460*34492Skarels 		tp->t_flags &= 0xffff;
461*34492Skarels 		tp->t_flags |= *(int *)data << 16;
462*34492Skarels 		break;
463*34492Skarels 
464*34492Skarels 	case TIOCLGET:
465*34492Skarels 		*(int *)data = ((unsigned)tp->t_flags) >> 16;
466*34492Skarels 		break;
467*34492Skarels 
468*34492Skarels 	/*
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 
50430534Skarels 	case TIOCCONS:
50530534Skarels 		if (*(int *)data) {
50630534Skarels 			if (constty != NULL)
50730534Skarels 				return (EBUSY);
50830534Skarels #ifndef	UCONSOLE
50930534Skarels 			if (!suser())
51030534Skarels 				return (EPERM);
51130534Skarels #endif
51230534Skarels 			constty = tp;
51330534Skarels 		} else if (tp == constty)
51433404Skarels 			constty = NULL;
51530534Skarels 		break;
51630534Skarels 
51739Sbill 	default:
5188556Sroot 		return (-1);
51939Sbill 	}
5208556Sroot 	return (0);
52139Sbill }
5224484Swnj 
5234484Swnj ttnread(tp)
5244484Swnj 	struct tty *tp;
5254484Swnj {
5264484Swnj 	int nread = 0;
5274484Swnj 
528*34492Skarels 	if (tp->t_flags & PENDIN)
5294484Swnj 		ttypend(tp);
5304484Swnj 	nread = tp->t_canq.c_cc;
531*34492Skarels 	if (tp->t_flags & (RAW|CBREAK))
5324484Swnj 		nread += tp->t_rawq.c_cc;
5334484Swnj 	return (nread);
5344484Swnj }
5354484Swnj 
5365408Swnj ttselect(dev, rw)
5374484Swnj 	dev_t dev;
5385408Swnj 	int rw;
5394484Swnj {
5404484Swnj 	register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)];
5414484Swnj 	int nread;
54217545Skarels 	int s = spltty();
5434484Swnj 
5445408Swnj 	switch (rw) {
5454484Swnj 
5464484Swnj 	case FREAD:
5474484Swnj 		nread = ttnread(tp);
54829946Skarels 		if (nread > 0 || (tp->t_state & TS_CARR_ON) == 0)
5495408Swnj 			goto win;
5504938Swnj 		if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait)
5515408Swnj 			tp->t_state |= TS_RCOLL;
5524484Swnj 		else
5534484Swnj 			tp->t_rsel = u.u_procp;
5545408Swnj 		break;
5554484Swnj 
5565408Swnj 	case FWRITE:
5575408Swnj 		if (tp->t_outq.c_cc <= TTLOWAT(tp))
5585408Swnj 			goto win;
5595408Swnj 		if (tp->t_wsel && tp->t_wsel->p_wchan == (caddr_t)&selwait)
5605408Swnj 			tp->t_state |= TS_WCOLL;
5615408Swnj 		else
5625408Swnj 			tp->t_wsel = u.u_procp;
5635408Swnj 		break;
5644484Swnj 	}
5655408Swnj 	splx(s);
5665408Swnj 	return (0);
5675408Swnj win:
5685408Swnj 	splx(s);
5695408Swnj 	return (1);
5704484Swnj }
5717436Skre 
5727502Sroot /*
57325391Skarels  * Initial open of tty, or (re)entry to line discipline.
5749578Ssam  * Establish a process group for distribution of
5757502Sroot  * quits and interrupts from the tty.
5767502Sroot  */
5777502Sroot ttyopen(dev, tp)
5787625Ssam 	dev_t dev;
5797625Ssam 	register struct tty *tp;
5807502Sroot {
5817502Sroot 	register struct proc *pp;
5827502Sroot 
5837502Sroot 	pp = u.u_procp;
5847502Sroot 	tp->t_dev = dev;
585*34492Skarels 	if (pp->p_pgrp == 0) {
5867502Sroot 		u.u_ttyp = tp;
5877502Sroot 		u.u_ttyd = dev;
5887502Sroot 		if (tp->t_pgrp == 0)
5897502Sroot 			tp->t_pgrp = pp->p_pid;
5907502Sroot 		pp->p_pgrp = tp->t_pgrp;
5917502Sroot 	}
5927502Sroot 	tp->t_state &= ~TS_WOPEN;
59317545Skarels 	if ((tp->t_state & TS_ISOPEN) == 0) {
59417545Skarels 		tp->t_state |= TS_ISOPEN;
59517598Sbloom 		bzero((caddr_t)&tp->t_winsize, sizeof(tp->t_winsize));
596*34492Skarels 		if (tp->t_line != NTTYDISC)
597*34492Skarels 			ttywflush(tp);
59817545Skarels 	}
5998556Sroot 	return (0);
6007502Sroot }
6017502Sroot 
6027502Sroot /*
60325391Skarels  * "close" a line discipline
60425391Skarels  */
60525391Skarels ttylclose(tp)
60625391Skarels 	register struct tty *tp;
60725391Skarels {
60825391Skarels 
60925391Skarels 	ttywflush(tp);
610*34492Skarels 	tp->t_line = 0;
61125391Skarels }
61225391Skarels 
61325391Skarels /*
6147502Sroot  * clean tp on last close
6157502Sroot  */
6167502Sroot ttyclose(tp)
6177625Ssam 	register struct tty *tp;
6187502Sroot {
6197502Sroot 
62030534Skarels 	if (constty == tp)
62130534Skarels 		constty = NULL;
62225391Skarels 	ttyflush(tp, FREAD|FWRITE);
6237502Sroot 	tp->t_pgrp = 0;
6247502Sroot 	tp->t_state = 0;
6257502Sroot }
6267502Sroot 
6277502Sroot /*
62825391Skarels  * Handle modem control transition on a tty.
62925391Skarels  * Flag indicates new state of carrier.
63025391Skarels  * Returns 0 if the line should be turned off, otherwise 1.
63125391Skarels  */
63225391Skarels ttymodem(tp, flag)
63325391Skarels 	register struct tty *tp;
63425391Skarels {
63525391Skarels 
636*34492Skarels 	if ((tp->t_state&TS_WOPEN) == 0 && (tp->t_flags & MDMBUF)) {
63725391Skarels 		/*
63825391Skarels 		 * MDMBUF: do flow control according to carrier flag
63925391Skarels 		 */
64025391Skarels 		if (flag) {
64125391Skarels 			tp->t_state &= ~TS_TTSTOP;
64225391Skarels 			ttstart(tp);
64325391Skarels 		} else if ((tp->t_state&TS_TTSTOP) == 0) {
64425391Skarels 			tp->t_state |= TS_TTSTOP;
64525391Skarels 			(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
64625391Skarels 		}
64725391Skarels 	} else if (flag == 0) {
64825391Skarels 		/*
64925391Skarels 		 * Lost carrier.
65025391Skarels 		 */
65125391Skarels 		tp->t_state &= ~TS_CARR_ON;
65225391Skarels 		if (tp->t_state & TS_ISOPEN) {
653*34492Skarels 			if ((tp->t_flags & NOHANG) == 0) {
65425391Skarels 				gsignal(tp->t_pgrp, SIGHUP);
65525391Skarels 				gsignal(tp->t_pgrp, SIGCONT);
65625391Skarels 				ttyflush(tp, FREAD|FWRITE);
65725391Skarels 				return (0);
65825391Skarels 			}
65925391Skarels 		}
66025391Skarels 	} else {
66125391Skarels 		/*
66225391Skarels 		 * Carrier now on.
66325391Skarels 		 */
66425391Skarels 		tp->t_state |= TS_CARR_ON;
66525391Skarels 		wakeup((caddr_t)&tp->t_rawq);
66625391Skarels 	}
66725391Skarels 	return (1);
66825391Skarels }
66925391Skarels 
67025391Skarels /*
67125404Skarels  * Default modem control routine (for other line disciplines).
67225404Skarels  * Return argument flag, to turn off device on carrier drop.
67325404Skarels  */
67425415Skarels nullmodem(tp, flag)
67525415Skarels 	register struct tty *tp;
67625404Skarels 	int flag;
67725404Skarels {
67825404Skarels 
67925404Skarels 	if (flag)
68025404Skarels 		tp->t_state |= TS_CARR_ON;
68125404Skarels 	else
68225404Skarels 		tp->t_state &= ~TS_CARR_ON;
68325404Skarels 	return (flag);
68425404Skarels }
68525404Skarels 
68625404Skarels /*
6877502Sroot  * reinput pending characters after state switch
68817545Skarels  * call at spltty().
6897502Sroot  */
6907502Sroot ttypend(tp)
6917625Ssam 	register struct tty *tp;
6927502Sroot {
6937502Sroot 	struct clist tq;
6947502Sroot 	register c;
6957502Sroot 
696*34492Skarels 	tp->t_flags &= ~PENDIN;
6979578Ssam 	tp->t_state |= TS_TYPEN;
6987502Sroot 	tq = tp->t_rawq;
6997502Sroot 	tp->t_rawq.c_cc = 0;
7007502Sroot 	tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0;
7017502Sroot 	while ((c = getc(&tq)) >= 0)
7027502Sroot 		ttyinput(c, tp);
7039578Ssam 	tp->t_state &= ~TS_TYPEN;
7047502Sroot }
7057502Sroot 
7067502Sroot /*
7079578Ssam  * Place a character on raw TTY input queue,
7089578Ssam  * putting in delimiters and waking up top
7099578Ssam  * half as needed.  Also echo if required.
7109578Ssam  * The arguments are the character and the
7119578Ssam  * appropriate tty structure.
7127502Sroot  */
7137502Sroot ttyinput(c, tp)
7147625Ssam 	register c;
7157625Ssam 	register struct tty *tp;
7167502Sroot {
717*34492Skarels 	register int t_flags = tp->t_flags;
718*34492Skarels 	int i;
7197502Sroot 
7209578Ssam 	/*
7219578Ssam 	 * If input is pending take it first.
7229578Ssam 	 */
723*34492Skarels 	if (t_flags&PENDIN)
7247502Sroot 		ttypend(tp);
7257502Sroot 	tk_nin++;
726*34492Skarels 	c &= 0377;
7279578Ssam 
7289578Ssam 	/*
729*34492Skarels 	 * In tandem mode, check high water mark.
7309578Ssam 	 */
731*34492Skarels 	if (t_flags&TANDEM)
732*34492Skarels 		ttyblock(tp);
733*34492Skarels 
734*34492Skarels 	if (t_flags&RAW) {
735*34492Skarels 		/*
736*34492Skarels 		 * Raw mode, just put character
737*34492Skarels 		 * in input q w/o interpretation.
738*34492Skarels 		 */
739*34492Skarels 		if (tp->t_rawq.c_cc > TTYHOG)
740*34492Skarels 			ttyflush(tp, FREAD|FWRITE);
741*34492Skarels 		else {
742*34492Skarels 			if (putc(c, &tp->t_rawq) >= 0)
743*34492Skarels 				ttwakeup(tp);
744*34492Skarels 			ttyecho(c, tp);
7457502Sroot 		}
746*34492Skarels 		goto endcase;
7479578Ssam 	}
7489578Ssam 
7499578Ssam 	/*
7509578Ssam 	 * Ignore any high bit added during
7519578Ssam 	 * previous ttyinput processing.
7529578Ssam 	 */
753*34492Skarels 	if ((tp->t_state&TS_TYPEN) == 0 && (t_flags&PASS8) == 0)
7549578Ssam 		c &= 0177;
7559578Ssam 	/*
7569578Ssam 	 * Check for literal nexting very first
7579578Ssam 	 */
7589578Ssam 	if (tp->t_state&TS_LNCH) {
7599578Ssam 		c |= 0200;
7609578Ssam 		tp->t_state &= ~TS_LNCH;
7619578Ssam 	}
7629578Ssam 
7639578Ssam 	/*
7649578Ssam 	 * Scan for special characters.  This code
7659578Ssam 	 * is really just a big case statement with
7669578Ssam 	 * non-constant cases.  The bottom of the
7679578Ssam 	 * case statement is labeled ``endcase'', so goto
7689578Ssam 	 * it after a case match, or similar.
7699578Ssam 	 */
770*34492Skarels 	if (tp->t_line == NTTYDISC) {
771*34492Skarels 		if (c == tp->t_lnextc) {
772*34492Skarels 			if (t_flags&ECHO)
773*34492Skarels 				ttyout("^\b", tp);
7749578Ssam 			tp->t_state |= TS_LNCH;
7759578Ssam 			goto endcase;
7769578Ssam 		}
777*34492Skarels 		if (c == tp->t_flushc) {
778*34492Skarels 			if (t_flags&FLUSHO)
779*34492Skarels 				tp->t_flags &= ~FLUSHO;
7807502Sroot 			else {
78112752Ssam 				ttyflush(tp, FWRITE);
7827502Sroot 				ttyecho(c, tp);
7839578Ssam 				if (tp->t_rawq.c_cc + tp->t_canq.c_cc)
7847502Sroot 					ttyretype(tp);
785*34492Skarels 				tp->t_flags |= FLUSHO;
7867502Sroot 			}
7879578Ssam 			goto startoutput;
7889578Ssam 		}
789*34492Skarels 		if (c == tp->t_suspc) {
790*34492Skarels 			if ((t_flags&NOFLSH) == 0)
79112752Ssam 				ttyflush(tp, FREAD);
7929578Ssam 			ttyecho(c, tp);
7939578Ssam 			gsignal(tp->t_pgrp, SIGTSTP);
7949578Ssam 			goto endcase;
7959578Ssam 		}
7969578Ssam 	}
7979578Ssam 
7989578Ssam 	/*
7999578Ssam 	 * Handle start/stop characters.
8009578Ssam 	 */
801*34492Skarels 	if (c == tp->t_stopc) {
802*34492Skarels 		if ((tp->t_state&TS_TTSTOP) == 0) {
803*34492Skarels 			tp->t_state |= TS_TTSTOP;
804*34492Skarels 			(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
805*34492Skarels 			return;
8069578Ssam 		}
807*34492Skarels 		if (c != tp->t_startc)
808*34492Skarels 			return;
809*34492Skarels 		goto endcase;
8109578Ssam 	}
811*34492Skarels 	if (c == tp->t_startc)
812*34492Skarels 		goto restartoutput;
8139578Ssam 
8149578Ssam 	/*
815*34492Skarels 	 * Look for interrupt/quit chars.
8169578Ssam 	 */
817*34492Skarels 	if (c == tp->t_intrc || c == tp->t_quitc) {
818*34492Skarels 		if ((t_flags&NOFLSH) == 0)
819*34492Skarels 			ttyflush(tp, FREAD|FWRITE);
820*34492Skarels 		ttyecho(c, tp);
821*34492Skarels 		gsignal(tp->t_pgrp, c == tp->t_intrc ? SIGINT : SIGQUIT);
822*34492Skarels 		goto endcase;
8239578Ssam 	}
8249578Ssam 
82523165Sbloom 	if (tp->t_flags & LCASE && c <= 0177) {
82623165Sbloom 		if (tp->t_state&TS_BKSL) {
82723165Sbloom 			ttyrub(unputc(&tp->t_rawq), tp);
82823165Sbloom 			if (maptab[c])
82923165Sbloom 				c = maptab[c];
83023165Sbloom 			c |= 0200;
83123165Sbloom 			tp->t_state &= ~(TS_BKSL|TS_QUOT);
83223165Sbloom 		} else if (c >= 'A' && c <= 'Z')
83323165Sbloom 			c += 'a' - 'A';
83423165Sbloom 		else if (c == '\\')
83523165Sbloom 			tp->t_state |= TS_BKSL;
83623165Sbloom 	}
83723165Sbloom 
8389578Ssam 	/*
839*34492Skarels 	 * Cbreak mode, don't process line editing
8409578Ssam 	 * characters; check high water mark for wakeup.
8419578Ssam 	 */
842*34492Skarels 	if (t_flags&CBREAK) {
8439578Ssam 		if (tp->t_rawq.c_cc > TTYHOG) {
844*34492Skarels 			if (tp->t_outq.c_cc < TTHIWAT(tp) &&
845*34492Skarels 			    tp->t_line == NTTYDISC)
846*34492Skarels 				(void) ttyoutput(CTRL('g'), tp);
8477502Sroot 		} else if (putc(c, &tp->t_rawq) >= 0) {
8487502Sroot 			ttwakeup(tp);
8497502Sroot 			ttyecho(c, tp);
8507502Sroot 		}
8519578Ssam 		goto endcase;
8529578Ssam 	}
8539578Ssam 
8549578Ssam 	/*
855*34492Skarels 	 * From here on down cooked mode character
8569578Ssam 	 * processing takes place.
8579578Ssam 	 */
8589578Ssam 	if ((tp->t_state&TS_QUOT) &&
859*34492Skarels 	    (c == tp->t_erase || c == tp->t_kill)) {
8609578Ssam 		ttyrub(unputc(&tp->t_rawq), tp);
8619578Ssam 		c |= 0200;
8629578Ssam 	}
863*34492Skarels 	if (c == tp->t_erase) {
8649578Ssam 		if (tp->t_rawq.c_cc)
8659578Ssam 			ttyrub(unputc(&tp->t_rawq), tp);
8669578Ssam 		goto endcase;
8679578Ssam 	}
868*34492Skarels 	if (c == tp->t_kill) {
869*34492Skarels 		if (t_flags&CRTKIL &&
8709578Ssam 		    tp->t_rawq.c_cc == tp->t_rocount) {
8719578Ssam 			while (tp->t_rawq.c_cc)
8729578Ssam 				ttyrub(unputc(&tp->t_rawq), tp);
8739578Ssam 		} else {
8749578Ssam 			ttyecho(c, tp);
875*34492Skarels 			ttyecho('\n', tp);
8769578Ssam 			while (getc(&tp->t_rawq) > 0)
8779578Ssam 				;
8789578Ssam 			tp->t_rocount = 0;
8799578Ssam 		}
8809578Ssam 		tp->t_state &= ~TS_LOCAL;
8819578Ssam 		goto endcase;
8829578Ssam 	}
8839578Ssam 
8849578Ssam 	/*
885*34492Skarels 	 * New line discipline,
886*34492Skarels 	 * check word erase/reprint line.
8879578Ssam 	 */
888*34492Skarels 	if (tp->t_line == NTTYDISC) {
889*34492Skarels 		if (c == tp->t_werasc) {
8909578Ssam 			if (tp->t_rawq.c_cc == 0)
8919578Ssam 				goto endcase;
892*34492Skarels 			do {
893*34492Skarels 				c = unputc(&tp->t_rawq);
894*34492Skarels 				if (c != ' ' && c != '\t')
895*34492Skarels 					goto erasenb;
896*34492Skarels 				ttyrub(c, tp);
897*34492Skarels 			} while (tp->t_rawq.c_cc);
898*34492Skarels 			goto endcase;
899*34492Skarels 	erasenb:
900*34492Skarels 			do {
901*34492Skarels 				ttyrub(c, tp);
902*34492Skarels 				if (tp->t_rawq.c_cc == 0)
903*34492Skarels 					goto endcase;
904*34492Skarels 				c = unputc(&tp->t_rawq);
905*34492Skarels 			} while (c != ' ' && c != '\t');
906*34492Skarels 			(void) putc(c, &tp->t_rawq);
907*34492Skarels 			goto endcase;
908*34492Skarels 		}
909*34492Skarels 		if (c == tp->t_rprntc) {
910*34492Skarels 			ttyretype(tp);
911*34492Skarels 			goto endcase;
912*34492Skarels 		}
9139578Ssam 	}
9149578Ssam 
9159578Ssam 	/*
9169578Ssam 	 * Check for input buffer overflow
9179578Ssam 	 */
91810391Ssam 	if (tp->t_rawq.c_cc+tp->t_canq.c_cc >= TTYHOG) {
919*34492Skarels 		if (tp->t_line == NTTYDISC)
920*34492Skarels 			(void) ttyoutput(CTRL('g'), tp);
9219578Ssam 		goto endcase;
92210391Ssam 	}
9239578Ssam 
9249578Ssam 	/*
9259578Ssam 	 * Put data char in q for user and
9269578Ssam 	 * wakeup on seeing a line delimiter.
9279578Ssam 	 */
9289578Ssam 	if (putc(c, &tp->t_rawq) >= 0) {
929*34492Skarels 		if (ttbreakc(c, tp)) {
9309578Ssam 			tp->t_rocount = 0;
9319578Ssam 			catq(&tp->t_rawq, &tp->t_canq);
9327502Sroot 			ttwakeup(tp);
9339578Ssam 		} else if (tp->t_rocount++ == 0)
9349578Ssam 			tp->t_rocol = tp->t_col;
9359578Ssam 		tp->t_state &= ~TS_QUOT;
936*34492Skarels 		if (c == '\\')
937*34492Skarels 			tp->t_state |= TS_QUOT;
9389578Ssam 		if (tp->t_state&TS_ERASE) {
9399578Ssam 			tp->t_state &= ~TS_ERASE;
9409578Ssam 			(void) ttyoutput('/', tp);
9419578Ssam 		}
9429578Ssam 		i = tp->t_col;
9437502Sroot 		ttyecho(c, tp);
944*34492Skarels 		if (c == tp->t_eofc && t_flags&ECHO) {
9459578Ssam 			i = MIN(2, tp->t_col - i);
9469578Ssam 			while (i > 0) {
9479578Ssam 				(void) ttyoutput('\b', tp);
9489578Ssam 				i--;
9499578Ssam 			}
9509578Ssam 		}
9517502Sroot 	}
9529578Ssam endcase:
9539578Ssam 	/*
954*34492Skarels 	 * If DEC-style start/stop is enabled don't restart
955*34492Skarels 	 * output until seeing the start character.
9569578Ssam 	 */
957*34492Skarels 	if (t_flags&DECCTQ && tp->t_state&TS_TTSTOP &&
958*34492Skarels 	    tp->t_startc != tp->t_stopc)
9597502Sroot 		return;
9609578Ssam restartoutput:
9617502Sroot 	tp->t_state &= ~TS_TTSTOP;
962*34492Skarels 	tp->t_flags &= ~FLUSHO;
9639578Ssam startoutput:
9647502Sroot 	ttstart(tp);
9657502Sroot }
9667502Sroot 
9677502Sroot /*
9689578Ssam  * Put character on TTY output queue, adding delays,
9697502Sroot  * expanding tabs, and handling the CR/NL bit.
9709578Ssam  * This is called both from the top half for output,
9719578Ssam  * and from interrupt level for echoing.
9727502Sroot  * The arguments are the character and the tty structure.
9737502Sroot  * Returns < 0 if putc succeeds, otherwise returns char to resend
9747502Sroot  * Must be recursive.
9757502Sroot  */
9767502Sroot ttyoutput(c, tp)
9777502Sroot 	register c;
9787502Sroot 	register struct tty *tp;
9797502Sroot {
9807502Sroot 	register char *colp;
9817502Sroot 	register ctype;
9827502Sroot 
983*34492Skarels 	if (tp->t_flags & (RAW|LITOUT)) {
984*34492Skarels 		if (tp->t_flags&FLUSHO)
9857502Sroot 			return (-1);
9867502Sroot 		if (putc(c, &tp->t_outq))
9877625Ssam 			return (c);
9887502Sroot 		tk_nout++;
9897502Sroot 		return (-1);
9907502Sroot 	}
991*34492Skarels 
9927502Sroot 	/*
993*34492Skarels 	 * Ignore EOT in normal mode to avoid
994*34492Skarels 	 * hanging up certain terminals.
995*34492Skarels 	 */
996*34492Skarels 	c &= 0177;
997*34492Skarels 	if (c == CEOT && (tp->t_flags&CBREAK) == 0)
998*34492Skarels 		return (-1);
999*34492Skarels 	/*
10007502Sroot 	 * Turn tabs to spaces as required
10017502Sroot 	 */
1002*34492Skarels 	if (c == '\t' && (tp->t_flags&TBDELAY) == XTABS) {
10037502Sroot 		register int s;
10047502Sroot 
10057502Sroot 		c = 8 - (tp->t_col&7);
1006*34492Skarels 		if ((tp->t_flags&FLUSHO) == 0) {
100717545Skarels 			s = spltty();		/* don't interrupt tabs */
10087502Sroot 			c -= b_to_q("        ", c, &tp->t_outq);
10097502Sroot 			tk_nout += c;
10107502Sroot 			splx(s);
10117502Sroot 		}
10127502Sroot 		tp->t_col += c;
10137502Sroot 		return (c ? -1 : '\t');
10147502Sroot 	}
10157502Sroot 	tk_nout++;
10167502Sroot 	/*
10177502Sroot 	 * for upper-case-only terminals,
10187502Sroot 	 * generate escapes.
10197502Sroot 	 */
10207502Sroot 	if (tp->t_flags&LCASE) {
10217502Sroot 		colp = "({)}!|^~'`";
10227625Ssam 		while (*colp++)
10237625Ssam 			if (c == *colp++) {
10247502Sroot 				if (ttyoutput('\\', tp) >= 0)
10257502Sroot 					return (c);
10267502Sroot 				c = colp[-2];
10277502Sroot 				break;
10287502Sroot 			}
10299578Ssam 		if ('A' <= c && c <= 'Z') {
10307502Sroot 			if (ttyoutput('\\', tp) >= 0)
10317502Sroot 				return (c);
10329578Ssam 		} else if ('a' <= c && c <= 'z')
10337502Sroot 			c += 'A' - 'a';
10347502Sroot 	}
10359578Ssam 
10367502Sroot 	/*
10377502Sroot 	 * turn <nl> to <cr><lf> if desired.
10387502Sroot 	 */
1039*34492Skarels 	if (c == '\n' && tp->t_flags&CRMOD)
1040*34492Skarels 		if (ttyoutput('\r', tp) >= 0)
10417502Sroot 			return (c);
10429578Ssam 	if (c == '~' && tp->t_flags&TILDE)
10437502Sroot 		c = '`';
1044*34492Skarels 	if ((tp->t_flags&FLUSHO) == 0 && putc(c, &tp->t_outq))
10457502Sroot 		return (c);
10467502Sroot 	/*
10477502Sroot 	 * Calculate delays.
10487502Sroot 	 * The numbers here represent clock ticks
10497502Sroot 	 * and are not necessarily optimal for all terminals.
10507502Sroot 	 * The delays are indicated by characters above 0200.
10517502Sroot 	 * In raw mode there are no delays and the
10527502Sroot 	 * transmission path is 8 bits wide.
10539578Ssam 	 *
10549578Ssam 	 * SHOULD JUST ALLOW USER TO SPECIFY DELAYS
10557502Sroot 	 */
10567502Sroot 	colp = &tp->t_col;
10577502Sroot 	ctype = partab[c];
10587502Sroot 	c = 0;
10597502Sroot 	switch (ctype&077) {
10607502Sroot 
10617502Sroot 	case ORDINARY:
10627502Sroot 		(*colp)++;
10637502Sroot 
10647502Sroot 	case CONTROL:
10657502Sroot 		break;
10667502Sroot 
10677502Sroot 	case BACKSPACE:
10687502Sroot 		if (*colp)
10697502Sroot 			(*colp)--;
10707502Sroot 		break;
10717502Sroot 
107213821Ssam 	/*
107313821Ssam 	 * This macro is close enough to the correct thing;
107413821Ssam 	 * it should be replaced by real user settable delays
107513821Ssam 	 * in any event...
107613821Ssam 	 */
107713821Ssam #define	mstohz(ms)	(((ms) * hz) >> 10)
10787502Sroot 	case NEWLINE:
10797502Sroot 		ctype = (tp->t_flags >> 8) & 03;
10807625Ssam 		if (ctype == 1) { /* tty 37 */
108126357Skarels 			if (*colp > 0) {
108226357Skarels 				c = (((unsigned)*colp) >> 4) + 3;
108326357Skarels 				if ((unsigned)c > 6)
108426357Skarels 					c = 6;
108526357Skarels 			}
10869578Ssam 		} else if (ctype == 2) /* vt05 */
108713821Ssam 			c = mstohz(100);
10887502Sroot 		*colp = 0;
10897502Sroot 		break;
10907502Sroot 
10917502Sroot 	case TAB:
10927502Sroot 		ctype = (tp->t_flags >> 10) & 03;
10937625Ssam 		if (ctype == 1) { /* tty 37 */
10947502Sroot 			c = 1 - (*colp | ~07);
10957625Ssam 			if (c < 5)
10967502Sroot 				c = 0;
10977502Sroot 		}
10987502Sroot 		*colp |= 07;
10997502Sroot 		(*colp)++;
11007502Sroot 		break;
11017502Sroot 
11027502Sroot 	case VTAB:
11039578Ssam 		if (tp->t_flags&VTDELAY) /* tty 37 */
11047502Sroot 			c = 0177;
11057502Sroot 		break;
11067502Sroot 
11077502Sroot 	case RETURN:
11087502Sroot 		ctype = (tp->t_flags >> 12) & 03;
11099578Ssam 		if (ctype == 1) /* tn 300 */
111013821Ssam 			c = mstohz(83);
11119578Ssam 		else if (ctype == 2) /* ti 700 */
111213821Ssam 			c = mstohz(166);
11139578Ssam 		else if (ctype == 3) { /* concept 100 */
11147502Sroot 			int i;
11159578Ssam 
11167502Sroot 			if ((i = *colp) >= 0)
11179578Ssam 				for (; i < 9; i++)
11187502Sroot 					(void) putc(0177, &tp->t_outq);
11197502Sroot 		}
11207502Sroot 		*colp = 0;
11217502Sroot 	}
1122*34492Skarels 	if (c && (tp->t_flags&FLUSHO) == 0)
11237502Sroot 		(void) putc(c|0200, &tp->t_outq);
11247502Sroot 	return (-1);
11257502Sroot }
112613821Ssam #undef mstohz
11277502Sroot 
11287502Sroot /*
11297502Sroot  * Called from device's read routine after it has
11307502Sroot  * calculated the tty-structure given as argument.
11317502Sroot  */
11327722Swnj ttread(tp, uio)
11337625Ssam 	register struct tty *tp;
11347722Swnj 	struct uio *uio;
11357502Sroot {
11367502Sroot 	register struct clist *qp;
1137*34492Skarels 	register c, t_flags;
11389859Ssam 	int s, first, error = 0;
11397502Sroot 
11407502Sroot loop:
11419578Ssam 	/*
11429578Ssam 	 * Take any pending input first.
11439578Ssam 	 */
114417545Skarels 	s = spltty();
1145*34492Skarels 	if (tp->t_flags&PENDIN)
11467502Sroot 		ttypend(tp);
11479859Ssam 	splx(s);
11489578Ssam 
114923165Sbloom 	if ((tp->t_state&TS_CARR_ON)==0)
115023165Sbloom 		return (EIO);
115123165Sbloom 
11529578Ssam 	/*
11539578Ssam 	 * Hang process if it's in the background.
11549578Ssam 	 */
115523165Sbloom 	if (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) {
115624392Skarels 		if ((u.u_procp->p_sigignore & sigmask(SIGTTIN)) ||
115724392Skarels 		   (u.u_procp->p_sigmask & sigmask(SIGTTIN)) ||
11587502Sroot 		    u.u_procp->p_flag&SVFORK)
11598520Sroot 			return (EIO);
11607502Sroot 		gsignal(u.u_procp->p_pgrp, SIGTTIN);
11617502Sroot 		sleep((caddr_t)&lbolt, TTIPRI);
116223165Sbloom 		goto loop;
11637502Sroot 	}
11649578Ssam 	t_flags = tp->t_flags;
11659578Ssam 
11669578Ssam 	/*
1167*34492Skarels 	 * In raw mode take characters directly from the
1168*34492Skarels 	 * raw queue w/o processing.  Interlock against
1169*34492Skarels 	 * device interrupts when interrogating rawq.
11709578Ssam 	 */
1171*34492Skarels 	if (t_flags&RAW) {
1172*34492Skarels 		s = spltty();
1173*34492Skarels 		if (tp->t_rawq.c_cc <= 0) {
1174*34492Skarels 			if ((tp->t_state&TS_CARR_ON) == 0 ||
1175*34492Skarels 			    (tp->t_state&TS_NBIO)) {
1176*34492Skarels 				splx(s);
1177*34492Skarels 				return (EWOULDBLOCK);
1178*34492Skarels 			}
1179*34492Skarels 			sleep((caddr_t)&tp->t_rawq, TTIPRI);
1180*34492Skarels 			splx(s);
1181*34492Skarels 			goto loop;
1182*34492Skarels 		}
1183*34492Skarels 		splx(s);
1184*34492Skarels  		while (!error && tp->t_rawq.c_cc && uio->uio_resid)
1185*34492Skarels  			error = ureadc(getc(&tp->t_rawq), uio);
1186*34492Skarels 		goto checktandem;
1187*34492Skarels 	}
11889578Ssam 
11899578Ssam 	/*
1190*34492Skarels 	 * In cbreak mode use the rawq, otherwise
1191*34492Skarels 	 * take characters from the canonicalized q.
1192*34492Skarels 	 */
1193*34492Skarels 	qp = t_flags&CBREAK ? &tp->t_rawq : &tp->t_canq;
1194*34492Skarels 
1195*34492Skarels 	/*
11969578Ssam 	 * No input, sleep on rawq awaiting hardware
11979578Ssam 	 * receipt and notification.
11989578Ssam 	 */
119917545Skarels 	s = spltty();
12009578Ssam 	if (qp->c_cc <= 0) {
12019578Ssam 		if ((tp->t_state&TS_CARR_ON) == 0 ||
12029578Ssam 		    (tp->t_state&TS_NBIO)) {
12039859Ssam 			splx(s);
12049578Ssam 			return (EWOULDBLOCK);
12057502Sroot 		}
12069578Ssam 		sleep((caddr_t)&tp->t_rawq, TTIPRI);
12079859Ssam 		splx(s);
12089578Ssam 		goto loop;
12099578Ssam 	}
12109859Ssam 	splx(s);
12119578Ssam 
12129578Ssam 	/*
1213*34492Skarels 	 * Input present, perform input mapping
1214*34492Skarels 	 * and processing (we're not in raw mode).
12159578Ssam 	 */
12169578Ssam 	first = 1;
12179578Ssam 	while ((c = getc(qp)) >= 0) {
1218*34492Skarels 		if (t_flags&CRMOD && c == '\r')
1219*34492Skarels 			c = '\n';
12209578Ssam 		/*
1221*34492Skarels 		 * Check for delayed suspend character.
12229578Ssam 		 */
1223*34492Skarels 		if (tp->t_line == NTTYDISC && c == tp->t_dsuspc) {
12249578Ssam 			gsignal(tp->t_pgrp, SIGTSTP);
12259578Ssam 			if (first) {
12269578Ssam 				sleep((caddr_t)&lbolt, TTIPRI);
12279578Ssam 				goto loop;
12289578Ssam 			}
12299578Ssam 			break;
12307502Sroot 		}
12319578Ssam 		/*
1232*34492Skarels 		 * Interpret EOF only in cooked mode.
12339578Ssam 		 */
1234*34492Skarels 		if (c == tp->t_eofc && (t_flags&CBREAK) == 0)
12359578Ssam 			break;
12369578Ssam 		/*
12379578Ssam 		 * Give user character.
12389578Ssam 		 */
1239*34492Skarels  		error = ureadc(t_flags&PASS8 ? c : c & 0177, uio);
12409578Ssam 		if (error)
12419578Ssam 			break;
124214938Smckusick  		if (uio->uio_resid == 0)
12439578Ssam 			break;
12449578Ssam 		/*
1245*34492Skarels 		 * In cooked mode check for a "break character"
12469578Ssam 		 * marking the end of a "line of input".
12479578Ssam 		 */
1248*34492Skarels 		if ((t_flags&CBREAK) == 0 && ttbreakc(c, tp))
12499578Ssam 			break;
12509578Ssam 		first = 0;
12517502Sroot 	}
12529578Ssam 
12539859Ssam checktandem:
12549578Ssam 	/*
12559578Ssam 	 * Look to unblock output now that (presumably)
12569578Ssam 	 * the input queue has gone down.
12579578Ssam 	 */
1258*34492Skarels 	if (tp->t_state&TS_TBLOCK && tp->t_rawq.c_cc < TTYHOG/5)
1259*34492Skarels 		if (putc(tp->t_startc, &tp->t_outq) == 0) {
12607502Sroot 			tp->t_state &= ~TS_TBLOCK;
12617502Sroot 			ttstart(tp);
12627502Sroot 		}
12638520Sroot 	return (error);
12647502Sroot }
12657502Sroot 
12667502Sroot /*
126725391Skarels  * Check the output queue on tp for space for a kernel message
126825391Skarels  * (from uprintf/tprintf).  Allow some space over the normal
126925391Skarels  * hiwater mark so we don't lose messages due to normal flow
127025391Skarels  * control, but don't let the tty run amok.
127130695Skarels  * Sleeps here are not interruptible, but we return prematurely
127230695Skarels  * if new signals come in.
127325391Skarels  */
127425391Skarels ttycheckoutq(tp, wait)
127525391Skarels 	register struct tty *tp;
127625391Skarels 	int wait;
127725391Skarels {
127830695Skarels 	int hiwat, s, oldsig;
127925391Skarels 
128025391Skarels 	hiwat = TTHIWAT(tp);
128125391Skarels 	s = spltty();
128230695Skarels 	oldsig = u.u_procp->p_sig;
128325391Skarels 	if (tp->t_outq.c_cc > hiwat + 200)
128429946Skarels 		while (tp->t_outq.c_cc > hiwat) {
128529946Skarels 			ttstart(tp);
128630695Skarels 			if (wait == 0 || u.u_procp->p_sig != oldsig) {
128729946Skarels 				splx(s);
128829946Skarels 				return (0);
128929946Skarels 			}
129030695Skarels 			timeout(wakeup, (caddr_t)&tp->t_outq, hz);
129129946Skarels 			tp->t_state |= TS_ASLEEP;
129230695Skarels 			sleep((caddr_t)&tp->t_outq, PZERO - 1);
129325391Skarels 		}
129425391Skarels 	splx(s);
129525391Skarels 	return (1);
129625391Skarels }
129725391Skarels 
129825391Skarels /*
12997502Sroot  * Called from the device's write routine after it has
13007502Sroot  * calculated the tty-structure given as argument.
13017502Sroot  */
13027822Sroot ttwrite(tp, uio)
13037625Ssam 	register struct tty *tp;
13049578Ssam 	register struct uio *uio;
13057502Sroot {
13067502Sroot 	register char *cp;
13079578Ssam 	register int cc, ce, c;
13089578Ssam 	int i, hiwat, cnt, error, s;
13097502Sroot 	char obuf[OBUFSIZ];
13107502Sroot 
13119578Ssam 	hiwat = TTHIWAT(tp);
13129578Ssam 	cnt = uio->uio_resid;
13139578Ssam 	error = 0;
13147502Sroot loop:
131521776Sbloom 	if ((tp->t_state&TS_CARR_ON) == 0)
131621776Sbloom 		return (EIO);
13179578Ssam 	/*
13189578Ssam 	 * Hang the process if it's in the background.
13199578Ssam 	 */
132021776Sbloom 	if (u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp &&
1321*34492Skarels 	    (tp->t_flags&TOSTOP) && (u.u_procp->p_flag&SVFORK)==0 &&
132224392Skarels 	    !(u.u_procp->p_sigignore & sigmask(SIGTTOU)) &&
132324392Skarels 	    !(u.u_procp->p_sigmask & sigmask(SIGTTOU))) {
13247502Sroot 		gsignal(u.u_procp->p_pgrp, SIGTTOU);
13257502Sroot 		sleep((caddr_t)&lbolt, TTIPRI);
132621776Sbloom 		goto loop;
13277502Sroot 	}
13289578Ssam 
13299578Ssam 	/*
13309578Ssam 	 * Process the user's data in at most OBUFSIZ
13319578Ssam 	 * chunks.  Perform lower case simulation and
13329578Ssam 	 * similar hacks.  Keep track of high water
13339578Ssam 	 * mark, sleep on overflow awaiting device aid
13349578Ssam 	 * in acquiring new space.
13359578Ssam 	 */
13367822Sroot 	while (uio->uio_resid > 0) {
133732067Skarels 		if (tp->t_outq.c_cc > hiwat) {
133832067Skarels 			cc = 0;
133932067Skarels 			goto ovhiwat;
134032067Skarels 		}
13419578Ssam 		/*
13429578Ssam 		 * Grab a hunk of data from the user.
13439578Ssam 		 */
13447822Sroot 		cc = uio->uio_iov->iov_len;
13457822Sroot 		if (cc == 0) {
13467822Sroot 			uio->uio_iovcnt--;
13477822Sroot 			uio->uio_iov++;
134821776Sbloom 			if (uio->uio_iovcnt <= 0)
13497822Sroot 				panic("ttwrite");
13507822Sroot 			continue;
13517822Sroot 		}
13527822Sroot 		if (cc > OBUFSIZ)
13537822Sroot 			cc = OBUFSIZ;
13547502Sroot 		cp = obuf;
135512752Ssam 		error = uiomove(cp, cc, UIO_WRITE, uio);
13568520Sroot 		if (error)
13577502Sroot 			break;
1358*34492Skarels 		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) {
1398*34492Skarels 			if (tp->t_flags & (RAW|LITOUT))
13997502Sroot 				ce = cc;
14007502Sroot 			else {
1401*34492Skarels 				ce = cc - scanc((unsigned)cc, (u_char *)cp,
1402*34492Skarels 				   (u_char *)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--;
1422*34492Skarels 					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 			}
1451*34492Skarels 			if (tp->t_flags&FLUSHO || tp->t_outq.c_cc > hiwat)
14527502Sroot 				goto ovhiwat;
14537502Sroot 		}
14547502Sroot 	}
1455*34492Skarels 	ttstart(tp);
14568520Sroot 	return (error);
14577502Sroot 
14587502Sroot ovhiwat:
14599578Ssam 	if (cc != 0) {
14609578Ssam 		uio->uio_iov->iov_base -= cc;
14619578Ssam 		uio->uio_iov->iov_len += cc;
14629578Ssam 		uio->uio_resid += cc;
14639578Ssam 		uio->uio_offset -= cc;
14649578Ssam 	}
146532067Skarels 	ttstart(tp);
146632067Skarels 	s = spltty();
14679578Ssam 	/*
1468*34492Skarels 	 * This can only occur if FLUSHO is set in t_flags,
146932067Skarels 	 * or if ttstart/oproc is synchronous (or very fast).
14709578Ssam 	 */
14717502Sroot 	if (tp->t_outq.c_cc <= hiwat) {
14729578Ssam 		splx(s);
14737502Sroot 		goto loop;
14747502Sroot 	}
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 
1500*34492Skarels 	if ((tp->t_flags&ECHO) == 0)
15017502Sroot 		return;
1502*34492Skarels 	tp->t_flags &= ~FLUSHO;
15037502Sroot 	c &= 0377;
1504*34492Skarels 	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:
1527*34492Skarels 			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;
1539*34492Skarels 			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);
1544*34492Skarels 			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 		}
1561*34492Skarels 	} 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
1568*34492Skarels 		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 {
1580*34492Skarels 	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 
1597*34492Skarels 	if (tp->t_rprntc != 0377)
1598*34492Skarels 		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 /*
1612*34492Skarels  * 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)
1620*34492Skarels 		tp->t_flags &= ~FLUSHO;
1621*34492Skarels 	if ((tp->t_flags&ECHO) == 0)
16227502Sroot 		return;
1623*34492Skarels 	c &= 0377;
1624*34492Skarels 	if (tp->t_flags&RAW) {
1625*34492Skarels 		(void) ttyoutput(c, tp);
1626*34492Skarels 		return;
1627*34492Skarels 	}
1628*34492Skarels 	if (c == '\r' && tp->t_flags&CRMOD)
1629*34492Skarels 		c = '\n';
1630*34492Skarels 	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 /*
1646*34492Skarels  * Is c a break char for tp?
1647*34492Skarels  */
1648*34492Skarels ttbreakc(c, tp)
1649*34492Skarels 	register c;
1650*34492Skarels 	register struct tty *tp;
1651*34492Skarels {
1652*34492Skarels 	return (c == '\n' || c == tp->t_eofc || c == tp->t_brkc ||
1653*34492Skarels 		c == '\r' && (tp->t_flags&CRMOD));
1654*34492Skarels }
1655*34492Skarels 
1656*34492Skarels /*
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