xref: /csrg-svn/sys/kern/tty.c (revision 8154)
1*8154Sroot /*	tty.c	4.29	82/09/12	*/
239Sbill 
339Sbill /*
4903Sbill  * TTY subroutines common to more than one line discipline
539Sbill  */
639Sbill #include "../h/param.h"
739Sbill #include "../h/systm.h"
839Sbill #include "../h/dir.h"
939Sbill #include "../h/user.h"
1039Sbill #include "../h/tty.h"
1139Sbill #include "../h/proc.h"
1239Sbill #include "../h/inode.h"
1339Sbill #include "../h/file.h"
1439Sbill #include "../h/reg.h"
1539Sbill #include "../h/conf.h"
1639Sbill #include "../h/buf.h"
17340Sbill #include "../h/dk.h"
187722Swnj #include "../h/uio.h"
19*8154Sroot #include "../h/kernel.h"
2039Sbill 
217436Skre /*
227436Skre  * Table giving parity for characters and indicating
237436Skre  * character classes to tty driver.  In particular,
247436Skre  * if the low 6 bits are 0, then the character needs
257436Skre  * no special processing on output.
267436Skre  */
2739Sbill 
287436Skre char partab[] = {
297436Skre 	0001,0201,0201,0001,0201,0001,0001,0201,
307436Skre 	0202,0004,0003,0201,0005,0206,0201,0001,
317436Skre 	0201,0001,0001,0201,0001,0201,0201,0001,
327436Skre 	0001,0201,0201,0001,0201,0001,0001,0201,
337436Skre 	0200,0000,0000,0200,0000,0200,0200,0000,
347436Skre 	0000,0200,0200,0000,0200,0000,0000,0200,
357436Skre 	0000,0200,0200,0000,0200,0000,0000,0200,
367436Skre 	0200,0000,0000,0200,0000,0200,0200,0000,
377436Skre 	0200,0000,0000,0200,0000,0200,0200,0000,
387436Skre 	0000,0200,0200,0000,0200,0000,0000,0200,
397436Skre 	0000,0200,0200,0000,0200,0000,0000,0200,
407436Skre 	0200,0000,0000,0200,0000,0200,0200,0000,
417436Skre 	0000,0200,0200,0000,0200,0000,0000,0200,
427436Skre 	0200,0000,0000,0200,0000,0200,0200,0000,
437436Skre 	0200,0000,0000,0200,0000,0200,0200,0000,
447436Skre 	0000,0200,0200,0000,0200,0000,0000,0201,
457436Skre 
467436Skre 	/*
477436Skre 	 * 7 bit ascii ends with the last character above,
487436Skre 	 * but we contine through all 256 codes for the sake
497436Skre 	 * of the tty output routines which use special vax
507436Skre 	 * instructions which need a 256 character trt table.
517436Skre 	 */
527436Skre 
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 	0007,0007,0007,0007,0007,0007,0007,0007
697436Skre };
707436Skre 
71146Sbill /*
7239Sbill  * Input mapping table-- if an entry is non-zero, when the
7339Sbill  * corresponding character is typed preceded by "\" the escape
7439Sbill  * sequence is replaced by the table value.  Mostly used for
7539Sbill  * upper-case only terminals.
7639Sbill  */
7739Sbill 
7839Sbill char	maptab[] ={
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,000,000,
8239Sbill 	000,000,000,000,000,000,000,000,
8339Sbill 	000,'|',000,000,000,000,000,'`',
8439Sbill 	'{','}',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,000,
8939Sbill 	000,000,000,000,000,000,000,000,
9039Sbill 	000,000,000,000,000,000,'~',000,
9139Sbill 	000,'A','B','C','D','E','F','G',
9239Sbill 	'H','I','J','K','L','M','N','O',
9339Sbill 	'P','Q','R','S','T','U','V','W',
9439Sbill 	'X','Y','Z',000,000,000,000,000,
9539Sbill };
9639Sbill 
97925Sbill short	tthiwat[16] =
98925Sbill    { 100,100,100,100,100,100,100,200,200,400,400,400,650,650,650,650 };
99925Sbill short	ttlowat[16] =
100925Sbill    {  30, 30, 30, 30, 30, 30, 30, 50, 50,120,120,120,125,125,125,125 };
101925Sbill 
10239Sbill #define	OBUFSIZ	100
10339Sbill 
10439Sbill /*
10539Sbill  * set default control characters.
10639Sbill  */
10739Sbill ttychars(tp)
1087625Ssam 	register struct tty *tp;
10939Sbill {
110174Sbill 
11139Sbill 	tun.t_intrc = CINTR;
11239Sbill 	tun.t_quitc = CQUIT;
11339Sbill 	tun.t_startc = CSTART;
11439Sbill 	tun.t_stopc = CSTOP;
11539Sbill 	tun.t_eofc = CEOT;
11639Sbill 	tun.t_brkc = CBRK;
11739Sbill 	tp->t_erase = CERASE;
11839Sbill 	tp->t_kill = CKILL;
119174Sbill /* begin local */
120208Sbill 	tlun.t_suspc = CTRL(z);
121208Sbill 	tlun.t_dsuspc = CTRL(y);
122174Sbill 	tlun.t_rprntc = CTRL(r);
123174Sbill 	tlun.t_flushc = CTRL(o);
124174Sbill 	tlun.t_werasc = CTRL(w);
125174Sbill 	tlun.t_lnextc = CTRL(v);
126174Sbill 	tp->t_local = 0;
127174Sbill 	tp->t_lstate = 0;
128174Sbill /* end local */
12939Sbill }
13039Sbill 
13139Sbill /*
132903Sbill  * Wait for output to drain, then flush input waiting.
13339Sbill  */
134903Sbill wflushtty(tp)
1355408Swnj 	register struct tty *tp;
13639Sbill {
13739Sbill 
138903Sbill 	(void) spl5();
1395622Swnj 	while (tp->t_outq.c_cc && tp->t_state&TS_CARR_ON
1405622Swnj 	    && tp->t_oproc) {		/* kludge for pty */
141903Sbill 		(*tp->t_oproc)(tp);
1425408Swnj 		tp->t_state |= TS_ASLEEP;
143903Sbill 		sleep((caddr_t)&tp->t_outq, TTOPRI);
144903Sbill 	}
1455426Swnj 	flushtty(tp, FREAD);
146903Sbill 	(void) spl0();
14739Sbill }
14839Sbill 
14939Sbill /*
150903Sbill  * flush all TTY queues
15139Sbill  */
152903Sbill flushtty(tp, rw)
1537625Ssam 	register struct tty *tp;
15439Sbill {
155903Sbill 	register s;
156903Sbill 
157903Sbill 	s = spl6();
158903Sbill 	if (rw & FREAD) {
159903Sbill 		while (getc(&tp->t_canq) >= 0)
160903Sbill 			;
161903Sbill 		wakeup((caddr_t)&tp->t_rawq);
162903Sbill 	}
163903Sbill 	if (rw & FWRITE) {
164903Sbill 		wakeup((caddr_t)&tp->t_outq);
1655408Swnj 		tp->t_state &= ~TS_TTSTOP;
1665426Swnj 		(*cdevsw[major(tp->t_dev)].d_stop)(tp, rw);
167903Sbill 		while (getc(&tp->t_outq) >= 0)
168903Sbill 			;
169903Sbill 	}
170903Sbill 	if (rw & FREAD) {
171903Sbill 		while (getc(&tp->t_rawq) >= 0)
172903Sbill 			;
173903Sbill 		tp->t_delct = 0;
174903Sbill 		tp->t_rocount = 0;		/* local */
175903Sbill 		tp->t_rocol = 0;
176903Sbill 		tp->t_lstate = 0;
177903Sbill 	}
178903Sbill 	splx(s);
17939Sbill }
18039Sbill 
181903Sbill /*
182903Sbill  * Send stop character on input overflow.
183903Sbill  */
184903Sbill ttyblock(tp)
1857625Ssam 	register struct tty *tp;
18639Sbill {
187903Sbill 	register x;
188903Sbill 	x = tp->t_rawq.c_cc + tp->t_canq.c_cc;
189903Sbill 	if (tp->t_rawq.c_cc > TTYHOG) {
190903Sbill 		flushtty(tp, FREAD|FWRITE);
1915408Swnj 		tp->t_state &= ~TS_TBLOCK;
192903Sbill 	}
193903Sbill 	if (x >= TTYHOG/2) {
194903Sbill 		if (putc(tun.t_stopc, &tp->t_outq)==0) {
1955408Swnj 			tp->t_state |= TS_TBLOCK;
196903Sbill 			tp->t_char++;
197903Sbill 			ttstart(tp);
198903Sbill 		}
199903Sbill 	}
20039Sbill }
20139Sbill 
20239Sbill /*
203903Sbill  * Restart typewriter output following a delay
204903Sbill  * timeout.
205903Sbill  * The name of the routine is passed to the timeout
206903Sbill  * subroutine and it is called during a clock interrupt.
207121Sbill  */
208903Sbill ttrstrt(tp)
2097625Ssam 	register struct tty *tp;
210121Sbill {
211121Sbill 
2123351Swnj 	if (tp == 0) {
2133351Swnj 		printf("ttrstrt: arg was 0!\n");
2143351Swnj 		return;
2153351Swnj 	}
2165408Swnj 	tp->t_state &= ~TS_TIMEOUT;
217903Sbill 	ttstart(tp);
218121Sbill }
219121Sbill 
220121Sbill /*
221903Sbill  * Start output on the typewriter. It is used from the top half
222903Sbill  * after some characters have been put on the output queue,
223903Sbill  * from the interrupt routine to transmit the next
224903Sbill  * character, and after a timeout has finished.
22539Sbill  */
226903Sbill ttstart(tp)
2277625Ssam 	register struct tty *tp;
22839Sbill {
229903Sbill 	register s;
23039Sbill 
231903Sbill 	s = spl5();
2327625Ssam 	if ((tp->t_state&(TS_TIMEOUT|TS_TTSTOP|TS_BUSY)) == 0 &&
2335622Swnj 	    tp->t_oproc)		/* kludge for pty */
234903Sbill 		(*tp->t_oproc)(tp);
235903Sbill 	splx(s);
23639Sbill }
23739Sbill 
23839Sbill /*
239903Sbill  * Common code for tty ioctls.
24039Sbill  */
2411780Sbill /*ARGSUSED*/
2427625Ssam ttioctl(tp, com, data, flag)
2437625Ssam 	register struct tty *tp;
2447625Ssam 	caddr_t data;
24539Sbill {
2461904Swnj 	int dev;
24739Sbill 	extern int nldisp;
24839Sbill 
249903Sbill 	/*
250915Sbill 	 * This is especially so that isatty() will
251915Sbill 	 * fail when carrier is gone.
252915Sbill 	 */
2535408Swnj 	if ((tp->t_state&TS_CARR_ON) == 0) {
254915Sbill 		u.u_error = EBADF;
255915Sbill 		return (1);
256915Sbill 	}
257915Sbill 
2581904Swnj 	dev = tp->t_dev;
259915Sbill 	/*
260903Sbill 	 * If the ioctl involves modification,
261903Sbill 	 * insist on being able to write the device,
262903Sbill 	 * and hang if in the background.
263903Sbill 	 */
2647625Ssam 	switch (com) {
26539Sbill 
266915Sbill 	case TIOCSETD:
267915Sbill 	case TIOCSETP:
268915Sbill 	case TIOCSETN:
269903Sbill 	case TIOCFLUSH:
270903Sbill 	case TIOCSETC:
271903Sbill 	case TIOCSLTC:
272903Sbill 	case TIOCSPGRP:
273903Sbill 	case TIOCLBIS:
274903Sbill 	case TIOCLBIC:
275903Sbill 	case TIOCLSET:
276915Sbill /* this is reasonable, but impractical...
277903Sbill 		if ((flag & FWRITE) == 0) {
278903Sbill 			u.u_error = EBADF;
279903Sbill 			return (1);
280903Sbill 		}
281915Sbill  */
282903Sbill 		while (tp->t_line == NTTYDISC &&
283903Sbill 		   u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp &&
284903Sbill 		   (u.u_procp->p_flag&SVFORK) == 0 &&
285903Sbill 		   u.u_signal[SIGTTOU] != SIG_IGN &&
2865626Swnj 		   u.u_signal[SIGTTOU] != SIG_HOLD
2875626Swnj /*
2885626Swnj 						   &&
289903Sbill 		   (u.u_procp->p_flag&SDETACH)==0) {
2905626Swnj */
2915626Swnj 		   ) {
292903Sbill 			gsignal(u.u_procp->p_pgrp, SIGTTOU);
293903Sbill 			sleep((caddr_t)&lbolt, TTOPRI);
294903Sbill 		}
295903Sbill 		break;
296903Sbill 	}
297903Sbill 
29839Sbill 	/*
299903Sbill 	 * Process the ioctl.
30039Sbill 	 */
3017625Ssam 	switch (com) {
302903Sbill 
303903Sbill 	/*
304903Sbill 	 * Get discipline number
305903Sbill 	 */
30639Sbill 	case TIOCGETD:
3077625Ssam 		*(int *)data = tp->t_line;
30839Sbill 		break;
30939Sbill 
31039Sbill 	/*
311903Sbill 	 * Set line discipline
31239Sbill 	 */
3137625Ssam 	case TIOCSETD: {
3147625Ssam 		register int t = *(int *)data;
3157625Ssam 
31639Sbill 		if (t >= nldisp) {
31739Sbill 			u.u_error = ENXIO;
31839Sbill 			break;
31939Sbill 		}
320174Sbill 		(void) spl5();
32139Sbill 		if (tp->t_line)
32239Sbill 			(*linesw[tp->t_line].l_close)(tp);
32339Sbill 		if (t)
3247625Ssam 			(*linesw[t].l_open)(dev, tp);
32539Sbill 		if (u.u_error==0)
32639Sbill 			tp->t_line = t;
327174Sbill 		(void) spl0();
32839Sbill 		break;
3297625Ssam 	}
33039Sbill 
33139Sbill 	/*
3325614Swnj 	 * Prevent more opens on channel
3335614Swnj 	 */
3345614Swnj 	case TIOCEXCL:
3355614Swnj 		tp->t_state |= TS_XCLUDE;
3365614Swnj 		break;
3375614Swnj 
3385614Swnj 	case TIOCNXCL:
3395614Swnj 		tp->t_state &= ~TS_XCLUDE;
3405614Swnj 		break;
3415614Swnj 
3425614Swnj 	/*
34339Sbill 	 * Set new parameters
34439Sbill 	 */
34539Sbill 	case TIOCSETP:
3467625Ssam 	case TIOCSETN: {
3477625Ssam 		register struct sgttyb *sg = (struct sgttyb *)data;
3487625Ssam 		struct clist tq;
3497625Ssam 
350121Sbill 		(void) spl5();
3517625Ssam 		if (tp->t_flags&RAW || sg->sg_flags&RAW || com == TIOCSETP)
3524484Swnj 			wflushtty(tp);
3537625Ssam 		else if ((tp->t_flags&CBREAK) != (sg->sg_flags&CBREAK)) {
3547625Ssam 			if (sg->sg_flags & CBREAK) {
3554484Swnj 				catq(&tp->t_rawq, &tp->t_canq);
3564484Swnj 				tq = tp->t_rawq;
3574484Swnj 				tp->t_rawq = tp->t_canq;
3584484Swnj 				tp->t_canq = tq;
3594484Swnj 			} else {
3604484Swnj 				tp->t_local |= LPENDIN;
3614484Swnj 				ttwakeup(tp);
362174Sbill 			}
363174Sbill 		}
3647625Ssam 		tp->t_ispeed = sg->sg_ispeed;
3657625Ssam 		tp->t_ospeed = sg->sg_ospeed;
3667625Ssam 		tp->t_erase = sg->sg_erase;
3677625Ssam 		tp->t_kill = sg->sg_kill;
3687625Ssam 		tp->t_flags = sg->sg_flags;
3693941Sbugs 		if (tp->t_flags & RAW) {
3705408Swnj 			tp->t_state &= ~TS_TTSTOP;
3713941Sbugs 			ttstart(tp);
3723941Sbugs 		}
373121Sbill 		(void) spl0();
37439Sbill 		break;
3757625Ssam 	}
37639Sbill 
37739Sbill 	/*
378903Sbill 	 * Send current parameters to user
37939Sbill 	 */
3807625Ssam 	case TIOCGETP: {
3817625Ssam 		register struct sgttyb *sg = (struct sgttyb *)data;
3827625Ssam 
3837625Ssam 		sg->sg_ispeed = tp->t_ispeed;
3847625Ssam 		sg->sg_ospeed = tp->t_ospeed;
3857625Ssam 		sg->sg_erase = tp->t_erase;
3867625Ssam 		sg->sg_kill = tp->t_kill;
3877625Ssam 		sg->sg_flags = tp->t_flags;
38839Sbill 		break;
3897625Ssam 	}
39039Sbill 
39139Sbill 	/*
39239Sbill 	 * Hang up line on last close
39339Sbill 	 */
39439Sbill 	case TIOCHPCL:
3955408Swnj 		tp->t_state |= TS_HUPCLS;
39639Sbill 		break;
39739Sbill 
3983942Sbugs 	case TIOCFLUSH: {
3997625Ssam 		register int flags = *(int *)data;
4007625Ssam 
4017625Ssam 		if (flags == 0)
4023942Sbugs 			flags = FREAD|FWRITE;
4037625Ssam 		else
4047625Ssam 			flags &= FREAD|FWRITE;
4053942Sbugs 		flushtty(tp, flags);
40639Sbill 		break;
4073944Sbugs 	}
40839Sbill 
4097625Ssam 	case FIONBIO:
4107625Ssam 		if (*(int *)data)
4115408Swnj 			tp->t_state |= TS_NBIO;
4125408Swnj 		else
4135408Swnj 			tp->t_state &= ~TS_NBIO;
4145408Swnj 		break;
4155408Swnj 
4167625Ssam 	case FIOASYNC:
4177625Ssam 		if (*(int *)data)
4186216Swnj 			tp->t_state |= TS_ASYNC;
4196216Swnj 		else
4206216Swnj 			tp->t_state &= ~TS_ASYNC;
4216216Swnj 		break;
4226216Swnj 
42339Sbill 	/*
424903Sbill 	 * Set and fetch special characters
42539Sbill 	 */
42639Sbill 	case TIOCSETC:
4277625Ssam 		bcopy(data, (caddr_t)&tun, sizeof (struct tchars));
42839Sbill 		break;
42939Sbill 
43039Sbill 	case TIOCGETC:
4317625Ssam 		bcopy((caddr_t)&tun, data, sizeof (struct tchars));
43239Sbill 		break;
43339Sbill 
434174Sbill /* local ioctls */
435903Sbill 	/*
436903Sbill 	 * Set/get local special characters.
437903Sbill 	 */
438174Sbill 	case TIOCSLTC:
4397625Ssam 		bcopy(data, (caddr_t)&tlun, sizeof (struct ltchars));
440174Sbill 		break;
441174Sbill 
442174Sbill 	case TIOCGLTC:
4437625Ssam 		bcopy((caddr_t)&tlun, data, sizeof (struct ltchars));
444174Sbill 		break;
445174Sbill 
446903Sbill 	/*
447903Sbill 	 * Return number of characters immediately available.
448903Sbill 	 */
4497625Ssam 	case FIONREAD:
4507625Ssam 		*(off_t *)data = ttnread(tp);
451174Sbill 		break;
452174Sbill 
453174Sbill 	/*
454174Sbill 	 * Should allow SPGRP and GPGRP only if tty open for reading.
455174Sbill 	 */
456174Sbill 	case TIOCSPGRP:
4577625Ssam 		tp->t_pgrp = *(int *)data;
458174Sbill 		break;
459174Sbill 
460174Sbill 	case TIOCGPGRP:
4617625Ssam 		*(int *)data = tp->t_pgrp;
462174Sbill 		break;
463174Sbill 
464174Sbill 	/*
465174Sbill 	 * Modify local mode word.
466174Sbill 	 */
467174Sbill 	case TIOCLBIS:
4687625Ssam 		tp->t_local |= *(int *)data;
469174Sbill 		break;
470174Sbill 
471174Sbill 	case TIOCLBIC:
4727625Ssam 		tp->t_local &= ~(*(int *)data);
473174Sbill 		break;
474174Sbill 
475174Sbill 	case TIOCLSET:
4767625Ssam 		tp->t_local = *(int *)data;
477174Sbill 		break;
478174Sbill 
479174Sbill 	case TIOCLGET:
4807625Ssam 		*(int *)data = tp->t_local;
481174Sbill 		break;
482174Sbill 
4837625Ssam 	case TIOCSTOP: {
4847625Ssam 		int s = spl5();
485213Sbill 
4865573Swnj 		if ((tp->t_state & TS_TTSTOP) == 0) {
4875573Swnj 			tp->t_state |= TS_TTSTOP;
4885573Swnj 			(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
4895573Swnj 		}
4907625Ssam 		splx(s);
4915573Swnj 		break;
4927625Ssam 	}
4935573Swnj 
4947625Ssam 	case TIOCSTART: {
4957625Ssam 		int s = spl5();
4967625Ssam 
4975573Swnj 		if ((tp->t_state & TS_TTSTOP) || (tp->t_local & LFLUSHO)) {
4985573Swnj 			tp->t_state &= ~TS_TTSTOP;
4995573Swnj 			tp->t_local &= ~LFLUSHO;
5005573Swnj 			ttstart(tp);
5015573Swnj 		}
5027625Ssam 		splx(s);
5035573Swnj 		break;
5047625Ssam 	}
5055573Swnj 
506174Sbill /* end of locals */
507887Sbill 
50839Sbill 	default:
5097625Ssam 		return (0);
51039Sbill 	}
5117625Ssam 	return (1);
51239Sbill }
5134484Swnj 
5144484Swnj ttnread(tp)
5154484Swnj 	struct tty *tp;
5164484Swnj {
5174484Swnj 	int nread = 0;
5184484Swnj 
5194484Swnj 	if (tp->t_local & LPENDIN)
5204484Swnj 		ttypend(tp);
5214484Swnj 	nread = tp->t_canq.c_cc;
5224484Swnj 	if (tp->t_flags & (RAW|CBREAK))
5234484Swnj 		nread += tp->t_rawq.c_cc;
5244484Swnj 	return (nread);
5254484Swnj }
5264484Swnj 
5275408Swnj ttselect(dev, rw)
5284484Swnj 	dev_t dev;
5295408Swnj 	int rw;
5304484Swnj {
5314484Swnj 	register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)];
5324484Swnj 	int nread;
5335408Swnj 	int s = spl5();
5344484Swnj 
5355408Swnj 	switch (rw) {
5364484Swnj 
5374484Swnj 	case FREAD:
5384484Swnj 		nread = ttnread(tp);
5394484Swnj 		if (nread > 0)
5405408Swnj 			goto win;
5414938Swnj 		if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait)
5425408Swnj 			tp->t_state |= TS_RCOLL;
5434484Swnj 		else
5444484Swnj 			tp->t_rsel = u.u_procp;
5455408Swnj 		break;
5464484Swnj 
5475408Swnj 	case FWRITE:
5485408Swnj 		if (tp->t_outq.c_cc <= TTLOWAT(tp))
5495408Swnj 			goto win;
5505408Swnj 		if (tp->t_wsel && tp->t_wsel->p_wchan == (caddr_t)&selwait)
5515408Swnj 			tp->t_state |= TS_WCOLL;
5525408Swnj 		else
5535408Swnj 			tp->t_wsel = u.u_procp;
5545408Swnj 		break;
5554484Swnj 	}
5565408Swnj 	splx(s);
5575408Swnj 	return (0);
5585408Swnj win:
5595408Swnj 	splx(s);
5605408Swnj 	return (1);
5614484Swnj }
5627436Skre 
5637502Sroot #define	OBUFSIZ	100
5647502Sroot 
5657502Sroot /*
5667502Sroot  * routine called on opens while tp->t_line == NTTYDISC
5677502Sroot  * establishes a process group for distribution of
5687502Sroot  * quits and interrupts from the tty.
5697502Sroot  * (actually, pp->p_pgrp can't be 0 when this routine
5707502Sroot  * is called since NTTYDISC is not the default discipline)
5717502Sroot  */
5727502Sroot ttyopen(dev, tp)
5737625Ssam 	dev_t dev;
5747625Ssam 	register struct tty *tp;
5757502Sroot {
5767502Sroot 	register struct proc *pp;
5777502Sroot 
5787502Sroot 	pp = u.u_procp;
5797502Sroot 	tp->t_dev = dev;
5807625Ssam 	if (pp->p_pgrp == 0) {
5817502Sroot 		u.u_ttyp = tp;
5827502Sroot 		u.u_ttyd = dev;
5837502Sroot 		if (tp->t_pgrp == 0)
5847502Sroot 			tp->t_pgrp = pp->p_pid;
5857502Sroot 		pp->p_pgrp = tp->t_pgrp;
5867502Sroot 	}
5877502Sroot 	tp->t_state &= ~TS_WOPEN;
5887502Sroot 	tp->t_state |= TS_ISOPEN;
5897502Sroot 	if (tp->t_line != NTTYDISC)
5907502Sroot 		wflushtty(tp);
5917502Sroot }
5927502Sroot 
5937502Sroot /*
5947502Sroot  * clean tp on last close
5957502Sroot  */
5967502Sroot ttyclose(tp)
5977625Ssam 	register struct tty *tp;
5987502Sroot {
5997502Sroot 
6007502Sroot 	if (tp->t_line) {
6017502Sroot 		wflushtty(tp);
6027502Sroot 		tp->t_line = 0;
6037502Sroot 		return;
6047502Sroot 	}
6057502Sroot 	tp->t_pgrp = 0;
6067502Sroot 	wflushtty(tp);
6077502Sroot 	tp->t_state = 0;
6087502Sroot }
6097502Sroot 
6107502Sroot /*
6117502Sroot  * reinput pending characters after state switch
6127502Sroot  * call at spl5().
6137502Sroot  */
6147502Sroot ttypend(tp)
6157625Ssam 	register struct tty *tp;
6167502Sroot {
6177502Sroot 	struct clist tq;
6187502Sroot 	register c;
6197502Sroot 
6207502Sroot 	tp->t_local &= ~LPENDIN;
6217502Sroot 	tp->t_lstate |= LSTYPEN;
6227502Sroot 	tq = tp->t_rawq;
6237502Sroot 	tp->t_rawq.c_cc = 0;
6247502Sroot 	tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0;
6257502Sroot 	while ((c = getc(&tq)) >= 0)
6267502Sroot 		ttyinput(c, tp);
6277502Sroot 	tp->t_lstate &= ~LSTYPEN;
6287502Sroot }
6297502Sroot 
6307502Sroot /*
6317502Sroot  * Place a character on raw TTY input queue, putting in delimiters
6327502Sroot  * and waking up top half as needed.
6337502Sroot  * Also echo if required.
6347502Sroot  * The arguments are the character and the appropriate
6357502Sroot  * tty structure.
6367502Sroot  */
6377502Sroot ttyinput(c, tp)
6387625Ssam 	register c;
6397625Ssam 	register struct tty *tp;
6407502Sroot {
6417502Sroot 	register int t_flags;
6427502Sroot 	int i;
6437502Sroot 
6447502Sroot 	if (tp->t_local&LPENDIN)
6457502Sroot 		ttypend(tp);
6467502Sroot 	tk_nin++;
6477502Sroot 	c &= 0377;
6487502Sroot 	t_flags = tp->t_flags;
6497502Sroot 	if (t_flags&TANDEM)
6507502Sroot 		ttyblock(tp);
6517502Sroot 	if ((t_flags&RAW)==0) {
6527502Sroot 		if ((tp->t_lstate&LSTYPEN) == 0)
6537502Sroot 			c &= 0177;
6547502Sroot 	/* check for literal nexting very first */
6557502Sroot 		if (tp->t_lstate&LSLNCH) {
6567502Sroot 			c |= 0200;
6577502Sroot 			tp->t_lstate &= ~LSLNCH;
6587502Sroot 		}
6597502Sroot 		if (tp->t_line == NTTYDISC && c==tlun.t_lnextc) {
6607502Sroot 			if (tp->t_flags&ECHO)
6617502Sroot 				ttyout("^\b", tp);
6627502Sroot 			tp->t_lstate |= LSLNCH;
6637502Sroot 	/* check for output control functions */
6647502Sroot 		} else if (c==tun.t_stopc) {
6657502Sroot 			if ((tp->t_state&TS_TTSTOP)==0) {
6667502Sroot 				tp->t_state |= TS_TTSTOP;
6677502Sroot 				(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
6687502Sroot 				return;
6697502Sroot 			}
6707502Sroot 			if (c!=tun.t_startc)
6717502Sroot 				return;
6727502Sroot 		} else if (c==tun.t_startc) {
6737502Sroot 			tp->t_state &= ~TS_TTSTOP;
6747502Sroot 			tp->t_local &= ~LFLUSHO;
6757502Sroot 			ttstart(tp);
6767502Sroot 			return;
6777502Sroot 		} else if (tp->t_line == NTTYDISC && c==tlun.t_flushc) {
6787502Sroot 			if (tp->t_local & LFLUSHO)
6797502Sroot 				tp->t_local &= ~LFLUSHO;
6807502Sroot 			else {
6817502Sroot 				flushtty(tp, FWRITE);
6827502Sroot 				ttyecho(c, tp);
6837502Sroot 				if (tp->t_rawq.c_cc+tp->t_canq.c_cc)
6847502Sroot 					ttyretype(tp);
6857502Sroot 				tp->t_local |= LFLUSHO;
6867502Sroot 			}
6877502Sroot 			ttstart(tp);
6887502Sroot 			return;
6897502Sroot 		} else if (c==tun.t_intrc || c==tun.t_quitc ||
6907502Sroot 		    (tp->t_line == NTTYDISC && c==tlun.t_suspc)) {
6917502Sroot 			if ((tp->t_local & LNOFLSH) == 0)
6927502Sroot 				flushtty(tp,
6937502Sroot 				    c==tlun.t_suspc ? FREAD : FREAD|FWRITE);
6947502Sroot 			ttyecho(c, tp);
6957502Sroot 			c = c==tun.t_intrc ? SIGINT :
6967502Sroot 				((c==tun.t_quitc) ? SIGQUIT : SIGTSTP);
6977502Sroot 			ttsignal(tp, c);
6987502Sroot 	/* check for buffer editing functions - cooked mode */
6997502Sroot 		} else if ((t_flags&CBREAK) == 0) {
7007502Sroot 			if ((tp->t_lstate&LSQUOT) &&
7017502Sroot 			    (c==tp->t_erase||c==tp->t_kill)) {
7027502Sroot 				ttyrub(unputc(&tp->t_rawq), tp);
7037502Sroot 				c |= 0200;
7047502Sroot 			}
7057502Sroot 			if (c==tp->t_erase) {
7067502Sroot 				if (tp->t_rawq.c_cc)
7077502Sroot 					ttyrub(unputc(&tp->t_rawq), tp);
7087502Sroot 			} else if (c==tp->t_kill) {
7097502Sroot 				if (tp->t_local&LCRTKIL &&
7107502Sroot 				    tp->t_rawq.c_cc == tp->t_rocount) {
7117502Sroot 					while (tp->t_rawq.c_cc)
7127502Sroot 						ttyrub(unputc(&tp->t_rawq), tp);
7137502Sroot 				} else {
7147502Sroot 					ttyecho(c, tp);
7157502Sroot 					ttyecho('\n', tp);
7167502Sroot 					while (getc(&tp->t_rawq) > 0)
7177502Sroot 						;
7187502Sroot 					tp->t_rocount = 0;
7197502Sroot 				}
7207502Sroot 				tp->t_lstate = 0;
7217502Sroot 			} else if (tp->t_line == NTTYDISC && c==tlun.t_werasc) {
7227502Sroot 				if (tp->t_rawq.c_cc == 0)
7237502Sroot 					goto out;
7247502Sroot 				do {
7257502Sroot 					c = unputc(&tp->t_rawq);
7267502Sroot 					if (c != ' ' && c != '\t')
7277502Sroot 						goto erasenb;
7287502Sroot 					ttyrub(c, tp);
7297502Sroot 				} while (tp->t_rawq.c_cc);
7307502Sroot 				goto out;
7317502Sroot 			    erasenb:
7327502Sroot 				do {
7337502Sroot 					ttyrub(c, tp);
7347502Sroot 					if (tp->t_rawq.c_cc == 0)
7357502Sroot 						goto out;
7367502Sroot 					c = unputc(&tp->t_rawq);
7377502Sroot 				} while (c != ' ' && c != '\t');
7387502Sroot 				(void) putc(c, &tp->t_rawq);
7397502Sroot 			} else if (tp->t_line == NTTYDISC && c==tlun.t_rprntc) {
7407502Sroot 				ttyretype(tp);
7417502Sroot 	/* check for cooked mode input buffer overflow */
7427502Sroot 			} else if (tp->t_rawq.c_cc+tp->t_canq.c_cc >= TTYHOG) {
7437502Sroot 				;
7447502Sroot 	/* put data char in q for user and wakeup if a break char */
7457502Sroot 			} else if (putc(c, &tp->t_rawq) >= 0) {
7467502Sroot 				if (tp->t_rawq.c_cc+tp->t_canq.c_cc==TTYHOG
7477502Sroot 				    && tp->t_line == NTTYDISC)
7487502Sroot 					(void) ttyoutput(CTRL(g), tp);
7497502Sroot 				if (!ttbreakc(c, tp)) {
7507502Sroot 					if (tp->t_rocount++ == 0)
7517502Sroot 						tp->t_rocol = tp->t_col;
7527502Sroot 				} else {
7537502Sroot 					tp->t_rocount = 0;
7547502Sroot 					catq(&tp->t_rawq, &tp->t_canq);
7557502Sroot 					/* IF (TP->T_CHAN) (VOID) SDATA(TP->T_CHAN); */
7567502Sroot 					ttwakeup(tp);
7577502Sroot 				}
7587502Sroot 				tp->t_lstate &= ~LSQUOT;
7597502Sroot 				if (c == '\\')
7607502Sroot 					tp->t_lstate |= LSQUOT;
7617502Sroot 				if (tp->t_lstate&LSERASE) {
7627502Sroot 					tp->t_lstate &= ~LSERASE;
7637502Sroot 					(void) ttyoutput('/', tp);
7647502Sroot 				}
7657502Sroot 				i = tp->t_col;
7667502Sroot 				ttyecho(c, tp);
7677502Sroot 				if (c==tun.t_eofc && tp->t_flags&ECHO) {
7687502Sroot 					i = MIN(2, tp->t_col - i);
7697502Sroot 					while (i > 0) {
7707502Sroot 						(void) ttyoutput('\b', tp);
7717502Sroot 						i--;
7727502Sroot 					}
7737502Sroot 				}
7747502Sroot 			}
7757502Sroot 	/* CBREAK mode */
7767502Sroot 		} else if (tp->t_rawq.c_cc > TTYHOG) {
7777502Sroot 			if (tp->t_outq.c_cc < TTHIWAT(tp) &&
7787502Sroot 			    tp->t_line == NTTYDISC)
7797502Sroot 				(void) ttyoutput(CTRL(g), tp);
7807502Sroot 		} else if (putc(c, &tp->t_rawq) >= 0) {
7817502Sroot 			ttwakeup(tp);
7827502Sroot 			ttyecho(c, tp);
7837502Sroot 		}
7847502Sroot 	/* RAW mode */
7857502Sroot 	} else if (tp->t_rawq.c_cc > TTYHOG)
7867502Sroot 		flushtty(tp, FREAD|FWRITE);
7877502Sroot 	else {
7887502Sroot 		if (putc(c, &tp->t_rawq) >= 0)
7897502Sroot 			ttwakeup(tp);
7907502Sroot 		ttyecho(c, tp);
7917502Sroot 	}
7927502Sroot out:
7937502Sroot 	if (tp->t_local & LDECCTQ && tp->t_state & TS_TTSTOP &&
7947502Sroot 	    tun.t_startc != tun.t_stopc)
7957502Sroot 		return;
7967502Sroot 	tp->t_state &= ~TS_TTSTOP;
7977502Sroot 	tp->t_local &= ~LFLUSHO;
7987502Sroot 	ttstart(tp);
7997502Sroot }
8007502Sroot 
8017502Sroot /*
8027502Sroot  * put character on TTY output queue, adding delays,
8037502Sroot  * expanding tabs, and handling the CR/NL bit.
8047502Sroot  * It is called both from the top half for output, and from
8057502Sroot  * interrupt level for echoing.
8067502Sroot  * The arguments are the character and the tty structure.
8077502Sroot  * Returns < 0 if putc succeeds, otherwise returns char to resend
8087502Sroot  * Must be recursive.
8097502Sroot  */
8107502Sroot ttyoutput(c, tp)
8117502Sroot 	register c;
8127502Sroot 	register struct tty *tp;
8137502Sroot {
8147502Sroot 	register char *colp;
8157502Sroot 	register ctype;
8167502Sroot 
8177502Sroot 	if (tp->t_flags&RAW || tp->t_local&LLITOUT) {
8187502Sroot 		if (tp->t_local&LFLUSHO)
8197502Sroot 			return (-1);
8207502Sroot 		if (putc(c, &tp->t_outq))
8217625Ssam 			return (c);
8227502Sroot 		tk_nout++;
8237502Sroot 		return (-1);
8247502Sroot 	}
8257502Sroot 	/*
8267502Sroot 	 * Ignore EOT in normal mode to avoid hanging up
8277502Sroot 	 * certain terminals.
8287502Sroot 	 */
8297502Sroot 	c &= 0177;
8307502Sroot 	if (c==CEOT && (tp->t_flags&CBREAK)==0)
8317502Sroot 		return (-1);
8327502Sroot 	/*
8337502Sroot 	 * Turn tabs to spaces as required
8347502Sroot 	 */
8357502Sroot 	if (c=='\t' && (tp->t_flags&TBDELAY)==XTABS) {
8367502Sroot 		register int s;
8377502Sroot 
8387502Sroot 		c = 8 - (tp->t_col&7);
8397502Sroot 		if ((tp->t_local&LFLUSHO) == 0) {
8407502Sroot 			s = spl5();		/* don't interrupt tabs */
8417502Sroot 			c -= b_to_q("        ", c, &tp->t_outq);
8427502Sroot 			tk_nout += c;
8437502Sroot 			splx(s);
8447502Sroot 		}
8457502Sroot 		tp->t_col += c;
8467502Sroot 		return (c ? -1 : '\t');
8477502Sroot 	}
8487502Sroot 	tk_nout++;
8497502Sroot 	/*
8507502Sroot 	 * for upper-case-only terminals,
8517502Sroot 	 * generate escapes.
8527502Sroot 	 */
8537502Sroot 	if (tp->t_flags&LCASE) {
8547502Sroot 		colp = "({)}!|^~'`";
8557625Ssam 		while (*colp++)
8567625Ssam 			if (c == *colp++) {
8577502Sroot 				if (ttyoutput('\\', tp) >= 0)
8587502Sroot 					return (c);
8597502Sroot 				c = colp[-2];
8607502Sroot 				break;
8617502Sroot 			}
8627502Sroot 		if ('A'<=c && c<='Z') {
8637502Sroot 			if (ttyoutput('\\', tp) >= 0)
8647502Sroot 				return (c);
8657502Sroot 		} else if ('a'<=c && c<='z')
8667502Sroot 			c += 'A' - 'a';
8677502Sroot 	}
8687502Sroot 	/*
8697502Sroot 	 * turn <nl> to <cr><lf> if desired.
8707502Sroot 	 */
8717502Sroot 	if (c=='\n' && tp->t_flags&CRMOD)
8727502Sroot 		if (ttyoutput('\r', tp) >= 0)
8737502Sroot 			return (c);
8747502Sroot 	if (c=='~' && tp->t_local&LTILDE)
8757502Sroot 		c = '`';
8767502Sroot 	if ((tp->t_local&LFLUSHO) == 0 && putc(c, &tp->t_outq))
8777502Sroot 		return (c);
8787502Sroot 	/*
8797502Sroot 	 * Calculate delays.
8807502Sroot 	 * The numbers here represent clock ticks
8817502Sroot 	 * and are not necessarily optimal for all terminals.
8827502Sroot 	 * The delays are indicated by characters above 0200.
8837502Sroot 	 * In raw mode there are no delays and the
8847502Sroot 	 * transmission path is 8 bits wide.
8857502Sroot 	 */
8867502Sroot 	colp = &tp->t_col;
8877502Sroot 	ctype = partab[c];
8887502Sroot 	c = 0;
8897502Sroot 	switch (ctype&077) {
8907502Sroot 
8917502Sroot 	case ORDINARY:
8927502Sroot 		(*colp)++;
8937502Sroot 
8947502Sroot 	case CONTROL:
8957502Sroot 		break;
8967502Sroot 
8977502Sroot 	case BACKSPACE:
8987502Sroot 		if (*colp)
8997502Sroot 			(*colp)--;
9007502Sroot 		break;
9017502Sroot 
9027502Sroot 	case NEWLINE:
9037502Sroot 		ctype = (tp->t_flags >> 8) & 03;
9047625Ssam 		if (ctype == 1) { /* tty 37 */
9057502Sroot 			if (*colp)
9067502Sroot 				c = max(((unsigned)*colp>>4) + 3, (unsigned)6);
9077502Sroot 		} else
9087625Ssam 		if (ctype == 2) { /* vt05 */
9097502Sroot 			c = 6;
9107502Sroot 		}
9117502Sroot 		*colp = 0;
9127502Sroot 		break;
9137502Sroot 
9147502Sroot 	case TAB:
9157502Sroot 		ctype = (tp->t_flags >> 10) & 03;
9167625Ssam 		if (ctype == 1) { /* tty 37 */
9177502Sroot 			c = 1 - (*colp | ~07);
9187625Ssam 			if (c < 5)
9197502Sroot 				c = 0;
9207502Sroot 		}
9217502Sroot 		*colp |= 07;
9227502Sroot 		(*colp)++;
9237502Sroot 		break;
9247502Sroot 
9257502Sroot 	case VTAB:
9267625Ssam 		if (tp->t_flags & VTDELAY) /* tty 37 */
9277502Sroot 			c = 0177;
9287502Sroot 		break;
9297502Sroot 
9307502Sroot 	case RETURN:
9317502Sroot 		ctype = (tp->t_flags >> 12) & 03;
9327625Ssam 		if (ctype == 1) { /* tn 300 */
9337502Sroot 			c = 5;
9347625Ssam 		} else if (ctype == 2) { /* ti 700 */
9357502Sroot 			c = 10;
9367625Ssam 		} else if (ctype == 3) { /* concept 100 */
9377502Sroot 			int i;
9387502Sroot 			if ((i = *colp) >= 0)
9397502Sroot 				for (; i<9; i++)
9407502Sroot 					(void) putc(0177, &tp->t_outq);
9417502Sroot 		}
9427502Sroot 		*colp = 0;
9437502Sroot 	}
9447625Ssam 	if (c && (tp->t_local&LFLUSHO) == 0)
9457502Sroot 		(void) putc(c|0200, &tp->t_outq);
9467502Sroot 	return (-1);
9477502Sroot }
9487502Sroot 
9497502Sroot /*
9507502Sroot  * Called from device's read routine after it has
9517502Sroot  * calculated the tty-structure given as argument.
9527502Sroot  */
9537722Swnj ttread(tp, uio)
9547625Ssam 	register struct tty *tp;
9557722Swnj 	struct uio *uio;
9567502Sroot {
9577502Sroot 	register struct clist *qp;
9587502Sroot 	register c, first;
9597502Sroot 
9607502Sroot 	if ((tp->t_state&TS_CARR_ON)==0)
9617625Ssam 		return (0);
9627502Sroot loop:
9637502Sroot 	(void) spl5();
9647502Sroot 	if (tp->t_local&LPENDIN)
9657502Sroot 		ttypend(tp);
9667502Sroot 	(void) spl0();
9677502Sroot 	while (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) {
9687502Sroot 		if (u.u_signal[SIGTTIN] == SIG_IGN ||
9697502Sroot 		    u.u_signal[SIGTTIN] == SIG_HOLD ||
9707502Sroot /*
9717502Sroot 		    (u.u_procp->p_flag&SDETACH) ||
9727502Sroot */
9737502Sroot 		    u.u_procp->p_flag&SVFORK)
9747502Sroot 			return (0);
9757502Sroot 		gsignal(u.u_procp->p_pgrp, SIGTTIN);
9767502Sroot 		sleep((caddr_t)&lbolt, TTIPRI);
9777502Sroot 	}
9787502Sroot 	if (tp->t_flags&RAW) {
9797502Sroot 		(void) spl5();
9807502Sroot 		if (tp->t_rawq.c_cc <= 0) {
9817502Sroot 			if ((tp->t_state&TS_CARR_ON)==0 ||
9827502Sroot 			    (tp->t_state&TS_NBIO)) {
9837502Sroot 				(void) spl0();
9847502Sroot 				return (0);
9857502Sroot 			}
9867502Sroot 			sleep((caddr_t)&tp->t_rawq, TTIPRI);
9877502Sroot 			(void) spl0();
9887502Sroot 			goto loop;
9897502Sroot 		}
9907502Sroot 		(void) spl0();
9917722Swnj 		while (tp->t_rawq.c_cc && uio->uio_iovcnt) {
9927722Swnj 			u.u_error = passuc(getc(&tp->t_rawq), uio);
9937722Swnj 			if (u.u_error)
9947722Swnj 				break;
9957722Swnj 		}
9967502Sroot 		return (0);
9977502Sroot 	} else {
9987502Sroot 		qp = tp->t_flags & CBREAK ? &tp->t_rawq : &tp->t_canq;
9997502Sroot 		(void) spl5();
10007502Sroot 		if (qp->c_cc <= 0) {
10017502Sroot 			if ((tp->t_state&TS_CARR_ON)==0 ||
10027502Sroot 			    (tp->t_state&TS_NBIO)) {
10037502Sroot 				(void) spl0();
10047502Sroot 				return (0);
10057502Sroot 			}
10067502Sroot 			sleep((caddr_t)&tp->t_rawq, TTIPRI);
10077502Sroot 			(void) spl0();
10087502Sroot 			goto loop;
10097502Sroot 		}
10107502Sroot 		(void) spl0();
10117502Sroot 		first = 1;
10127502Sroot 		while ((c = getc(qp)) >= 0) {
10137502Sroot 			if (tp->t_flags&CRMOD && c == '\r')
10147502Sroot 				c = '\n';
10157502Sroot 			if (tp->t_flags&LCASE && c <= 0177)
10167502Sroot 				if (tp->t_lstate&LSBKSL) {
10177502Sroot 					if (maptab[c])
10187502Sroot 						c = maptab[c];
10197502Sroot 					tp->t_lstate &= ~LSBKSL;
10207502Sroot 				} else if (c >= 'A' && c <= 'Z')
10217502Sroot 					c += 'a' - 'A';
10227502Sroot 				else if (c == '\\') {
10237502Sroot 					tp->t_lstate |= LSBKSL;
10247502Sroot 					continue;
10257502Sroot 				}
10267658Ssam 			if (tp->t_line == NTTYDISC && c == tlun.t_dsuspc) {
10277502Sroot 				ttsignal(tp, SIGTSTP);
10287502Sroot 				if (first) {
10297502Sroot 					sleep((caddr_t)&lbolt, TTIPRI);
10307502Sroot 					goto loop;
10317502Sroot 				}
10327502Sroot 				break;
10337502Sroot 			}
10347502Sroot 			if (c == tun.t_eofc && (tp->t_flags&CBREAK)==0)
10357502Sroot 				break;
10367722Swnj 			u.u_error = passuc(c & 0177, uio);
10377722Swnj 			if (u.u_error)
10387502Sroot 				break;
10397722Swnj 			if (uio->uio_iovcnt == 0)
10407722Swnj 				break;
10417502Sroot 			if ((tp->t_flags&CBREAK)==0 && ttbreakc(c, tp))
10427502Sroot 				break;
10437502Sroot 			first = 0;
10447502Sroot 		}
10457502Sroot 		tp->t_lstate &= ~LSBKSL;
10467502Sroot 	}
10477502Sroot 
10487502Sroot 	if (tp->t_state&TS_TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) {
10497502Sroot 		if (putc(tun.t_startc, &tp->t_outq)==0) {
10507502Sroot 			tp->t_state &= ~TS_TBLOCK;
10517502Sroot 			ttstart(tp);
10527502Sroot 		}
10537502Sroot 		tp->t_char = 0;
10547502Sroot 	}
10557502Sroot 
10567502Sroot 	return (tp->t_rawq.c_cc + tp->t_canq.c_cc);
10577502Sroot }
10587502Sroot 
10597502Sroot /*
10607502Sroot  * Called from the device's write routine after it has
10617502Sroot  * calculated the tty-structure given as argument.
10627502Sroot  */
10637502Sroot caddr_t
10647822Sroot ttwrite(tp, uio)
10657625Ssam 	register struct tty *tp;
10667822Sroot 	struct uio *uio;
10677502Sroot {
10687502Sroot #ifdef vax
10697502Sroot 	/*
10707502Sroot 	 * THE POSITIONING OF CP, CC, AND CE ARE CRITICAL
10717502Sroot 	 * AND MUST NOT BE CHANGED WITHOUT PATCHING
10727502Sroot 	 * THE 'ASM' INLINES BELOW.  WATCH OUT.
10737502Sroot 	 */
10747502Sroot #endif
10757502Sroot 	register char *cp;
10767502Sroot 	register int cc, ce;
10777502Sroot 	register i;
10787502Sroot 	char obuf[OBUFSIZ];
10797502Sroot 	register c;
10807502Sroot 	int hiwat = TTHIWAT(tp);
10817822Sroot 	int cnt = uio->uio_resid;
10827502Sroot 
10837502Sroot 	if ((tp->t_state&TS_CARR_ON)==0)
10847502Sroot 		return (NULL);
10857502Sroot loop:
10867502Sroot 	while (u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp &&
10877502Sroot 	    (tp->t_local&LTOSTOP) && (u.u_procp->p_flag&SVFORK)==0 &&
10887502Sroot 	    u.u_signal[SIGTTOU] != SIG_IGN &&
10897502Sroot 	    u.u_signal[SIGTTOU] != SIG_HOLD
10907502Sroot /*
10917502Sroot 					     &&
10927502Sroot 	    (u.u_procp->p_flag&SDETACH)==0) {
10937502Sroot */
10947502Sroot 	    ) {
10957502Sroot 		gsignal(u.u_procp->p_pgrp, SIGTTOU);
10967502Sroot 		sleep((caddr_t)&lbolt, TTIPRI);
10977502Sroot 	}
10987822Sroot 	while (uio->uio_resid > 0) {
10997822Sroot 		cc = uio->uio_iov->iov_len;
11007822Sroot 		if (cc == 0) {
11017822Sroot 			uio->uio_iovcnt--;
11027822Sroot 			uio->uio_iov++;
11037822Sroot 			if (uio->uio_iovcnt < 0)
11047822Sroot 				panic("ttwrite");
11057822Sroot 			continue;
11067822Sroot 		}
11077822Sroot 		if (cc > OBUFSIZ)
11087822Sroot 			cc = OBUFSIZ;
11097502Sroot 		cp = obuf;
11107822Sroot 		u.u_error = uiomove(cp, cc, UIO_WRITE, uio);
11117502Sroot 		if (u.u_error)
11127502Sroot 			break;
11137502Sroot 		if (tp->t_outq.c_cc > hiwat)
11147502Sroot 			goto ovhiwat;
11157502Sroot 		if (tp->t_local&LFLUSHO)
11167502Sroot 			continue;
11177502Sroot 		if (tp->t_flags&LCASE || tp->t_local&LTILDE) {
11187502Sroot 			while (cc) {
11197502Sroot 				c = *cp++;
11207502Sroot 				tp->t_rocount = 0;
11217625Ssam 				while ((c = ttyoutput(c, tp)) >= 0) {
11227502Sroot 					/* out of clists, wait a bit */
11237502Sroot 					ttstart(tp);
11247502Sroot 					sleep((caddr_t)&lbolt, TTOPRI);
11257502Sroot 					tp->t_rocount = 0;
11267502Sroot 				}
11277502Sroot 				--cc;
11287502Sroot 				if (tp->t_outq.c_cc > hiwat)
11297502Sroot 					goto ovhiwat;
11307502Sroot 			}
11317502Sroot 			continue;
11327502Sroot 		}
11337502Sroot 		while (cc) {
11347502Sroot 			if (tp->t_flags&RAW || tp->t_local&LLITOUT)
11357502Sroot 				ce = cc;
11367502Sroot 			else {
11377502Sroot #ifdef vax
11387502Sroot 				asm("	scanc	r9,(r10),_partab,$077");
11397502Sroot 				asm("	subl3	r0,r9,r8");
11407502Sroot #else
11417502Sroot 				ce=0;
11427625Ssam 				while (((partab[*(unsigned char *)(cp+ce)]&077)==0)&&(ce<cc))
11437502Sroot 					ce++;
11447502Sroot #endif
11457502Sroot 				if (ce==0) {
11467502Sroot 					tp->t_rocount = 0;
11477502Sroot 					if (ttyoutput(*cp, tp) >= 0) {
11487502Sroot 						ttstart(tp);
11497502Sroot 						sleep((caddr_t)&lbolt, TTOPRI);
11507502Sroot 						continue;
11517502Sroot 					}
11527502Sroot 					cp++;
11537502Sroot 					cc--;
11547502Sroot 					if (tp->t_outq.c_cc > hiwat)
11557502Sroot 						goto ovhiwat;
11567502Sroot 				}
11577502Sroot 			}
11587502Sroot 			tp->t_rocount = 0;
11597502Sroot 			i=b_to_q(cp,ce,&tp->t_outq);
11607502Sroot 			ce-=i;
11617502Sroot 			tk_nout+=ce;
11627502Sroot 			tp->t_col+=ce;
11637502Sroot 			cp+=ce;
11647502Sroot 			cc-=ce;
11657502Sroot 			if (i) {
11667502Sroot 				ttstart(tp);
11677502Sroot 				sleep((caddr_t)&lbolt, TTOPRI);
11687502Sroot 			}
11697502Sroot 			if (ce || tp->t_outq.c_cc > hiwat)
11707502Sroot 				goto ovhiwat;
11717502Sroot 		}
11727502Sroot 	}
11737502Sroot 	ttstart(tp);
11747625Ssam 	return (NULL);
11757502Sroot 
11767502Sroot ovhiwat:
11777502Sroot 	(void) spl5();
11787822Sroot 	uio->uio_iov->iov_base -= cc;
11797822Sroot 	uio->uio_iov->iov_len += cc;
11807822Sroot 	uio->uio_resid += cc;
11817822Sroot 	uio->uio_offset -= cc;
11827502Sroot 	if (tp->t_outq.c_cc <= hiwat) {
11837502Sroot 		(void) spl0();
11847502Sroot 		goto loop;
11857502Sroot 	}
11867502Sroot 	ttstart(tp);
11877502Sroot 	if (tp->t_state & TS_NBIO) {
11887822Sroot 		if (uio->uio_resid == cnt)
11897502Sroot 			u.u_error = EWOULDBLOCK;
11907502Sroot 		return (NULL);
11917502Sroot 	}
11927502Sroot 	tp->t_state |= TS_ASLEEP;
11937502Sroot 	sleep((caddr_t)&tp->t_outq, TTOPRI);
11947502Sroot 	(void) spl0();
11957502Sroot 	goto loop;
11967502Sroot }
11977502Sroot 
11987502Sroot /*
11997502Sroot  * Rubout one character from the rawq of tp
12007502Sroot  * as cleanly as possible.
12017502Sroot  */
12027502Sroot ttyrub(c, tp)
12037625Ssam 	register c;
12047625Ssam 	register struct tty *tp;
12057502Sroot {
12067502Sroot 	register char *cp;
12077502Sroot 	register int savecol;
12087502Sroot 	int s;
12097502Sroot 	char *nextc();
12107502Sroot 
12117502Sroot 	if ((tp->t_flags&ECHO)==0)
12127502Sroot 		return;
12137502Sroot 	tp->t_local &= ~LFLUSHO;
12147502Sroot 	c &= 0377;
12157502Sroot 	if (tp->t_local&LCRTBS) {
12167502Sroot 		if (tp->t_rocount == 0) {
12177502Sroot 			/*
12187502Sroot 			 * Screwed by ttwrite; retype
12197502Sroot 			 */
12207502Sroot 			ttyretype(tp);
12217502Sroot 			return;
12227502Sroot 		}
12237502Sroot 		if (c==('\t'|0200) || c==('\n'|0200))
12247502Sroot 			ttyrubo(tp, 2);
12257625Ssam 		else switch (partab[c&=0177] & 0177) {
12267502Sroot 
12277502Sroot 		case ORDINARY:
12287502Sroot 			if (tp->t_flags&LCASE && c >= 'A' && c <= 'Z')
12297502Sroot 				ttyrubo(tp, 2);
12307502Sroot 			else
12317502Sroot 				ttyrubo(tp, 1);
12327502Sroot 			break;
12337502Sroot 
12347502Sroot 		case VTAB:
12357502Sroot 		case BACKSPACE:
12367502Sroot 		case CONTROL:
12377502Sroot 		case RETURN:
12387502Sroot 			if (tp->t_local & LCTLECH)
12397502Sroot 				ttyrubo(tp, 2);
12407502Sroot 			break;
12417502Sroot 
12427502Sroot 		case TAB:
12437502Sroot 			if (tp->t_rocount < tp->t_rawq.c_cc) {
12447502Sroot 				ttyretype(tp);
12457502Sroot 				return;
12467502Sroot 			}
12477502Sroot 			s = spl5();
12487502Sroot 			savecol = tp->t_col;
12497502Sroot 			tp->t_lstate |= LSCNTTB;
12507502Sroot 			tp->t_local |= LFLUSHO;
12517502Sroot 			tp->t_col = tp->t_rocol;
12527502Sroot 			for (cp = tp->t_rawq.c_cf; cp; cp = nextc(&tp->t_rawq, cp))
12537502Sroot 				ttyecho(*cp, tp);
12547502Sroot 			tp->t_local &= ~LFLUSHO;
12557502Sroot 			tp->t_lstate &= ~LSCNTTB;
12567502Sroot 			splx(s);
12577502Sroot 			/*
12587502Sroot 			 * savecol will now be length of the tab
12597502Sroot 			 */
12607502Sroot 			savecol -= tp->t_col;
12617502Sroot 			tp->t_col += savecol;
12627502Sroot 			if (savecol > 8)
12637502Sroot 				savecol = 8;		/* overflow screw */
12647502Sroot 			while (--savecol >= 0)
12657502Sroot 				(void) ttyoutput('\b', tp);
12667502Sroot 			break;
12677502Sroot 
12687502Sroot 		default:
12697502Sroot 			panic("ttyrub");
12707502Sroot 		}
12717502Sroot 	} else if (tp->t_local&LPRTERA) {
12727502Sroot 		if ((tp->t_lstate&LSERASE) == 0) {
12737502Sroot 			(void) ttyoutput('\\', tp);
12747502Sroot 			tp->t_lstate |= LSERASE;
12757502Sroot 		}
12767502Sroot 		ttyecho(c, tp);
12777502Sroot 	} else
12787502Sroot 		ttyecho(tp->t_erase, tp);
12797502Sroot 	tp->t_rocount--;
12807502Sroot }
12817502Sroot 
12827502Sroot /*
12837502Sroot  * Crt back over cnt chars perhaps
12847502Sroot  * erasing them.
12857502Sroot  */
12867502Sroot ttyrubo(tp, cnt)
12877625Ssam 	register struct tty *tp;
12887625Ssam 	int cnt;
12897502Sroot {
12907502Sroot 
12917502Sroot 	while (--cnt >= 0)
12927502Sroot 		ttyout(tp->t_local&LCRTERA ? "\b \b" : "\b", tp);
12937502Sroot }
12947502Sroot 
12957502Sroot /*
12967502Sroot  * Reprint the rawq line.
12977502Sroot  * We assume c_cc has already been checked.
12987502Sroot  */
12997502Sroot ttyretype(tp)
13007625Ssam 	register struct tty *tp;
13017502Sroot {
13027502Sroot 	register char *cp;
13037502Sroot 	char *nextc();
13047502Sroot 	int s;
13057502Sroot 
13067502Sroot 	if (tlun.t_rprntc != 0377)
13077502Sroot 		ttyecho(tlun.t_rprntc, tp);
13087502Sroot 	(void) ttyoutput('\n', tp);
13097502Sroot 	s = spl5();
13107502Sroot 	for (cp = tp->t_canq.c_cf; cp; cp = nextc(&tp->t_canq, cp))
13117502Sroot 		ttyecho(*cp, tp);
13127502Sroot 	for (cp = tp->t_rawq.c_cf; cp; cp = nextc(&tp->t_rawq, cp))
13137502Sroot 		ttyecho(*cp, tp);
13147502Sroot 	tp->t_lstate &= ~LSERASE;
13157502Sroot 	splx(s);
13167502Sroot 	tp->t_rocount = tp->t_rawq.c_cc;
13177502Sroot 	tp->t_rocol = 0;
13187502Sroot }
13197502Sroot 
13207502Sroot /*
13217502Sroot  * Echo a typed character to the terminal
13227502Sroot  */
13237502Sroot ttyecho(c, tp)
13247625Ssam 	register c;
13257625Ssam 	register struct tty *tp;
13267502Sroot {
13277502Sroot 
13287502Sroot 	if ((tp->t_lstate & LSCNTTB) == 0)
13297502Sroot 		tp->t_local &= ~LFLUSHO;
13307502Sroot 	if ((tp->t_flags&ECHO) == 0)
13317502Sroot 		return;
13327502Sroot 	c &= 0377;
13337502Sroot 	if (tp->t_flags&RAW) {
13347502Sroot 		(void) ttyoutput(c, tp);
13357502Sroot 		return;
13367502Sroot 	}
13377502Sroot 	if (c == '\r' && tp->t_flags&CRMOD)
13387502Sroot 		c = '\n';
13397502Sroot 	if (tp->t_local&LCTLECH) {
13407502Sroot 		if ((c&0177) <= 037 && c!='\t' && c!='\n' || (c&0177)==0177) {
13417502Sroot 			(void) ttyoutput('^', tp);
13427502Sroot 			c &= 0177;
13437502Sroot 			if (c == 0177)
13447502Sroot 				c = '?';
13457502Sroot 			else if (tp->t_flags&LCASE)
13467502Sroot 				c += 'a' - 1;
13477502Sroot 			else
13487502Sroot 				c += 'A' - 1;
13497502Sroot 		}
13507502Sroot 	}
13517502Sroot 	if ((tp->t_flags&LCASE) && (c >= 'A' && c <= 'Z'))
13527502Sroot 		c += 'a' - 'A';
13537502Sroot 	(void) ttyoutput(c & 0177, tp);
13547502Sroot }
13557502Sroot 
13567502Sroot /*
13577502Sroot  * Is c a break char for tp?
13587502Sroot  */
13597502Sroot ttbreakc(c, tp)
13607625Ssam 	register c;
13617625Ssam 	register struct tty *tp;
13627502Sroot {
13637502Sroot 	return (c == '\n' || c == tun.t_eofc || c == tun.t_brkc ||
13647502Sroot 		c == '\r' && (tp->t_flags&CRMOD));
13657502Sroot }
13667502Sroot 
13677502Sroot /*
13687502Sroot  * send string cp to tp
13697502Sroot  */
13707502Sroot ttyout(cp, tp)
13717625Ssam 	register char *cp;
13727625Ssam 	register struct tty *tp;
13737502Sroot {
13747502Sroot 	register char c;
13757502Sroot 
13767502Sroot 	while (c = *cp++)
13777502Sroot 		(void) ttyoutput(c, tp);
13787502Sroot }
13797502Sroot 
13807502Sroot ttwakeup(tp)
13817502Sroot 	struct tty *tp;
13827502Sroot {
13837502Sroot 
13847502Sroot 	if (tp->t_rsel) {
13857502Sroot 		selwakeup(tp->t_rsel, tp->t_state&TS_RCOLL);
13867502Sroot 		tp->t_state &= ~TS_RCOLL;
13877502Sroot 		tp->t_rsel = 0;
13887502Sroot 	}
13897502Sroot 	wakeup((caddr_t)&tp->t_rawq);
13907502Sroot }
13917502Sroot 
13927502Sroot ttsignal(tp, signo)
13937502Sroot 	struct tty *tp;
13947502Sroot 	int signo;
13957502Sroot {
13967502Sroot 
13977502Sroot 	gsignal(tp->t_pgrp, signo);
13987502Sroot }
1399