xref: /csrg-svn/sys/kern/tty.c (revision 7822)
1*7822Sroot /*	tty.c	4.28	82/08/22	*/
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"
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  */
9527722Swnj ttread(tp, uio)
9537625Ssam 	register struct tty *tp;
9547722Swnj 	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();
9907722Swnj 		while (tp->t_rawq.c_cc && uio->uio_iovcnt) {
9917722Swnj 			u.u_error = passuc(getc(&tp->t_rawq), uio);
9927722Swnj 			if (u.u_error)
9937722Swnj 				break;
9947722Swnj 		}
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;
10357722Swnj 			u.u_error = passuc(c & 0177, uio);
10367722Swnj 			if (u.u_error)
10377502Sroot 				break;
10387722Swnj 			if (uio->uio_iovcnt == 0)
10397722Swnj 				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
1063*7822Sroot ttwrite(tp, uio)
10647625Ssam 	register struct tty *tp;
1065*7822Sroot 	struct uio *uio;
10667502Sroot {
10677502Sroot #ifdef vax
10687502Sroot 	/*
10697502Sroot 	 * THE POSITIONING OF CP, CC, AND CE ARE CRITICAL
10707502Sroot 	 * AND MUST NOT BE CHANGED WITHOUT PATCHING
10717502Sroot 	 * THE 'ASM' INLINES BELOW.  WATCH OUT.
10727502Sroot 	 */
10737502Sroot #endif
10747502Sroot 	register char *cp;
10757502Sroot 	register int cc, ce;
10767502Sroot 	register i;
10777502Sroot 	char obuf[OBUFSIZ];
10787502Sroot 	register c;
10797502Sroot 	int hiwat = TTHIWAT(tp);
1080*7822Sroot 	int cnt = uio->uio_resid;
10817502Sroot 
10827502Sroot 	if ((tp->t_state&TS_CARR_ON)==0)
10837502Sroot 		return (NULL);
10847502Sroot loop:
10857502Sroot 	while (u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp &&
10867502Sroot 	    (tp->t_local&LTOSTOP) && (u.u_procp->p_flag&SVFORK)==0 &&
10877502Sroot 	    u.u_signal[SIGTTOU] != SIG_IGN &&
10887502Sroot 	    u.u_signal[SIGTTOU] != SIG_HOLD
10897502Sroot /*
10907502Sroot 					     &&
10917502Sroot 	    (u.u_procp->p_flag&SDETACH)==0) {
10927502Sroot */
10937502Sroot 	    ) {
10947502Sroot 		gsignal(u.u_procp->p_pgrp, SIGTTOU);
10957502Sroot 		sleep((caddr_t)&lbolt, TTIPRI);
10967502Sroot 	}
1097*7822Sroot 	while (uio->uio_resid > 0) {
1098*7822Sroot 		cc = uio->uio_iov->iov_len;
1099*7822Sroot 		if (cc == 0) {
1100*7822Sroot 			uio->uio_iovcnt--;
1101*7822Sroot 			uio->uio_iov++;
1102*7822Sroot 			if (uio->uio_iovcnt < 0)
1103*7822Sroot 				panic("ttwrite");
1104*7822Sroot 			continue;
1105*7822Sroot 		}
1106*7822Sroot 		if (cc > OBUFSIZ)
1107*7822Sroot 			cc = OBUFSIZ;
11087502Sroot 		cp = obuf;
1109*7822Sroot 		u.u_error = uiomove(cp, cc, UIO_WRITE, uio);
11107502Sroot 		if (u.u_error)
11117502Sroot 			break;
11127502Sroot 		if (tp->t_outq.c_cc > hiwat)
11137502Sroot 			goto ovhiwat;
11147502Sroot 		if (tp->t_local&LFLUSHO)
11157502Sroot 			continue;
11167502Sroot 		if (tp->t_flags&LCASE || tp->t_local&LTILDE) {
11177502Sroot 			while (cc) {
11187502Sroot 				c = *cp++;
11197502Sroot 				tp->t_rocount = 0;
11207625Ssam 				while ((c = ttyoutput(c, tp)) >= 0) {
11217502Sroot 					/* out of clists, wait a bit */
11227502Sroot 					ttstart(tp);
11237502Sroot 					sleep((caddr_t)&lbolt, TTOPRI);
11247502Sroot 					tp->t_rocount = 0;
11257502Sroot 				}
11267502Sroot 				--cc;
11277502Sroot 				if (tp->t_outq.c_cc > hiwat)
11287502Sroot 					goto ovhiwat;
11297502Sroot 			}
11307502Sroot 			continue;
11317502Sroot 		}
11327502Sroot 		while (cc) {
11337502Sroot 			if (tp->t_flags&RAW || tp->t_local&LLITOUT)
11347502Sroot 				ce = cc;
11357502Sroot 			else {
11367502Sroot #ifdef vax
11377502Sroot 				asm("	scanc	r9,(r10),_partab,$077");
11387502Sroot 				asm("	subl3	r0,r9,r8");
11397502Sroot #else
11407502Sroot 				ce=0;
11417625Ssam 				while (((partab[*(unsigned char *)(cp+ce)]&077)==0)&&(ce<cc))
11427502Sroot 					ce++;
11437502Sroot #endif
11447502Sroot 				if (ce==0) {
11457502Sroot 					tp->t_rocount = 0;
11467502Sroot 					if (ttyoutput(*cp, tp) >= 0) {
11477502Sroot 						ttstart(tp);
11487502Sroot 						sleep((caddr_t)&lbolt, TTOPRI);
11497502Sroot 						continue;
11507502Sroot 					}
11517502Sroot 					cp++;
11527502Sroot 					cc--;
11537502Sroot 					if (tp->t_outq.c_cc > hiwat)
11547502Sroot 						goto ovhiwat;
11557502Sroot 				}
11567502Sroot 			}
11577502Sroot 			tp->t_rocount = 0;
11587502Sroot 			i=b_to_q(cp,ce,&tp->t_outq);
11597502Sroot 			ce-=i;
11607502Sroot 			tk_nout+=ce;
11617502Sroot 			tp->t_col+=ce;
11627502Sroot 			cp+=ce;
11637502Sroot 			cc-=ce;
11647502Sroot 			if (i) {
11657502Sroot 				ttstart(tp);
11667502Sroot 				sleep((caddr_t)&lbolt, TTOPRI);
11677502Sroot 			}
11687502Sroot 			if (ce || tp->t_outq.c_cc > hiwat)
11697502Sroot 				goto ovhiwat;
11707502Sroot 		}
11717502Sroot 	}
11727502Sroot 	ttstart(tp);
11737625Ssam 	return (NULL);
11747502Sroot 
11757502Sroot ovhiwat:
11767502Sroot 	(void) spl5();
1177*7822Sroot 	uio->uio_iov->iov_base -= cc;
1178*7822Sroot 	uio->uio_iov->iov_len += cc;
1179*7822Sroot 	uio->uio_resid += cc;
1180*7822Sroot 	uio->uio_offset -= cc;
11817502Sroot 	if (tp->t_outq.c_cc <= hiwat) {
11827502Sroot 		(void) spl0();
11837502Sroot 		goto loop;
11847502Sroot 	}
11857502Sroot 	ttstart(tp);
11867502Sroot 	if (tp->t_state & TS_NBIO) {
1187*7822Sroot 		if (uio->uio_resid == cnt)
11887502Sroot 			u.u_error = EWOULDBLOCK;
11897502Sroot 		return (NULL);
11907502Sroot 	}
11917502Sroot 	tp->t_state |= TS_ASLEEP;
11927502Sroot 	sleep((caddr_t)&tp->t_outq, TTOPRI);
11937502Sroot 	(void) spl0();
11947502Sroot 	goto loop;
11957502Sroot }
11967502Sroot 
11977502Sroot /*
11987502Sroot  * Rubout one character from the rawq of tp
11997502Sroot  * as cleanly as possible.
12007502Sroot  */
12017502Sroot ttyrub(c, tp)
12027625Ssam 	register c;
12037625Ssam 	register struct tty *tp;
12047502Sroot {
12057502Sroot 	register char *cp;
12067502Sroot 	register int savecol;
12077502Sroot 	int s;
12087502Sroot 	char *nextc();
12097502Sroot 
12107502Sroot 	if ((tp->t_flags&ECHO)==0)
12117502Sroot 		return;
12127502Sroot 	tp->t_local &= ~LFLUSHO;
12137502Sroot 	c &= 0377;
12147502Sroot 	if (tp->t_local&LCRTBS) {
12157502Sroot 		if (tp->t_rocount == 0) {
12167502Sroot 			/*
12177502Sroot 			 * Screwed by ttwrite; retype
12187502Sroot 			 */
12197502Sroot 			ttyretype(tp);
12207502Sroot 			return;
12217502Sroot 		}
12227502Sroot 		if (c==('\t'|0200) || c==('\n'|0200))
12237502Sroot 			ttyrubo(tp, 2);
12247625Ssam 		else switch (partab[c&=0177] & 0177) {
12257502Sroot 
12267502Sroot 		case ORDINARY:
12277502Sroot 			if (tp->t_flags&LCASE && c >= 'A' && c <= 'Z')
12287502Sroot 				ttyrubo(tp, 2);
12297502Sroot 			else
12307502Sroot 				ttyrubo(tp, 1);
12317502Sroot 			break;
12327502Sroot 
12337502Sroot 		case VTAB:
12347502Sroot 		case BACKSPACE:
12357502Sroot 		case CONTROL:
12367502Sroot 		case RETURN:
12377502Sroot 			if (tp->t_local & LCTLECH)
12387502Sroot 				ttyrubo(tp, 2);
12397502Sroot 			break;
12407502Sroot 
12417502Sroot 		case TAB:
12427502Sroot 			if (tp->t_rocount < tp->t_rawq.c_cc) {
12437502Sroot 				ttyretype(tp);
12447502Sroot 				return;
12457502Sroot 			}
12467502Sroot 			s = spl5();
12477502Sroot 			savecol = tp->t_col;
12487502Sroot 			tp->t_lstate |= LSCNTTB;
12497502Sroot 			tp->t_local |= LFLUSHO;
12507502Sroot 			tp->t_col = tp->t_rocol;
12517502Sroot 			for (cp = tp->t_rawq.c_cf; cp; cp = nextc(&tp->t_rawq, cp))
12527502Sroot 				ttyecho(*cp, tp);
12537502Sroot 			tp->t_local &= ~LFLUSHO;
12547502Sroot 			tp->t_lstate &= ~LSCNTTB;
12557502Sroot 			splx(s);
12567502Sroot 			/*
12577502Sroot 			 * savecol will now be length of the tab
12587502Sroot 			 */
12597502Sroot 			savecol -= tp->t_col;
12607502Sroot 			tp->t_col += savecol;
12617502Sroot 			if (savecol > 8)
12627502Sroot 				savecol = 8;		/* overflow screw */
12637502Sroot 			while (--savecol >= 0)
12647502Sroot 				(void) ttyoutput('\b', tp);
12657502Sroot 			break;
12667502Sroot 
12677502Sroot 		default:
12687502Sroot 			panic("ttyrub");
12697502Sroot 		}
12707502Sroot 	} else if (tp->t_local&LPRTERA) {
12717502Sroot 		if ((tp->t_lstate&LSERASE) == 0) {
12727502Sroot 			(void) ttyoutput('\\', tp);
12737502Sroot 			tp->t_lstate |= LSERASE;
12747502Sroot 		}
12757502Sroot 		ttyecho(c, tp);
12767502Sroot 	} else
12777502Sroot 		ttyecho(tp->t_erase, tp);
12787502Sroot 	tp->t_rocount--;
12797502Sroot }
12807502Sroot 
12817502Sroot /*
12827502Sroot  * Crt back over cnt chars perhaps
12837502Sroot  * erasing them.
12847502Sroot  */
12857502Sroot ttyrubo(tp, cnt)
12867625Ssam 	register struct tty *tp;
12877625Ssam 	int cnt;
12887502Sroot {
12897502Sroot 
12907502Sroot 	while (--cnt >= 0)
12917502Sroot 		ttyout(tp->t_local&LCRTERA ? "\b \b" : "\b", tp);
12927502Sroot }
12937502Sroot 
12947502Sroot /*
12957502Sroot  * Reprint the rawq line.
12967502Sroot  * We assume c_cc has already been checked.
12977502Sroot  */
12987502Sroot ttyretype(tp)
12997625Ssam 	register struct tty *tp;
13007502Sroot {
13017502Sroot 	register char *cp;
13027502Sroot 	char *nextc();
13037502Sroot 	int s;
13047502Sroot 
13057502Sroot 	if (tlun.t_rprntc != 0377)
13067502Sroot 		ttyecho(tlun.t_rprntc, tp);
13077502Sroot 	(void) ttyoutput('\n', tp);
13087502Sroot 	s = spl5();
13097502Sroot 	for (cp = tp->t_canq.c_cf; cp; cp = nextc(&tp->t_canq, cp))
13107502Sroot 		ttyecho(*cp, tp);
13117502Sroot 	for (cp = tp->t_rawq.c_cf; cp; cp = nextc(&tp->t_rawq, cp))
13127502Sroot 		ttyecho(*cp, tp);
13137502Sroot 	tp->t_lstate &= ~LSERASE;
13147502Sroot 	splx(s);
13157502Sroot 	tp->t_rocount = tp->t_rawq.c_cc;
13167502Sroot 	tp->t_rocol = 0;
13177502Sroot }
13187502Sroot 
13197502Sroot /*
13207502Sroot  * Echo a typed character to the terminal
13217502Sroot  */
13227502Sroot ttyecho(c, tp)
13237625Ssam 	register c;
13247625Ssam 	register struct tty *tp;
13257502Sroot {
13267502Sroot 
13277502Sroot 	if ((tp->t_lstate & LSCNTTB) == 0)
13287502Sroot 		tp->t_local &= ~LFLUSHO;
13297502Sroot 	if ((tp->t_flags&ECHO) == 0)
13307502Sroot 		return;
13317502Sroot 	c &= 0377;
13327502Sroot 	if (tp->t_flags&RAW) {
13337502Sroot 		(void) ttyoutput(c, tp);
13347502Sroot 		return;
13357502Sroot 	}
13367502Sroot 	if (c == '\r' && tp->t_flags&CRMOD)
13377502Sroot 		c = '\n';
13387502Sroot 	if (tp->t_local&LCTLECH) {
13397502Sroot 		if ((c&0177) <= 037 && c!='\t' && c!='\n' || (c&0177)==0177) {
13407502Sroot 			(void) ttyoutput('^', tp);
13417502Sroot 			c &= 0177;
13427502Sroot 			if (c == 0177)
13437502Sroot 				c = '?';
13447502Sroot 			else if (tp->t_flags&LCASE)
13457502Sroot 				c += 'a' - 1;
13467502Sroot 			else
13477502Sroot 				c += 'A' - 1;
13487502Sroot 		}
13497502Sroot 	}
13507502Sroot 	if ((tp->t_flags&LCASE) && (c >= 'A' && c <= 'Z'))
13517502Sroot 		c += 'a' - 'A';
13527502Sroot 	(void) ttyoutput(c & 0177, tp);
13537502Sroot }
13547502Sroot 
13557502Sroot /*
13567502Sroot  * Is c a break char for tp?
13577502Sroot  */
13587502Sroot ttbreakc(c, tp)
13597625Ssam 	register c;
13607625Ssam 	register struct tty *tp;
13617502Sroot {
13627502Sroot 	return (c == '\n' || c == tun.t_eofc || c == tun.t_brkc ||
13637502Sroot 		c == '\r' && (tp->t_flags&CRMOD));
13647502Sroot }
13657502Sroot 
13667502Sroot /*
13677502Sroot  * send string cp to tp
13687502Sroot  */
13697502Sroot ttyout(cp, tp)
13707625Ssam 	register char *cp;
13717625Ssam 	register struct tty *tp;
13727502Sroot {
13737502Sroot 	register char c;
13747502Sroot 
13757502Sroot 	while (c = *cp++)
13767502Sroot 		(void) ttyoutput(c, tp);
13777502Sroot }
13787502Sroot 
13797502Sroot ttwakeup(tp)
13807502Sroot 	struct tty *tp;
13817502Sroot {
13827502Sroot 
13837502Sroot 	if (tp->t_rsel) {
13847502Sroot 		selwakeup(tp->t_rsel, tp->t_state&TS_RCOLL);
13857502Sroot 		tp->t_state &= ~TS_RCOLL;
13867502Sroot 		tp->t_rsel = 0;
13877502Sroot 	}
13887502Sroot 	wakeup((caddr_t)&tp->t_rawq);
13897502Sroot }
13907502Sroot 
13917502Sroot ttsignal(tp, signo)
13927502Sroot 	struct tty *tp;
13937502Sroot 	int signo;
13947502Sroot {
13957502Sroot 
13967502Sroot 	gsignal(tp->t_pgrp, signo);
13977502Sroot }
1398