xref: /csrg-svn/sys/kern/tty.c (revision 7722)
1*7722Swnj /*	tty.c	4.27	82/08/13	*/
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"
18*7722Swnj #include "../h/uio.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 
7739Sbill char	maptab[] ={
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,000,000,
8239Sbill 	000,'|',000,000,000,000,000,'`',
8339Sbill 	'{','}',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,000,
8939Sbill 	000,000,000,000,000,000,'~',000,
9039Sbill 	000,'A','B','C','D','E','F','G',
9139Sbill 	'H','I','J','K','L','M','N','O',
9239Sbill 	'P','Q','R','S','T','U','V','W',
9339Sbill 	'X','Y','Z',000,000,000,000,000,
9439Sbill };
9539Sbill 
96925Sbill short	tthiwat[16] =
97925Sbill    { 100,100,100,100,100,100,100,200,200,400,400,400,650,650,650,650 };
98925Sbill short	ttlowat[16] =
99925Sbill    {  30, 30, 30, 30, 30, 30, 30, 50, 50,120,120,120,125,125,125,125 };
100925Sbill 
10139Sbill #define	OBUFSIZ	100
10239Sbill 
10339Sbill /*
10439Sbill  * set default control characters.
10539Sbill  */
10639Sbill ttychars(tp)
1077625Ssam 	register struct tty *tp;
10839Sbill {
109174Sbill 
11039Sbill 	tun.t_intrc = CINTR;
11139Sbill 	tun.t_quitc = CQUIT;
11239Sbill 	tun.t_startc = CSTART;
11339Sbill 	tun.t_stopc = CSTOP;
11439Sbill 	tun.t_eofc = CEOT;
11539Sbill 	tun.t_brkc = CBRK;
11639Sbill 	tp->t_erase = CERASE;
11739Sbill 	tp->t_kill = CKILL;
118174Sbill /* begin local */
119208Sbill 	tlun.t_suspc = CTRL(z);
120208Sbill 	tlun.t_dsuspc = CTRL(y);
121174Sbill 	tlun.t_rprntc = CTRL(r);
122174Sbill 	tlun.t_flushc = CTRL(o);
123174Sbill 	tlun.t_werasc = CTRL(w);
124174Sbill 	tlun.t_lnextc = CTRL(v);
125174Sbill 	tp->t_local = 0;
126174Sbill 	tp->t_lstate = 0;
127174Sbill /* end local */
12839Sbill }
12939Sbill 
13039Sbill /*
131903Sbill  * Wait for output to drain, then flush input waiting.
13239Sbill  */
133903Sbill wflushtty(tp)
1345408Swnj 	register struct tty *tp;
13539Sbill {
13639Sbill 
137903Sbill 	(void) spl5();
1385622Swnj 	while (tp->t_outq.c_cc && tp->t_state&TS_CARR_ON
1395622Swnj 	    && tp->t_oproc) {		/* kludge for pty */
140903Sbill 		(*tp->t_oproc)(tp);
1415408Swnj 		tp->t_state |= TS_ASLEEP;
142903Sbill 		sleep((caddr_t)&tp->t_outq, TTOPRI);
143903Sbill 	}
1445426Swnj 	flushtty(tp, FREAD);
145903Sbill 	(void) spl0();
14639Sbill }
14739Sbill 
14839Sbill /*
149903Sbill  * flush all TTY queues
15039Sbill  */
151903Sbill flushtty(tp, rw)
1527625Ssam 	register struct tty *tp;
15339Sbill {
154903Sbill 	register s;
155903Sbill 
156903Sbill 	s = spl6();
157903Sbill 	if (rw & FREAD) {
158903Sbill 		while (getc(&tp->t_canq) >= 0)
159903Sbill 			;
160903Sbill 		wakeup((caddr_t)&tp->t_rawq);
161903Sbill 	}
162903Sbill 	if (rw & FWRITE) {
163903Sbill 		wakeup((caddr_t)&tp->t_outq);
1645408Swnj 		tp->t_state &= ~TS_TTSTOP;
1655426Swnj 		(*cdevsw[major(tp->t_dev)].d_stop)(tp, rw);
166903Sbill 		while (getc(&tp->t_outq) >= 0)
167903Sbill 			;
168903Sbill 	}
169903Sbill 	if (rw & FREAD) {
170903Sbill 		while (getc(&tp->t_rawq) >= 0)
171903Sbill 			;
172903Sbill 		tp->t_delct = 0;
173903Sbill 		tp->t_rocount = 0;		/* local */
174903Sbill 		tp->t_rocol = 0;
175903Sbill 		tp->t_lstate = 0;
176903Sbill 	}
177903Sbill 	splx(s);
17839Sbill }
17939Sbill 
180903Sbill /*
181903Sbill  * Send stop character on input overflow.
182903Sbill  */
183903Sbill ttyblock(tp)
1847625Ssam 	register struct tty *tp;
18539Sbill {
186903Sbill 	register x;
187903Sbill 	x = tp->t_rawq.c_cc + tp->t_canq.c_cc;
188903Sbill 	if (tp->t_rawq.c_cc > TTYHOG) {
189903Sbill 		flushtty(tp, FREAD|FWRITE);
1905408Swnj 		tp->t_state &= ~TS_TBLOCK;
191903Sbill 	}
192903Sbill 	if (x >= TTYHOG/2) {
193903Sbill 		if (putc(tun.t_stopc, &tp->t_outq)==0) {
1945408Swnj 			tp->t_state |= TS_TBLOCK;
195903Sbill 			tp->t_char++;
196903Sbill 			ttstart(tp);
197903Sbill 		}
198903Sbill 	}
19939Sbill }
20039Sbill 
20139Sbill /*
202903Sbill  * Restart typewriter output following a delay
203903Sbill  * timeout.
204903Sbill  * The name of the routine is passed to the timeout
205903Sbill  * subroutine and it is called during a clock interrupt.
206121Sbill  */
207903Sbill ttrstrt(tp)
2087625Ssam 	register struct tty *tp;
209121Sbill {
210121Sbill 
2113351Swnj 	if (tp == 0) {
2123351Swnj 		printf("ttrstrt: arg was 0!\n");
2133351Swnj 		return;
2143351Swnj 	}
2155408Swnj 	tp->t_state &= ~TS_TIMEOUT;
216903Sbill 	ttstart(tp);
217121Sbill }
218121Sbill 
219121Sbill /*
220903Sbill  * Start output on the typewriter. It is used from the top half
221903Sbill  * after some characters have been put on the output queue,
222903Sbill  * from the interrupt routine to transmit the next
223903Sbill  * character, and after a timeout has finished.
22439Sbill  */
225903Sbill ttstart(tp)
2267625Ssam 	register struct tty *tp;
22739Sbill {
228903Sbill 	register s;
22939Sbill 
230903Sbill 	s = spl5();
2317625Ssam 	if ((tp->t_state&(TS_TIMEOUT|TS_TTSTOP|TS_BUSY)) == 0 &&
2325622Swnj 	    tp->t_oproc)		/* kludge for pty */
233903Sbill 		(*tp->t_oproc)(tp);
234903Sbill 	splx(s);
23539Sbill }
23639Sbill 
23739Sbill /*
238903Sbill  * Common code for tty ioctls.
23939Sbill  */
2401780Sbill /*ARGSUSED*/
2417625Ssam ttioctl(tp, com, data, flag)
2427625Ssam 	register struct tty *tp;
2437625Ssam 	caddr_t data;
24439Sbill {
2451904Swnj 	int dev;
24639Sbill 	extern int nldisp;
24739Sbill 
248903Sbill 	/*
249915Sbill 	 * This is especially so that isatty() will
250915Sbill 	 * fail when carrier is gone.
251915Sbill 	 */
2525408Swnj 	if ((tp->t_state&TS_CARR_ON) == 0) {
253915Sbill 		u.u_error = EBADF;
254915Sbill 		return (1);
255915Sbill 	}
256915Sbill 
2571904Swnj 	dev = tp->t_dev;
258915Sbill 	/*
259903Sbill 	 * If the ioctl involves modification,
260903Sbill 	 * insist on being able to write the device,
261903Sbill 	 * and hang if in the background.
262903Sbill 	 */
2637625Ssam 	switch (com) {
26439Sbill 
265915Sbill 	case TIOCSETD:
266915Sbill 	case TIOCSETP:
267915Sbill 	case TIOCSETN:
268903Sbill 	case TIOCFLUSH:
269903Sbill 	case TIOCSETC:
270903Sbill 	case TIOCSLTC:
271903Sbill 	case TIOCSPGRP:
272903Sbill 	case TIOCLBIS:
273903Sbill 	case TIOCLBIC:
274903Sbill 	case TIOCLSET:
275915Sbill /* this is reasonable, but impractical...
276903Sbill 		if ((flag & FWRITE) == 0) {
277903Sbill 			u.u_error = EBADF;
278903Sbill 			return (1);
279903Sbill 		}
280915Sbill  */
281903Sbill 		while (tp->t_line == NTTYDISC &&
282903Sbill 		   u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp &&
283903Sbill 		   (u.u_procp->p_flag&SVFORK) == 0 &&
284903Sbill 		   u.u_signal[SIGTTOU] != SIG_IGN &&
2855626Swnj 		   u.u_signal[SIGTTOU] != SIG_HOLD
2865626Swnj /*
2875626Swnj 						   &&
288903Sbill 		   (u.u_procp->p_flag&SDETACH)==0) {
2895626Swnj */
2905626Swnj 		   ) {
291903Sbill 			gsignal(u.u_procp->p_pgrp, SIGTTOU);
292903Sbill 			sleep((caddr_t)&lbolt, TTOPRI);
293903Sbill 		}
294903Sbill 		break;
295903Sbill 	}
296903Sbill 
29739Sbill 	/*
298903Sbill 	 * Process the ioctl.
29939Sbill 	 */
3007625Ssam 	switch (com) {
301903Sbill 
302903Sbill 	/*
303903Sbill 	 * Get discipline number
304903Sbill 	 */
30539Sbill 	case TIOCGETD:
3067625Ssam 		*(int *)data = tp->t_line;
30739Sbill 		break;
30839Sbill 
30939Sbill 	/*
310903Sbill 	 * Set line discipline
31139Sbill 	 */
3127625Ssam 	case TIOCSETD: {
3137625Ssam 		register int t = *(int *)data;
3147625Ssam 
31539Sbill 		if (t >= nldisp) {
31639Sbill 			u.u_error = ENXIO;
31739Sbill 			break;
31839Sbill 		}
319174Sbill 		(void) spl5();
32039Sbill 		if (tp->t_line)
32139Sbill 			(*linesw[tp->t_line].l_close)(tp);
32239Sbill 		if (t)
3237625Ssam 			(*linesw[t].l_open)(dev, tp);
32439Sbill 		if (u.u_error==0)
32539Sbill 			tp->t_line = t;
326174Sbill 		(void) spl0();
32739Sbill 		break;
3287625Ssam 	}
32939Sbill 
33039Sbill 	/*
3315614Swnj 	 * Prevent more opens on channel
3325614Swnj 	 */
3335614Swnj 	case TIOCEXCL:
3345614Swnj 		tp->t_state |= TS_XCLUDE;
3355614Swnj 		break;
3365614Swnj 
3375614Swnj 	case TIOCNXCL:
3385614Swnj 		tp->t_state &= ~TS_XCLUDE;
3395614Swnj 		break;
3405614Swnj 
3415614Swnj 	/*
34239Sbill 	 * Set new parameters
34339Sbill 	 */
34439Sbill 	case TIOCSETP:
3457625Ssam 	case TIOCSETN: {
3467625Ssam 		register struct sgttyb *sg = (struct sgttyb *)data;
3477625Ssam 		struct clist tq;
3487625Ssam 
349121Sbill 		(void) spl5();
3507625Ssam 		if (tp->t_flags&RAW || sg->sg_flags&RAW || com == TIOCSETP)
3514484Swnj 			wflushtty(tp);
3527625Ssam 		else if ((tp->t_flags&CBREAK) != (sg->sg_flags&CBREAK)) {
3537625Ssam 			if (sg->sg_flags & CBREAK) {
3544484Swnj 				catq(&tp->t_rawq, &tp->t_canq);
3554484Swnj 				tq = tp->t_rawq;
3564484Swnj 				tp->t_rawq = tp->t_canq;
3574484Swnj 				tp->t_canq = tq;
3584484Swnj 			} else {
3594484Swnj 				tp->t_local |= LPENDIN;
3604484Swnj 				ttwakeup(tp);
361174Sbill 			}
362174Sbill 		}
3637625Ssam 		tp->t_ispeed = sg->sg_ispeed;
3647625Ssam 		tp->t_ospeed = sg->sg_ospeed;
3657625Ssam 		tp->t_erase = sg->sg_erase;
3667625Ssam 		tp->t_kill = sg->sg_kill;
3677625Ssam 		tp->t_flags = sg->sg_flags;
3683941Sbugs 		if (tp->t_flags & RAW) {
3695408Swnj 			tp->t_state &= ~TS_TTSTOP;
3703941Sbugs 			ttstart(tp);
3713941Sbugs 		}
372121Sbill 		(void) spl0();
37339Sbill 		break;
3747625Ssam 	}
37539Sbill 
37639Sbill 	/*
377903Sbill 	 * Send current parameters to user
37839Sbill 	 */
3797625Ssam 	case TIOCGETP: {
3807625Ssam 		register struct sgttyb *sg = (struct sgttyb *)data;
3817625Ssam 
3827625Ssam 		sg->sg_ispeed = tp->t_ispeed;
3837625Ssam 		sg->sg_ospeed = tp->t_ospeed;
3847625Ssam 		sg->sg_erase = tp->t_erase;
3857625Ssam 		sg->sg_kill = tp->t_kill;
3867625Ssam 		sg->sg_flags = tp->t_flags;
38739Sbill 		break;
3887625Ssam 	}
38939Sbill 
39039Sbill 	/*
39139Sbill 	 * Hang up line on last close
39239Sbill 	 */
39339Sbill 	case TIOCHPCL:
3945408Swnj 		tp->t_state |= TS_HUPCLS;
39539Sbill 		break;
39639Sbill 
3973942Sbugs 	case TIOCFLUSH: {
3987625Ssam 		register int flags = *(int *)data;
3997625Ssam 
4007625Ssam 		if (flags == 0)
4013942Sbugs 			flags = FREAD|FWRITE;
4027625Ssam 		else
4037625Ssam 			flags &= FREAD|FWRITE;
4043942Sbugs 		flushtty(tp, flags);
40539Sbill 		break;
4063944Sbugs 	}
40739Sbill 
4087625Ssam 	case FIONBIO:
4097625Ssam 		if (*(int *)data)
4105408Swnj 			tp->t_state |= TS_NBIO;
4115408Swnj 		else
4125408Swnj 			tp->t_state &= ~TS_NBIO;
4135408Swnj 		break;
4145408Swnj 
4157625Ssam 	case FIOASYNC:
4167625Ssam 		if (*(int *)data)
4176216Swnj 			tp->t_state |= TS_ASYNC;
4186216Swnj 		else
4196216Swnj 			tp->t_state &= ~TS_ASYNC;
4206216Swnj 		break;
4216216Swnj 
42239Sbill 	/*
423903Sbill 	 * Set and fetch special characters
42439Sbill 	 */
42539Sbill 	case TIOCSETC:
4267625Ssam 		bcopy(data, (caddr_t)&tun, sizeof (struct tchars));
42739Sbill 		break;
42839Sbill 
42939Sbill 	case TIOCGETC:
4307625Ssam 		bcopy((caddr_t)&tun, data, sizeof (struct tchars));
43139Sbill 		break;
43239Sbill 
433174Sbill /* local ioctls */
434903Sbill 	/*
435903Sbill 	 * Set/get local special characters.
436903Sbill 	 */
437174Sbill 	case TIOCSLTC:
4387625Ssam 		bcopy(data, (caddr_t)&tlun, sizeof (struct ltchars));
439174Sbill 		break;
440174Sbill 
441174Sbill 	case TIOCGLTC:
4427625Ssam 		bcopy((caddr_t)&tlun, data, sizeof (struct ltchars));
443174Sbill 		break;
444174Sbill 
445903Sbill 	/*
446903Sbill 	 * Return number of characters immediately available.
447903Sbill 	 */
4487625Ssam 	case FIONREAD:
4497625Ssam 		*(off_t *)data = ttnread(tp);
450174Sbill 		break;
451174Sbill 
452174Sbill 	/*
453174Sbill 	 * Should allow SPGRP and GPGRP only if tty open for reading.
454174Sbill 	 */
455174Sbill 	case TIOCSPGRP:
4567625Ssam 		tp->t_pgrp = *(int *)data;
457174Sbill 		break;
458174Sbill 
459174Sbill 	case TIOCGPGRP:
4607625Ssam 		*(int *)data = tp->t_pgrp;
461174Sbill 		break;
462174Sbill 
463174Sbill 	/*
464174Sbill 	 * Modify local mode word.
465174Sbill 	 */
466174Sbill 	case TIOCLBIS:
4677625Ssam 		tp->t_local |= *(int *)data;
468174Sbill 		break;
469174Sbill 
470174Sbill 	case TIOCLBIC:
4717625Ssam 		tp->t_local &= ~(*(int *)data);
472174Sbill 		break;
473174Sbill 
474174Sbill 	case TIOCLSET:
4757625Ssam 		tp->t_local = *(int *)data;
476174Sbill 		break;
477174Sbill 
478174Sbill 	case TIOCLGET:
4797625Ssam 		*(int *)data = tp->t_local;
480174Sbill 		break;
481174Sbill 
4827625Ssam 	case TIOCSTOP: {
4837625Ssam 		int s = spl5();
484213Sbill 
4855573Swnj 		if ((tp->t_state & TS_TTSTOP) == 0) {
4865573Swnj 			tp->t_state |= TS_TTSTOP;
4875573Swnj 			(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
4885573Swnj 		}
4897625Ssam 		splx(s);
4905573Swnj 		break;
4917625Ssam 	}
4925573Swnj 
4937625Ssam 	case TIOCSTART: {
4947625Ssam 		int s = spl5();
4957625Ssam 
4965573Swnj 		if ((tp->t_state & TS_TTSTOP) || (tp->t_local & LFLUSHO)) {
4975573Swnj 			tp->t_state &= ~TS_TTSTOP;
4985573Swnj 			tp->t_local &= ~LFLUSHO;
4995573Swnj 			ttstart(tp);
5005573Swnj 		}
5017625Ssam 		splx(s);
5025573Swnj 		break;
5037625Ssam 	}
5045573Swnj 
505174Sbill /* end of locals */
506887Sbill 
50739Sbill 	default:
5087625Ssam 		return (0);
50939Sbill 	}
5107625Ssam 	return (1);
51139Sbill }
5124484Swnj 
5134484Swnj ttnread(tp)
5144484Swnj 	struct tty *tp;
5154484Swnj {
5164484Swnj 	int nread = 0;
5174484Swnj 
5184484Swnj 	if (tp->t_local & LPENDIN)
5194484Swnj 		ttypend(tp);
5204484Swnj 	nread = tp->t_canq.c_cc;
5214484Swnj 	if (tp->t_flags & (RAW|CBREAK))
5224484Swnj 		nread += tp->t_rawq.c_cc;
5234484Swnj 	return (nread);
5244484Swnj }
5254484Swnj 
5265408Swnj ttselect(dev, rw)
5274484Swnj 	dev_t dev;
5285408Swnj 	int rw;
5294484Swnj {
5304484Swnj 	register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)];
5314484Swnj 	int nread;
5325408Swnj 	int s = spl5();
5334484Swnj 
5345408Swnj 	switch (rw) {
5354484Swnj 
5364484Swnj 	case FREAD:
5374484Swnj 		nread = ttnread(tp);
5384484Swnj 		if (nread > 0)
5395408Swnj 			goto win;
5404938Swnj 		if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait)
5415408Swnj 			tp->t_state |= TS_RCOLL;
5424484Swnj 		else
5434484Swnj 			tp->t_rsel = u.u_procp;
5445408Swnj 		break;
5454484Swnj 
5465408Swnj 	case FWRITE:
5475408Swnj 		if (tp->t_outq.c_cc <= TTLOWAT(tp))
5485408Swnj 			goto win;
5495408Swnj 		if (tp->t_wsel && tp->t_wsel->p_wchan == (caddr_t)&selwait)
5505408Swnj 			tp->t_state |= TS_WCOLL;
5515408Swnj 		else
5525408Swnj 			tp->t_wsel = u.u_procp;
5535408Swnj 		break;
5544484Swnj 	}
5555408Swnj 	splx(s);
5565408Swnj 	return (0);
5575408Swnj win:
5585408Swnj 	splx(s);
5595408Swnj 	return (1);
5604484Swnj }
5617436Skre 
5627502Sroot #define	OBUFSIZ	100
5637502Sroot 
5647502Sroot /*
5657502Sroot  * routine called on opens while tp->t_line == NTTYDISC
5667502Sroot  * establishes a process group for distribution of
5677502Sroot  * quits and interrupts from the tty.
5687502Sroot  * (actually, pp->p_pgrp can't be 0 when this routine
5697502Sroot  * is called since NTTYDISC is not the default discipline)
5707502Sroot  */
5717502Sroot ttyopen(dev, tp)
5727625Ssam 	dev_t dev;
5737625Ssam 	register struct tty *tp;
5747502Sroot {
5757502Sroot 	register struct proc *pp;
5767502Sroot 
5777502Sroot 	pp = u.u_procp;
5787502Sroot 	tp->t_dev = dev;
5797625Ssam 	if (pp->p_pgrp == 0) {
5807502Sroot 		u.u_ttyp = tp;
5817502Sroot 		u.u_ttyd = dev;
5827502Sroot 		if (tp->t_pgrp == 0)
5837502Sroot 			tp->t_pgrp = pp->p_pid;
5847502Sroot 		pp->p_pgrp = tp->t_pgrp;
5857502Sroot 	}
5867502Sroot 	tp->t_state &= ~TS_WOPEN;
5877502Sroot 	tp->t_state |= TS_ISOPEN;
5887502Sroot 	if (tp->t_line != NTTYDISC)
5897502Sroot 		wflushtty(tp);
5907502Sroot }
5917502Sroot 
5927502Sroot /*
5937502Sroot  * clean tp on last close
5947502Sroot  */
5957502Sroot ttyclose(tp)
5967625Ssam 	register struct tty *tp;
5977502Sroot {
5987502Sroot 
5997502Sroot 	if (tp->t_line) {
6007502Sroot 		wflushtty(tp);
6017502Sroot 		tp->t_line = 0;
6027502Sroot 		return;
6037502Sroot 	}
6047502Sroot 	tp->t_pgrp = 0;
6057502Sroot 	wflushtty(tp);
6067502Sroot 	tp->t_state = 0;
6077502Sroot }
6087502Sroot 
6097502Sroot /*
6107502Sroot  * reinput pending characters after state switch
6117502Sroot  * call at spl5().
6127502Sroot  */
6137502Sroot ttypend(tp)
6147625Ssam 	register struct tty *tp;
6157502Sroot {
6167502Sroot 	struct clist tq;
6177502Sroot 	register c;
6187502Sroot 
6197502Sroot 	tp->t_local &= ~LPENDIN;
6207502Sroot 	tp->t_lstate |= LSTYPEN;
6217502Sroot 	tq = tp->t_rawq;
6227502Sroot 	tp->t_rawq.c_cc = 0;
6237502Sroot 	tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0;
6247502Sroot 	while ((c = getc(&tq)) >= 0)
6257502Sroot 		ttyinput(c, tp);
6267502Sroot 	tp->t_lstate &= ~LSTYPEN;
6277502Sroot }
6287502Sroot 
6297502Sroot /*
6307502Sroot  * Place a character on raw TTY input queue, putting in delimiters
6317502Sroot  * and waking up top half as needed.
6327502Sroot  * Also echo if required.
6337502Sroot  * The arguments are the character and the appropriate
6347502Sroot  * tty structure.
6357502Sroot  */
6367502Sroot ttyinput(c, tp)
6377625Ssam 	register c;
6387625Ssam 	register struct tty *tp;
6397502Sroot {
6407502Sroot 	register int t_flags;
6417502Sroot 	int i;
6427502Sroot 
6437502Sroot 	if (tp->t_local&LPENDIN)
6447502Sroot 		ttypend(tp);
6457502Sroot 	tk_nin++;
6467502Sroot 	c &= 0377;
6477502Sroot 	t_flags = tp->t_flags;
6487502Sroot 	if (t_flags&TANDEM)
6497502Sroot 		ttyblock(tp);
6507502Sroot 	if ((t_flags&RAW)==0) {
6517502Sroot 		if ((tp->t_lstate&LSTYPEN) == 0)
6527502Sroot 			c &= 0177;
6537502Sroot 	/* check for literal nexting very first */
6547502Sroot 		if (tp->t_lstate&LSLNCH) {
6557502Sroot 			c |= 0200;
6567502Sroot 			tp->t_lstate &= ~LSLNCH;
6577502Sroot 		}
6587502Sroot 		if (tp->t_line == NTTYDISC && c==tlun.t_lnextc) {
6597502Sroot 			if (tp->t_flags&ECHO)
6607502Sroot 				ttyout("^\b", tp);
6617502Sroot 			tp->t_lstate |= LSLNCH;
6627502Sroot 	/* check for output control functions */
6637502Sroot 		} else if (c==tun.t_stopc) {
6647502Sroot 			if ((tp->t_state&TS_TTSTOP)==0) {
6657502Sroot 				tp->t_state |= TS_TTSTOP;
6667502Sroot 				(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
6677502Sroot 				return;
6687502Sroot 			}
6697502Sroot 			if (c!=tun.t_startc)
6707502Sroot 				return;
6717502Sroot 		} else if (c==tun.t_startc) {
6727502Sroot 			tp->t_state &= ~TS_TTSTOP;
6737502Sroot 			tp->t_local &= ~LFLUSHO;
6747502Sroot 			ttstart(tp);
6757502Sroot 			return;
6767502Sroot 		} else if (tp->t_line == NTTYDISC && c==tlun.t_flushc) {
6777502Sroot 			if (tp->t_local & LFLUSHO)
6787502Sroot 				tp->t_local &= ~LFLUSHO;
6797502Sroot 			else {
6807502Sroot 				flushtty(tp, FWRITE);
6817502Sroot 				ttyecho(c, tp);
6827502Sroot 				if (tp->t_rawq.c_cc+tp->t_canq.c_cc)
6837502Sroot 					ttyretype(tp);
6847502Sroot 				tp->t_local |= LFLUSHO;
6857502Sroot 			}
6867502Sroot 			ttstart(tp);
6877502Sroot 			return;
6887502Sroot 		} else if (c==tun.t_intrc || c==tun.t_quitc ||
6897502Sroot 		    (tp->t_line == NTTYDISC && c==tlun.t_suspc)) {
6907502Sroot 			if ((tp->t_local & LNOFLSH) == 0)
6917502Sroot 				flushtty(tp,
6927502Sroot 				    c==tlun.t_suspc ? FREAD : FREAD|FWRITE);
6937502Sroot 			ttyecho(c, tp);
6947502Sroot 			c = c==tun.t_intrc ? SIGINT :
6957502Sroot 				((c==tun.t_quitc) ? SIGQUIT : SIGTSTP);
6967502Sroot 			ttsignal(tp, c);
6977502Sroot 	/* check for buffer editing functions - cooked mode */
6987502Sroot 		} else if ((t_flags&CBREAK) == 0) {
6997502Sroot 			if ((tp->t_lstate&LSQUOT) &&
7007502Sroot 			    (c==tp->t_erase||c==tp->t_kill)) {
7017502Sroot 				ttyrub(unputc(&tp->t_rawq), tp);
7027502Sroot 				c |= 0200;
7037502Sroot 			}
7047502Sroot 			if (c==tp->t_erase) {
7057502Sroot 				if (tp->t_rawq.c_cc)
7067502Sroot 					ttyrub(unputc(&tp->t_rawq), tp);
7077502Sroot 			} else if (c==tp->t_kill) {
7087502Sroot 				if (tp->t_local&LCRTKIL &&
7097502Sroot 				    tp->t_rawq.c_cc == tp->t_rocount) {
7107502Sroot 					while (tp->t_rawq.c_cc)
7117502Sroot 						ttyrub(unputc(&tp->t_rawq), tp);
7127502Sroot 				} else {
7137502Sroot 					ttyecho(c, tp);
7147502Sroot 					ttyecho('\n', tp);
7157502Sroot 					while (getc(&tp->t_rawq) > 0)
7167502Sroot 						;
7177502Sroot 					tp->t_rocount = 0;
7187502Sroot 				}
7197502Sroot 				tp->t_lstate = 0;
7207502Sroot 			} else if (tp->t_line == NTTYDISC && c==tlun.t_werasc) {
7217502Sroot 				if (tp->t_rawq.c_cc == 0)
7227502Sroot 					goto out;
7237502Sroot 				do {
7247502Sroot 					c = unputc(&tp->t_rawq);
7257502Sroot 					if (c != ' ' && c != '\t')
7267502Sroot 						goto erasenb;
7277502Sroot 					ttyrub(c, tp);
7287502Sroot 				} while (tp->t_rawq.c_cc);
7297502Sroot 				goto out;
7307502Sroot 			    erasenb:
7317502Sroot 				do {
7327502Sroot 					ttyrub(c, tp);
7337502Sroot 					if (tp->t_rawq.c_cc == 0)
7347502Sroot 						goto out;
7357502Sroot 					c = unputc(&tp->t_rawq);
7367502Sroot 				} while (c != ' ' && c != '\t');
7377502Sroot 				(void) putc(c, &tp->t_rawq);
7387502Sroot 			} else if (tp->t_line == NTTYDISC && c==tlun.t_rprntc) {
7397502Sroot 				ttyretype(tp);
7407502Sroot 	/* check for cooked mode input buffer overflow */
7417502Sroot 			} else if (tp->t_rawq.c_cc+tp->t_canq.c_cc >= TTYHOG) {
7427502Sroot 				;
7437502Sroot 	/* put data char in q for user and wakeup if a break char */
7447502Sroot 			} else if (putc(c, &tp->t_rawq) >= 0) {
7457502Sroot 				if (tp->t_rawq.c_cc+tp->t_canq.c_cc==TTYHOG
7467502Sroot 				    && tp->t_line == NTTYDISC)
7477502Sroot 					(void) ttyoutput(CTRL(g), tp);
7487502Sroot 				if (!ttbreakc(c, tp)) {
7497502Sroot 					if (tp->t_rocount++ == 0)
7507502Sroot 						tp->t_rocol = tp->t_col;
7517502Sroot 				} else {
7527502Sroot 					tp->t_rocount = 0;
7537502Sroot 					catq(&tp->t_rawq, &tp->t_canq);
7547502Sroot 					/* IF (TP->T_CHAN) (VOID) SDATA(TP->T_CHAN); */
7557502Sroot 					ttwakeup(tp);
7567502Sroot 				}
7577502Sroot 				tp->t_lstate &= ~LSQUOT;
7587502Sroot 				if (c == '\\')
7597502Sroot 					tp->t_lstate |= LSQUOT;
7607502Sroot 				if (tp->t_lstate&LSERASE) {
7617502Sroot 					tp->t_lstate &= ~LSERASE;
7627502Sroot 					(void) ttyoutput('/', tp);
7637502Sroot 				}
7647502Sroot 				i = tp->t_col;
7657502Sroot 				ttyecho(c, tp);
7667502Sroot 				if (c==tun.t_eofc && tp->t_flags&ECHO) {
7677502Sroot 					i = MIN(2, tp->t_col - i);
7687502Sroot 					while (i > 0) {
7697502Sroot 						(void) ttyoutput('\b', tp);
7707502Sroot 						i--;
7717502Sroot 					}
7727502Sroot 				}
7737502Sroot 			}
7747502Sroot 	/* CBREAK mode */
7757502Sroot 		} else if (tp->t_rawq.c_cc > TTYHOG) {
7767502Sroot 			if (tp->t_outq.c_cc < TTHIWAT(tp) &&
7777502Sroot 			    tp->t_line == NTTYDISC)
7787502Sroot 				(void) ttyoutput(CTRL(g), tp);
7797502Sroot 		} else if (putc(c, &tp->t_rawq) >= 0) {
7807502Sroot 			ttwakeup(tp);
7817502Sroot 			ttyecho(c, tp);
7827502Sroot 		}
7837502Sroot 	/* RAW mode */
7847502Sroot 	} else if (tp->t_rawq.c_cc > TTYHOG)
7857502Sroot 		flushtty(tp, FREAD|FWRITE);
7867502Sroot 	else {
7877502Sroot 		if (putc(c, &tp->t_rawq) >= 0)
7887502Sroot 			ttwakeup(tp);
7897502Sroot 		ttyecho(c, tp);
7907502Sroot 	}
7917502Sroot out:
7927502Sroot 	if (tp->t_local & LDECCTQ && tp->t_state & TS_TTSTOP &&
7937502Sroot 	    tun.t_startc != tun.t_stopc)
7947502Sroot 		return;
7957502Sroot 	tp->t_state &= ~TS_TTSTOP;
7967502Sroot 	tp->t_local &= ~LFLUSHO;
7977502Sroot 	ttstart(tp);
7987502Sroot }
7997502Sroot 
8007502Sroot /*
8017502Sroot  * put character on TTY output queue, adding delays,
8027502Sroot  * expanding tabs, and handling the CR/NL bit.
8037502Sroot  * It is called both from the top half for output, and from
8047502Sroot  * interrupt level for echoing.
8057502Sroot  * The arguments are the character and the tty structure.
8067502Sroot  * Returns < 0 if putc succeeds, otherwise returns char to resend
8077502Sroot  * Must be recursive.
8087502Sroot  */
8097502Sroot ttyoutput(c, tp)
8107502Sroot 	register c;
8117502Sroot 	register struct tty *tp;
8127502Sroot {
8137502Sroot 	register char *colp;
8147502Sroot 	register ctype;
8157502Sroot 
8167502Sroot 	if (tp->t_flags&RAW || tp->t_local&LLITOUT) {
8177502Sroot 		if (tp->t_local&LFLUSHO)
8187502Sroot 			return (-1);
8197502Sroot 		if (putc(c, &tp->t_outq))
8207625Ssam 			return (c);
8217502Sroot 		tk_nout++;
8227502Sroot 		return (-1);
8237502Sroot 	}
8247502Sroot 	/*
8257502Sroot 	 * Ignore EOT in normal mode to avoid hanging up
8267502Sroot 	 * certain terminals.
8277502Sroot 	 */
8287502Sroot 	c &= 0177;
8297502Sroot 	if (c==CEOT && (tp->t_flags&CBREAK)==0)
8307502Sroot 		return (-1);
8317502Sroot 	/*
8327502Sroot 	 * Turn tabs to spaces as required
8337502Sroot 	 */
8347502Sroot 	if (c=='\t' && (tp->t_flags&TBDELAY)==XTABS) {
8357502Sroot 		register int s;
8367502Sroot 
8377502Sroot 		c = 8 - (tp->t_col&7);
8387502Sroot 		if ((tp->t_local&LFLUSHO) == 0) {
8397502Sroot 			s = spl5();		/* don't interrupt tabs */
8407502Sroot 			c -= b_to_q("        ", c, &tp->t_outq);
8417502Sroot 			tk_nout += c;
8427502Sroot 			splx(s);
8437502Sroot 		}
8447502Sroot 		tp->t_col += c;
8457502Sroot 		return (c ? -1 : '\t');
8467502Sroot 	}
8477502Sroot 	tk_nout++;
8487502Sroot 	/*
8497502Sroot 	 * for upper-case-only terminals,
8507502Sroot 	 * generate escapes.
8517502Sroot 	 */
8527502Sroot 	if (tp->t_flags&LCASE) {
8537502Sroot 		colp = "({)}!|^~'`";
8547625Ssam 		while (*colp++)
8557625Ssam 			if (c == *colp++) {
8567502Sroot 				if (ttyoutput('\\', tp) >= 0)
8577502Sroot 					return (c);
8587502Sroot 				c = colp[-2];
8597502Sroot 				break;
8607502Sroot 			}
8617502Sroot 		if ('A'<=c && c<='Z') {
8627502Sroot 			if (ttyoutput('\\', tp) >= 0)
8637502Sroot 				return (c);
8647502Sroot 		} else if ('a'<=c && c<='z')
8657502Sroot 			c += 'A' - 'a';
8667502Sroot 	}
8677502Sroot 	/*
8687502Sroot 	 * turn <nl> to <cr><lf> if desired.
8697502Sroot 	 */
8707502Sroot 	if (c=='\n' && tp->t_flags&CRMOD)
8717502Sroot 		if (ttyoutput('\r', tp) >= 0)
8727502Sroot 			return (c);
8737502Sroot 	if (c=='~' && tp->t_local&LTILDE)
8747502Sroot 		c = '`';
8757502Sroot 	if ((tp->t_local&LFLUSHO) == 0 && putc(c, &tp->t_outq))
8767502Sroot 		return (c);
8777502Sroot 	/*
8787502Sroot 	 * Calculate delays.
8797502Sroot 	 * The numbers here represent clock ticks
8807502Sroot 	 * and are not necessarily optimal for all terminals.
8817502Sroot 	 * The delays are indicated by characters above 0200.
8827502Sroot 	 * In raw mode there are no delays and the
8837502Sroot 	 * transmission path is 8 bits wide.
8847502Sroot 	 */
8857502Sroot 	colp = &tp->t_col;
8867502Sroot 	ctype = partab[c];
8877502Sroot 	c = 0;
8887502Sroot 	switch (ctype&077) {
8897502Sroot 
8907502Sroot 	case ORDINARY:
8917502Sroot 		(*colp)++;
8927502Sroot 
8937502Sroot 	case CONTROL:
8947502Sroot 		break;
8957502Sroot 
8967502Sroot 	case BACKSPACE:
8977502Sroot 		if (*colp)
8987502Sroot 			(*colp)--;
8997502Sroot 		break;
9007502Sroot 
9017502Sroot 	case NEWLINE:
9027502Sroot 		ctype = (tp->t_flags >> 8) & 03;
9037625Ssam 		if (ctype == 1) { /* tty 37 */
9047502Sroot 			if (*colp)
9057502Sroot 				c = max(((unsigned)*colp>>4) + 3, (unsigned)6);
9067502Sroot 		} else
9077625Ssam 		if (ctype == 2) { /* vt05 */
9087502Sroot 			c = 6;
9097502Sroot 		}
9107502Sroot 		*colp = 0;
9117502Sroot 		break;
9127502Sroot 
9137502Sroot 	case TAB:
9147502Sroot 		ctype = (tp->t_flags >> 10) & 03;
9157625Ssam 		if (ctype == 1) { /* tty 37 */
9167502Sroot 			c = 1 - (*colp | ~07);
9177625Ssam 			if (c < 5)
9187502Sroot 				c = 0;
9197502Sroot 		}
9207502Sroot 		*colp |= 07;
9217502Sroot 		(*colp)++;
9227502Sroot 		break;
9237502Sroot 
9247502Sroot 	case VTAB:
9257625Ssam 		if (tp->t_flags & VTDELAY) /* tty 37 */
9267502Sroot 			c = 0177;
9277502Sroot 		break;
9287502Sroot 
9297502Sroot 	case RETURN:
9307502Sroot 		ctype = (tp->t_flags >> 12) & 03;
9317625Ssam 		if (ctype == 1) { /* tn 300 */
9327502Sroot 			c = 5;
9337625Ssam 		} else if (ctype == 2) { /* ti 700 */
9347502Sroot 			c = 10;
9357625Ssam 		} else if (ctype == 3) { /* concept 100 */
9367502Sroot 			int i;
9377502Sroot 			if ((i = *colp) >= 0)
9387502Sroot 				for (; i<9; i++)
9397502Sroot 					(void) putc(0177, &tp->t_outq);
9407502Sroot 		}
9417502Sroot 		*colp = 0;
9427502Sroot 	}
9437625Ssam 	if (c && (tp->t_local&LFLUSHO) == 0)
9447502Sroot 		(void) putc(c|0200, &tp->t_outq);
9457502Sroot 	return (-1);
9467502Sroot }
9477502Sroot 
9487502Sroot /*
9497502Sroot  * Called from device's read routine after it has
9507502Sroot  * calculated the tty-structure given as argument.
9517502Sroot  */
952*7722Swnj ttread(tp, uio)
9537625Ssam 	register struct tty *tp;
954*7722Swnj 	struct uio *uio;
9557502Sroot {
9567502Sroot 	register struct clist *qp;
9577502Sroot 	register c, first;
9587502Sroot 
9597502Sroot 	if ((tp->t_state&TS_CARR_ON)==0)
9607625Ssam 		return (0);
9617502Sroot loop:
9627502Sroot 	(void) spl5();
9637502Sroot 	if (tp->t_local&LPENDIN)
9647502Sroot 		ttypend(tp);
9657502Sroot 	(void) spl0();
9667502Sroot 	while (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) {
9677502Sroot 		if (u.u_signal[SIGTTIN] == SIG_IGN ||
9687502Sroot 		    u.u_signal[SIGTTIN] == SIG_HOLD ||
9697502Sroot /*
9707502Sroot 		    (u.u_procp->p_flag&SDETACH) ||
9717502Sroot */
9727502Sroot 		    u.u_procp->p_flag&SVFORK)
9737502Sroot 			return (0);
9747502Sroot 		gsignal(u.u_procp->p_pgrp, SIGTTIN);
9757502Sroot 		sleep((caddr_t)&lbolt, TTIPRI);
9767502Sroot 	}
9777502Sroot 	if (tp->t_flags&RAW) {
9787502Sroot 		(void) spl5();
9797502Sroot 		if (tp->t_rawq.c_cc <= 0) {
9807502Sroot 			if ((tp->t_state&TS_CARR_ON)==0 ||
9817502Sroot 			    (tp->t_state&TS_NBIO)) {
9827502Sroot 				(void) spl0();
9837502Sroot 				return (0);
9847502Sroot 			}
9857502Sroot 			sleep((caddr_t)&tp->t_rawq, TTIPRI);
9867502Sroot 			(void) spl0();
9877502Sroot 			goto loop;
9887502Sroot 		}
9897502Sroot 		(void) spl0();
990*7722Swnj 		while (tp->t_rawq.c_cc && uio->uio_iovcnt) {
991*7722Swnj 			u.u_error = passuc(getc(&tp->t_rawq), uio);
992*7722Swnj 			if (u.u_error)
993*7722Swnj 				break;
994*7722Swnj 		}
9957502Sroot 		return (0);
9967502Sroot 	} else {
9977502Sroot 		qp = tp->t_flags & CBREAK ? &tp->t_rawq : &tp->t_canq;
9987502Sroot 		(void) spl5();
9997502Sroot 		if (qp->c_cc <= 0) {
10007502Sroot 			if ((tp->t_state&TS_CARR_ON)==0 ||
10017502Sroot 			    (tp->t_state&TS_NBIO)) {
10027502Sroot 				(void) spl0();
10037502Sroot 				return (0);
10047502Sroot 			}
10057502Sroot 			sleep((caddr_t)&tp->t_rawq, TTIPRI);
10067502Sroot 			(void) spl0();
10077502Sroot 			goto loop;
10087502Sroot 		}
10097502Sroot 		(void) spl0();
10107502Sroot 		first = 1;
10117502Sroot 		while ((c = getc(qp)) >= 0) {
10127502Sroot 			if (tp->t_flags&CRMOD && c == '\r')
10137502Sroot 				c = '\n';
10147502Sroot 			if (tp->t_flags&LCASE && c <= 0177)
10157502Sroot 				if (tp->t_lstate&LSBKSL) {
10167502Sroot 					if (maptab[c])
10177502Sroot 						c = maptab[c];
10187502Sroot 					tp->t_lstate &= ~LSBKSL;
10197502Sroot 				} else if (c >= 'A' && c <= 'Z')
10207502Sroot 					c += 'a' - 'A';
10217502Sroot 				else if (c == '\\') {
10227502Sroot 					tp->t_lstate |= LSBKSL;
10237502Sroot 					continue;
10247502Sroot 				}
10257658Ssam 			if (tp->t_line == NTTYDISC && c == tlun.t_dsuspc) {
10267502Sroot 				ttsignal(tp, SIGTSTP);
10277502Sroot 				if (first) {
10287502Sroot 					sleep((caddr_t)&lbolt, TTIPRI);
10297502Sroot 					goto loop;
10307502Sroot 				}
10317502Sroot 				break;
10327502Sroot 			}
10337502Sroot 			if (c == tun.t_eofc && (tp->t_flags&CBREAK)==0)
10347502Sroot 				break;
1035*7722Swnj 			u.u_error = passuc(c & 0177, uio);
1036*7722Swnj 			if (u.u_error)
10377502Sroot 				break;
1038*7722Swnj 			if (uio->uio_iovcnt == 0)
1039*7722Swnj 				break;
10407502Sroot 			if ((tp->t_flags&CBREAK)==0 && ttbreakc(c, tp))
10417502Sroot 				break;
10427502Sroot 			first = 0;
10437502Sroot 		}
10447502Sroot 		tp->t_lstate &= ~LSBKSL;
10457502Sroot 	}
10467502Sroot 
10477502Sroot 	if (tp->t_state&TS_TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) {
10487502Sroot 		if (putc(tun.t_startc, &tp->t_outq)==0) {
10497502Sroot 			tp->t_state &= ~TS_TBLOCK;
10507502Sroot 			ttstart(tp);
10517502Sroot 		}
10527502Sroot 		tp->t_char = 0;
10537502Sroot 	}
10547502Sroot 
10557502Sroot 	return (tp->t_rawq.c_cc + tp->t_canq.c_cc);
10567502Sroot }
10577502Sroot 
10587502Sroot /*
10597502Sroot  * Called from the device's write routine after it has
10607502Sroot  * calculated the tty-structure given as argument.
10617502Sroot  */
10627502Sroot caddr_t
10637502Sroot ttwrite(tp)
10647625Ssam 	register struct tty *tp;
10657502Sroot {
10667502Sroot #ifdef vax
10677502Sroot 	/*
10687502Sroot 	 * THE POSITIONING OF CP, CC, AND CE ARE CRITICAL
10697502Sroot 	 * AND MUST NOT BE CHANGED WITHOUT PATCHING
10707502Sroot 	 * THE 'ASM' INLINES BELOW.  WATCH OUT.
10717502Sroot 	 */
10727502Sroot #endif
10737502Sroot 	register char *cp;
10747502Sroot 	register int cc, ce;
10757502Sroot 	register i;
10767502Sroot 	char obuf[OBUFSIZ];
10777502Sroot 	register c;
10787502Sroot 	int hiwat = TTHIWAT(tp);
10797502Sroot 	int cnt = u.u_count;
10807502Sroot 
10817502Sroot 	if ((tp->t_state&TS_CARR_ON)==0)
10827502Sroot 		return (NULL);
10837502Sroot loop:
10847502Sroot 	while (u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp &&
10857502Sroot 	    (tp->t_local&LTOSTOP) && (u.u_procp->p_flag&SVFORK)==0 &&
10867502Sroot 	    u.u_signal[SIGTTOU] != SIG_IGN &&
10877502Sroot 	    u.u_signal[SIGTTOU] != SIG_HOLD
10887502Sroot /*
10897502Sroot 					     &&
10907502Sroot 	    (u.u_procp->p_flag&SDETACH)==0) {
10917502Sroot */
10927502Sroot 	    ) {
10937502Sroot 		gsignal(u.u_procp->p_pgrp, SIGTTOU);
10947502Sroot 		sleep((caddr_t)&lbolt, TTIPRI);
10957502Sroot 	}
10967502Sroot 	while (u.u_count) {
10977502Sroot 		cc = MIN(u.u_count, OBUFSIZ);
10987502Sroot 		cp = obuf;
10997502Sroot 		iomove(cp, (unsigned)cc, B_WRITE);
11007502Sroot 		if (u.u_error)
11017502Sroot 			break;
11027502Sroot 		if (tp->t_outq.c_cc > hiwat)
11037502Sroot 			goto ovhiwat;
11047502Sroot 		if (tp->t_local&LFLUSHO)
11057502Sroot 			continue;
11067502Sroot 		if (tp->t_flags&LCASE || tp->t_local&LTILDE) {
11077502Sroot 			while (cc) {
11087502Sroot 				c = *cp++;
11097502Sroot 				tp->t_rocount = 0;
11107625Ssam 				while ((c = ttyoutput(c, tp)) >= 0) {
11117502Sroot 					/* out of clists, wait a bit */
11127502Sroot 					ttstart(tp);
11137502Sroot 					sleep((caddr_t)&lbolt, TTOPRI);
11147502Sroot 					tp->t_rocount = 0;
11157502Sroot 				}
11167502Sroot 				--cc;
11177502Sroot 				if (tp->t_outq.c_cc > hiwat)
11187502Sroot 					goto ovhiwat;
11197502Sroot 			}
11207502Sroot 			continue;
11217502Sroot 		}
11227502Sroot 		while (cc) {
11237502Sroot 			if (tp->t_flags&RAW || tp->t_local&LLITOUT)
11247502Sroot 				ce = cc;
11257502Sroot 			else {
11267502Sroot #ifdef vax
11277502Sroot 				asm("	scanc	r9,(r10),_partab,$077");
11287502Sroot 				asm("	subl3	r0,r9,r8");
11297502Sroot #else
11307502Sroot 				ce=0;
11317625Ssam 				while (((partab[*(unsigned char *)(cp+ce)]&077)==0)&&(ce<cc))
11327502Sroot 					ce++;
11337502Sroot #endif
11347502Sroot 				if (ce==0) {
11357502Sroot 					tp->t_rocount = 0;
11367502Sroot 					if (ttyoutput(*cp, tp) >= 0) {
11377502Sroot 						ttstart(tp);
11387502Sroot 						sleep((caddr_t)&lbolt, TTOPRI);
11397502Sroot 						continue;
11407502Sroot 					}
11417502Sroot 					cp++;
11427502Sroot 					cc--;
11437502Sroot 					if (tp->t_outq.c_cc > hiwat)
11447502Sroot 						goto ovhiwat;
11457502Sroot 				}
11467502Sroot 			}
11477502Sroot 			tp->t_rocount = 0;
11487502Sroot 			i=b_to_q(cp,ce,&tp->t_outq);
11497502Sroot 			ce-=i;
11507502Sroot 			tk_nout+=ce;
11517502Sroot 			tp->t_col+=ce;
11527502Sroot 			cp+=ce;
11537502Sroot 			cc-=ce;
11547502Sroot 			if (i) {
11557502Sroot 				ttstart(tp);
11567502Sroot 				sleep((caddr_t)&lbolt, TTOPRI);
11577502Sroot 			}
11587502Sroot 			if (ce || tp->t_outq.c_cc > hiwat)
11597502Sroot 				goto ovhiwat;
11607502Sroot 		}
11617502Sroot 	}
11627502Sroot 	ttstart(tp);
11637625Ssam 	return (NULL);
11647502Sroot 
11657502Sroot ovhiwat:
11667502Sroot 	(void) spl5();
11677502Sroot 	u.u_base -= cc;
11687502Sroot 	u.u_offset -= cc;
11697502Sroot 	u.u_count += cc;
11707502Sroot 	if (tp->t_outq.c_cc <= hiwat) {
11717502Sroot 		(void) spl0();
11727502Sroot 		goto loop;
11737502Sroot 	}
11747502Sroot 	ttstart(tp);
11757502Sroot 	if (tp->t_state & TS_NBIO) {
11767502Sroot 		if (u.u_count == cnt)
11777502Sroot 			u.u_error = EWOULDBLOCK;
11787502Sroot 		return (NULL);
11797502Sroot 	}
11807502Sroot 	tp->t_state |= TS_ASLEEP;
11817502Sroot 	sleep((caddr_t)&tp->t_outq, TTOPRI);
11827502Sroot 	(void) spl0();
11837502Sroot 	goto loop;
11847502Sroot }
11857502Sroot 
11867502Sroot /*
11877502Sroot  * Rubout one character from the rawq of tp
11887502Sroot  * as cleanly as possible.
11897502Sroot  */
11907502Sroot ttyrub(c, tp)
11917625Ssam 	register c;
11927625Ssam 	register struct tty *tp;
11937502Sroot {
11947502Sroot 	register char *cp;
11957502Sroot 	register int savecol;
11967502Sroot 	int s;
11977502Sroot 	char *nextc();
11987502Sroot 
11997502Sroot 	if ((tp->t_flags&ECHO)==0)
12007502Sroot 		return;
12017502Sroot 	tp->t_local &= ~LFLUSHO;
12027502Sroot 	c &= 0377;
12037502Sroot 	if (tp->t_local&LCRTBS) {
12047502Sroot 		if (tp->t_rocount == 0) {
12057502Sroot 			/*
12067502Sroot 			 * Screwed by ttwrite; retype
12077502Sroot 			 */
12087502Sroot 			ttyretype(tp);
12097502Sroot 			return;
12107502Sroot 		}
12117502Sroot 		if (c==('\t'|0200) || c==('\n'|0200))
12127502Sroot 			ttyrubo(tp, 2);
12137625Ssam 		else switch (partab[c&=0177] & 0177) {
12147502Sroot 
12157502Sroot 		case ORDINARY:
12167502Sroot 			if (tp->t_flags&LCASE && c >= 'A' && c <= 'Z')
12177502Sroot 				ttyrubo(tp, 2);
12187502Sroot 			else
12197502Sroot 				ttyrubo(tp, 1);
12207502Sroot 			break;
12217502Sroot 
12227502Sroot 		case VTAB:
12237502Sroot 		case BACKSPACE:
12247502Sroot 		case CONTROL:
12257502Sroot 		case RETURN:
12267502Sroot 			if (tp->t_local & LCTLECH)
12277502Sroot 				ttyrubo(tp, 2);
12287502Sroot 			break;
12297502Sroot 
12307502Sroot 		case TAB:
12317502Sroot 			if (tp->t_rocount < tp->t_rawq.c_cc) {
12327502Sroot 				ttyretype(tp);
12337502Sroot 				return;
12347502Sroot 			}
12357502Sroot 			s = spl5();
12367502Sroot 			savecol = tp->t_col;
12377502Sroot 			tp->t_lstate |= LSCNTTB;
12387502Sroot 			tp->t_local |= LFLUSHO;
12397502Sroot 			tp->t_col = tp->t_rocol;
12407502Sroot 			for (cp = tp->t_rawq.c_cf; cp; cp = nextc(&tp->t_rawq, cp))
12417502Sroot 				ttyecho(*cp, tp);
12427502Sroot 			tp->t_local &= ~LFLUSHO;
12437502Sroot 			tp->t_lstate &= ~LSCNTTB;
12447502Sroot 			splx(s);
12457502Sroot 			/*
12467502Sroot 			 * savecol will now be length of the tab
12477502Sroot 			 */
12487502Sroot 			savecol -= tp->t_col;
12497502Sroot 			tp->t_col += savecol;
12507502Sroot 			if (savecol > 8)
12517502Sroot 				savecol = 8;		/* overflow screw */
12527502Sroot 			while (--savecol >= 0)
12537502Sroot 				(void) ttyoutput('\b', tp);
12547502Sroot 			break;
12557502Sroot 
12567502Sroot 		default:
12577502Sroot 			panic("ttyrub");
12587502Sroot 		}
12597502Sroot 	} else if (tp->t_local&LPRTERA) {
12607502Sroot 		if ((tp->t_lstate&LSERASE) == 0) {
12617502Sroot 			(void) ttyoutput('\\', tp);
12627502Sroot 			tp->t_lstate |= LSERASE;
12637502Sroot 		}
12647502Sroot 		ttyecho(c, tp);
12657502Sroot 	} else
12667502Sroot 		ttyecho(tp->t_erase, tp);
12677502Sroot 	tp->t_rocount--;
12687502Sroot }
12697502Sroot 
12707502Sroot /*
12717502Sroot  * Crt back over cnt chars perhaps
12727502Sroot  * erasing them.
12737502Sroot  */
12747502Sroot ttyrubo(tp, cnt)
12757625Ssam 	register struct tty *tp;
12767625Ssam 	int cnt;
12777502Sroot {
12787502Sroot 
12797502Sroot 	while (--cnt >= 0)
12807502Sroot 		ttyout(tp->t_local&LCRTERA ? "\b \b" : "\b", tp);
12817502Sroot }
12827502Sroot 
12837502Sroot /*
12847502Sroot  * Reprint the rawq line.
12857502Sroot  * We assume c_cc has already been checked.
12867502Sroot  */
12877502Sroot ttyretype(tp)
12887625Ssam 	register struct tty *tp;
12897502Sroot {
12907502Sroot 	register char *cp;
12917502Sroot 	char *nextc();
12927502Sroot 	int s;
12937502Sroot 
12947502Sroot 	if (tlun.t_rprntc != 0377)
12957502Sroot 		ttyecho(tlun.t_rprntc, tp);
12967502Sroot 	(void) ttyoutput('\n', tp);
12977502Sroot 	s = spl5();
12987502Sroot 	for (cp = tp->t_canq.c_cf; cp; cp = nextc(&tp->t_canq, cp))
12997502Sroot 		ttyecho(*cp, tp);
13007502Sroot 	for (cp = tp->t_rawq.c_cf; cp; cp = nextc(&tp->t_rawq, cp))
13017502Sroot 		ttyecho(*cp, tp);
13027502Sroot 	tp->t_lstate &= ~LSERASE;
13037502Sroot 	splx(s);
13047502Sroot 	tp->t_rocount = tp->t_rawq.c_cc;
13057502Sroot 	tp->t_rocol = 0;
13067502Sroot }
13077502Sroot 
13087502Sroot /*
13097502Sroot  * Echo a typed character to the terminal
13107502Sroot  */
13117502Sroot ttyecho(c, tp)
13127625Ssam 	register c;
13137625Ssam 	register struct tty *tp;
13147502Sroot {
13157502Sroot 
13167502Sroot 	if ((tp->t_lstate & LSCNTTB) == 0)
13177502Sroot 		tp->t_local &= ~LFLUSHO;
13187502Sroot 	if ((tp->t_flags&ECHO) == 0)
13197502Sroot 		return;
13207502Sroot 	c &= 0377;
13217502Sroot 	if (tp->t_flags&RAW) {
13227502Sroot 		(void) ttyoutput(c, tp);
13237502Sroot 		return;
13247502Sroot 	}
13257502Sroot 	if (c == '\r' && tp->t_flags&CRMOD)
13267502Sroot 		c = '\n';
13277502Sroot 	if (tp->t_local&LCTLECH) {
13287502Sroot 		if ((c&0177) <= 037 && c!='\t' && c!='\n' || (c&0177)==0177) {
13297502Sroot 			(void) ttyoutput('^', tp);
13307502Sroot 			c &= 0177;
13317502Sroot 			if (c == 0177)
13327502Sroot 				c = '?';
13337502Sroot 			else if (tp->t_flags&LCASE)
13347502Sroot 				c += 'a' - 1;
13357502Sroot 			else
13367502Sroot 				c += 'A' - 1;
13377502Sroot 		}
13387502Sroot 	}
13397502Sroot 	if ((tp->t_flags&LCASE) && (c >= 'A' && c <= 'Z'))
13407502Sroot 		c += 'a' - 'A';
13417502Sroot 	(void) ttyoutput(c & 0177, tp);
13427502Sroot }
13437502Sroot 
13447502Sroot /*
13457502Sroot  * Is c a break char for tp?
13467502Sroot  */
13477502Sroot ttbreakc(c, tp)
13487625Ssam 	register c;
13497625Ssam 	register struct tty *tp;
13507502Sroot {
13517502Sroot 	return (c == '\n' || c == tun.t_eofc || c == tun.t_brkc ||
13527502Sroot 		c == '\r' && (tp->t_flags&CRMOD));
13537502Sroot }
13547502Sroot 
13557502Sroot /*
13567502Sroot  * send string cp to tp
13577502Sroot  */
13587502Sroot ttyout(cp, tp)
13597625Ssam 	register char *cp;
13607625Ssam 	register struct tty *tp;
13617502Sroot {
13627502Sroot 	register char c;
13637502Sroot 
13647502Sroot 	while (c = *cp++)
13657502Sroot 		(void) ttyoutput(c, tp);
13667502Sroot }
13677502Sroot 
13687502Sroot ttwakeup(tp)
13697502Sroot 	struct tty *tp;
13707502Sroot {
13717502Sroot 
13727502Sroot 	if (tp->t_rsel) {
13737502Sroot 		selwakeup(tp->t_rsel, tp->t_state&TS_RCOLL);
13747502Sroot 		tp->t_state &= ~TS_RCOLL;
13757502Sroot 		tp->t_rsel = 0;
13767502Sroot 	}
13777502Sroot 	wakeup((caddr_t)&tp->t_rawq);
13787502Sroot }
13797502Sroot 
13807502Sroot ttsignal(tp, signo)
13817502Sroot 	struct tty *tp;
13827502Sroot 	int signo;
13837502Sroot {
13847502Sroot 
13857502Sroot 	gsignal(tp->t_pgrp, signo);
13867502Sroot }
1387