xref: /csrg-svn/sys/kern/tty.c (revision 12752)
1*12752Ssam /*	tty.c	4.41	83/05/27	*/
239Sbill 
39760Ssam #include "../machine/reg.h"
49760Ssam 
539Sbill #include "../h/param.h"
639Sbill #include "../h/systm.h"
739Sbill #include "../h/dir.h"
839Sbill #include "../h/user.h"
99578Ssam #include "../h/ioctl.h"
1039Sbill #include "../h/tty.h"
1139Sbill #include "../h/proc.h"
1239Sbill #include "../h/inode.h"
1339Sbill #include "../h/file.h"
1439Sbill #include "../h/conf.h"
1539Sbill #include "../h/buf.h"
16340Sbill #include "../h/dk.h"
177722Swnj #include "../h/uio.h"
188154Sroot #include "../h/kernel.h"
1939Sbill 
207436Skre /*
217436Skre  * Table giving parity for characters and indicating
227436Skre  * character classes to tty driver.  In particular,
237436Skre  * if the low 6 bits are 0, then the character needs
247436Skre  * no special processing on output.
257436Skre  */
2639Sbill 
277436Skre char partab[] = {
287436Skre 	0001,0201,0201,0001,0201,0001,0001,0201,
297436Skre 	0202,0004,0003,0201,0005,0206,0201,0001,
307436Skre 	0201,0001,0001,0201,0001,0201,0201,0001,
317436Skre 	0001,0201,0201,0001,0201,0001,0001,0201,
327436Skre 	0200,0000,0000,0200,0000,0200,0200,0000,
337436Skre 	0000,0200,0200,0000,0200,0000,0000,0200,
347436Skre 	0000,0200,0200,0000,0200,0000,0000,0200,
357436Skre 	0200,0000,0000,0200,0000,0200,0200,0000,
367436Skre 	0200,0000,0000,0200,0000,0200,0200,0000,
377436Skre 	0000,0200,0200,0000,0200,0000,0000,0200,
387436Skre 	0000,0200,0200,0000,0200,0000,0000,0200,
397436Skre 	0200,0000,0000,0200,0000,0200,0200,0000,
407436Skre 	0000,0200,0200,0000,0200,0000,0000,0200,
417436Skre 	0200,0000,0000,0200,0000,0200,0200,0000,
427436Skre 	0200,0000,0000,0200,0000,0200,0200,0000,
437436Skre 	0000,0200,0200,0000,0200,0000,0000,0201,
447436Skre 
457436Skre 	/*
467436Skre 	 * 7 bit ascii ends with the last character above,
477436Skre 	 * but we contine through all 256 codes for the sake
487436Skre 	 * of the tty output routines which use special vax
497436Skre 	 * instructions which need a 256 character trt table.
507436Skre 	 */
517436Skre 
527436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
537436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
547436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
557436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
567436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
577436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
587436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
597436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
607436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
617436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
627436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
637436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
647436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
657436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
667436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
677436Skre 	0007,0007,0007,0007,0007,0007,0007,0007
687436Skre };
697436Skre 
70146Sbill /*
7139Sbill  * Input mapping table-- if an entry is non-zero, when the
7239Sbill  * corresponding character is typed preceded by "\" the escape
7339Sbill  * sequence is replaced by the table value.  Mostly used for
7439Sbill  * upper-case only terminals.
7539Sbill  */
7639Sbill char	maptab[] ={
7739Sbill 	000,000,000,000,000,000,000,000,
7839Sbill 	000,000,000,000,000,000,000,000,
7939Sbill 	000,000,000,000,000,000,000,000,
8039Sbill 	000,000,000,000,000,000,000,000,
8139Sbill 	000,'|',000,000,000,000,000,'`',
8239Sbill 	'{','}',000,000,000,000,000,000,
8339Sbill 	000,000,000,000,000,000,000,000,
8439Sbill 	000,000,000,000,000,000,000,000,
8539Sbill 	000,000,000,000,000,000,000,000,
8639Sbill 	000,000,000,000,000,000,000,000,
8739Sbill 	000,000,000,000,000,000,000,000,
8839Sbill 	000,000,000,000,000,000,'~',000,
8939Sbill 	000,'A','B','C','D','E','F','G',
9039Sbill 	'H','I','J','K','L','M','N','O',
9139Sbill 	'P','Q','R','S','T','U','V','W',
9239Sbill 	'X','Y','Z',000,000,000,000,000,
9339Sbill };
9439Sbill 
95925Sbill short	tthiwat[16] =
968954Sroot    { 100,100,100,100,100,100,100,200,200,400,400,400,650,650,1300,2000 };
97925Sbill short	ttlowat[16] =
98925Sbill    {  30, 30, 30, 30, 30, 30, 30, 50, 50,120,120,120,125,125,125,125 };
99925Sbill 
1009578Ssam struct	ttychars ttydefaults = {
1019578Ssam 	CERASE,	CKILL,	CINTR,	CQUIT,	CSTART,	CSTOP,	CEOF,
1029578Ssam 	CBRK,	CSUSP,	CDSUSP, CRPRNT, CFLUSH, CWERASE,CLNEXT
1039578Ssam };
10439Sbill 
10539Sbill ttychars(tp)
1069578Ssam 	struct tty *tp;
10739Sbill {
108174Sbill 
1099578Ssam 	tp->t_chars = ttydefaults;
11039Sbill }
11139Sbill 
11239Sbill /*
113903Sbill  * Wait for output to drain, then flush input waiting.
11439Sbill  */
115*12752Ssam ttywflush(tp)
1165408Swnj 	register struct tty *tp;
11739Sbill {
11839Sbill 
119*12752Ssam 	ttywait(tp);
120*12752Ssam 	ttyflush(tp, FREAD);
121*12752Ssam }
122*12752Ssam 
123*12752Ssam ttywait(tp)
124*12752Ssam 	register struct tty *tp;
125*12752Ssam {
126*12752Ssam 	register int s = spl5();
127*12752Ssam 
1285622Swnj 	while (tp->t_outq.c_cc && tp->t_state&TS_CARR_ON
1295622Swnj 	    && tp->t_oproc) {		/* kludge for pty */
130903Sbill 		(*tp->t_oproc)(tp);
1315408Swnj 		tp->t_state |= TS_ASLEEP;
132903Sbill 		sleep((caddr_t)&tp->t_outq, TTOPRI);
133903Sbill 	}
1349859Ssam 	splx(s);
13539Sbill }
13639Sbill 
13739Sbill /*
1389578Ssam  * Flush all TTY queues
13939Sbill  */
140*12752Ssam ttyflush(tp, rw)
1417625Ssam 	register struct tty *tp;
14239Sbill {
143903Sbill 	register s;
144903Sbill 
145903Sbill 	s = spl6();
146903Sbill 	if (rw & FREAD) {
147903Sbill 		while (getc(&tp->t_canq) >= 0)
148903Sbill 			;
149903Sbill 		wakeup((caddr_t)&tp->t_rawq);
150903Sbill 	}
151903Sbill 	if (rw & FWRITE) {
152903Sbill 		wakeup((caddr_t)&tp->t_outq);
1535408Swnj 		tp->t_state &= ~TS_TTSTOP;
1545426Swnj 		(*cdevsw[major(tp->t_dev)].d_stop)(tp, rw);
155903Sbill 		while (getc(&tp->t_outq) >= 0)
156903Sbill 			;
157903Sbill 	}
158903Sbill 	if (rw & FREAD) {
159903Sbill 		while (getc(&tp->t_rawq) >= 0)
160903Sbill 			;
161903Sbill 		tp->t_delct = 0;
1629578Ssam 		tp->t_rocount = 0;
163903Sbill 		tp->t_rocol = 0;
1649578Ssam 		tp->t_state &= ~TS_LOCAL;
165903Sbill 	}
166903Sbill 	splx(s);
16739Sbill }
16839Sbill 
169903Sbill /*
170903Sbill  * Send stop character on input overflow.
171903Sbill  */
172903Sbill ttyblock(tp)
1737625Ssam 	register struct tty *tp;
17439Sbill {
175903Sbill 	register x;
1769578Ssam 
177903Sbill 	x = tp->t_rawq.c_cc + tp->t_canq.c_cc;
178903Sbill 	if (tp->t_rawq.c_cc > TTYHOG) {
179*12752Ssam 		ttyflush(tp, FREAD|FWRITE);
1805408Swnj 		tp->t_state &= ~TS_TBLOCK;
181903Sbill 	}
1829578Ssam 	if (x >= TTYHOG/2 && putc(tp->t_stopc, &tp->t_outq) == 0) {
1839578Ssam 		tp->t_state |= TS_TBLOCK;
1849578Ssam 		ttstart(tp);
185903Sbill 	}
18639Sbill }
18739Sbill 
18839Sbill /*
189903Sbill  * Restart typewriter output following a delay
190903Sbill  * timeout.
191903Sbill  * The name of the routine is passed to the timeout
192903Sbill  * subroutine and it is called during a clock interrupt.
193121Sbill  */
194903Sbill ttrstrt(tp)
1957625Ssam 	register struct tty *tp;
196121Sbill {
197121Sbill 
1989578Ssam 	if (tp == 0)
1999578Ssam 		panic("ttrstrt");
2005408Swnj 	tp->t_state &= ~TS_TIMEOUT;
201903Sbill 	ttstart(tp);
202121Sbill }
203121Sbill 
204121Sbill /*
205903Sbill  * Start output on the typewriter. It is used from the top half
206903Sbill  * after some characters have been put on the output queue,
207903Sbill  * from the interrupt routine to transmit the next
208903Sbill  * character, and after a timeout has finished.
20939Sbill  */
210903Sbill ttstart(tp)
2117625Ssam 	register struct tty *tp;
21239Sbill {
213903Sbill 	register s;
21439Sbill 
215903Sbill 	s = spl5();
2169578Ssam 	if ((tp->t_state & (TS_TIMEOUT|TS_TTSTOP|TS_BUSY)) == 0 &&
2175622Swnj 	    tp->t_oproc)		/* kludge for pty */
218903Sbill 		(*tp->t_oproc)(tp);
219903Sbill 	splx(s);
22039Sbill }
22139Sbill 
22239Sbill /*
223903Sbill  * Common code for tty ioctls.
22439Sbill  */
2251780Sbill /*ARGSUSED*/
2267625Ssam ttioctl(tp, com, data, flag)
2277625Ssam 	register struct tty *tp;
2287625Ssam 	caddr_t data;
22939Sbill {
2308520Sroot 	int dev = tp->t_dev;
23139Sbill 	extern int nldisp;
2328556Sroot 	int s;
233*12752Ssam 	register int newflags;
23439Sbill 
235903Sbill 	/*
236903Sbill 	 * If the ioctl involves modification,
237903Sbill 	 * insist on being able to write the device,
238903Sbill 	 * and hang if in the background.
239903Sbill 	 */
2407625Ssam 	switch (com) {
24139Sbill 
242915Sbill 	case TIOCSETD:
243915Sbill 	case TIOCSETP:
244915Sbill 	case TIOCSETN:
245903Sbill 	case TIOCFLUSH:
246903Sbill 	case TIOCSETC:
247903Sbill 	case TIOCSLTC:
248903Sbill 	case TIOCSPGRP:
249903Sbill 	case TIOCLBIS:
250903Sbill 	case TIOCLBIC:
251903Sbill 	case TIOCLSET:
2529624Ssam 	case TIOCBIS:
2539624Ssam 	case TIOCBIC:
2549624Ssam 	case TIOCSET:
2559325Ssam 	case TIOCSTI:
256903Sbill 		while (tp->t_line == NTTYDISC &&
257903Sbill 		   u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp &&
258903Sbill 		   (u.u_procp->p_flag&SVFORK) == 0 &&
259903Sbill 		   u.u_signal[SIGTTOU] != SIG_IGN &&
2608556Sroot 		   u.u_signal[SIGTTOU] != SIG_HOLD) {
261903Sbill 			gsignal(u.u_procp->p_pgrp, SIGTTOU);
262903Sbill 			sleep((caddr_t)&lbolt, TTOPRI);
263903Sbill 		}
264903Sbill 		break;
265903Sbill 	}
266903Sbill 
2679578Ssam 	/*
2689578Ssam 	 * Process the ioctl.
2699578Ssam 	 */
2707625Ssam 	switch (com) {
271903Sbill 
2728556Sroot 	/* get discipline number */
27339Sbill 	case TIOCGETD:
2747625Ssam 		*(int *)data = tp->t_line;
27539Sbill 		break;
27639Sbill 
2778556Sroot 	/* set line discipline */
2787625Ssam 	case TIOCSETD: {
2797625Ssam 		register int t = *(int *)data;
2809578Ssam 		int error = 0;
2817625Ssam 
28210851Ssam 		if (t >= nldisp)
28310851Ssam 			return (ENXIO);
2848556Sroot 		s = spl5();
28539Sbill 		if (tp->t_line)
28639Sbill 			(*linesw[tp->t_line].l_close)(tp);
28739Sbill 		if (t)
2888556Sroot 			error = (*linesw[t].l_open)(dev, tp);
2898556Sroot 		splx(s);
29010851Ssam 		if (error) {
29110851Ssam 			s = spl5();
29210851Ssam 			if (tp->t_line)
29310851Ssam 				(void) (*linesw[tp->t_line].l_open)(dev, tp);
29410851Ssam 			splx(s);
2958556Sroot 			return (error);
29610851Ssam 		}
2978556Sroot 		tp->t_line = t;
29839Sbill 		break;
2997625Ssam 	}
30039Sbill 
3018556Sroot 	/* prevent more opens on channel */
3025614Swnj 	case TIOCEXCL:
3035614Swnj 		tp->t_state |= TS_XCLUDE;
3045614Swnj 		break;
3055614Swnj 
3065614Swnj 	case TIOCNXCL:
3075614Swnj 		tp->t_state &= ~TS_XCLUDE;
3085614Swnj 		break;
3095614Swnj 
3107625Ssam 
3119624Ssam 	case TIOCGET:
312*12752Ssam 		*(int *)data = tp->t_flags;
3139624Ssam 		break;
3149624Ssam 
3159624Ssam 	case TIOCCGET:
3169624Ssam 		bcopy((caddr_t)&tp->t_chars, data, sizeof (struct ttychars));
3179624Ssam 		break;
3189624Ssam 
3199624Ssam 	case TIOCCSET:
3209624Ssam 		bcopy(data, (caddr_t)&tp->t_chars, sizeof (struct ttychars));
3219624Ssam 		break;
3229624Ssam 
3238556Sroot 	/* hang up line on last close */
32439Sbill 	case TIOCHPCL:
3255408Swnj 		tp->t_state |= TS_HUPCLS;
32639Sbill 		break;
32739Sbill 
3283942Sbugs 	case TIOCFLUSH: {
3297625Ssam 		register int flags = *(int *)data;
3307625Ssam 
3317625Ssam 		if (flags == 0)
3323942Sbugs 			flags = FREAD|FWRITE;
3337625Ssam 		else
3347625Ssam 			flags &= FREAD|FWRITE;
335*12752Ssam 		ttyflush(tp, flags);
33639Sbill 		break;
3373944Sbugs 	}
33839Sbill 
3398556Sroot 	/* return number of characters immediately available */
3407625Ssam 	case FIONREAD:
3417625Ssam 		*(off_t *)data = ttnread(tp);
342174Sbill 		break;
343174Sbill 
3448589Sroot 	case TIOCSTOP:
3458589Sroot 		s = spl5();
3469578Ssam 		if ((tp->t_state&TS_TTSTOP) == 0) {
3475573Swnj 			tp->t_state |= TS_TTSTOP;
3485573Swnj 			(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
3495573Swnj 		}
3507625Ssam 		splx(s);
3515573Swnj 		break;
3525573Swnj 
3538589Sroot 	case TIOCSTART:
3548589Sroot 		s = spl5();
3559578Ssam 		if ((tp->t_state&TS_TTSTOP) || (tp->t_flags&FLUSHO)) {
3565573Swnj 			tp->t_state &= ~TS_TTSTOP;
3579578Ssam 			tp->t_flags &= ~FLUSHO;
3585573Swnj 			ttstart(tp);
3595573Swnj 		}
3607625Ssam 		splx(s);
3615573Swnj 		break;
3625573Swnj 
3639325Ssam 	/*
3649325Ssam 	 * Simulate typing of a character at the terminal.
3659325Ssam 	 */
3669325Ssam 	case TIOCSTI:
3679325Ssam 		if (u.u_uid && u.u_ttyp != tp)
3689325Ssam 			return (EACCES);
3699578Ssam 		(*linesw[tp->t_line].l_rint)(*(char *)data, tp);
3709325Ssam 		break;
3719325Ssam 
372*12752Ssam 	case TIOCSET:
373*12752Ssam 	case TIOCBIS:
374*12752Ssam 	case TIOCBIC:
375*12752Ssam 		newflags = *(int *)data;
376*12752Ssam 		if (com == TIOCBIS)
377*12752Ssam 			newflags |= tp->t_flags;
378*12752Ssam 		else if (com == TIOCBIC)
379*12752Ssam 			newflags = tp->t_flags &~ newflags;
380*12752Ssam 		goto setin;
381*12752Ssam 
382*12752Ssam 	case TIOCSETP:
383*12752Ssam 	case TIOCSETN: {
384*12752Ssam 		register struct sgttyb *sg = (struct sgttyb *)data;
385*12752Ssam 
386*12752Ssam 		tp->t_erase = sg->sg_erase;
387*12752Ssam 		tp->t_kill = sg->sg_kill;
388*12752Ssam 		tp->t_ispeed = sg->sg_ispeed;
389*12752Ssam 		tp->t_ospeed = sg->sg_ospeed;
390*12752Ssam 		newflags = (tp->t_flags&0xffff0000) | (sg->sg_flags&0xffff);
391*12752Ssam setin:
392*12752Ssam 		s = spl5();
393*12752Ssam 		if (tp->t_flags&RAW || newflags&RAW || com == TIOCSETP) {
394*12752Ssam 			ttywait(tp);
395*12752Ssam 			ttyflush(tp, FREAD);
396*12752Ssam 		} else if ((tp->t_flags&CBREAK) != (newflags&CBREAK)) {
397*12752Ssam 			if (newflags&CBREAK) {
398*12752Ssam 				struct clist tq;
399*12752Ssam 
400*12752Ssam 				catq(&tp->t_rawq, &tp->t_canq);
401*12752Ssam 				tq = tp->t_rawq;
402*12752Ssam 				tp->t_rawq = tp->t_canq;
403*12752Ssam 				tp->t_canq = tq;
404*12752Ssam 			} else {
405*12752Ssam 				tp->t_flags |= PENDIN;
406*12752Ssam 				ttwakeup(tp);
407*12752Ssam 			}
408*12752Ssam 		}
409*12752Ssam 		tp->t_flags = newflags;
410*12752Ssam 		if (tp->t_flags&RAW) {
411*12752Ssam 			tp->t_state &= ~TS_TTSTOP;
412*12752Ssam 			ttstart(tp);
413*12752Ssam 		}
414*12752Ssam 		splx(s);
415*12752Ssam 		break;
416*12752Ssam 	}
417*12752Ssam 
418*12752Ssam 	/* send current parameters to user */
419*12752Ssam 	case TIOCGETP: {
420*12752Ssam 		register struct sgttyb *sg = (struct sgttyb *)data;
421*12752Ssam 
422*12752Ssam 		sg->sg_ispeed = tp->t_ispeed;
423*12752Ssam 		sg->sg_ospeed = tp->t_ospeed;
424*12752Ssam 		sg->sg_erase = tp->t_erase;
425*12752Ssam 		sg->sg_kill = tp->t_kill;
426*12752Ssam 		sg->sg_flags = tp->t_flags;
427*12752Ssam 		break;
428*12752Ssam 	}
429*12752Ssam 
430*12752Ssam 	case FIONBIO:
431*12752Ssam 		if (*(int *)data)
432*12752Ssam 			tp->t_state |= TS_NBIO;
433*12752Ssam 		else
434*12752Ssam 			tp->t_state &= ~TS_NBIO;
435*12752Ssam 		break;
436*12752Ssam 
437*12752Ssam 	case FIOASYNC:
438*12752Ssam 		if (*(int *)data)
439*12752Ssam 			tp->t_state |= TS_ASYNC;
440*12752Ssam 		else
441*12752Ssam 			tp->t_state &= ~TS_ASYNC;
442*12752Ssam 		break;
443*12752Ssam 
444*12752Ssam 	/* set/get local special characters */
445*12752Ssam 	case TIOCSLTC:
446*12752Ssam 		bcopy(data, (caddr_t)&tp->t_suspc, sizeof (struct ltchars));
447*12752Ssam 		break;
448*12752Ssam 
449*12752Ssam 	case TIOCGLTC:
450*12752Ssam 		bcopy((caddr_t)&tp->t_suspc, data, sizeof (struct ltchars));
451*12752Ssam 		break;
452*12752Ssam 
453*12752Ssam 	/*
454*12752Ssam 	 * Modify local mode word.
455*12752Ssam 	 */
456*12752Ssam 	case TIOCLBIS:
457*12752Ssam 		tp->t_flags |= *(int *)data << 16;
458*12752Ssam 		break;
459*12752Ssam 
460*12752Ssam 	case TIOCLBIC:
461*12752Ssam 		tp->t_flags &= ~(*(int *)data << 16);
462*12752Ssam 		break;
463*12752Ssam 
464*12752Ssam 	case TIOCLSET:
465*12752Ssam 		tp->t_flags &= 0xffff;
466*12752Ssam 		tp->t_flags |= *(int *)data << 16;
467*12752Ssam 		break;
468*12752Ssam 
469*12752Ssam 	case TIOCLGET:
470*12752Ssam 		*(int *)data = tp->t_flags >> 16;
471*12752Ssam 		break;
472*12752Ssam 
473*12752Ssam 	/* should allow SPGRP and GPGRP only if tty open for reading */
474*12752Ssam 	case TIOCSPGRP:
475*12752Ssam 		tp->t_pgrp = *(int *)data;
476*12752Ssam 		break;
477*12752Ssam 
478*12752Ssam 	case TIOCGPGRP:
479*12752Ssam 		*(int *)data = tp->t_pgrp;
480*12752Ssam 		break;
481*12752Ssam 
48239Sbill 	default:
4838556Sroot 		return (-1);
48439Sbill 	}
4858556Sroot 	return (0);
48639Sbill }
4874484Swnj 
4884484Swnj ttnread(tp)
4894484Swnj 	struct tty *tp;
4904484Swnj {
4914484Swnj 	int nread = 0;
4924484Swnj 
4939578Ssam 	if (tp->t_flags & PENDIN)
4944484Swnj 		ttypend(tp);
4954484Swnj 	nread = tp->t_canq.c_cc;
4964484Swnj 	if (tp->t_flags & (RAW|CBREAK))
4974484Swnj 		nread += tp->t_rawq.c_cc;
4984484Swnj 	return (nread);
4994484Swnj }
5004484Swnj 
5015408Swnj ttselect(dev, rw)
5024484Swnj 	dev_t dev;
5035408Swnj 	int rw;
5044484Swnj {
5054484Swnj 	register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)];
5064484Swnj 	int nread;
5075408Swnj 	int s = spl5();
5084484Swnj 
5095408Swnj 	switch (rw) {
5104484Swnj 
5114484Swnj 	case FREAD:
5124484Swnj 		nread = ttnread(tp);
5134484Swnj 		if (nread > 0)
5145408Swnj 			goto win;
5154938Swnj 		if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait)
5165408Swnj 			tp->t_state |= TS_RCOLL;
5174484Swnj 		else
5184484Swnj 			tp->t_rsel = u.u_procp;
5195408Swnj 		break;
5204484Swnj 
5215408Swnj 	case FWRITE:
5225408Swnj 		if (tp->t_outq.c_cc <= TTLOWAT(tp))
5235408Swnj 			goto win;
5245408Swnj 		if (tp->t_wsel && tp->t_wsel->p_wchan == (caddr_t)&selwait)
5255408Swnj 			tp->t_state |= TS_WCOLL;
5265408Swnj 		else
5275408Swnj 			tp->t_wsel = u.u_procp;
5285408Swnj 		break;
5294484Swnj 	}
5305408Swnj 	splx(s);
5315408Swnj 	return (0);
5325408Swnj win:
5335408Swnj 	splx(s);
5345408Swnj 	return (1);
5354484Swnj }
5367436Skre 
5377502Sroot /*
5389578Ssam  * Establish a process group for distribution of
5397502Sroot  * quits and interrupts from the tty.
5407502Sroot  */
5417502Sroot ttyopen(dev, tp)
5427625Ssam 	dev_t dev;
5437625Ssam 	register struct tty *tp;
5447502Sroot {
5457502Sroot 	register struct proc *pp;
5467502Sroot 
5477502Sroot 	pp = u.u_procp;
5487502Sroot 	tp->t_dev = dev;
5497625Ssam 	if (pp->p_pgrp == 0) {
5507502Sroot 		u.u_ttyp = tp;
5517502Sroot 		u.u_ttyd = dev;
5527502Sroot 		if (tp->t_pgrp == 0)
5537502Sroot 			tp->t_pgrp = pp->p_pid;
5547502Sroot 		pp->p_pgrp = tp->t_pgrp;
5557502Sroot 	}
5567502Sroot 	tp->t_state &= ~TS_WOPEN;
5577502Sroot 	tp->t_state |= TS_ISOPEN;
5587502Sroot 	if (tp->t_line != NTTYDISC)
559*12752Ssam 		ttywflush(tp);
5608556Sroot 	return (0);
5617502Sroot }
5627502Sroot 
5637502Sroot /*
5647502Sroot  * clean tp on last close
5657502Sroot  */
5667502Sroot ttyclose(tp)
5677625Ssam 	register struct tty *tp;
5687502Sroot {
5697502Sroot 
5707502Sroot 	if (tp->t_line) {
571*12752Ssam 		ttywflush(tp);
5727502Sroot 		tp->t_line = 0;
5737502Sroot 		return;
5747502Sroot 	}
5757502Sroot 	tp->t_pgrp = 0;
576*12752Ssam 	ttywflush(tp);
5777502Sroot 	tp->t_state = 0;
5787502Sroot }
5797502Sroot 
5807502Sroot /*
5817502Sroot  * reinput pending characters after state switch
5827502Sroot  * call at spl5().
5837502Sroot  */
5847502Sroot ttypend(tp)
5857625Ssam 	register struct tty *tp;
5867502Sroot {
5877502Sroot 	struct clist tq;
5887502Sroot 	register c;
5897502Sroot 
5909578Ssam 	tp->t_flags &= ~PENDIN;
5919578Ssam 	tp->t_state |= TS_TYPEN;
5927502Sroot 	tq = tp->t_rawq;
5937502Sroot 	tp->t_rawq.c_cc = 0;
5947502Sroot 	tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0;
5957502Sroot 	while ((c = getc(&tq)) >= 0)
5967502Sroot 		ttyinput(c, tp);
5979578Ssam 	tp->t_state &= ~TS_TYPEN;
5987502Sroot }
5997502Sroot 
6007502Sroot /*
6019578Ssam  * Place a character on raw TTY input queue,
6029578Ssam  * putting in delimiters and waking up top
6039578Ssam  * half as needed.  Also echo if required.
6049578Ssam  * The arguments are the character and the
6059578Ssam  * appropriate tty structure.
6067502Sroot  */
6077502Sroot ttyinput(c, tp)
6087625Ssam 	register c;
6097625Ssam 	register struct tty *tp;
6107502Sroot {
6119578Ssam 	register int t_flags = tp->t_flags;
6127502Sroot 	int i;
6137502Sroot 
6149578Ssam 	/*
6159578Ssam 	 * If input is pending take it first.
6169578Ssam 	 */
6179578Ssam 	if (t_flags&PENDIN)
6187502Sroot 		ttypend(tp);
6197502Sroot 	tk_nin++;
6207502Sroot 	c &= 0377;
6219578Ssam 
6229578Ssam 	/*
6239578Ssam 	 * In tandem mode, check high water mark.
6249578Ssam 	 */
6257502Sroot 	if (t_flags&TANDEM)
6267502Sroot 		ttyblock(tp);
6279578Ssam 
6289578Ssam 	if (t_flags&RAW) {
6299578Ssam 		/*
6309578Ssam 		 * Raw mode, just put character
6319578Ssam 		 * in input q w/o interpretation.
6329578Ssam 		 */
6339578Ssam 		if (tp->t_rawq.c_cc > TTYHOG)
634*12752Ssam 			ttyflush(tp, FREAD|FWRITE);
6359578Ssam 		else {
6369578Ssam 			if (putc(c, &tp->t_rawq) >= 0)
6379578Ssam 				ttwakeup(tp);
6389578Ssam 			ttyecho(c, tp);
6397502Sroot 		}
6409578Ssam 		goto endcase;
6419578Ssam 	}
6429578Ssam 
6439578Ssam 	/*
6449578Ssam 	 * Ignore any high bit added during
6459578Ssam 	 * previous ttyinput processing.
6469578Ssam 	 */
6479578Ssam 	if ((tp->t_state&TS_TYPEN) == 0)
6489578Ssam 		c &= 0177;
6499578Ssam 	/*
6509578Ssam 	 * Check for literal nexting very first
6519578Ssam 	 */
6529578Ssam 	if (tp->t_state&TS_LNCH) {
6539578Ssam 		c |= 0200;
6549578Ssam 		tp->t_state &= ~TS_LNCH;
6559578Ssam 	}
6569578Ssam 
6579578Ssam 	/*
6589578Ssam 	 * Scan for special characters.  This code
6599578Ssam 	 * is really just a big case statement with
6609578Ssam 	 * non-constant cases.  The bottom of the
6619578Ssam 	 * case statement is labeled ``endcase'', so goto
6629578Ssam 	 * it after a case match, or similar.
6639578Ssam 	 */
6649578Ssam 	if (tp->t_line == NTTYDISC) {
6659578Ssam 		if (c == tp->t_lnextc) {
6667502Sroot 			if (tp->t_flags&ECHO)
6677502Sroot 				ttyout("^\b", tp);
6689578Ssam 			tp->t_state |= TS_LNCH;
6699578Ssam 			goto endcase;
6709578Ssam 		}
6719578Ssam 		if (c == tp->t_flushc) {
6729578Ssam 			if (tp->t_flags&FLUSHO)
6739578Ssam 				tp->t_flags &= ~FLUSHO;
6747502Sroot 			else {
675*12752Ssam 				ttyflush(tp, FWRITE);
6767502Sroot 				ttyecho(c, tp);
6779578Ssam 				if (tp->t_rawq.c_cc + tp->t_canq.c_cc)
6787502Sroot 					ttyretype(tp);
6799578Ssam 				tp->t_flags |= FLUSHO;
6807502Sroot 			}
6819578Ssam 			goto startoutput;
6829578Ssam 		}
6839578Ssam 		if (c == tp->t_suspc) {
6849578Ssam 			if ((tp->t_flags&NOFLSH) == 0)
685*12752Ssam 				ttyflush(tp, FREAD);
6869578Ssam 			ttyecho(c, tp);
6879578Ssam 			gsignal(tp->t_pgrp, SIGTSTP);
6889578Ssam 			goto endcase;
6899578Ssam 		}
6909578Ssam 	}
6919578Ssam 
6929578Ssam 	/*
6939578Ssam 	 * Handle start/stop characters.
6949578Ssam 	 */
6959578Ssam 	if (c == tp->t_stopc) {
6969578Ssam 		if ((tp->t_state&TS_TTSTOP) == 0) {
6979578Ssam 			tp->t_state |= TS_TTSTOP;
6989578Ssam 			(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
6997502Sroot 			return;
7009578Ssam 		}
7019578Ssam 		if (c != tp->t_startc)
7029578Ssam 			return;
7039578Ssam 		goto endcase;
7049578Ssam 	}
7059578Ssam 	if (c == tp->t_startc)
7069578Ssam 		goto restartoutput;
7079578Ssam 
7089578Ssam 	/*
7099578Ssam 	 * Look for interrupt/quit chars.
7109578Ssam 	 */
7119578Ssam 	if (c == tp->t_intrc || c == tp->t_quitc) {
7129578Ssam 		if ((tp->t_flags&NOFLSH) == 0)
713*12752Ssam 			ttyflush(tp, FREAD|FWRITE);
7149578Ssam 		ttyecho(c, tp);
7159578Ssam 		gsignal(tp->t_pgrp, c == tp->t_intrc ? SIGINT : SIGQUIT);
7169578Ssam 		goto endcase;
7179578Ssam 	}
7189578Ssam 
7199578Ssam 	/*
7209578Ssam 	 * Cbreak mode, don't process line editing
7219578Ssam 	 * characters; check high water mark for wakeup.
7229578Ssam 	 */
7239578Ssam 	if (t_flags&CBREAK) {
7249578Ssam 		if (tp->t_rawq.c_cc > TTYHOG) {
7257502Sroot 			if (tp->t_outq.c_cc < TTHIWAT(tp) &&
7267502Sroot 			    tp->t_line == NTTYDISC)
7277502Sroot 				(void) ttyoutput(CTRL(g), tp);
7287502Sroot 		} else if (putc(c, &tp->t_rawq) >= 0) {
7297502Sroot 			ttwakeup(tp);
7307502Sroot 			ttyecho(c, tp);
7317502Sroot 		}
7329578Ssam 		goto endcase;
7339578Ssam 	}
7349578Ssam 
7359578Ssam 	/*
7369578Ssam 	 * From here on down cooked mode character
7379578Ssam 	 * processing takes place.
7389578Ssam 	 */
7399578Ssam 	if ((tp->t_state&TS_QUOT) &&
7409578Ssam 	    (c == tp->t_erase || c == tp->t_kill)) {
7419578Ssam 		ttyrub(unputc(&tp->t_rawq), tp);
7429578Ssam 		c |= 0200;
7439578Ssam 	}
7449578Ssam 	if (c == tp->t_erase) {
7459578Ssam 		if (tp->t_rawq.c_cc)
7469578Ssam 			ttyrub(unputc(&tp->t_rawq), tp);
7479578Ssam 		goto endcase;
7489578Ssam 	}
7499578Ssam 	if (c == tp->t_kill) {
7509578Ssam 		if (tp->t_flags&CRTKIL &&
7519578Ssam 		    tp->t_rawq.c_cc == tp->t_rocount) {
7529578Ssam 			while (tp->t_rawq.c_cc)
7539578Ssam 				ttyrub(unputc(&tp->t_rawq), tp);
7549578Ssam 		} else {
7559578Ssam 			ttyecho(c, tp);
7569578Ssam 			ttyecho('\n', tp);
7579578Ssam 			while (getc(&tp->t_rawq) > 0)
7589578Ssam 				;
7599578Ssam 			tp->t_rocount = 0;
7609578Ssam 		}
7619578Ssam 		tp->t_state &= ~TS_LOCAL;
7629578Ssam 		goto endcase;
7639578Ssam 	}
7649578Ssam 
7659578Ssam 	/*
7669578Ssam 	 * New line discipline,
7679578Ssam 	 * check word erase/reprint line.
7689578Ssam 	 */
7699578Ssam 	if (tp->t_line == NTTYDISC) {
7709578Ssam 		if (c == tp->t_werasc) {
7719578Ssam 			if (tp->t_rawq.c_cc == 0)
7729578Ssam 				goto endcase;
7739578Ssam 			do {
7749578Ssam 				c = unputc(&tp->t_rawq);
7759578Ssam 				if (c != ' ' && c != '\t')
7769578Ssam 					goto erasenb;
7779578Ssam 				ttyrub(c, tp);
7789578Ssam 			} while (tp->t_rawq.c_cc);
7799578Ssam 			goto endcase;
7809578Ssam 	erasenb:
7819578Ssam 			do {
7829578Ssam 				ttyrub(c, tp);
7839578Ssam 				if (tp->t_rawq.c_cc == 0)
7849578Ssam 					goto endcase;
7859578Ssam 				c = unputc(&tp->t_rawq);
7869578Ssam 			} while (c != ' ' && c != '\t');
7879578Ssam 			(void) putc(c, &tp->t_rawq);
7889578Ssam 			goto endcase;
7899578Ssam 		}
7909578Ssam 		if (c == tp->t_rprntc) {
7919578Ssam 			ttyretype(tp);
7929578Ssam 			goto endcase;
7939578Ssam 		}
7949578Ssam 	}
7959578Ssam 
7969578Ssam 	/*
7979578Ssam 	 * Check for input buffer overflow
7989578Ssam 	 */
79910391Ssam 	if (tp->t_rawq.c_cc+tp->t_canq.c_cc >= TTYHOG) {
80010391Ssam 		if (tp->t_line == NTTYDISC)
80110391Ssam 			(void) ttyoutput(CTRL(g), tp);
8029578Ssam 		goto endcase;
80310391Ssam 	}
8049578Ssam 
8059578Ssam 	/*
8069578Ssam 	 * Put data char in q for user and
8079578Ssam 	 * wakeup on seeing a line delimiter.
8089578Ssam 	 */
8099578Ssam 	if (putc(c, &tp->t_rawq) >= 0) {
8109578Ssam 		if (ttbreakc(c, tp)) {
8119578Ssam 			tp->t_rocount = 0;
8129578Ssam 			catq(&tp->t_rawq, &tp->t_canq);
8137502Sroot 			ttwakeup(tp);
8149578Ssam 		} else if (tp->t_rocount++ == 0)
8159578Ssam 			tp->t_rocol = tp->t_col;
8169578Ssam 		tp->t_state &= ~TS_QUOT;
8179578Ssam 		if (c == '\\')
8189578Ssam 			tp->t_state |= TS_QUOT;
8199578Ssam 		if (tp->t_state&TS_ERASE) {
8209578Ssam 			tp->t_state &= ~TS_ERASE;
8219578Ssam 			(void) ttyoutput('/', tp);
8229578Ssam 		}
8239578Ssam 		i = tp->t_col;
8247502Sroot 		ttyecho(c, tp);
8259578Ssam 		if (c == tp->t_eofc && tp->t_flags&ECHO) {
8269578Ssam 			i = MIN(2, tp->t_col - i);
8279578Ssam 			while (i > 0) {
8289578Ssam 				(void) ttyoutput('\b', tp);
8299578Ssam 				i--;
8309578Ssam 			}
8319578Ssam 		}
8327502Sroot 	}
8339578Ssam 
8349578Ssam endcase:
8359578Ssam 	/*
8369578Ssam 	 * If DEC-style start/stop is enabled don't restart
8379578Ssam 	 * output until seeing the start character.
8389578Ssam 	 */
8399578Ssam 	if (tp->t_flags&DECCTQ && tp->t_state&TS_TTSTOP &&
8409578Ssam 	    tp->t_startc != tp->t_stopc)
8417502Sroot 		return;
8429578Ssam 
8439578Ssam restartoutput:
8447502Sroot 	tp->t_state &= ~TS_TTSTOP;
8459578Ssam 	tp->t_flags &= ~FLUSHO;
8469578Ssam 
8479578Ssam startoutput:
8487502Sroot 	ttstart(tp);
8497502Sroot }
8507502Sroot 
8517502Sroot /*
8529578Ssam  * Put character on TTY output queue, adding delays,
8537502Sroot  * expanding tabs, and handling the CR/NL bit.
8549578Ssam  * This is called both from the top half for output,
8559578Ssam  * and from interrupt level for echoing.
8567502Sroot  * The arguments are the character and the tty structure.
8577502Sroot  * Returns < 0 if putc succeeds, otherwise returns char to resend
8587502Sroot  * Must be recursive.
8597502Sroot  */
8607502Sroot ttyoutput(c, tp)
8617502Sroot 	register c;
8627502Sroot 	register struct tty *tp;
8637502Sroot {
8647502Sroot 	register char *colp;
8657502Sroot 	register ctype;
8667502Sroot 
8679578Ssam 	if (tp->t_flags & (RAW|LITOUT)) {
8689578Ssam 		if (tp->t_flags&FLUSHO)
8697502Sroot 			return (-1);
8707502Sroot 		if (putc(c, &tp->t_outq))
8717625Ssam 			return (c);
8727502Sroot 		tk_nout++;
8737502Sroot 		return (-1);
8747502Sroot 	}
8759578Ssam 
8767502Sroot 	/*
8779578Ssam 	 * Ignore EOT in normal mode to avoid
8789578Ssam 	 * hanging up certain terminals.
8797502Sroot 	 */
8807502Sroot 	c &= 0177;
8819578Ssam 	if (c == CEOT && (tp->t_flags&CBREAK) == 0)
8827502Sroot 		return (-1);
8837502Sroot 	/*
8847502Sroot 	 * Turn tabs to spaces as required
8857502Sroot 	 */
8869578Ssam 	if (c == '\t' && (tp->t_flags&TBDELAY) == XTABS) {
8877502Sroot 		register int s;
8887502Sroot 
8897502Sroot 		c = 8 - (tp->t_col&7);
8909578Ssam 		if ((tp->t_flags&FLUSHO) == 0) {
8917502Sroot 			s = spl5();		/* don't interrupt tabs */
8927502Sroot 			c -= b_to_q("        ", c, &tp->t_outq);
8937502Sroot 			tk_nout += c;
8947502Sroot 			splx(s);
8957502Sroot 		}
8967502Sroot 		tp->t_col += c;
8977502Sroot 		return (c ? -1 : '\t');
8987502Sroot 	}
8997502Sroot 	tk_nout++;
9007502Sroot 	/*
9017502Sroot 	 * for upper-case-only terminals,
9027502Sroot 	 * generate escapes.
9037502Sroot 	 */
9047502Sroot 	if (tp->t_flags&LCASE) {
9057502Sroot 		colp = "({)}!|^~'`";
9067625Ssam 		while (*colp++)
9077625Ssam 			if (c == *colp++) {
9087502Sroot 				if (ttyoutput('\\', tp) >= 0)
9097502Sroot 					return (c);
9107502Sroot 				c = colp[-2];
9117502Sroot 				break;
9127502Sroot 			}
9139578Ssam 		if ('A' <= c && c <= 'Z') {
9147502Sroot 			if (ttyoutput('\\', tp) >= 0)
9157502Sroot 				return (c);
9169578Ssam 		} else if ('a' <= c && c <= 'z')
9177502Sroot 			c += 'A' - 'a';
9187502Sroot 	}
9199578Ssam 
9207502Sroot 	/*
9217502Sroot 	 * turn <nl> to <cr><lf> if desired.
9227502Sroot 	 */
9239578Ssam 	if (c == '\n' && tp->t_flags&CRMOD)
9247502Sroot 		if (ttyoutput('\r', tp) >= 0)
9257502Sroot 			return (c);
9269578Ssam 	if (c == '~' && tp->t_flags&TILDE)
9277502Sroot 		c = '`';
9289578Ssam 	if ((tp->t_flags&FLUSHO) == 0 && putc(c, &tp->t_outq))
9297502Sroot 		return (c);
9307502Sroot 	/*
9317502Sroot 	 * Calculate delays.
9327502Sroot 	 * The numbers here represent clock ticks
9337502Sroot 	 * and are not necessarily optimal for all terminals.
9347502Sroot 	 * The delays are indicated by characters above 0200.
9357502Sroot 	 * In raw mode there are no delays and the
9367502Sroot 	 * transmission path is 8 bits wide.
9379578Ssam 	 *
9389578Ssam 	 * SHOULD JUST ALLOW USER TO SPECIFY DELAYS
9397502Sroot 	 */
9407502Sroot 	colp = &tp->t_col;
9417502Sroot 	ctype = partab[c];
9427502Sroot 	c = 0;
9437502Sroot 	switch (ctype&077) {
9447502Sroot 
9457502Sroot 	case ORDINARY:
9467502Sroot 		(*colp)++;
9477502Sroot 
9487502Sroot 	case CONTROL:
9497502Sroot 		break;
9507502Sroot 
9517502Sroot 	case BACKSPACE:
9527502Sroot 		if (*colp)
9537502Sroot 			(*colp)--;
9547502Sroot 		break;
9557502Sroot 
9567502Sroot 	case NEWLINE:
9577502Sroot 		ctype = (tp->t_flags >> 8) & 03;
9587625Ssam 		if (ctype == 1) { /* tty 37 */
959*12752Ssam 			if (*colp > 0)
9607502Sroot 				c = max(((unsigned)*colp>>4) + 3, (unsigned)6);
9619578Ssam 		} else if (ctype == 2) /* vt05 */
9627502Sroot 			c = 6;
9637502Sroot 		*colp = 0;
9647502Sroot 		break;
9657502Sroot 
9667502Sroot 	case TAB:
9677502Sroot 		ctype = (tp->t_flags >> 10) & 03;
9687625Ssam 		if (ctype == 1) { /* tty 37 */
9697502Sroot 			c = 1 - (*colp | ~07);
9707625Ssam 			if (c < 5)
9717502Sroot 				c = 0;
9727502Sroot 		}
9737502Sroot 		*colp |= 07;
9747502Sroot 		(*colp)++;
9757502Sroot 		break;
9767502Sroot 
9777502Sroot 	case VTAB:
9789578Ssam 		if (tp->t_flags&VTDELAY) /* tty 37 */
9797502Sroot 			c = 0177;
9807502Sroot 		break;
9817502Sroot 
9827502Sroot 	case RETURN:
9837502Sroot 		ctype = (tp->t_flags >> 12) & 03;
9849578Ssam 		if (ctype == 1) /* tn 300 */
9857502Sroot 			c = 5;
9869578Ssam 		else if (ctype == 2) /* ti 700 */
9877502Sroot 			c = 10;
9889578Ssam 		else if (ctype == 3) { /* concept 100 */
9897502Sroot 			int i;
9909578Ssam 
9917502Sroot 			if ((i = *colp) >= 0)
9929578Ssam 				for (; i < 9; i++)
9937502Sroot 					(void) putc(0177, &tp->t_outq);
9947502Sroot 		}
9957502Sroot 		*colp = 0;
9967502Sroot 	}
9979578Ssam 	if (c && (tp->t_flags&FLUSHO) == 0)
9987502Sroot 		(void) putc(c|0200, &tp->t_outq);
9997502Sroot 	return (-1);
10007502Sroot }
10017502Sroot 
10027502Sroot /*
10037502Sroot  * Called from device's read routine after it has
10047502Sroot  * calculated the tty-structure given as argument.
10057502Sroot  */
10067722Swnj ttread(tp, uio)
10077625Ssam 	register struct tty *tp;
10087722Swnj 	struct uio *uio;
10097502Sroot {
10107502Sroot 	register struct clist *qp;
10119578Ssam 	register c, t_flags;
10129859Ssam 	int s, first, error = 0;
10137502Sroot 
10147502Sroot 	if ((tp->t_state&TS_CARR_ON)==0)
10158520Sroot 		return (EIO);
10167502Sroot loop:
10179578Ssam 	/*
10189578Ssam 	 * Take any pending input first.
10199578Ssam 	 */
10209859Ssam 	s = spl5();
10219578Ssam 	if (tp->t_flags&PENDIN)
10227502Sroot 		ttypend(tp);
10239859Ssam 	splx(s);
10249578Ssam 
10259578Ssam 	/*
10269578Ssam 	 * Hang process if it's in the background.
10279578Ssam 	 */
10287502Sroot 	while (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) {
10297502Sroot 		if (u.u_signal[SIGTTIN] == SIG_IGN ||
10307502Sroot 		    u.u_signal[SIGTTIN] == SIG_HOLD ||
10317502Sroot /*
10327502Sroot 		    (u.u_procp->p_flag&SDETACH) ||
10337502Sroot */
10347502Sroot 		    u.u_procp->p_flag&SVFORK)
10358520Sroot 			return (EIO);
10367502Sroot 		gsignal(u.u_procp->p_pgrp, SIGTTIN);
10377502Sroot 		sleep((caddr_t)&lbolt, TTIPRI);
10387502Sroot 	}
10399578Ssam 	t_flags = tp->t_flags;
10409578Ssam 
10419578Ssam 	/*
10429578Ssam 	 * In raw mode take characters directly from the
10439578Ssam 	 * raw queue w/o processing.  Interlock against
10449578Ssam 	 * device interrupts when interrogating rawq.
10459578Ssam 	 */
10469578Ssam 	if (t_flags&RAW) {
10479859Ssam 		s = spl5();
10487502Sroot 		if (tp->t_rawq.c_cc <= 0) {
10499578Ssam 			if ((tp->t_state&TS_CARR_ON) == 0 ||
10507502Sroot 			    (tp->t_state&TS_NBIO)) {
10519859Ssam 				splx(s);
10529578Ssam 				return (0);
10537502Sroot 			}
10547502Sroot 			sleep((caddr_t)&tp->t_rawq, TTIPRI);
10559859Ssam 			splx(s);
10567502Sroot 			goto loop;
10577502Sroot 		}
10589859Ssam 		splx(s);
10599859Ssam 		while (!error && tp->t_rawq.c_cc && uio->uio_iovcnt)
10608520Sroot 			error = passuc(getc(&tp->t_rawq), uio);
10619859Ssam 		goto checktandem;
10629578Ssam 	}
10639578Ssam 
10649578Ssam 	/*
10659578Ssam 	 * In cbreak mode use the rawq, otherwise
10669578Ssam 	 * take characters from the canonicalized q.
10679578Ssam 	 */
10689578Ssam 	qp = t_flags&CBREAK ? &tp->t_rawq : &tp->t_canq;
10699578Ssam 
10709578Ssam 	/*
10719578Ssam 	 * No input, sleep on rawq awaiting hardware
10729578Ssam 	 * receipt and notification.
10739578Ssam 	 */
10749859Ssam 	s = spl5();
10759578Ssam 	if (qp->c_cc <= 0) {
10769578Ssam 		if ((tp->t_state&TS_CARR_ON) == 0 ||
10779578Ssam 		    (tp->t_state&TS_NBIO)) {
10789859Ssam 			splx(s);
10799578Ssam 			return (EWOULDBLOCK);
10807502Sroot 		}
10819578Ssam 		sleep((caddr_t)&tp->t_rawq, TTIPRI);
10829859Ssam 		splx(s);
10839578Ssam 		goto loop;
10849578Ssam 	}
10859859Ssam 	splx(s);
10869578Ssam 
10879578Ssam 	/*
10889578Ssam 	 * Input present, perform input mapping
10899578Ssam 	 * and processing (we're not in raw mode).
10909578Ssam 	 */
10919578Ssam 	first = 1;
10929578Ssam 	while ((c = getc(qp)) >= 0) {
10939578Ssam 		if (t_flags&CRMOD && c == '\r')
10949578Ssam 			c = '\n';
10959578Ssam 		/*
10969578Ssam 		 * Hack lower case simulation on
10979578Ssam 		 * upper case only terminals.
10989578Ssam 		 */
10999578Ssam 		if (t_flags&LCASE && c <= 0177)
11009578Ssam 			if (tp->t_state&TS_BKSL) {
11019578Ssam 				if (maptab[c])
11029578Ssam 					c = maptab[c];
11039578Ssam 				tp->t_state &= ~TS_BKSL;
11049578Ssam 			} else if (c >= 'A' && c <= 'Z')
11059578Ssam 				c += 'a' - 'A';
11069578Ssam 			else if (c == '\\') {
11079578Ssam 				tp->t_state |= TS_BKSL;
11089578Ssam 				continue;
11097502Sroot 			}
11109578Ssam 		/*
11119578Ssam 		 * Check for delayed suspend character.
11129578Ssam 		 */
11139578Ssam 		if (tp->t_line == NTTYDISC && c == tp->t_dsuspc) {
11149578Ssam 			gsignal(tp->t_pgrp, SIGTSTP);
11159578Ssam 			if (first) {
11169578Ssam 				sleep((caddr_t)&lbolt, TTIPRI);
11179578Ssam 				goto loop;
11189578Ssam 			}
11199578Ssam 			break;
11207502Sroot 		}
11219578Ssam 		/*
11229578Ssam 		 * Interpret EOF only in cooked mode.
11239578Ssam 		 */
11249578Ssam 		if (c == tp->t_eofc && (t_flags&CBREAK) == 0)
11259578Ssam 			break;
11269578Ssam 		/*
11279578Ssam 		 * Give user character.
11289578Ssam 		 */
11299578Ssam 		error = passuc(c & 0177, uio);
11309578Ssam 		if (error)
11319578Ssam 			break;
11329578Ssam 		if (uio->uio_iovcnt == 0)
11339578Ssam 			break;
11349578Ssam 		/*
11359578Ssam 		 * In cooked mode check for a "break character"
11369578Ssam 		 * marking the end of a "line of input".
11379578Ssam 		 */
11389578Ssam 		if ((t_flags&CBREAK) == 0 && ttbreakc(c, tp))
11399578Ssam 			break;
11409578Ssam 		first = 0;
11417502Sroot 	}
11429578Ssam 	tp->t_state &= ~TS_BKSL;
11439578Ssam 
11449859Ssam checktandem:
11459578Ssam 	/*
11469578Ssam 	 * Look to unblock output now that (presumably)
11479578Ssam 	 * the input queue has gone down.
11489578Ssam 	 */
11499859Ssam 	if (tp->t_state&TS_TBLOCK && tp->t_rawq.c_cc < TTYHOG/5)
11509578Ssam 		if (putc(tp->t_startc, &tp->t_outq) == 0) {
11517502Sroot 			tp->t_state &= ~TS_TBLOCK;
11527502Sroot 			ttstart(tp);
11537502Sroot 		}
11548520Sroot 	return (error);
11557502Sroot }
11567502Sroot 
11577502Sroot /*
11587502Sroot  * Called from the device's write routine after it has
11597502Sroot  * calculated the tty-structure given as argument.
11607502Sroot  */
11617822Sroot ttwrite(tp, uio)
11627625Ssam 	register struct tty *tp;
11639578Ssam 	register struct uio *uio;
11647502Sroot {
11657502Sroot 	register char *cp;
11669578Ssam 	register int cc, ce, c;
11679578Ssam 	int i, hiwat, cnt, error, s;
11687502Sroot 	char obuf[OBUFSIZ];
11697502Sroot 
11709578Ssam 	if ((tp->t_state&TS_CARR_ON) == 0)
11718520Sroot 		return (EIO);
11729578Ssam 	hiwat = TTHIWAT(tp);
11739578Ssam 	cnt = uio->uio_resid;
11749578Ssam 	error = 0;
11757502Sroot loop:
11769578Ssam 	/*
11779578Ssam 	 * Hang the process if it's in the background.
11789578Ssam 	 */
11797502Sroot 	while (u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp &&
11809578Ssam 	    (tp->t_flags&TOSTOP) && (u.u_procp->p_flag&SVFORK)==0 &&
11817502Sroot 	    u.u_signal[SIGTTOU] != SIG_IGN &&
11827502Sroot 	    u.u_signal[SIGTTOU] != SIG_HOLD
11837502Sroot /*
11847502Sroot 					     &&
11857502Sroot 	    (u.u_procp->p_flag&SDETACH)==0) {
11867502Sroot */
11877502Sroot 	    ) {
11887502Sroot 		gsignal(u.u_procp->p_pgrp, SIGTTOU);
11897502Sroot 		sleep((caddr_t)&lbolt, TTIPRI);
11907502Sroot 	}
11919578Ssam 
11929578Ssam 	/*
11939578Ssam 	 * Process the user's data in at most OBUFSIZ
11949578Ssam 	 * chunks.  Perform lower case simulation and
11959578Ssam 	 * similar hacks.  Keep track of high water
11969578Ssam 	 * mark, sleep on overflow awaiting device aid
11979578Ssam 	 * in acquiring new space.
11989578Ssam 	 */
11997822Sroot 	while (uio->uio_resid > 0) {
12009578Ssam 		/*
12019578Ssam 		 * Grab a hunk of data from the user.
12029578Ssam 		 */
12037822Sroot 		cc = uio->uio_iov->iov_len;
12047822Sroot 		if (cc == 0) {
12057822Sroot 			uio->uio_iovcnt--;
12067822Sroot 			uio->uio_iov++;
12077822Sroot 			if (uio->uio_iovcnt < 0)
12087822Sroot 				panic("ttwrite");
12097822Sroot 			continue;
12107822Sroot 		}
12117822Sroot 		if (cc > OBUFSIZ)
12127822Sroot 			cc = OBUFSIZ;
12137502Sroot 		cp = obuf;
1214*12752Ssam 		error = uiomove(cp, cc, UIO_WRITE, uio);
12158520Sroot 		if (error)
12167502Sroot 			break;
12177502Sroot 		if (tp->t_outq.c_cc > hiwat)
12187502Sroot 			goto ovhiwat;
12199578Ssam 		if (tp->t_flags&FLUSHO)
12207502Sroot 			continue;
12219578Ssam 		/*
12229578Ssam 		 * If we're mapping lower case or kludging tildes,
12239578Ssam 		 * then we've got to look at each character, so
12249578Ssam 		 * just feed the stuff to ttyoutput...
12259578Ssam 		 */
12269578Ssam 		if (tp->t_flags & (LCASE|TILDE)) {
12279578Ssam 			while (cc > 0) {
12287502Sroot 				c = *cp++;
12297502Sroot 				tp->t_rocount = 0;
12307625Ssam 				while ((c = ttyoutput(c, tp)) >= 0) {
12317502Sroot 					/* out of clists, wait a bit */
12327502Sroot 					ttstart(tp);
12337502Sroot 					sleep((caddr_t)&lbolt, TTOPRI);
12347502Sroot 					tp->t_rocount = 0;
12357502Sroot 				}
12367502Sroot 				--cc;
12377502Sroot 				if (tp->t_outq.c_cc > hiwat)
12387502Sroot 					goto ovhiwat;
12397502Sroot 			}
12407502Sroot 			continue;
12417502Sroot 		}
12429578Ssam 		/*
12439578Ssam 		 * If nothing fancy need be done, grab those characters we
12449578Ssam 		 * can handle without any of ttyoutput's processing and
12459578Ssam 		 * just transfer them to the output q.  For those chars
12469578Ssam 		 * which require special processing (as indicated by the
12479578Ssam 		 * bits in partab), call ttyoutput.  After processing
12489578Ssam 		 * a hunk of data, look for FLUSHO so ^O's will take effect
12499578Ssam 		 * immediately.
12509578Ssam 		 */
12519578Ssam 		while (cc > 0) {
12529578Ssam 			if (tp->t_flags & (RAW|LITOUT))
12537502Sroot 				ce = cc;
12547502Sroot 			else {
1255*12752Ssam 				ce = cc - scanc((unsigned)cc, (caddr_t)cp,
1256*12752Ssam 				   (caddr_t)partab, 077);
12579578Ssam 				/*
12589578Ssam 				 * If ce is zero, then we're processing
12599578Ssam 				 * a special character through ttyoutput.
12609578Ssam 				 */
12619578Ssam 				if (ce == 0) {
12627502Sroot 					tp->t_rocount = 0;
12637502Sroot 					if (ttyoutput(*cp, tp) >= 0) {
12649578Ssam 						/* no c-lists, wait a bit */
12657502Sroot 						ttstart(tp);
12667502Sroot 						sleep((caddr_t)&lbolt, TTOPRI);
12677502Sroot 						continue;
12687502Sroot 					}
12699578Ssam 					cp++, cc--;
12709578Ssam 					if (tp->t_flags&FLUSHO ||
12719578Ssam 					    tp->t_outq.c_cc > hiwat)
12727502Sroot 						goto ovhiwat;
12739578Ssam 					continue;
12747502Sroot 				}
12757502Sroot 			}
12769578Ssam 			/*
12779578Ssam 			 * A bunch of normal characters have been found,
12789578Ssam 			 * transfer them en masse to the output queue and
12799578Ssam 			 * continue processing at the top of the loop.
12809578Ssam 			 * If there are any further characters in this
12819578Ssam 			 * <= OBUFSIZ chunk, the first should be a character
12829578Ssam 			 * requiring special handling by ttyoutput.
12839578Ssam 			 */
12847502Sroot 			tp->t_rocount = 0;
12859578Ssam 			i = b_to_q(cp, ce, &tp->t_outq);
12869578Ssam 			ce -= i;
12879578Ssam 			tp->t_col += ce;
12889578Ssam 			cp += ce, cc -= ce, tk_nout += ce;
12899578Ssam 			if (i > 0) {
12909578Ssam 				/* out of c-lists, wait a bit */
12917502Sroot 				ttstart(tp);
12927502Sroot 				sleep((caddr_t)&lbolt, TTOPRI);
12937502Sroot 			}
12949578Ssam 			if (tp->t_flags&FLUSHO || tp->t_outq.c_cc > hiwat)
12957502Sroot 				goto ovhiwat;
12967502Sroot 		}
12977502Sroot 	}
12987502Sroot 	ttstart(tp);
12998520Sroot 	return (error);
13007502Sroot 
13017502Sroot ovhiwat:
13029578Ssam 	s = spl5();
13039578Ssam 	if (cc != 0) {
13049578Ssam 		uio->uio_iov->iov_base -= cc;
13059578Ssam 		uio->uio_iov->iov_len += cc;
13069578Ssam 		uio->uio_resid += cc;
13079578Ssam 		uio->uio_offset -= cc;
13089578Ssam 	}
13099578Ssam 	/*
13109578Ssam 	 * This can only occur if FLUSHO
13119578Ssam 	 * is also set in t_flags.
13129578Ssam 	 */
13137502Sroot 	if (tp->t_outq.c_cc <= hiwat) {
13149578Ssam 		splx(s);
13157502Sroot 		goto loop;
13167502Sroot 	}
13177502Sroot 	ttstart(tp);
13189578Ssam 	if (tp->t_state&TS_NBIO) {
13197822Sroot 		if (uio->uio_resid == cnt)
13208520Sroot 			return (EWOULDBLOCK);
13218520Sroot 		return (0);
13227502Sroot 	}
13237502Sroot 	tp->t_state |= TS_ASLEEP;
13247502Sroot 	sleep((caddr_t)&tp->t_outq, TTOPRI);
13259578Ssam 	splx(s);
13267502Sroot 	goto loop;
13277502Sroot }
13287502Sroot 
13297502Sroot /*
13307502Sroot  * Rubout one character from the rawq of tp
13317502Sroot  * as cleanly as possible.
13327502Sroot  */
13337502Sroot ttyrub(c, tp)
13347625Ssam 	register c;
13357625Ssam 	register struct tty *tp;
13367502Sroot {
13377502Sroot 	register char *cp;
13387502Sroot 	register int savecol;
13397502Sroot 	int s;
13407502Sroot 	char *nextc();
13417502Sroot 
13429578Ssam 	if ((tp->t_flags&ECHO) == 0)
13437502Sroot 		return;
13449578Ssam 	tp->t_flags &= ~FLUSHO;
13457502Sroot 	c &= 0377;
13469578Ssam 	if (tp->t_flags&CRTBS) {
13477502Sroot 		if (tp->t_rocount == 0) {
13487502Sroot 			/*
13497502Sroot 			 * Screwed by ttwrite; retype
13507502Sroot 			 */
13517502Sroot 			ttyretype(tp);
13527502Sroot 			return;
13537502Sroot 		}
13549578Ssam 		if (c == ('\t'|0200) || c == ('\n'|0200))
13557502Sroot 			ttyrubo(tp, 2);
13569578Ssam 		else switch (partab[c&=0177]&0177) {
13577502Sroot 
13587502Sroot 		case ORDINARY:
13597502Sroot 			if (tp->t_flags&LCASE && c >= 'A' && c <= 'Z')
13607502Sroot 				ttyrubo(tp, 2);
13617502Sroot 			else
13627502Sroot 				ttyrubo(tp, 1);
13637502Sroot 			break;
13647502Sroot 
13657502Sroot 		case VTAB:
13667502Sroot 		case BACKSPACE:
13677502Sroot 		case CONTROL:
13687502Sroot 		case RETURN:
13699578Ssam 			if (tp->t_flags&CTLECH)
13707502Sroot 				ttyrubo(tp, 2);
13717502Sroot 			break;
13727502Sroot 
13737502Sroot 		case TAB:
13747502Sroot 			if (tp->t_rocount < tp->t_rawq.c_cc) {
13757502Sroot 				ttyretype(tp);
13767502Sroot 				return;
13777502Sroot 			}
13787502Sroot 			s = spl5();
13797502Sroot 			savecol = tp->t_col;
13809578Ssam 			tp->t_state |= TS_CNTTB;
13819578Ssam 			tp->t_flags |= FLUSHO;
13827502Sroot 			tp->t_col = tp->t_rocol;
13839578Ssam 			cp = tp->t_rawq.c_cf;
13849578Ssam 			for (; cp; cp = nextc(&tp->t_rawq, cp))
13857502Sroot 				ttyecho(*cp, tp);
13869578Ssam 			tp->t_flags &= ~FLUSHO;
13879578Ssam 			tp->t_state &= ~TS_CNTTB;
13887502Sroot 			splx(s);
13897502Sroot 			/*
13907502Sroot 			 * savecol will now be length of the tab
13917502Sroot 			 */
13927502Sroot 			savecol -= tp->t_col;
13937502Sroot 			tp->t_col += savecol;
13947502Sroot 			if (savecol > 8)
13957502Sroot 				savecol = 8;		/* overflow screw */
13967502Sroot 			while (--savecol >= 0)
13977502Sroot 				(void) ttyoutput('\b', tp);
13987502Sroot 			break;
13997502Sroot 
14007502Sroot 		default:
14017502Sroot 			panic("ttyrub");
14027502Sroot 		}
14039578Ssam 	} else if (tp->t_flags&PRTERA) {
14049578Ssam 		if ((tp->t_state&TS_ERASE) == 0) {
14057502Sroot 			(void) ttyoutput('\\', tp);
14069578Ssam 			tp->t_state |= TS_ERASE;
14077502Sroot 		}
14087502Sroot 		ttyecho(c, tp);
14097502Sroot 	} else
14107502Sroot 		ttyecho(tp->t_erase, tp);
14117502Sroot 	tp->t_rocount--;
14127502Sroot }
14137502Sroot 
14147502Sroot /*
14157502Sroot  * Crt back over cnt chars perhaps
14167502Sroot  * erasing them.
14177502Sroot  */
14187502Sroot ttyrubo(tp, cnt)
14197625Ssam 	register struct tty *tp;
14207625Ssam 	int cnt;
14217502Sroot {
14229578Ssam 	register char *rubostring = tp->t_flags&CRTERA ? "\b \b" : "\b";
14237502Sroot 
14247502Sroot 	while (--cnt >= 0)
14259578Ssam 		ttyout(rubostring, tp);
14267502Sroot }
14277502Sroot 
14287502Sroot /*
14297502Sroot  * Reprint the rawq line.
14307502Sroot  * We assume c_cc has already been checked.
14317502Sroot  */
14327502Sroot ttyretype(tp)
14337625Ssam 	register struct tty *tp;
14347502Sroot {
14357502Sroot 	register char *cp;
14367502Sroot 	char *nextc();
14377502Sroot 	int s;
14387502Sroot 
14399578Ssam 	if (tp->t_rprntc != 0377)
14409578Ssam 		ttyecho(tp->t_rprntc, tp);
14417502Sroot 	(void) ttyoutput('\n', tp);
14427502Sroot 	s = spl5();
14437502Sroot 	for (cp = tp->t_canq.c_cf; cp; cp = nextc(&tp->t_canq, cp))
14447502Sroot 		ttyecho(*cp, tp);
14457502Sroot 	for (cp = tp->t_rawq.c_cf; cp; cp = nextc(&tp->t_rawq, cp))
14467502Sroot 		ttyecho(*cp, tp);
14479578Ssam 	tp->t_state &= ~TS_ERASE;
14487502Sroot 	splx(s);
14497502Sroot 	tp->t_rocount = tp->t_rawq.c_cc;
14507502Sroot 	tp->t_rocol = 0;
14517502Sroot }
14527502Sroot 
14537502Sroot /*
14547502Sroot  * Echo a typed character to the terminal
14557502Sroot  */
14567502Sroot ttyecho(c, tp)
14577625Ssam 	register c;
14587625Ssam 	register struct tty *tp;
14597502Sroot {
14607502Sroot 
14619578Ssam 	if ((tp->t_state&TS_CNTTB) == 0)
14629578Ssam 		tp->t_flags &= ~FLUSHO;
14637502Sroot 	if ((tp->t_flags&ECHO) == 0)
14647502Sroot 		return;
14657502Sroot 	c &= 0377;
14667502Sroot 	if (tp->t_flags&RAW) {
14677502Sroot 		(void) ttyoutput(c, tp);
14687502Sroot 		return;
14697502Sroot 	}
14707502Sroot 	if (c == '\r' && tp->t_flags&CRMOD)
14717502Sroot 		c = '\n';
14729578Ssam 	if (tp->t_flags&CTLECH) {
14737502Sroot 		if ((c&0177) <= 037 && c!='\t' && c!='\n' || (c&0177)==0177) {
14747502Sroot 			(void) ttyoutput('^', tp);
14757502Sroot 			c &= 0177;
14767502Sroot 			if (c == 0177)
14777502Sroot 				c = '?';
14787502Sroot 			else if (tp->t_flags&LCASE)
14797502Sroot 				c += 'a' - 1;
14807502Sroot 			else
14817502Sroot 				c += 'A' - 1;
14827502Sroot 		}
14837502Sroot 	}
14847502Sroot 	if ((tp->t_flags&LCASE) && (c >= 'A' && c <= 'Z'))
14857502Sroot 		c += 'a' - 'A';
14869578Ssam 	(void) ttyoutput(c&0177, tp);
14877502Sroot }
14887502Sroot 
14897502Sroot /*
14907502Sroot  * Is c a break char for tp?
14917502Sroot  */
14927502Sroot ttbreakc(c, tp)
14937625Ssam 	register c;
14947625Ssam 	register struct tty *tp;
14957502Sroot {
14969578Ssam 	return (c == '\n' || c == tp->t_eofc || c == tp->t_brkc ||
14977502Sroot 		c == '\r' && (tp->t_flags&CRMOD));
14987502Sroot }
14997502Sroot 
15007502Sroot /*
15017502Sroot  * send string cp to tp
15027502Sroot  */
15037502Sroot ttyout(cp, tp)
15047625Ssam 	register char *cp;
15057625Ssam 	register struct tty *tp;
15067502Sroot {
15077502Sroot 	register char c;
15087502Sroot 
15097502Sroot 	while (c = *cp++)
15107502Sroot 		(void) ttyoutput(c, tp);
15117502Sroot }
15127502Sroot 
15137502Sroot ttwakeup(tp)
15147502Sroot 	struct tty *tp;
15157502Sroot {
15167502Sroot 
15177502Sroot 	if (tp->t_rsel) {
15187502Sroot 		selwakeup(tp->t_rsel, tp->t_state&TS_RCOLL);
15197502Sroot 		tp->t_state &= ~TS_RCOLL;
15207502Sroot 		tp->t_rsel = 0;
15217502Sroot 	}
1522*12752Ssam 	if (tp->t_state & TS_ASYNC)
1523*12752Ssam 		gsignal(tp->t_pgrp, SIGIO);
15247502Sroot 	wakeup((caddr_t)&tp->t_rawq);
15257502Sroot }
15267502Sroot 
152710391Ssam #if !defined(vax) && !defined(sun)
15289578Ssam scanc(size, cp, table, mask)
15299578Ssam 	register int size;
15309578Ssam 	register char *cp, table[];
15319578Ssam 	register int mask;
15327502Sroot {
15339578Ssam 	register int i = 0;
15347502Sroot 
15359578Ssam 	while ((table[*(u_char *)(cp + i)]&mask) == 0 && i < size)
15369578Ssam 		i++;
15379578Ssam 	return (i);
15387502Sroot }
15399578Ssam #endif
1540