xref: /csrg-svn/sys/kern/tty.c (revision 7625)
1*7625Ssam /*	tty.c	4.25	82/08/01	*/
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"
1839Sbill 
197436Skre /*
207436Skre  * Table giving parity for characters and indicating
217436Skre  * character classes to tty driver.  In particular,
227436Skre  * if the low 6 bits are 0, then the character needs
237436Skre  * no special processing on output.
247436Skre  */
2539Sbill 
267436Skre char partab[] = {
277436Skre 	0001,0201,0201,0001,0201,0001,0001,0201,
287436Skre 	0202,0004,0003,0201,0005,0206,0201,0001,
297436Skre 	0201,0001,0001,0201,0001,0201,0201,0001,
307436Skre 	0001,0201,0201,0001,0201,0001,0001,0201,
317436Skre 	0200,0000,0000,0200,0000,0200,0200,0000,
327436Skre 	0000,0200,0200,0000,0200,0000,0000,0200,
337436Skre 	0000,0200,0200,0000,0200,0000,0000,0200,
347436Skre 	0200,0000,0000,0200,0000,0200,0200,0000,
357436Skre 	0200,0000,0000,0200,0000,0200,0200,0000,
367436Skre 	0000,0200,0200,0000,0200,0000,0000,0200,
377436Skre 	0000,0200,0200,0000,0200,0000,0000,0200,
387436Skre 	0200,0000,0000,0200,0000,0200,0200,0000,
397436Skre 	0000,0200,0200,0000,0200,0000,0000,0200,
407436Skre 	0200,0000,0000,0200,0000,0200,0200,0000,
417436Skre 	0200,0000,0000,0200,0000,0200,0200,0000,
427436Skre 	0000,0200,0200,0000,0200,0000,0000,0201,
437436Skre 
447436Skre 	/*
457436Skre 	 * 7 bit ascii ends with the last character above,
467436Skre 	 * but we contine through all 256 codes for the sake
477436Skre 	 * of the tty output routines which use special vax
487436Skre 	 * instructions which need a 256 character trt table.
497436Skre 	 */
507436Skre 
517436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
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 };
687436Skre 
69146Sbill /*
7039Sbill  * Input mapping table-- if an entry is non-zero, when the
7139Sbill  * corresponding character is typed preceded by "\" the escape
7239Sbill  * sequence is replaced by the table value.  Mostly used for
7339Sbill  * upper-case only terminals.
7439Sbill  */
7539Sbill 
7639Sbill char	maptab[] ={
7739Sbill 	000,000,000,000,000,000,000,000,
7839Sbill 	000,000,000,000,000,000,000,000,
7939Sbill 	000,000,000,000,000,000,000,000,
8039Sbill 	000,000,000,000,000,000,000,000,
8139Sbill 	000,'|',000,000,000,000,000,'`',
8239Sbill 	'{','}',000,000,000,000,000,000,
8339Sbill 	000,000,000,000,000,000,000,000,
8439Sbill 	000,000,000,000,000,000,000,000,
8539Sbill 	000,000,000,000,000,000,000,000,
8639Sbill 	000,000,000,000,000,000,000,000,
8739Sbill 	000,000,000,000,000,000,000,000,
8839Sbill 	000,000,000,000,000,000,'~',000,
8939Sbill 	000,'A','B','C','D','E','F','G',
9039Sbill 	'H','I','J','K','L','M','N','O',
9139Sbill 	'P','Q','R','S','T','U','V','W',
9239Sbill 	'X','Y','Z',000,000,000,000,000,
9339Sbill };
9439Sbill 
95925Sbill short	tthiwat[16] =
96925Sbill    { 100,100,100,100,100,100,100,200,200,400,400,400,650,650,650,650 };
97925Sbill short	ttlowat[16] =
98925Sbill    {  30, 30, 30, 30, 30, 30, 30, 50, 50,120,120,120,125,125,125,125 };
99925Sbill 
10039Sbill #define	OBUFSIZ	100
10139Sbill 
10239Sbill /*
10339Sbill  * set default control characters.
10439Sbill  */
10539Sbill ttychars(tp)
106*7625Ssam 	register struct tty *tp;
10739Sbill {
108174Sbill 
10939Sbill 	tun.t_intrc = CINTR;
11039Sbill 	tun.t_quitc = CQUIT;
11139Sbill 	tun.t_startc = CSTART;
11239Sbill 	tun.t_stopc = CSTOP;
11339Sbill 	tun.t_eofc = CEOT;
11439Sbill 	tun.t_brkc = CBRK;
11539Sbill 	tp->t_erase = CERASE;
11639Sbill 	tp->t_kill = CKILL;
117174Sbill /* begin local */
118208Sbill 	tlun.t_suspc = CTRL(z);
119208Sbill 	tlun.t_dsuspc = CTRL(y);
120174Sbill 	tlun.t_rprntc = CTRL(r);
121174Sbill 	tlun.t_flushc = CTRL(o);
122174Sbill 	tlun.t_werasc = CTRL(w);
123174Sbill 	tlun.t_lnextc = CTRL(v);
124174Sbill 	tp->t_local = 0;
125174Sbill 	tp->t_lstate = 0;
126174Sbill /* end local */
12739Sbill }
12839Sbill 
12939Sbill /*
130903Sbill  * Wait for output to drain, then flush input waiting.
13139Sbill  */
132903Sbill wflushtty(tp)
1335408Swnj 	register struct tty *tp;
13439Sbill {
13539Sbill 
136903Sbill 	(void) spl5();
1375622Swnj 	while (tp->t_outq.c_cc && tp->t_state&TS_CARR_ON
1385622Swnj 	    && tp->t_oproc) {		/* kludge for pty */
139903Sbill 		(*tp->t_oproc)(tp);
1405408Swnj 		tp->t_state |= TS_ASLEEP;
141903Sbill 		sleep((caddr_t)&tp->t_outq, TTOPRI);
142903Sbill 	}
1435426Swnj 	flushtty(tp, FREAD);
144903Sbill 	(void) spl0();
14539Sbill }
14639Sbill 
14739Sbill /*
148903Sbill  * flush all TTY queues
14939Sbill  */
150903Sbill flushtty(tp, rw)
151*7625Ssam 	register struct tty *tp;
15239Sbill {
153903Sbill 	register s;
154903Sbill 
155903Sbill 	s = spl6();
156903Sbill 	if (rw & FREAD) {
157903Sbill 		while (getc(&tp->t_canq) >= 0)
158903Sbill 			;
159903Sbill 		wakeup((caddr_t)&tp->t_rawq);
160903Sbill 	}
161903Sbill 	if (rw & FWRITE) {
162903Sbill 		wakeup((caddr_t)&tp->t_outq);
1635408Swnj 		tp->t_state &= ~TS_TTSTOP;
1645426Swnj 		(*cdevsw[major(tp->t_dev)].d_stop)(tp, rw);
165903Sbill 		while (getc(&tp->t_outq) >= 0)
166903Sbill 			;
167903Sbill 	}
168903Sbill 	if (rw & FREAD) {
169903Sbill 		while (getc(&tp->t_rawq) >= 0)
170903Sbill 			;
171903Sbill 		tp->t_delct = 0;
172903Sbill 		tp->t_rocount = 0;		/* local */
173903Sbill 		tp->t_rocol = 0;
174903Sbill 		tp->t_lstate = 0;
175903Sbill 	}
176903Sbill 	splx(s);
17739Sbill }
17839Sbill 
179903Sbill /*
180903Sbill  * Send stop character on input overflow.
181903Sbill  */
182903Sbill ttyblock(tp)
183*7625Ssam 	register struct tty *tp;
18439Sbill {
185903Sbill 	register x;
186903Sbill 	x = tp->t_rawq.c_cc + tp->t_canq.c_cc;
187903Sbill 	if (tp->t_rawq.c_cc > TTYHOG) {
188903Sbill 		flushtty(tp, FREAD|FWRITE);
1895408Swnj 		tp->t_state &= ~TS_TBLOCK;
190903Sbill 	}
191903Sbill 	if (x >= TTYHOG/2) {
192903Sbill 		if (putc(tun.t_stopc, &tp->t_outq)==0) {
1935408Swnj 			tp->t_state |= TS_TBLOCK;
194903Sbill 			tp->t_char++;
195903Sbill 			ttstart(tp);
196903Sbill 		}
197903Sbill 	}
19839Sbill }
19939Sbill 
20039Sbill /*
201903Sbill  * Restart typewriter output following a delay
202903Sbill  * timeout.
203903Sbill  * The name of the routine is passed to the timeout
204903Sbill  * subroutine and it is called during a clock interrupt.
205121Sbill  */
206903Sbill ttrstrt(tp)
207*7625Ssam 	register struct tty *tp;
208121Sbill {
209121Sbill 
2103351Swnj 	if (tp == 0) {
2113351Swnj 		printf("ttrstrt: arg was 0!\n");
2123351Swnj 		return;
2133351Swnj 	}
2145408Swnj 	tp->t_state &= ~TS_TIMEOUT;
215903Sbill 	ttstart(tp);
216121Sbill }
217121Sbill 
218121Sbill /*
219903Sbill  * Start output on the typewriter. It is used from the top half
220903Sbill  * after some characters have been put on the output queue,
221903Sbill  * from the interrupt routine to transmit the next
222903Sbill  * character, and after a timeout has finished.
22339Sbill  */
224903Sbill ttstart(tp)
225*7625Ssam 	register struct tty *tp;
22639Sbill {
227903Sbill 	register s;
22839Sbill 
229903Sbill 	s = spl5();
230*7625Ssam 	if ((tp->t_state&(TS_TIMEOUT|TS_TTSTOP|TS_BUSY)) == 0 &&
2315622Swnj 	    tp->t_oproc)		/* kludge for pty */
232903Sbill 		(*tp->t_oproc)(tp);
233903Sbill 	splx(s);
23439Sbill }
23539Sbill 
23639Sbill /*
237903Sbill  * Common code for tty ioctls.
23839Sbill  */
2391780Sbill /*ARGSUSED*/
240*7625Ssam ttioctl(tp, com, data, flag)
241*7625Ssam 	register struct tty *tp;
242*7625Ssam 	caddr_t data;
24339Sbill {
2441904Swnj 	int dev;
24539Sbill 	extern int nldisp;
24639Sbill 
247903Sbill 	/*
248915Sbill 	 * This is especially so that isatty() will
249915Sbill 	 * fail when carrier is gone.
250915Sbill 	 */
2515408Swnj 	if ((tp->t_state&TS_CARR_ON) == 0) {
252915Sbill 		u.u_error = EBADF;
253915Sbill 		return (1);
254915Sbill 	}
255915Sbill 
2561904Swnj 	dev = tp->t_dev;
257915Sbill 	/*
258903Sbill 	 * If the ioctl involves modification,
259903Sbill 	 * insist on being able to write the device,
260903Sbill 	 * and hang if in the background.
261903Sbill 	 */
262*7625Ssam 	switch (com) {
26339Sbill 
264915Sbill 	case TIOCSETD:
265915Sbill 	case TIOCSETP:
266915Sbill 	case TIOCSETN:
267903Sbill 	case TIOCFLUSH:
268903Sbill 	case TIOCSETC:
269903Sbill 	case TIOCSLTC:
270903Sbill 	case TIOCSPGRP:
271903Sbill 	case TIOCLBIS:
272903Sbill 	case TIOCLBIC:
273903Sbill 	case TIOCLSET:
274915Sbill /* this is reasonable, but impractical...
275903Sbill 		if ((flag & FWRITE) == 0) {
276903Sbill 			u.u_error = EBADF;
277903Sbill 			return (1);
278903Sbill 		}
279915Sbill  */
280903Sbill 		while (tp->t_line == NTTYDISC &&
281903Sbill 		   u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp &&
282903Sbill 		   (u.u_procp->p_flag&SVFORK) == 0 &&
283903Sbill 		   u.u_signal[SIGTTOU] != SIG_IGN &&
2845626Swnj 		   u.u_signal[SIGTTOU] != SIG_HOLD
2855626Swnj /*
2865626Swnj 						   &&
287903Sbill 		   (u.u_procp->p_flag&SDETACH)==0) {
2885626Swnj */
2895626Swnj 		   ) {
290903Sbill 			gsignal(u.u_procp->p_pgrp, SIGTTOU);
291903Sbill 			sleep((caddr_t)&lbolt, TTOPRI);
292903Sbill 		}
293903Sbill 		break;
294903Sbill 	}
295903Sbill 
29639Sbill 	/*
297903Sbill 	 * Process the ioctl.
29839Sbill 	 */
299*7625Ssam 	switch (com) {
300903Sbill 
301903Sbill 	/*
302903Sbill 	 * Get discipline number
303903Sbill 	 */
30439Sbill 	case TIOCGETD:
305*7625Ssam 		*(int *)data = tp->t_line;
30639Sbill 		break;
30739Sbill 
30839Sbill 	/*
309903Sbill 	 * Set line discipline
31039Sbill 	 */
311*7625Ssam 	case TIOCSETD: {
312*7625Ssam 		register int t = *(int *)data;
313*7625Ssam 
31439Sbill 		if (t >= nldisp) {
31539Sbill 			u.u_error = ENXIO;
31639Sbill 			break;
31739Sbill 		}
318174Sbill 		(void) spl5();
31939Sbill 		if (tp->t_line)
32039Sbill 			(*linesw[tp->t_line].l_close)(tp);
32139Sbill 		if (t)
322*7625Ssam 			(*linesw[t].l_open)(dev, tp);
32339Sbill 		if (u.u_error==0)
32439Sbill 			tp->t_line = t;
325174Sbill 		(void) spl0();
32639Sbill 		break;
327*7625Ssam 	}
32839Sbill 
32939Sbill 	/*
3305614Swnj 	 * Prevent more opens on channel
3315614Swnj 	 */
3325614Swnj 	case TIOCEXCL:
3335614Swnj 		tp->t_state |= TS_XCLUDE;
3345614Swnj 		break;
3355614Swnj 
3365614Swnj 	case TIOCNXCL:
3375614Swnj 		tp->t_state &= ~TS_XCLUDE;
3385614Swnj 		break;
3395614Swnj 
3405614Swnj 	/*
34139Sbill 	 * Set new parameters
34239Sbill 	 */
34339Sbill 	case TIOCSETP:
344*7625Ssam 	case TIOCSETN: {
345*7625Ssam 		register struct sgttyb *sg = (struct sgttyb *)data;
346*7625Ssam 		struct clist tq;
347*7625Ssam 
348121Sbill 		(void) spl5();
349*7625Ssam 		if (tp->t_flags&RAW || sg->sg_flags&RAW || com == TIOCSETP)
3504484Swnj 			wflushtty(tp);
351*7625Ssam 		else if ((tp->t_flags&CBREAK) != (sg->sg_flags&CBREAK)) {
352*7625Ssam 			if (sg->sg_flags & CBREAK) {
3534484Swnj 				catq(&tp->t_rawq, &tp->t_canq);
3544484Swnj 				tq = tp->t_rawq;
3554484Swnj 				tp->t_rawq = tp->t_canq;
3564484Swnj 				tp->t_canq = tq;
3574484Swnj 			} else {
3584484Swnj 				tp->t_local |= LPENDIN;
3594484Swnj 				ttwakeup(tp);
360174Sbill 			}
361174Sbill 		}
362*7625Ssam 		tp->t_ispeed = sg->sg_ispeed;
363*7625Ssam 		tp->t_ospeed = sg->sg_ospeed;
364*7625Ssam 		tp->t_erase = sg->sg_erase;
365*7625Ssam 		tp->t_kill = sg->sg_kill;
366*7625Ssam 		tp->t_flags = sg->sg_flags;
3673941Sbugs 		if (tp->t_flags & RAW) {
3685408Swnj 			tp->t_state &= ~TS_TTSTOP;
3693941Sbugs 			ttstart(tp);
3703941Sbugs 		}
371121Sbill 		(void) spl0();
37239Sbill 		break;
373*7625Ssam 	}
37439Sbill 
37539Sbill 	/*
376903Sbill 	 * Send current parameters to user
37739Sbill 	 */
378*7625Ssam 	case TIOCGETP: {
379*7625Ssam 		register struct sgttyb *sg = (struct sgttyb *)data;
380*7625Ssam 
381*7625Ssam 		sg->sg_ispeed = tp->t_ispeed;
382*7625Ssam 		sg->sg_ospeed = tp->t_ospeed;
383*7625Ssam 		sg->sg_erase = tp->t_erase;
384*7625Ssam 		sg->sg_kill = tp->t_kill;
385*7625Ssam 		sg->sg_flags = tp->t_flags;
38639Sbill 		break;
387*7625Ssam 	}
38839Sbill 
38939Sbill 	/*
39039Sbill 	 * Hang up line on last close
39139Sbill 	 */
39239Sbill 	case TIOCHPCL:
3935408Swnj 		tp->t_state |= TS_HUPCLS;
39439Sbill 		break;
39539Sbill 
3963942Sbugs 	case TIOCFLUSH: {
397*7625Ssam 		register int flags = *(int *)data;
398*7625Ssam 
399*7625Ssam 		if (flags == 0)
4003942Sbugs 			flags = FREAD|FWRITE;
401*7625Ssam 		else
402*7625Ssam 			flags &= FREAD|FWRITE;
4033942Sbugs 		flushtty(tp, flags);
40439Sbill 		break;
4053944Sbugs 	}
40639Sbill 
407*7625Ssam 	case FIONBIO:
408*7625Ssam 		if (*(int *)data)
4095408Swnj 			tp->t_state |= TS_NBIO;
4105408Swnj 		else
4115408Swnj 			tp->t_state &= ~TS_NBIO;
4125408Swnj 		break;
4135408Swnj 
414*7625Ssam 	case FIOASYNC:
415*7625Ssam 		if (*(int *)data)
4166216Swnj 			tp->t_state |= TS_ASYNC;
4176216Swnj 		else
4186216Swnj 			tp->t_state &= ~TS_ASYNC;
4196216Swnj 		break;
4206216Swnj 
42139Sbill 	/*
422903Sbill 	 * Set and fetch special characters
42339Sbill 	 */
42439Sbill 	case TIOCSETC:
425*7625Ssam 		bcopy(data, (caddr_t)&tun, sizeof (struct tchars));
42639Sbill 		break;
42739Sbill 
42839Sbill 	case TIOCGETC:
429*7625Ssam 		bcopy((caddr_t)&tun, data, sizeof (struct tchars));
43039Sbill 		break;
43139Sbill 
432174Sbill /* local ioctls */
433903Sbill 	/*
434903Sbill 	 * Set/get local special characters.
435903Sbill 	 */
436174Sbill 	case TIOCSLTC:
437*7625Ssam 		bcopy(data, (caddr_t)&tlun, sizeof (struct ltchars));
438174Sbill 		break;
439174Sbill 
440174Sbill 	case TIOCGLTC:
441*7625Ssam 		bcopy((caddr_t)&tlun, data, sizeof (struct ltchars));
442174Sbill 		break;
443174Sbill 
444903Sbill 	/*
445903Sbill 	 * Return number of characters immediately available.
446903Sbill 	 */
447*7625Ssam 	case FIONREAD:
448*7625Ssam 		*(off_t *)data = ttnread(tp);
449174Sbill 		break;
450174Sbill 
451174Sbill 	/*
452174Sbill 	 * Should allow SPGRP and GPGRP only if tty open for reading.
453174Sbill 	 */
454174Sbill 	case TIOCSPGRP:
455*7625Ssam 		tp->t_pgrp = *(int *)data;
456174Sbill 		break;
457174Sbill 
458174Sbill 	case TIOCGPGRP:
459*7625Ssam 		*(int *)data = tp->t_pgrp;
460174Sbill 		break;
461174Sbill 
462174Sbill 	/*
463174Sbill 	 * Modify local mode word.
464174Sbill 	 */
465174Sbill 	case TIOCLBIS:
466*7625Ssam 		tp->t_local |= *(int *)data;
467174Sbill 		break;
468174Sbill 
469174Sbill 	case TIOCLBIC:
470*7625Ssam 		tp->t_local &= ~(*(int *)data);
471174Sbill 		break;
472174Sbill 
473174Sbill 	case TIOCLSET:
474*7625Ssam 		tp->t_local = *(int *)data;
475174Sbill 		break;
476174Sbill 
477174Sbill 	case TIOCLGET:
478*7625Ssam 		*(int *)data = tp->t_local;
479174Sbill 		break;
480174Sbill 
481*7625Ssam 	case TIOCSTOP: {
482*7625Ssam 		int s = spl5();
483213Sbill 
4845573Swnj 		if ((tp->t_state & TS_TTSTOP) == 0) {
4855573Swnj 			tp->t_state |= TS_TTSTOP;
4865573Swnj 			(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
4875573Swnj 		}
488*7625Ssam 		splx(s);
4895573Swnj 		break;
490*7625Ssam 	}
4915573Swnj 
492*7625Ssam 	case TIOCSTART: {
493*7625Ssam 		int s = spl5();
494*7625Ssam 
4955573Swnj 		if ((tp->t_state & TS_TTSTOP) || (tp->t_local & LFLUSHO)) {
4965573Swnj 			tp->t_state &= ~TS_TTSTOP;
4975573Swnj 			tp->t_local &= ~LFLUSHO;
4985573Swnj 			ttstart(tp);
4995573Swnj 		}
500*7625Ssam 		splx(s);
5015573Swnj 		break;
502*7625Ssam 	}
5035573Swnj 
504174Sbill /* end of locals */
505887Sbill 
50639Sbill 	default:
507*7625Ssam 		return (0);
50839Sbill 	}
509*7625Ssam 	return (1);
51039Sbill }
5114484Swnj 
5124484Swnj ttnread(tp)
5134484Swnj 	struct tty *tp;
5144484Swnj {
5154484Swnj 	int nread = 0;
5164484Swnj 
5174484Swnj 	if (tp->t_local & LPENDIN)
5184484Swnj 		ttypend(tp);
5194484Swnj 	nread = tp->t_canq.c_cc;
5204484Swnj 	if (tp->t_flags & (RAW|CBREAK))
5214484Swnj 		nread += tp->t_rawq.c_cc;
5224484Swnj 	return (nread);
5234484Swnj }
5244484Swnj 
5255408Swnj ttselect(dev, rw)
5264484Swnj 	dev_t dev;
5275408Swnj 	int rw;
5284484Swnj {
5294484Swnj 	register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)];
5304484Swnj 	int nread;
5315408Swnj 	int s = spl5();
5324484Swnj 
5335408Swnj 	switch (rw) {
5344484Swnj 
5354484Swnj 	case FREAD:
5364484Swnj 		nread = ttnread(tp);
5374484Swnj 		if (nread > 0)
5385408Swnj 			goto win;
5394938Swnj 		if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait)
5405408Swnj 			tp->t_state |= TS_RCOLL;
5414484Swnj 		else
5424484Swnj 			tp->t_rsel = u.u_procp;
5435408Swnj 		break;
5444484Swnj 
5455408Swnj 	case FWRITE:
5465408Swnj 		if (tp->t_outq.c_cc <= TTLOWAT(tp))
5475408Swnj 			goto win;
5485408Swnj 		if (tp->t_wsel && tp->t_wsel->p_wchan == (caddr_t)&selwait)
5495408Swnj 			tp->t_state |= TS_WCOLL;
5505408Swnj 		else
5515408Swnj 			tp->t_wsel = u.u_procp;
5525408Swnj 		break;
5534484Swnj 	}
5545408Swnj 	splx(s);
5555408Swnj 	return (0);
5565408Swnj win:
5575408Swnj 	splx(s);
5585408Swnj 	return (1);
5594484Swnj }
5607436Skre 
5617502Sroot #define	OBUFSIZ	100
5627502Sroot 
5637502Sroot /*
5647502Sroot  * routine called on opens while tp->t_line == NTTYDISC
5657502Sroot  * establishes a process group for distribution of
5667502Sroot  * quits and interrupts from the tty.
5677502Sroot  * (actually, pp->p_pgrp can't be 0 when this routine
5687502Sroot  * is called since NTTYDISC is not the default discipline)
5697502Sroot  */
5707502Sroot ttyopen(dev, tp)
571*7625Ssam 	dev_t dev;
572*7625Ssam 	register struct tty *tp;
5737502Sroot {
5747502Sroot 	register struct proc *pp;
5757502Sroot 
5767502Sroot 	pp = u.u_procp;
5777502Sroot 	tp->t_dev = dev;
578*7625Ssam 	if (pp->p_pgrp == 0) {
5797502Sroot 		u.u_ttyp = tp;
5807502Sroot 		u.u_ttyd = dev;
5817502Sroot 		if (tp->t_pgrp == 0)
5827502Sroot 			tp->t_pgrp = pp->p_pid;
5837502Sroot 		pp->p_pgrp = tp->t_pgrp;
5847502Sroot 	}
5857502Sroot 	tp->t_state &= ~TS_WOPEN;
5867502Sroot 	tp->t_state |= TS_ISOPEN;
5877502Sroot 	if (tp->t_line != NTTYDISC)
5887502Sroot 		wflushtty(tp);
5897502Sroot }
5907502Sroot 
5917502Sroot /*
5927502Sroot  * clean tp on last close
5937502Sroot  */
5947502Sroot ttyclose(tp)
595*7625Ssam 	register struct tty *tp;
5967502Sroot {
5977502Sroot 
5987502Sroot 	if (tp->t_line) {
5997502Sroot 		wflushtty(tp);
6007502Sroot 		tp->t_line = 0;
6017502Sroot 		return;
6027502Sroot 	}
6037502Sroot 	tp->t_pgrp = 0;
6047502Sroot 	wflushtty(tp);
6057502Sroot 	tp->t_state = 0;
6067502Sroot }
6077502Sroot 
6087502Sroot /*
6097502Sroot  * reinput pending characters after state switch
6107502Sroot  * call at spl5().
6117502Sroot  */
6127502Sroot ttypend(tp)
613*7625Ssam 	register struct tty *tp;
6147502Sroot {
6157502Sroot 	struct clist tq;
6167502Sroot 	register c;
6177502Sroot 
6187502Sroot 	tp->t_local &= ~LPENDIN;
6197502Sroot 	tp->t_lstate |= LSTYPEN;
6207502Sroot 	tq = tp->t_rawq;
6217502Sroot 	tp->t_rawq.c_cc = 0;
6227502Sroot 	tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0;
6237502Sroot 	while ((c = getc(&tq)) >= 0)
6247502Sroot 		ttyinput(c, tp);
6257502Sroot 	tp->t_lstate &= ~LSTYPEN;
6267502Sroot }
6277502Sroot 
6287502Sroot /*
6297502Sroot  * Place a character on raw TTY input queue, putting in delimiters
6307502Sroot  * and waking up top half as needed.
6317502Sroot  * Also echo if required.
6327502Sroot  * The arguments are the character and the appropriate
6337502Sroot  * tty structure.
6347502Sroot  */
6357502Sroot ttyinput(c, tp)
636*7625Ssam 	register c;
637*7625Ssam 	register struct tty *tp;
6387502Sroot {
6397502Sroot 	register int t_flags;
6407502Sroot 	int i;
6417502Sroot 
6427502Sroot 	if (tp->t_local&LPENDIN)
6437502Sroot 		ttypend(tp);
6447502Sroot 	tk_nin++;
6457502Sroot 	c &= 0377;
6467502Sroot 	t_flags = tp->t_flags;
6477502Sroot 	if (t_flags&TANDEM)
6487502Sroot 		ttyblock(tp);
6497502Sroot 	if ((t_flags&RAW)==0) {
6507502Sroot 		if ((tp->t_lstate&LSTYPEN) == 0)
6517502Sroot 			c &= 0177;
6527502Sroot 	/* check for literal nexting very first */
6537502Sroot 		if (tp->t_lstate&LSLNCH) {
6547502Sroot 			c |= 0200;
6557502Sroot 			tp->t_lstate &= ~LSLNCH;
6567502Sroot 		}
6577502Sroot 		if (tp->t_line == NTTYDISC && c==tlun.t_lnextc) {
6587502Sroot 			if (tp->t_flags&ECHO)
6597502Sroot 				ttyout("^\b", tp);
6607502Sroot 			tp->t_lstate |= LSLNCH;
6617502Sroot 	/* check for output control functions */
6627502Sroot 		} else if (c==tun.t_stopc) {
6637502Sroot 			if ((tp->t_state&TS_TTSTOP)==0) {
6647502Sroot 				tp->t_state |= TS_TTSTOP;
6657502Sroot 				(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
6667502Sroot 				return;
6677502Sroot 			}
6687502Sroot 			if (c!=tun.t_startc)
6697502Sroot 				return;
6707502Sroot 		} else if (c==tun.t_startc) {
6717502Sroot 			tp->t_state &= ~TS_TTSTOP;
6727502Sroot 			tp->t_local &= ~LFLUSHO;
6737502Sroot 			ttstart(tp);
6747502Sroot 			return;
6757502Sroot 		} else if (tp->t_line == NTTYDISC && c==tlun.t_flushc) {
6767502Sroot 			if (tp->t_local & LFLUSHO)
6777502Sroot 				tp->t_local &= ~LFLUSHO;
6787502Sroot 			else {
6797502Sroot 				flushtty(tp, FWRITE);
6807502Sroot 				ttyecho(c, tp);
6817502Sroot 				if (tp->t_rawq.c_cc+tp->t_canq.c_cc)
6827502Sroot 					ttyretype(tp);
6837502Sroot 				tp->t_local |= LFLUSHO;
6847502Sroot 			}
6857502Sroot 			ttstart(tp);
6867502Sroot 			return;
6877502Sroot 		} else if (c==tun.t_intrc || c==tun.t_quitc ||
6887502Sroot 		    (tp->t_line == NTTYDISC && c==tlun.t_suspc)) {
6897502Sroot 			if ((tp->t_local & LNOFLSH) == 0)
6907502Sroot 				flushtty(tp,
6917502Sroot 				    c==tlun.t_suspc ? FREAD : FREAD|FWRITE);
6927502Sroot 			ttyecho(c, tp);
6937502Sroot 			c = c==tun.t_intrc ? SIGINT :
6947502Sroot 				((c==tun.t_quitc) ? SIGQUIT : SIGTSTP);
6957502Sroot 			ttsignal(tp, c);
6967502Sroot 	/* check for buffer editing functions - cooked mode */
6977502Sroot 		} else if ((t_flags&CBREAK) == 0) {
6987502Sroot 			if ((tp->t_lstate&LSQUOT) &&
6997502Sroot 			    (c==tp->t_erase||c==tp->t_kill)) {
7007502Sroot 				ttyrub(unputc(&tp->t_rawq), tp);
7017502Sroot 				c |= 0200;
7027502Sroot 			}
7037502Sroot 			if (c==tp->t_erase) {
7047502Sroot 				if (tp->t_rawq.c_cc)
7057502Sroot 					ttyrub(unputc(&tp->t_rawq), tp);
7067502Sroot 			} else if (c==tp->t_kill) {
7077502Sroot 				if (tp->t_local&LCRTKIL &&
7087502Sroot 				    tp->t_rawq.c_cc == tp->t_rocount) {
7097502Sroot 					while (tp->t_rawq.c_cc)
7107502Sroot 						ttyrub(unputc(&tp->t_rawq), tp);
7117502Sroot 				} else {
7127502Sroot 					ttyecho(c, tp);
7137502Sroot 					ttyecho('\n', tp);
7147502Sroot 					while (getc(&tp->t_rawq) > 0)
7157502Sroot 						;
7167502Sroot 					tp->t_rocount = 0;
7177502Sroot 				}
7187502Sroot 				tp->t_lstate = 0;
7197502Sroot 			} else if (tp->t_line == NTTYDISC && c==tlun.t_werasc) {
7207502Sroot 				if (tp->t_rawq.c_cc == 0)
7217502Sroot 					goto out;
7227502Sroot 				do {
7237502Sroot 					c = unputc(&tp->t_rawq);
7247502Sroot 					if (c != ' ' && c != '\t')
7257502Sroot 						goto erasenb;
7267502Sroot 					ttyrub(c, tp);
7277502Sroot 				} while (tp->t_rawq.c_cc);
7287502Sroot 				goto out;
7297502Sroot 			    erasenb:
7307502Sroot 				do {
7317502Sroot 					ttyrub(c, tp);
7327502Sroot 					if (tp->t_rawq.c_cc == 0)
7337502Sroot 						goto out;
7347502Sroot 					c = unputc(&tp->t_rawq);
7357502Sroot 				} while (c != ' ' && c != '\t');
7367502Sroot 				(void) putc(c, &tp->t_rawq);
7377502Sroot 			} else if (tp->t_line == NTTYDISC && c==tlun.t_rprntc) {
7387502Sroot 				ttyretype(tp);
7397502Sroot 	/* check for cooked mode input buffer overflow */
7407502Sroot 			} else if (tp->t_rawq.c_cc+tp->t_canq.c_cc >= TTYHOG) {
7417502Sroot 				;
7427502Sroot 	/* put data char in q for user and wakeup if a break char */
7437502Sroot 			} else if (putc(c, &tp->t_rawq) >= 0) {
7447502Sroot 				if (tp->t_rawq.c_cc+tp->t_canq.c_cc==TTYHOG
7457502Sroot 				    && tp->t_line == NTTYDISC)
7467502Sroot 					(void) ttyoutput(CTRL(g), tp);
7477502Sroot 				if (!ttbreakc(c, tp)) {
7487502Sroot 					if (tp->t_rocount++ == 0)
7497502Sroot 						tp->t_rocol = tp->t_col;
7507502Sroot 				} else {
7517502Sroot 					tp->t_rocount = 0;
7527502Sroot 					catq(&tp->t_rawq, &tp->t_canq);
7537502Sroot 					/* IF (TP->T_CHAN) (VOID) SDATA(TP->T_CHAN); */
7547502Sroot 					ttwakeup(tp);
7557502Sroot 				}
7567502Sroot 				tp->t_lstate &= ~LSQUOT;
7577502Sroot 				if (c == '\\')
7587502Sroot 					tp->t_lstate |= LSQUOT;
7597502Sroot 				if (tp->t_lstate&LSERASE) {
7607502Sroot 					tp->t_lstate &= ~LSERASE;
7617502Sroot 					(void) ttyoutput('/', tp);
7627502Sroot 				}
7637502Sroot 				i = tp->t_col;
7647502Sroot 				ttyecho(c, tp);
7657502Sroot 				if (c==tun.t_eofc && tp->t_flags&ECHO) {
7667502Sroot 					i = MIN(2, tp->t_col - i);
7677502Sroot 					while (i > 0) {
7687502Sroot 						(void) ttyoutput('\b', tp);
7697502Sroot 						i--;
7707502Sroot 					}
7717502Sroot 				}
7727502Sroot 			}
7737502Sroot 	/* CBREAK mode */
7747502Sroot 		} else if (tp->t_rawq.c_cc > TTYHOG) {
7757502Sroot 			if (tp->t_outq.c_cc < TTHIWAT(tp) &&
7767502Sroot 			    tp->t_line == NTTYDISC)
7777502Sroot 				(void) ttyoutput(CTRL(g), tp);
7787502Sroot 		} else if (putc(c, &tp->t_rawq) >= 0) {
7797502Sroot 			ttwakeup(tp);
7807502Sroot 			ttyecho(c, tp);
7817502Sroot 		}
7827502Sroot 	/* RAW mode */
7837502Sroot 	} else if (tp->t_rawq.c_cc > TTYHOG)
7847502Sroot 		flushtty(tp, FREAD|FWRITE);
7857502Sroot 	else {
7867502Sroot 		if (putc(c, &tp->t_rawq) >= 0)
7877502Sroot 			ttwakeup(tp);
7887502Sroot 		ttyecho(c, tp);
7897502Sroot 	}
7907502Sroot out:
7917502Sroot 	if (tp->t_local & LDECCTQ && tp->t_state & TS_TTSTOP &&
7927502Sroot 	    tun.t_startc != tun.t_stopc)
7937502Sroot 		return;
7947502Sroot 	tp->t_state &= ~TS_TTSTOP;
7957502Sroot 	tp->t_local &= ~LFLUSHO;
7967502Sroot 	ttstart(tp);
7977502Sroot }
7987502Sroot 
7997502Sroot /*
8007502Sroot  * put character on TTY output queue, adding delays,
8017502Sroot  * expanding tabs, and handling the CR/NL bit.
8027502Sroot  * It is called both from the top half for output, and from
8037502Sroot  * interrupt level for echoing.
8047502Sroot  * The arguments are the character and the tty structure.
8057502Sroot  * Returns < 0 if putc succeeds, otherwise returns char to resend
8067502Sroot  * Must be recursive.
8077502Sroot  */
8087502Sroot ttyoutput(c, tp)
8097502Sroot 	register c;
8107502Sroot 	register struct tty *tp;
8117502Sroot {
8127502Sroot 	register char *colp;
8137502Sroot 	register ctype;
8147502Sroot 
8157502Sroot 	if (tp->t_flags&RAW || tp->t_local&LLITOUT) {
8167502Sroot 		if (tp->t_local&LFLUSHO)
8177502Sroot 			return (-1);
8187502Sroot 		if (putc(c, &tp->t_outq))
819*7625Ssam 			return (c);
8207502Sroot 		tk_nout++;
8217502Sroot 		return (-1);
8227502Sroot 	}
8237502Sroot 	/*
8247502Sroot 	 * Ignore EOT in normal mode to avoid hanging up
8257502Sroot 	 * certain terminals.
8267502Sroot 	 */
8277502Sroot 	c &= 0177;
8287502Sroot 	if (c==CEOT && (tp->t_flags&CBREAK)==0)
8297502Sroot 		return (-1);
8307502Sroot 	/*
8317502Sroot 	 * Turn tabs to spaces as required
8327502Sroot 	 */
8337502Sroot 	if (c=='\t' && (tp->t_flags&TBDELAY)==XTABS) {
8347502Sroot 		register int s;
8357502Sroot 
8367502Sroot 		c = 8 - (tp->t_col&7);
8377502Sroot 		if ((tp->t_local&LFLUSHO) == 0) {
8387502Sroot 			s = spl5();		/* don't interrupt tabs */
8397502Sroot 			c -= b_to_q("        ", c, &tp->t_outq);
8407502Sroot 			tk_nout += c;
8417502Sroot 			splx(s);
8427502Sroot 		}
8437502Sroot 		tp->t_col += c;
8447502Sroot 		return (c ? -1 : '\t');
8457502Sroot 	}
8467502Sroot 	tk_nout++;
8477502Sroot 	/*
8487502Sroot 	 * for upper-case-only terminals,
8497502Sroot 	 * generate escapes.
8507502Sroot 	 */
8517502Sroot 	if (tp->t_flags&LCASE) {
8527502Sroot 		colp = "({)}!|^~'`";
853*7625Ssam 		while (*colp++)
854*7625Ssam 			if (c == *colp++) {
8557502Sroot 				if (ttyoutput('\\', tp) >= 0)
8567502Sroot 					return (c);
8577502Sroot 				c = colp[-2];
8587502Sroot 				break;
8597502Sroot 			}
8607502Sroot 		if ('A'<=c && c<='Z') {
8617502Sroot 			if (ttyoutput('\\', tp) >= 0)
8627502Sroot 				return (c);
8637502Sroot 		} else if ('a'<=c && c<='z')
8647502Sroot 			c += 'A' - 'a';
8657502Sroot 	}
8667502Sroot 	/*
8677502Sroot 	 * turn <nl> to <cr><lf> if desired.
8687502Sroot 	 */
8697502Sroot 	if (c=='\n' && tp->t_flags&CRMOD)
8707502Sroot 		if (ttyoutput('\r', tp) >= 0)
8717502Sroot 			return (c);
8727502Sroot 	if (c=='~' && tp->t_local&LTILDE)
8737502Sroot 		c = '`';
8747502Sroot 	if ((tp->t_local&LFLUSHO) == 0 && putc(c, &tp->t_outq))
8757502Sroot 		return (c);
8767502Sroot 	/*
8777502Sroot 	 * Calculate delays.
8787502Sroot 	 * The numbers here represent clock ticks
8797502Sroot 	 * and are not necessarily optimal for all terminals.
8807502Sroot 	 * The delays are indicated by characters above 0200.
8817502Sroot 	 * In raw mode there are no delays and the
8827502Sroot 	 * transmission path is 8 bits wide.
8837502Sroot 	 */
8847502Sroot 	colp = &tp->t_col;
8857502Sroot 	ctype = partab[c];
8867502Sroot 	c = 0;
8877502Sroot 	switch (ctype&077) {
8887502Sroot 
8897502Sroot 	case ORDINARY:
8907502Sroot 		(*colp)++;
8917502Sroot 
8927502Sroot 	case CONTROL:
8937502Sroot 		break;
8947502Sroot 
8957502Sroot 	case BACKSPACE:
8967502Sroot 		if (*colp)
8977502Sroot 			(*colp)--;
8987502Sroot 		break;
8997502Sroot 
9007502Sroot 	case NEWLINE:
9017502Sroot 		ctype = (tp->t_flags >> 8) & 03;
902*7625Ssam 		if (ctype == 1) { /* tty 37 */
9037502Sroot 			if (*colp)
9047502Sroot 				c = max(((unsigned)*colp>>4) + 3, (unsigned)6);
9057502Sroot 		} else
906*7625Ssam 		if (ctype == 2) { /* vt05 */
9077502Sroot 			c = 6;
9087502Sroot 		}
9097502Sroot 		*colp = 0;
9107502Sroot 		break;
9117502Sroot 
9127502Sroot 	case TAB:
9137502Sroot 		ctype = (tp->t_flags >> 10) & 03;
914*7625Ssam 		if (ctype == 1) { /* tty 37 */
9157502Sroot 			c = 1 - (*colp | ~07);
916*7625Ssam 			if (c < 5)
9177502Sroot 				c = 0;
9187502Sroot 		}
9197502Sroot 		*colp |= 07;
9207502Sroot 		(*colp)++;
9217502Sroot 		break;
9227502Sroot 
9237502Sroot 	case VTAB:
924*7625Ssam 		if (tp->t_flags & VTDELAY) /* tty 37 */
9257502Sroot 			c = 0177;
9267502Sroot 		break;
9277502Sroot 
9287502Sroot 	case RETURN:
9297502Sroot 		ctype = (tp->t_flags >> 12) & 03;
930*7625Ssam 		if (ctype == 1) { /* tn 300 */
9317502Sroot 			c = 5;
932*7625Ssam 		} else if (ctype == 2) { /* ti 700 */
9337502Sroot 			c = 10;
934*7625Ssam 		} else if (ctype == 3) { /* concept 100 */
9357502Sroot 			int i;
9367502Sroot 			if ((i = *colp) >= 0)
9377502Sroot 				for (; i<9; i++)
9387502Sroot 					(void) putc(0177, &tp->t_outq);
9397502Sroot 		}
9407502Sroot 		*colp = 0;
9417502Sroot 	}
942*7625Ssam 	if (c && (tp->t_local&LFLUSHO) == 0)
9437502Sroot 		(void) putc(c|0200, &tp->t_outq);
9447502Sroot 	return (-1);
9457502Sroot }
9467502Sroot 
9477502Sroot /*
9487502Sroot  * Called from device's read routine after it has
9497502Sroot  * calculated the tty-structure given as argument.
9507502Sroot  */
9517502Sroot ttread(tp)
952*7625Ssam 	register struct tty *tp;
9537502Sroot {
9547502Sroot 	register struct clist *qp;
9557502Sroot 	register c, first;
9567502Sroot 
9577502Sroot 	if ((tp->t_state&TS_CARR_ON)==0)
958*7625Ssam 		return (0);
9597502Sroot loop:
9607502Sroot 	(void) spl5();
9617502Sroot 	if (tp->t_local&LPENDIN)
9627502Sroot 		ttypend(tp);
9637502Sroot 	(void) spl0();
9647502Sroot 	while (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) {
9657502Sroot 		if (u.u_signal[SIGTTIN] == SIG_IGN ||
9667502Sroot 		    u.u_signal[SIGTTIN] == SIG_HOLD ||
9677502Sroot /*
9687502Sroot 		    (u.u_procp->p_flag&SDETACH) ||
9697502Sroot */
9707502Sroot 		    u.u_procp->p_flag&SVFORK)
9717502Sroot 			return (0);
9727502Sroot 		gsignal(u.u_procp->p_pgrp, SIGTTIN);
9737502Sroot 		sleep((caddr_t)&lbolt, TTIPRI);
9747502Sroot 	}
9757502Sroot 	if (tp->t_flags&RAW) {
9767502Sroot 		(void) spl5();
9777502Sroot 		if (tp->t_rawq.c_cc <= 0) {
9787502Sroot 			if ((tp->t_state&TS_CARR_ON)==0 ||
9797502Sroot 			    (tp->t_state&TS_NBIO)) {
9807502Sroot 				(void) spl0();
9817502Sroot 				return (0);
9827502Sroot 			}
9837502Sroot 			sleep((caddr_t)&tp->t_rawq, TTIPRI);
9847502Sroot 			(void) spl0();
9857502Sroot 			goto loop;
9867502Sroot 		}
9877502Sroot 		(void) spl0();
9887502Sroot 		while (tp->t_rawq.c_cc && passc(getc(&tp->t_rawq))>=0)
9897502Sroot 			;
9907502Sroot 		return (0);
9917502Sroot 	} else {
9927502Sroot 		qp = tp->t_flags & CBREAK ? &tp->t_rawq : &tp->t_canq;
9937502Sroot 		(void) spl5();
9947502Sroot 		if (qp->c_cc <= 0) {
9957502Sroot 			if ((tp->t_state&TS_CARR_ON)==0 ||
9967502Sroot 			    (tp->t_state&TS_NBIO)) {
9977502Sroot 				(void) spl0();
9987502Sroot 				return (0);
9997502Sroot 			}
10007502Sroot 			sleep((caddr_t)&tp->t_rawq, TTIPRI);
10017502Sroot 			(void) spl0();
10027502Sroot 			goto loop;
10037502Sroot 		}
10047502Sroot 		(void) spl0();
10057502Sroot 		first = 1;
10067502Sroot 		while ((c = getc(qp)) >= 0) {
10077502Sroot 			if (tp->t_flags&CRMOD && c == '\r')
10087502Sroot 				c = '\n';
10097502Sroot 			if (tp->t_flags&LCASE && c <= 0177)
10107502Sroot 				if (tp->t_lstate&LSBKSL) {
10117502Sroot 					if (maptab[c])
10127502Sroot 						c = maptab[c];
10137502Sroot 					tp->t_lstate &= ~LSBKSL;
10147502Sroot 				} else if (c >= 'A' && c <= 'Z')
10157502Sroot 					c += 'a' - 'A';
10167502Sroot 				else if (c == '\\') {
10177502Sroot 					tp->t_lstate |= LSBKSL;
10187502Sroot 					continue;
10197502Sroot 				}
10207502Sroot 			if (c == tlun.t_dsuspc) {
10217502Sroot 				ttsignal(tp, SIGTSTP);
10227502Sroot 				if (first) {
10237502Sroot 					sleep((caddr_t)&lbolt, TTIPRI);
10247502Sroot 					goto loop;
10257502Sroot 				}
10267502Sroot 				break;
10277502Sroot 			}
10287502Sroot 			if (c == tun.t_eofc && (tp->t_flags&CBREAK)==0)
10297502Sroot 				break;
10307502Sroot 			if (passc(c & 0177) < 0)
10317502Sroot 				break;
10327502Sroot 			if ((tp->t_flags&CBREAK)==0 && ttbreakc(c, tp))
10337502Sroot 				break;
10347502Sroot 			first = 0;
10357502Sroot 		}
10367502Sroot 		tp->t_lstate &= ~LSBKSL;
10377502Sroot 	}
10387502Sroot 
10397502Sroot 	if (tp->t_state&TS_TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) {
10407502Sroot 		if (putc(tun.t_startc, &tp->t_outq)==0) {
10417502Sroot 			tp->t_state &= ~TS_TBLOCK;
10427502Sroot 			ttstart(tp);
10437502Sroot 		}
10447502Sroot 		tp->t_char = 0;
10457502Sroot 	}
10467502Sroot 
10477502Sroot 	return (tp->t_rawq.c_cc + tp->t_canq.c_cc);
10487502Sroot }
10497502Sroot 
10507502Sroot /*
10517502Sroot  * Called from the device's write routine after it has
10527502Sroot  * calculated the tty-structure given as argument.
10537502Sroot  */
10547502Sroot caddr_t
10557502Sroot ttwrite(tp)
1056*7625Ssam 	register struct tty *tp;
10577502Sroot {
10587502Sroot #ifdef vax
10597502Sroot 	/*
10607502Sroot 	 * THE POSITIONING OF CP, CC, AND CE ARE CRITICAL
10617502Sroot 	 * AND MUST NOT BE CHANGED WITHOUT PATCHING
10627502Sroot 	 * THE 'ASM' INLINES BELOW.  WATCH OUT.
10637502Sroot 	 */
10647502Sroot #endif
10657502Sroot 	register char *cp;
10667502Sroot 	register int cc, ce;
10677502Sroot 	register i;
10687502Sroot 	char obuf[OBUFSIZ];
10697502Sroot 	register c;
10707502Sroot 	int hiwat = TTHIWAT(tp);
10717502Sroot 	int cnt = u.u_count;
10727502Sroot 
10737502Sroot 	if ((tp->t_state&TS_CARR_ON)==0)
10747502Sroot 		return (NULL);
10757502Sroot loop:
10767502Sroot 	while (u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp &&
10777502Sroot 	    (tp->t_local&LTOSTOP) && (u.u_procp->p_flag&SVFORK)==0 &&
10787502Sroot 	    u.u_signal[SIGTTOU] != SIG_IGN &&
10797502Sroot 	    u.u_signal[SIGTTOU] != SIG_HOLD
10807502Sroot /*
10817502Sroot 					     &&
10827502Sroot 	    (u.u_procp->p_flag&SDETACH)==0) {
10837502Sroot */
10847502Sroot 	    ) {
10857502Sroot 		gsignal(u.u_procp->p_pgrp, SIGTTOU);
10867502Sroot 		sleep((caddr_t)&lbolt, TTIPRI);
10877502Sroot 	}
10887502Sroot 	while (u.u_count) {
10897502Sroot 		cc = MIN(u.u_count, OBUFSIZ);
10907502Sroot 		cp = obuf;
10917502Sroot 		iomove(cp, (unsigned)cc, B_WRITE);
10927502Sroot 		if (u.u_error)
10937502Sroot 			break;
10947502Sroot 		if (tp->t_outq.c_cc > hiwat)
10957502Sroot 			goto ovhiwat;
10967502Sroot 		if (tp->t_local&LFLUSHO)
10977502Sroot 			continue;
10987502Sroot 		if (tp->t_flags&LCASE || tp->t_local&LTILDE) {
10997502Sroot 			while (cc) {
11007502Sroot 				c = *cp++;
11017502Sroot 				tp->t_rocount = 0;
1102*7625Ssam 				while ((c = ttyoutput(c, tp)) >= 0) {
11037502Sroot 					/* out of clists, wait a bit */
11047502Sroot 					ttstart(tp);
11057502Sroot 					sleep((caddr_t)&lbolt, TTOPRI);
11067502Sroot 					tp->t_rocount = 0;
11077502Sroot 				}
11087502Sroot 				--cc;
11097502Sroot 				if (tp->t_outq.c_cc > hiwat)
11107502Sroot 					goto ovhiwat;
11117502Sroot 			}
11127502Sroot 			continue;
11137502Sroot 		}
11147502Sroot 		while (cc) {
11157502Sroot 			if (tp->t_flags&RAW || tp->t_local&LLITOUT)
11167502Sroot 				ce = cc;
11177502Sroot 			else {
11187502Sroot #ifdef vax
11197502Sroot 				asm("	scanc	r9,(r10),_partab,$077");
11207502Sroot 				asm("	subl3	r0,r9,r8");
11217502Sroot #else
11227502Sroot 				ce=0;
1123*7625Ssam 				while (((partab[*(unsigned char *)(cp+ce)]&077)==0)&&(ce<cc))
11247502Sroot 					ce++;
11257502Sroot #endif
11267502Sroot 				if (ce==0) {
11277502Sroot 					tp->t_rocount = 0;
11287502Sroot 					if (ttyoutput(*cp, tp) >= 0) {
11297502Sroot 						ttstart(tp);
11307502Sroot 						sleep((caddr_t)&lbolt, TTOPRI);
11317502Sroot 						continue;
11327502Sroot 					}
11337502Sroot 					cp++;
11347502Sroot 					cc--;
11357502Sroot 					if (tp->t_outq.c_cc > hiwat)
11367502Sroot 						goto ovhiwat;
11377502Sroot 				}
11387502Sroot 			}
11397502Sroot 			tp->t_rocount = 0;
11407502Sroot 			i=b_to_q(cp,ce,&tp->t_outq);
11417502Sroot 			ce-=i;
11427502Sroot 			tk_nout+=ce;
11437502Sroot 			tp->t_col+=ce;
11447502Sroot 			cp+=ce;
11457502Sroot 			cc-=ce;
11467502Sroot 			if (i) {
11477502Sroot 				ttstart(tp);
11487502Sroot 				sleep((caddr_t)&lbolt, TTOPRI);
11497502Sroot 			}
11507502Sroot 			if (ce || tp->t_outq.c_cc > hiwat)
11517502Sroot 				goto ovhiwat;
11527502Sroot 		}
11537502Sroot 	}
11547502Sroot 	ttstart(tp);
1155*7625Ssam 	return (NULL);
11567502Sroot 
11577502Sroot ovhiwat:
11587502Sroot 	(void) spl5();
11597502Sroot 	u.u_base -= cc;
11607502Sroot 	u.u_offset -= cc;
11617502Sroot 	u.u_count += cc;
11627502Sroot 	if (tp->t_outq.c_cc <= hiwat) {
11637502Sroot 		(void) spl0();
11647502Sroot 		goto loop;
11657502Sroot 	}
11667502Sroot 	ttstart(tp);
11677502Sroot 	if (tp->t_state & TS_NBIO) {
11687502Sroot 		if (u.u_count == cnt)
11697502Sroot 			u.u_error = EWOULDBLOCK;
11707502Sroot 		return (NULL);
11717502Sroot 	}
11727502Sroot 	tp->t_state |= TS_ASLEEP;
11737502Sroot 	sleep((caddr_t)&tp->t_outq, TTOPRI);
11747502Sroot 	(void) spl0();
11757502Sroot 	goto loop;
11767502Sroot }
11777502Sroot 
11787502Sroot /*
11797502Sroot  * Rubout one character from the rawq of tp
11807502Sroot  * as cleanly as possible.
11817502Sroot  */
11827502Sroot ttyrub(c, tp)
1183*7625Ssam 	register c;
1184*7625Ssam 	register struct tty *tp;
11857502Sroot {
11867502Sroot 	register char *cp;
11877502Sroot 	register int savecol;
11887502Sroot 	int s;
11897502Sroot 	char *nextc();
11907502Sroot 
11917502Sroot 	if ((tp->t_flags&ECHO)==0)
11927502Sroot 		return;
11937502Sroot 	tp->t_local &= ~LFLUSHO;
11947502Sroot 	c &= 0377;
11957502Sroot 	if (tp->t_local&LCRTBS) {
11967502Sroot 		if (tp->t_rocount == 0) {
11977502Sroot 			/*
11987502Sroot 			 * Screwed by ttwrite; retype
11997502Sroot 			 */
12007502Sroot 			ttyretype(tp);
12017502Sroot 			return;
12027502Sroot 		}
12037502Sroot 		if (c==('\t'|0200) || c==('\n'|0200))
12047502Sroot 			ttyrubo(tp, 2);
1205*7625Ssam 		else switch (partab[c&=0177] & 0177) {
12067502Sroot 
12077502Sroot 		case ORDINARY:
12087502Sroot 			if (tp->t_flags&LCASE && c >= 'A' && c <= 'Z')
12097502Sroot 				ttyrubo(tp, 2);
12107502Sroot 			else
12117502Sroot 				ttyrubo(tp, 1);
12127502Sroot 			break;
12137502Sroot 
12147502Sroot 		case VTAB:
12157502Sroot 		case BACKSPACE:
12167502Sroot 		case CONTROL:
12177502Sroot 		case RETURN:
12187502Sroot 			if (tp->t_local & LCTLECH)
12197502Sroot 				ttyrubo(tp, 2);
12207502Sroot 			break;
12217502Sroot 
12227502Sroot 		case TAB:
12237502Sroot 			if (tp->t_rocount < tp->t_rawq.c_cc) {
12247502Sroot 				ttyretype(tp);
12257502Sroot 				return;
12267502Sroot 			}
12277502Sroot 			s = spl5();
12287502Sroot 			savecol = tp->t_col;
12297502Sroot 			tp->t_lstate |= LSCNTTB;
12307502Sroot 			tp->t_local |= LFLUSHO;
12317502Sroot 			tp->t_col = tp->t_rocol;
12327502Sroot 			for (cp = tp->t_rawq.c_cf; cp; cp = nextc(&tp->t_rawq, cp))
12337502Sroot 				ttyecho(*cp, tp);
12347502Sroot 			tp->t_local &= ~LFLUSHO;
12357502Sroot 			tp->t_lstate &= ~LSCNTTB;
12367502Sroot 			splx(s);
12377502Sroot 			/*
12387502Sroot 			 * savecol will now be length of the tab
12397502Sroot 			 */
12407502Sroot 			savecol -= tp->t_col;
12417502Sroot 			tp->t_col += savecol;
12427502Sroot 			if (savecol > 8)
12437502Sroot 				savecol = 8;		/* overflow screw */
12447502Sroot 			while (--savecol >= 0)
12457502Sroot 				(void) ttyoutput('\b', tp);
12467502Sroot 			break;
12477502Sroot 
12487502Sroot 		default:
12497502Sroot 			panic("ttyrub");
12507502Sroot 		}
12517502Sroot 	} else if (tp->t_local&LPRTERA) {
12527502Sroot 		if ((tp->t_lstate&LSERASE) == 0) {
12537502Sroot 			(void) ttyoutput('\\', tp);
12547502Sroot 			tp->t_lstate |= LSERASE;
12557502Sroot 		}
12567502Sroot 		ttyecho(c, tp);
12577502Sroot 	} else
12587502Sroot 		ttyecho(tp->t_erase, tp);
12597502Sroot 	tp->t_rocount--;
12607502Sroot }
12617502Sroot 
12627502Sroot /*
12637502Sroot  * Crt back over cnt chars perhaps
12647502Sroot  * erasing them.
12657502Sroot  */
12667502Sroot ttyrubo(tp, cnt)
1267*7625Ssam 	register struct tty *tp;
1268*7625Ssam 	int cnt;
12697502Sroot {
12707502Sroot 
12717502Sroot 	while (--cnt >= 0)
12727502Sroot 		ttyout(tp->t_local&LCRTERA ? "\b \b" : "\b", tp);
12737502Sroot }
12747502Sroot 
12757502Sroot /*
12767502Sroot  * Reprint the rawq line.
12777502Sroot  * We assume c_cc has already been checked.
12787502Sroot  */
12797502Sroot ttyretype(tp)
1280*7625Ssam 	register struct tty *tp;
12817502Sroot {
12827502Sroot 	register char *cp;
12837502Sroot 	char *nextc();
12847502Sroot 	int s;
12857502Sroot 
12867502Sroot 	if (tlun.t_rprntc != 0377)
12877502Sroot 		ttyecho(tlun.t_rprntc, tp);
12887502Sroot 	(void) ttyoutput('\n', tp);
12897502Sroot 	s = spl5();
12907502Sroot 	for (cp = tp->t_canq.c_cf; cp; cp = nextc(&tp->t_canq, cp))
12917502Sroot 		ttyecho(*cp, tp);
12927502Sroot 	for (cp = tp->t_rawq.c_cf; cp; cp = nextc(&tp->t_rawq, cp))
12937502Sroot 		ttyecho(*cp, tp);
12947502Sroot 	tp->t_lstate &= ~LSERASE;
12957502Sroot 	splx(s);
12967502Sroot 	tp->t_rocount = tp->t_rawq.c_cc;
12977502Sroot 	tp->t_rocol = 0;
12987502Sroot }
12997502Sroot 
13007502Sroot /*
13017502Sroot  * Echo a typed character to the terminal
13027502Sroot  */
13037502Sroot ttyecho(c, tp)
1304*7625Ssam 	register c;
1305*7625Ssam 	register struct tty *tp;
13067502Sroot {
13077502Sroot 
13087502Sroot 	if ((tp->t_lstate & LSCNTTB) == 0)
13097502Sroot 		tp->t_local &= ~LFLUSHO;
13107502Sroot 	if ((tp->t_flags&ECHO) == 0)
13117502Sroot 		return;
13127502Sroot 	c &= 0377;
13137502Sroot 	if (tp->t_flags&RAW) {
13147502Sroot 		(void) ttyoutput(c, tp);
13157502Sroot 		return;
13167502Sroot 	}
13177502Sroot 	if (c == '\r' && tp->t_flags&CRMOD)
13187502Sroot 		c = '\n';
13197502Sroot 	if (tp->t_local&LCTLECH) {
13207502Sroot 		if ((c&0177) <= 037 && c!='\t' && c!='\n' || (c&0177)==0177) {
13217502Sroot 			(void) ttyoutput('^', tp);
13227502Sroot 			c &= 0177;
13237502Sroot 			if (c == 0177)
13247502Sroot 				c = '?';
13257502Sroot 			else if (tp->t_flags&LCASE)
13267502Sroot 				c += 'a' - 1;
13277502Sroot 			else
13287502Sroot 				c += 'A' - 1;
13297502Sroot 		}
13307502Sroot 	}
13317502Sroot 	if ((tp->t_flags&LCASE) && (c >= 'A' && c <= 'Z'))
13327502Sroot 		c += 'a' - 'A';
13337502Sroot 	(void) ttyoutput(c & 0177, tp);
13347502Sroot }
13357502Sroot 
13367502Sroot /*
13377502Sroot  * Is c a break char for tp?
13387502Sroot  */
13397502Sroot ttbreakc(c, tp)
1340*7625Ssam 	register c;
1341*7625Ssam 	register struct tty *tp;
13427502Sroot {
13437502Sroot 	return (c == '\n' || c == tun.t_eofc || c == tun.t_brkc ||
13447502Sroot 		c == '\r' && (tp->t_flags&CRMOD));
13457502Sroot }
13467502Sroot 
13477502Sroot /*
13487502Sroot  * send string cp to tp
13497502Sroot  */
13507502Sroot ttyout(cp, tp)
1351*7625Ssam 	register char *cp;
1352*7625Ssam 	register struct tty *tp;
13537502Sroot {
13547502Sroot 	register char c;
13557502Sroot 
13567502Sroot 	while (c = *cp++)
13577502Sroot 		(void) ttyoutput(c, tp);
13587502Sroot }
13597502Sroot 
13607502Sroot ttwakeup(tp)
13617502Sroot 	struct tty *tp;
13627502Sroot {
13637502Sroot 
13647502Sroot 	if (tp->t_rsel) {
13657502Sroot 		selwakeup(tp->t_rsel, tp->t_state&TS_RCOLL);
13667502Sroot 		tp->t_state &= ~TS_RCOLL;
13677502Sroot 		tp->t_rsel = 0;
13687502Sroot 	}
13697502Sroot 	wakeup((caddr_t)&tp->t_rawq);
13707502Sroot }
13717502Sroot 
13727502Sroot ttsignal(tp, signo)
13737502Sroot 	struct tty *tp;
13747502Sroot 	int signo;
13757502Sroot {
13767502Sroot 
13777502Sroot 	gsignal(tp->t_pgrp, signo);
13787502Sroot }
1379