xref: /csrg-svn/sys/kern/tty.c (revision 7502)
1*7502Sroot /*	tty.c	4.24	82/07/24	*/
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)
10639Sbill 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)
151903Sbill 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)
183903Sbill 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)
207121Sbill 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)
225903Sbill register struct tty *tp;
22639Sbill {
227903Sbill 	register s;
22839Sbill 
229903Sbill 	s = spl5();
2305622Swnj 	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*/
2401904Swnj ttioctl(tp, com, addr, flag)
24139Sbill register struct tty *tp;
24239Sbill caddr_t addr;
24339Sbill {
2441904Swnj 	int dev;
24539Sbill 	unsigned t;
246174Sbill 	struct sgttyb iocb;
247191Sbill 	struct clist tq;
24839Sbill 	extern int nldisp;
249887Sbill 	register c;
250728Sbill 	int temp;
25139Sbill 
252903Sbill 	/*
253915Sbill 	 * This is especially so that isatty() will
254915Sbill 	 * fail when carrier is gone.
255915Sbill 	 */
2565408Swnj 	if ((tp->t_state&TS_CARR_ON) == 0) {
257915Sbill 		u.u_error = EBADF;
258915Sbill 		return (1);
259915Sbill 	}
260915Sbill 
2611904Swnj 	dev = tp->t_dev;
262915Sbill 	/*
263903Sbill 	 * If the ioctl involves modification,
264903Sbill 	 * insist on being able to write the device,
265903Sbill 	 * and hang if in the background.
266903Sbill 	 */
26739Sbill 	switch(com) {
26839Sbill 
269915Sbill 	case TIOCSETD:
270915Sbill 	case TIOCSETP:
271915Sbill 	case TIOCSETN:
272903Sbill 	case TIOCFLUSH:
273903Sbill 	case TIOCSETC:
274903Sbill 	case TIOCSLTC:
275903Sbill 	case TIOCSPGRP:
276903Sbill 	case TIOCLBIS:
277903Sbill 	case TIOCLBIC:
278903Sbill 	case TIOCLSET:
279903Sbill 	case TIOCSTI:
280915Sbill /* this is reasonable, but impractical...
281903Sbill 		if ((flag & FWRITE) == 0) {
282903Sbill 			u.u_error = EBADF;
283903Sbill 			return (1);
284903Sbill 		}
285915Sbill  */
286903Sbill 		while (tp->t_line == NTTYDISC &&
287903Sbill 		   u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp &&
288903Sbill 		   (u.u_procp->p_flag&SVFORK) == 0 &&
289903Sbill 		   u.u_signal[SIGTTOU] != SIG_IGN &&
2905626Swnj 		   u.u_signal[SIGTTOU] != SIG_HOLD
2915626Swnj /*
2925626Swnj 						   &&
293903Sbill 		   (u.u_procp->p_flag&SDETACH)==0) {
2945626Swnj */
2955626Swnj 		   ) {
296903Sbill 			gsignal(u.u_procp->p_pgrp, SIGTTOU);
297903Sbill 			sleep((caddr_t)&lbolt, TTOPRI);
298903Sbill 		}
299903Sbill 		break;
300903Sbill 	}
301903Sbill 
30239Sbill 	/*
303903Sbill 	 * Process the ioctl.
30439Sbill 	 */
305903Sbill 	switch(com) {
306903Sbill 
307903Sbill 	/*
308903Sbill 	 * Get discipline number
309903Sbill 	 */
31039Sbill 	case TIOCGETD:
31139Sbill 		t = tp->t_line;
31239Sbill 		if (copyout((caddr_t)&t, addr, sizeof(t)))
31339Sbill 			u.u_error = EFAULT;
31439Sbill 		break;
31539Sbill 
31639Sbill 	/*
317903Sbill 	 * Set line discipline
31839Sbill 	 */
31939Sbill 	case TIOCSETD:
32039Sbill 		if (copyin(addr, (caddr_t)&t, sizeof(t))) {
32139Sbill 			u.u_error = EFAULT;
32239Sbill 			break;
32339Sbill 		}
32439Sbill 		if (t >= nldisp) {
32539Sbill 			u.u_error = ENXIO;
32639Sbill 			break;
32739Sbill 		}
328174Sbill 		(void) spl5();
32939Sbill 		if (tp->t_line)
33039Sbill 			(*linesw[tp->t_line].l_close)(tp);
33139Sbill 		if (t)
33239Sbill 			(*linesw[t].l_open)(dev, tp, addr);
33339Sbill 		if (u.u_error==0)
33439Sbill 			tp->t_line = t;
335174Sbill 		(void) spl0();
33639Sbill 		break;
33739Sbill 
33839Sbill 	/*
3395614Swnj 	 * Prevent more opens on channel
3405614Swnj 	 */
3415614Swnj 	case TIOCEXCL:
3425614Swnj 		tp->t_state |= TS_XCLUDE;
3435614Swnj 		break;
3445614Swnj 
3455614Swnj 	case TIOCNXCL:
3465614Swnj 		tp->t_state &= ~TS_XCLUDE;
3475614Swnj 		break;
3485614Swnj 
3495614Swnj 	/*
35039Sbill 	 * Set new parameters
35139Sbill 	 */
35239Sbill 	case TIOCSETP:
353191Sbill 	case TIOCSETN:
35439Sbill 		if (copyin(addr, (caddr_t)&iocb, sizeof(iocb))) {
35539Sbill 			u.u_error = EFAULT;
35639Sbill 			return(1);
35739Sbill 		}
358121Sbill 		(void) spl5();
3594484Swnj 		if (tp->t_flags&RAW || iocb.sg_flags&RAW ||
3604484Swnj 		    com == TIOCSETP)
3614484Swnj 			wflushtty(tp);
3624484Swnj 		else if ((tp->t_flags&CBREAK) != (iocb.sg_flags&CBREAK)) {
3634484Swnj 			if (iocb.sg_flags & CBREAK) {
3644484Swnj 				catq(&tp->t_rawq, &tp->t_canq);
3654484Swnj 				tq = tp->t_rawq;
3664484Swnj 				tp->t_rawq = tp->t_canq;
3674484Swnj 				tp->t_canq = tq;
3684484Swnj 			} else {
3694484Swnj 				tp->t_local |= LPENDIN;
3704484Swnj 				ttwakeup(tp);
371174Sbill 			}
372174Sbill 		}
3734484Swnj 		tp->t_ispeed = iocb.sg_ispeed;
3744484Swnj 		tp->t_ospeed = iocb.sg_ospeed;
375174Sbill 		tp->t_erase = iocb.sg_erase;
376174Sbill 		tp->t_kill = iocb.sg_kill;
377174Sbill 		tp->t_flags = iocb.sg_flags;
3783941Sbugs 		if (tp->t_flags & RAW) {
3795408Swnj 			tp->t_state &= ~TS_TTSTOP;
3803941Sbugs 			ttstart(tp);
3813941Sbugs 		}
382121Sbill 		(void) spl0();
38339Sbill 		break;
38439Sbill 
38539Sbill 	/*
386903Sbill 	 * Send current parameters to user
38739Sbill 	 */
38839Sbill 	case TIOCGETP:
389174Sbill 		iocb.sg_ispeed = tp->t_ispeed;
390174Sbill 		iocb.sg_ospeed = tp->t_ospeed;
391174Sbill 		iocb.sg_erase = tp->t_erase;
392174Sbill 		iocb.sg_kill = tp->t_kill;
393174Sbill 		iocb.sg_flags = tp->t_flags;
39439Sbill 		if (copyout((caddr_t)&iocb, addr, sizeof(iocb)))
39539Sbill 			u.u_error = EFAULT;
39639Sbill 		break;
39739Sbill 
39839Sbill 	/*
39939Sbill 	 * Hang up line on last close
40039Sbill 	 */
40139Sbill 	case TIOCHPCL:
4025408Swnj 		tp->t_state |= TS_HUPCLS;
40339Sbill 		break;
40439Sbill 
4053942Sbugs 	case TIOCFLUSH: {
4063942Sbugs 		int flags;
4073942Sbugs 		if (addr == 0)
4083942Sbugs 			flags = FREAD|FWRITE;
4093942Sbugs 		else if (copyin(addr, (caddr_t)&flags, sizeof (flags))) {
4103942Sbugs 			u.u_error = EFAULT;
4113983Sroot 			return(1);
4123942Sbugs 		}
4133942Sbugs 		flushtty(tp, flags);
41439Sbill 		break;
4153944Sbugs 	}
41639Sbill 
4175408Swnj 	case FIONBIO: {
4185408Swnj 		int nbio;
4195408Swnj 		if (copyin(addr, (caddr_t)&nbio, sizeof (nbio))) {
4205408Swnj 			u.u_error = EFAULT;
4215408Swnj 			return(1);
4225408Swnj 		}
4235408Swnj 		if (nbio)
4245408Swnj 			tp->t_state |= TS_NBIO;
4255408Swnj 		else
4265408Swnj 			tp->t_state &= ~TS_NBIO;
4275408Swnj 		break;
4285408Swnj 	}
4295408Swnj 
4306216Swnj 	case FIOASYNC: {
4316216Swnj 		int async;
4326216Swnj 		if (copyin(addr, (caddr_t)&async, sizeof (async))) {
4336216Swnj 			u.u_error = EFAULT;
4346216Swnj 			return(1);
4356216Swnj 		}
4366216Swnj 		if (async)
4376216Swnj 			tp->t_state |= TS_ASYNC;
4386216Swnj 		else
4396216Swnj 			tp->t_state &= ~TS_ASYNC;
4406216Swnj 		break;
4416216Swnj 	}
4426216Swnj 
44339Sbill 	/*
444903Sbill 	 * Set and fetch special characters
44539Sbill 	 */
44639Sbill 	case TIOCSETC:
447174Sbill 		if (copyin(addr, (caddr_t)&tun, sizeof(struct tchars)))
44839Sbill 			u.u_error = EFAULT;
44939Sbill 		break;
45039Sbill 
45139Sbill 	case TIOCGETC:
452174Sbill 		if (copyout((caddr_t)&tun, addr, sizeof(struct tchars)))
45339Sbill 			u.u_error = EFAULT;
45439Sbill 		break;
45539Sbill 
456174Sbill /* local ioctls */
457903Sbill 	/*
458903Sbill 	 * Set/get local special characters.
459903Sbill 	 */
460174Sbill 	case TIOCSLTC:
461174Sbill 		if (copyin(addr, (caddr_t)&tlun, sizeof (struct ltchars)))
462174Sbill 			u.u_error = EFAULT;
463174Sbill 		break;
464174Sbill 
465174Sbill 	case TIOCGLTC:
466174Sbill 		if (copyout((caddr_t)&tlun, addr, sizeof (struct ltchars)))
467174Sbill 			u.u_error = EFAULT;
468174Sbill 		break;
469174Sbill 
470903Sbill 	/*
471903Sbill 	 * Return number of characters immediately available.
472903Sbill 	 */
473174Sbill 	case FIONREAD: {
4744484Swnj 		off_t nread = ttnread(tp);
475174Sbill 		if (copyout((caddr_t)&nread, addr, sizeof (off_t)))
476174Sbill 			u.u_error = EFAULT;
477174Sbill 		break;
478174Sbill 		}
479174Sbill 
480174Sbill 	/*
481174Sbill 	 * Should allow SPGRP and GPGRP only if tty open for reading.
482174Sbill 	 */
483174Sbill 	case TIOCSPGRP:
484728Sbill 		if (copyin(addr, (caddr_t)&tp->t_pgrp, sizeof (tp->t_pgrp)))
485728Sbill 			u.u_error = EFAULT;
486174Sbill 		break;
487174Sbill 
488174Sbill 	case TIOCGPGRP:
489174Sbill 		if (copyout((caddr_t)&tp->t_pgrp, addr, sizeof(tp->t_pgrp)))
490174Sbill 			u.u_error = EFAULT;
491174Sbill 		break;
492174Sbill 
493174Sbill 	/*
494174Sbill 	 * Modify local mode word.
495174Sbill 	 */
496174Sbill 	case TIOCLBIS:
497728Sbill 		if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local)))
498728Sbill 			u.u_error = EFAULT;
499728Sbill 		else
500728Sbill 			tp->t_local |= temp;
501174Sbill 		break;
502174Sbill 
503174Sbill 	case TIOCLBIC:
504728Sbill 		if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local)))
505728Sbill 			u.u_error = EFAULT;
506728Sbill 		else
507728Sbill 			tp->t_local &= ~temp;
508174Sbill 		break;
509174Sbill 
510174Sbill 	case TIOCLSET:
511728Sbill 		if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local)))
512728Sbill 			u.u_error = EFAULT;
513728Sbill 		else
514728Sbill 			tp->t_local = temp;
515174Sbill 		break;
516174Sbill 
517174Sbill 	case TIOCLGET:
518174Sbill 		if (copyout((caddr_t)&tp->t_local, addr, sizeof(tp->t_local)))
519174Sbill 			u.u_error = EFAULT;
520174Sbill 		break;
521174Sbill 
522903Sbill 	/*
523903Sbill 	 * Return number of characters in
524903Sbill 	 * the output.
525903Sbill 	 */
526213Sbill 	case TIOCOUTQ:
527213Sbill 		if (copyout((caddr_t)&tp->t_outq.c_cc, addr, sizeof(tp->t_outq.c_cc)))
528213Sbill 			u.u_error = EFAULT;
529213Sbill 		break;
530213Sbill 
531903Sbill 	/*
532903Sbill 	 * Simulate typing of a character at the terminal.
533903Sbill 	 */
534887Sbill 	case TIOCSTI:
535887Sbill 		c = fubyte(addr);
536887Sbill 		if (u.u_uid && u.u_ttyp != tp || c < 0)
537887Sbill 			u.u_error = EFAULT;
538887Sbill 		else
539887Sbill 			(*linesw[tp->t_line].l_rint)(c, tp);
540887Sbill 		break;
5415573Swnj 
5425573Swnj 	case TIOCSTOP:
5435573Swnj 		c = spl5();
5445573Swnj 		if ((tp->t_state & TS_TTSTOP) == 0) {
5455573Swnj 			tp->t_state |= TS_TTSTOP;
5465573Swnj 			(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
5475573Swnj 		}
5485573Swnj 		splx(c);
5495573Swnj 		break;
5505573Swnj 
5515573Swnj 	case TIOCSTART:
5525573Swnj 		c = spl5();
5535573Swnj 		if ((tp->t_state & TS_TTSTOP) || (tp->t_local & LFLUSHO)) {
5545573Swnj 			tp->t_state &= ~TS_TTSTOP;
5555573Swnj 			tp->t_local &= ~LFLUSHO;
5565573Swnj 			ttstart(tp);
5575573Swnj 		}
5585573Swnj 		splx(c);
5595573Swnj 		break;
5605573Swnj 
561174Sbill /* end of locals */
562887Sbill 
56339Sbill 	default:
56439Sbill 		return(0);
56539Sbill 	}
56639Sbill 	return(1);
56739Sbill }
5684484Swnj 
5694484Swnj ttnread(tp)
5704484Swnj 	struct tty *tp;
5714484Swnj {
5724484Swnj 	int nread = 0;
5734484Swnj 
5744484Swnj 	if (tp->t_local & LPENDIN)
5754484Swnj 		ttypend(tp);
5764484Swnj 	nread = tp->t_canq.c_cc;
5774484Swnj 	if (tp->t_flags & (RAW|CBREAK))
5784484Swnj 		nread += tp->t_rawq.c_cc;
5794484Swnj 	return (nread);
5804484Swnj }
5814484Swnj 
5825408Swnj ttselect(dev, rw)
5834484Swnj 	dev_t dev;
5845408Swnj 	int rw;
5854484Swnj {
5864484Swnj 	register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)];
5874484Swnj 	int nread;
5885408Swnj 	int s = spl5();
5894484Swnj 
5905408Swnj 	switch (rw) {
5914484Swnj 
5924484Swnj 	case FREAD:
5934484Swnj 		nread = ttnread(tp);
5944484Swnj 		if (nread > 0)
5955408Swnj 			goto win;
5964938Swnj 		if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait)
5975408Swnj 			tp->t_state |= TS_RCOLL;
5984484Swnj 		else
5994484Swnj 			tp->t_rsel = u.u_procp;
6005408Swnj 		break;
6014484Swnj 
6025408Swnj 	case FWRITE:
6035408Swnj 		if (tp->t_outq.c_cc <= TTLOWAT(tp))
6045408Swnj 			goto win;
6055408Swnj 		if (tp->t_wsel && tp->t_wsel->p_wchan == (caddr_t)&selwait)
6065408Swnj 			tp->t_state |= TS_WCOLL;
6075408Swnj 		else
6085408Swnj 			tp->t_wsel = u.u_procp;
6095408Swnj 		break;
6104484Swnj 	}
6115408Swnj 	splx(s);
6125408Swnj 	return (0);
6135408Swnj win:
6145408Swnj 	splx(s);
6155408Swnj 	return (1);
6164484Swnj }
6177436Skre 
618*7502Sroot #define	OBUFSIZ	100
619*7502Sroot 
620*7502Sroot /*
621*7502Sroot  * routine called on opens while tp->t_line == NTTYDISC
622*7502Sroot  * establishes a process group for distribution of
623*7502Sroot  * quits and interrupts from the tty.
624*7502Sroot  * (actually, pp->p_pgrp can't be 0 when this routine
625*7502Sroot  * is called since NTTYDISC is not the default discipline)
626*7502Sroot  */
627*7502Sroot ttyopen(dev, tp)
628*7502Sroot dev_t dev;
629*7502Sroot register struct tty *tp;
630*7502Sroot {
631*7502Sroot 	register struct proc *pp;
632*7502Sroot 
633*7502Sroot 	pp = u.u_procp;
634*7502Sroot 	tp->t_dev = dev;
635*7502Sroot 	if(pp->p_pgrp == 0) {
636*7502Sroot 		u.u_ttyp = tp;
637*7502Sroot 		u.u_ttyd = dev;
638*7502Sroot 		if (tp->t_pgrp == 0)
639*7502Sroot 			tp->t_pgrp = pp->p_pid;
640*7502Sroot 		pp->p_pgrp = tp->t_pgrp;
641*7502Sroot 	}
642*7502Sroot 	tp->t_state &= ~TS_WOPEN;
643*7502Sroot 	tp->t_state |= TS_ISOPEN;
644*7502Sroot 	if (tp->t_line != NTTYDISC)
645*7502Sroot 		wflushtty(tp);
646*7502Sroot }
647*7502Sroot 
648*7502Sroot /*
649*7502Sroot  * clean tp on last close
650*7502Sroot  */
651*7502Sroot ttyclose(tp)
652*7502Sroot register struct tty *tp;
653*7502Sroot {
654*7502Sroot 
655*7502Sroot 	if (tp->t_line) {
656*7502Sroot 		wflushtty(tp);
657*7502Sroot 		tp->t_line = 0;
658*7502Sroot 		return;
659*7502Sroot 	}
660*7502Sroot 	tp->t_pgrp = 0;
661*7502Sroot 	wflushtty(tp);
662*7502Sroot 	tp->t_state = 0;
663*7502Sroot }
664*7502Sroot 
665*7502Sroot /*
666*7502Sroot  * reinput pending characters after state switch
667*7502Sroot  * call at spl5().
668*7502Sroot  */
669*7502Sroot ttypend(tp)
670*7502Sroot register struct tty *tp;
671*7502Sroot {
672*7502Sroot 	struct clist tq;
673*7502Sroot 	register c;
674*7502Sroot 
675*7502Sroot 	tp->t_local &= ~LPENDIN;
676*7502Sroot 	tp->t_lstate |= LSTYPEN;
677*7502Sroot 	tq = tp->t_rawq;
678*7502Sroot 	tp->t_rawq.c_cc = 0;
679*7502Sroot 	tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0;
680*7502Sroot 	while ((c = getc(&tq)) >= 0)
681*7502Sroot 		ttyinput(c, tp);
682*7502Sroot 	tp->t_lstate &= ~LSTYPEN;
683*7502Sroot }
684*7502Sroot 
685*7502Sroot /*
686*7502Sroot  * Place a character on raw TTY input queue, putting in delimiters
687*7502Sroot  * and waking up top half as needed.
688*7502Sroot  * Also echo if required.
689*7502Sroot  * The arguments are the character and the appropriate
690*7502Sroot  * tty structure.
691*7502Sroot  */
692*7502Sroot ttyinput(c, tp)
693*7502Sroot register c;
694*7502Sroot register struct tty *tp;
695*7502Sroot {
696*7502Sroot 	register int t_flags;
697*7502Sroot 	int i;
698*7502Sroot 
699*7502Sroot 	if (tp->t_local&LPENDIN)
700*7502Sroot 		ttypend(tp);
701*7502Sroot 	tk_nin++;
702*7502Sroot 	c &= 0377;
703*7502Sroot 	t_flags = tp->t_flags;
704*7502Sroot 	if (t_flags&TANDEM)
705*7502Sroot 		ttyblock(tp);
706*7502Sroot 	if ((t_flags&RAW)==0) {
707*7502Sroot 		if ((tp->t_lstate&LSTYPEN) == 0)
708*7502Sroot 			c &= 0177;
709*7502Sroot 	/* check for literal nexting very first */
710*7502Sroot 		if (tp->t_lstate&LSLNCH) {
711*7502Sroot 			c |= 0200;
712*7502Sroot 			tp->t_lstate &= ~LSLNCH;
713*7502Sroot 		}
714*7502Sroot 		if (tp->t_line == NTTYDISC && c==tlun.t_lnextc) {
715*7502Sroot 			if (tp->t_flags&ECHO)
716*7502Sroot 				ttyout("^\b", tp);
717*7502Sroot 			tp->t_lstate |= LSLNCH;
718*7502Sroot 	/* check for output control functions */
719*7502Sroot 		} else if (c==tun.t_stopc) {
720*7502Sroot 			if ((tp->t_state&TS_TTSTOP)==0) {
721*7502Sroot 				tp->t_state |= TS_TTSTOP;
722*7502Sroot 				(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
723*7502Sroot 				return;
724*7502Sroot 			}
725*7502Sroot 			if (c!=tun.t_startc)
726*7502Sroot 				return;
727*7502Sroot 		} else if (c==tun.t_startc) {
728*7502Sroot 			tp->t_state &= ~TS_TTSTOP;
729*7502Sroot 			tp->t_local &= ~LFLUSHO;
730*7502Sroot 			ttstart(tp);
731*7502Sroot 			return;
732*7502Sroot 		} else if (tp->t_line == NTTYDISC && c==tlun.t_flushc) {
733*7502Sroot 			if (tp->t_local & LFLUSHO)
734*7502Sroot 				tp->t_local &= ~LFLUSHO;
735*7502Sroot 			else {
736*7502Sroot 				flushtty(tp, FWRITE);
737*7502Sroot 				ttyecho(c, tp);
738*7502Sroot 				if (tp->t_rawq.c_cc+tp->t_canq.c_cc)
739*7502Sroot 					ttyretype(tp);
740*7502Sroot 				tp->t_local |= LFLUSHO;
741*7502Sroot 			}
742*7502Sroot 			ttstart(tp);
743*7502Sroot 			return;
744*7502Sroot 		} else if (c==tun.t_intrc || c==tun.t_quitc ||
745*7502Sroot 		    (tp->t_line == NTTYDISC && c==tlun.t_suspc)) {
746*7502Sroot 			if ((tp->t_local & LNOFLSH) == 0)
747*7502Sroot 				flushtty(tp,
748*7502Sroot 				    c==tlun.t_suspc ? FREAD : FREAD|FWRITE);
749*7502Sroot 			ttyecho(c, tp);
750*7502Sroot 			c = c==tun.t_intrc ? SIGINT :
751*7502Sroot 				((c==tun.t_quitc) ? SIGQUIT : SIGTSTP);
752*7502Sroot 			ttsignal(tp, c);
753*7502Sroot 	/* check for buffer editing functions - cooked mode */
754*7502Sroot 		} else if ((t_flags&CBREAK) == 0) {
755*7502Sroot 			if ((tp->t_lstate&LSQUOT) &&
756*7502Sroot 			    (c==tp->t_erase||c==tp->t_kill)) {
757*7502Sroot 				ttyrub(unputc(&tp->t_rawq), tp);
758*7502Sroot 				c |= 0200;
759*7502Sroot 			}
760*7502Sroot 			if (c==tp->t_erase) {
761*7502Sroot 				if (tp->t_rawq.c_cc)
762*7502Sroot 					ttyrub(unputc(&tp->t_rawq), tp);
763*7502Sroot 			} else if (c==tp->t_kill) {
764*7502Sroot 				if (tp->t_local&LCRTKIL &&
765*7502Sroot 				    tp->t_rawq.c_cc == tp->t_rocount) {
766*7502Sroot 					while (tp->t_rawq.c_cc)
767*7502Sroot 						ttyrub(unputc(&tp->t_rawq), tp);
768*7502Sroot 				} else {
769*7502Sroot 					ttyecho(c, tp);
770*7502Sroot 					ttyecho('\n', tp);
771*7502Sroot 					while (getc(&tp->t_rawq) > 0)
772*7502Sroot 						;
773*7502Sroot 					tp->t_rocount = 0;
774*7502Sroot 				}
775*7502Sroot 				tp->t_lstate = 0;
776*7502Sroot 			} else if (tp->t_line == NTTYDISC && c==tlun.t_werasc) {
777*7502Sroot 				if (tp->t_rawq.c_cc == 0)
778*7502Sroot 					goto out;
779*7502Sroot 				do {
780*7502Sroot 					c = unputc(&tp->t_rawq);
781*7502Sroot 					if (c != ' ' && c != '\t')
782*7502Sroot 						goto erasenb;
783*7502Sroot 					ttyrub(c, tp);
784*7502Sroot 				} while (tp->t_rawq.c_cc);
785*7502Sroot 				goto out;
786*7502Sroot 			    erasenb:
787*7502Sroot 				do {
788*7502Sroot 					ttyrub(c, tp);
789*7502Sroot 					if (tp->t_rawq.c_cc == 0)
790*7502Sroot 						goto out;
791*7502Sroot 					c = unputc(&tp->t_rawq);
792*7502Sroot 				} while (c != ' ' && c != '\t');
793*7502Sroot 				(void) putc(c, &tp->t_rawq);
794*7502Sroot 			} else if (tp->t_line == NTTYDISC && c==tlun.t_rprntc) {
795*7502Sroot 				ttyretype(tp);
796*7502Sroot 	/* check for cooked mode input buffer overflow */
797*7502Sroot 			} else if (tp->t_rawq.c_cc+tp->t_canq.c_cc >= TTYHOG) {
798*7502Sroot 				;
799*7502Sroot 	/* put data char in q for user and wakeup if a break char */
800*7502Sroot 			} else if (putc(c, &tp->t_rawq) >= 0) {
801*7502Sroot 				if (tp->t_rawq.c_cc+tp->t_canq.c_cc==TTYHOG
802*7502Sroot 				    && tp->t_line == NTTYDISC)
803*7502Sroot 					(void) ttyoutput(CTRL(g), tp);
804*7502Sroot 				if (!ttbreakc(c, tp)) {
805*7502Sroot 					if (tp->t_rocount++ == 0)
806*7502Sroot 						tp->t_rocol = tp->t_col;
807*7502Sroot 				} else {
808*7502Sroot 					tp->t_rocount = 0;
809*7502Sroot 					catq(&tp->t_rawq, &tp->t_canq);
810*7502Sroot 					/* IF (TP->T_CHAN) (VOID) SDATA(TP->T_CHAN); */
811*7502Sroot 					ttwakeup(tp);
812*7502Sroot 				}
813*7502Sroot 				tp->t_lstate &= ~LSQUOT;
814*7502Sroot 				if (c == '\\')
815*7502Sroot 					tp->t_lstate |= LSQUOT;
816*7502Sroot 				if (tp->t_lstate&LSERASE) {
817*7502Sroot 					tp->t_lstate &= ~LSERASE;
818*7502Sroot 					(void) ttyoutput('/', tp);
819*7502Sroot 				}
820*7502Sroot 				i = tp->t_col;
821*7502Sroot 				ttyecho(c, tp);
822*7502Sroot 				if (c==tun.t_eofc && tp->t_flags&ECHO) {
823*7502Sroot 					i = MIN(2, tp->t_col - i);
824*7502Sroot 					while (i > 0) {
825*7502Sroot 						(void) ttyoutput('\b', tp);
826*7502Sroot 						i--;
827*7502Sroot 					}
828*7502Sroot 				}
829*7502Sroot 			}
830*7502Sroot 	/* CBREAK mode */
831*7502Sroot 		} else if (tp->t_rawq.c_cc > TTYHOG) {
832*7502Sroot 			if (tp->t_outq.c_cc < TTHIWAT(tp) &&
833*7502Sroot 			    tp->t_line == NTTYDISC)
834*7502Sroot 				(void) ttyoutput(CTRL(g), tp);
835*7502Sroot 		} else if (putc(c, &tp->t_rawq) >= 0) {
836*7502Sroot 			ttwakeup(tp);
837*7502Sroot 			ttyecho(c, tp);
838*7502Sroot 		}
839*7502Sroot 	/* RAW mode */
840*7502Sroot 	} else if (tp->t_rawq.c_cc > TTYHOG)
841*7502Sroot 		flushtty(tp, FREAD|FWRITE);
842*7502Sroot 	else {
843*7502Sroot 		if (putc(c, &tp->t_rawq) >= 0)
844*7502Sroot 			ttwakeup(tp);
845*7502Sroot 		ttyecho(c, tp);
846*7502Sroot 	}
847*7502Sroot out:
848*7502Sroot 	if (tp->t_local & LDECCTQ && tp->t_state & TS_TTSTOP &&
849*7502Sroot 	    tun.t_startc != tun.t_stopc)
850*7502Sroot 		return;
851*7502Sroot 	tp->t_state &= ~TS_TTSTOP;
852*7502Sroot 	tp->t_local &= ~LFLUSHO;
853*7502Sroot 	ttstart(tp);
854*7502Sroot }
855*7502Sroot 
856*7502Sroot /*
857*7502Sroot  * put character on TTY output queue, adding delays,
858*7502Sroot  * expanding tabs, and handling the CR/NL bit.
859*7502Sroot  * It is called both from the top half for output, and from
860*7502Sroot  * interrupt level for echoing.
861*7502Sroot  * The arguments are the character and the tty structure.
862*7502Sroot  * Returns < 0 if putc succeeds, otherwise returns char to resend
863*7502Sroot  * Must be recursive.
864*7502Sroot  */
865*7502Sroot ttyoutput(c, tp)
866*7502Sroot 	register c;
867*7502Sroot 	register struct tty *tp;
868*7502Sroot {
869*7502Sroot 	register char *colp;
870*7502Sroot 	register ctype;
871*7502Sroot 
872*7502Sroot 	if (tp->t_flags&RAW || tp->t_local&LLITOUT) {
873*7502Sroot 		if (tp->t_local&LFLUSHO)
874*7502Sroot 			return (-1);
875*7502Sroot 		if (putc(c, &tp->t_outq))
876*7502Sroot 			return(c);
877*7502Sroot 		tk_nout++;
878*7502Sroot 		return (-1);
879*7502Sroot 	}
880*7502Sroot 	/*
881*7502Sroot 	 * Ignore EOT in normal mode to avoid hanging up
882*7502Sroot 	 * certain terminals.
883*7502Sroot 	 */
884*7502Sroot 	c &= 0177;
885*7502Sroot 	if (c==CEOT && (tp->t_flags&CBREAK)==0)
886*7502Sroot 		return (-1);
887*7502Sroot 	/*
888*7502Sroot 	 * Turn tabs to spaces as required
889*7502Sroot 	 */
890*7502Sroot 	if (c=='\t' && (tp->t_flags&TBDELAY)==XTABS) {
891*7502Sroot 		register int s;
892*7502Sroot 
893*7502Sroot 		c = 8 - (tp->t_col&7);
894*7502Sroot 		if ((tp->t_local&LFLUSHO) == 0) {
895*7502Sroot 			s = spl5();		/* don't interrupt tabs */
896*7502Sroot 			c -= b_to_q("        ", c, &tp->t_outq);
897*7502Sroot 			tk_nout += c;
898*7502Sroot 			splx(s);
899*7502Sroot 		}
900*7502Sroot 		tp->t_col += c;
901*7502Sroot 		return (c ? -1 : '\t');
902*7502Sroot 	}
903*7502Sroot 	tk_nout++;
904*7502Sroot 	/*
905*7502Sroot 	 * for upper-case-only terminals,
906*7502Sroot 	 * generate escapes.
907*7502Sroot 	 */
908*7502Sroot 	if (tp->t_flags&LCASE) {
909*7502Sroot 		colp = "({)}!|^~'`";
910*7502Sroot 		while(*colp++)
911*7502Sroot 			if(c == *colp++) {
912*7502Sroot 				if (ttyoutput('\\', tp) >= 0)
913*7502Sroot 					return (c);
914*7502Sroot 				c = colp[-2];
915*7502Sroot 				break;
916*7502Sroot 			}
917*7502Sroot 		if ('A'<=c && c<='Z') {
918*7502Sroot 			if (ttyoutput('\\', tp) >= 0)
919*7502Sroot 				return (c);
920*7502Sroot 		} else if ('a'<=c && c<='z')
921*7502Sroot 			c += 'A' - 'a';
922*7502Sroot 	}
923*7502Sroot 	/*
924*7502Sroot 	 * turn <nl> to <cr><lf> if desired.
925*7502Sroot 	 */
926*7502Sroot 	if (c=='\n' && tp->t_flags&CRMOD)
927*7502Sroot 		if (ttyoutput('\r', tp) >= 0)
928*7502Sroot 			return (c);
929*7502Sroot 	if (c=='~' && tp->t_local&LTILDE)
930*7502Sroot 		c = '`';
931*7502Sroot 	if ((tp->t_local&LFLUSHO) == 0 && putc(c, &tp->t_outq))
932*7502Sroot 		return (c);
933*7502Sroot 	/*
934*7502Sroot 	 * Calculate delays.
935*7502Sroot 	 * The numbers here represent clock ticks
936*7502Sroot 	 * and are not necessarily optimal for all terminals.
937*7502Sroot 	 * The delays are indicated by characters above 0200.
938*7502Sroot 	 * In raw mode there are no delays and the
939*7502Sroot 	 * transmission path is 8 bits wide.
940*7502Sroot 	 */
941*7502Sroot 	colp = &tp->t_col;
942*7502Sroot 	ctype = partab[c];
943*7502Sroot 	c = 0;
944*7502Sroot 	switch (ctype&077) {
945*7502Sroot 
946*7502Sroot 	case ORDINARY:
947*7502Sroot 		(*colp)++;
948*7502Sroot 
949*7502Sroot 	case CONTROL:
950*7502Sroot 		break;
951*7502Sroot 
952*7502Sroot 	case BACKSPACE:
953*7502Sroot 		if (*colp)
954*7502Sroot 			(*colp)--;
955*7502Sroot 		break;
956*7502Sroot 
957*7502Sroot 	case NEWLINE:
958*7502Sroot 		ctype = (tp->t_flags >> 8) & 03;
959*7502Sroot 		if(ctype == 1) { /* tty 37 */
960*7502Sroot 			if (*colp)
961*7502Sroot 				c = max(((unsigned)*colp>>4) + 3, (unsigned)6);
962*7502Sroot 		} else
963*7502Sroot 		if(ctype == 2) { /* vt05 */
964*7502Sroot 			c = 6;
965*7502Sroot 		}
966*7502Sroot 		*colp = 0;
967*7502Sroot 		break;
968*7502Sroot 
969*7502Sroot 	case TAB:
970*7502Sroot 		ctype = (tp->t_flags >> 10) & 03;
971*7502Sroot 		if(ctype == 1) { /* tty 37 */
972*7502Sroot 			c = 1 - (*colp | ~07);
973*7502Sroot 			if(c < 5)
974*7502Sroot 				c = 0;
975*7502Sroot 		}
976*7502Sroot 		*colp |= 07;
977*7502Sroot 		(*colp)++;
978*7502Sroot 		break;
979*7502Sroot 
980*7502Sroot 	case VTAB:
981*7502Sroot 		if(tp->t_flags & VTDELAY) /* tty 37 */
982*7502Sroot 			c = 0177;
983*7502Sroot 		break;
984*7502Sroot 
985*7502Sroot 	case RETURN:
986*7502Sroot 		ctype = (tp->t_flags >> 12) & 03;
987*7502Sroot 		if(ctype == 1) { /* tn 300 */
988*7502Sroot 			c = 5;
989*7502Sroot 		} else if(ctype == 2) { /* ti 700 */
990*7502Sroot 			c = 10;
991*7502Sroot 		} else if(ctype == 3) { /* concept 100 */
992*7502Sroot 			int i;
993*7502Sroot 			if ((i = *colp) >= 0)
994*7502Sroot 				for (; i<9; i++)
995*7502Sroot 					(void) putc(0177, &tp->t_outq);
996*7502Sroot 		}
997*7502Sroot 		*colp = 0;
998*7502Sroot 	}
999*7502Sroot 	if(c && (tp->t_local&LFLUSHO) == 0)
1000*7502Sroot 		(void) putc(c|0200, &tp->t_outq);
1001*7502Sroot 	return (-1);
1002*7502Sroot }
1003*7502Sroot 
1004*7502Sroot /*
1005*7502Sroot  * Called from device's read routine after it has
1006*7502Sroot  * calculated the tty-structure given as argument.
1007*7502Sroot  */
1008*7502Sroot ttread(tp)
1009*7502Sroot register struct tty *tp;
1010*7502Sroot {
1011*7502Sroot 	register struct clist *qp;
1012*7502Sroot 	register c, first;
1013*7502Sroot 
1014*7502Sroot 	if ((tp->t_state&TS_CARR_ON)==0)
1015*7502Sroot 		return(0);
1016*7502Sroot loop:
1017*7502Sroot 	(void) spl5();
1018*7502Sroot 	if (tp->t_local&LPENDIN)
1019*7502Sroot 		ttypend(tp);
1020*7502Sroot 	(void) spl0();
1021*7502Sroot 	while (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) {
1022*7502Sroot 		if (u.u_signal[SIGTTIN] == SIG_IGN ||
1023*7502Sroot 		    u.u_signal[SIGTTIN] == SIG_HOLD ||
1024*7502Sroot /*
1025*7502Sroot 		    (u.u_procp->p_flag&SDETACH) ||
1026*7502Sroot */
1027*7502Sroot 		    u.u_procp->p_flag&SVFORK)
1028*7502Sroot 			return (0);
1029*7502Sroot 		gsignal(u.u_procp->p_pgrp, SIGTTIN);
1030*7502Sroot 		sleep((caddr_t)&lbolt, TTIPRI);
1031*7502Sroot 	}
1032*7502Sroot 	if (tp->t_flags&RAW) {
1033*7502Sroot 		(void) spl5();
1034*7502Sroot 		if (tp->t_rawq.c_cc <= 0) {
1035*7502Sroot 			if ((tp->t_state&TS_CARR_ON)==0 ||
1036*7502Sroot 			    (tp->t_state&TS_NBIO)) {
1037*7502Sroot 				(void) spl0();
1038*7502Sroot 				return (0);
1039*7502Sroot 			}
1040*7502Sroot 			sleep((caddr_t)&tp->t_rawq, TTIPRI);
1041*7502Sroot 			(void) spl0();
1042*7502Sroot 			goto loop;
1043*7502Sroot 		}
1044*7502Sroot 		(void) spl0();
1045*7502Sroot 		while (tp->t_rawq.c_cc && passc(getc(&tp->t_rawq))>=0)
1046*7502Sroot 			;
1047*7502Sroot 		return (0);
1048*7502Sroot 	} else {
1049*7502Sroot 		qp = tp->t_flags & CBREAK ? &tp->t_rawq : &tp->t_canq;
1050*7502Sroot 		(void) spl5();
1051*7502Sroot 		if (qp->c_cc <= 0) {
1052*7502Sroot 			if ((tp->t_state&TS_CARR_ON)==0 ||
1053*7502Sroot 			    (tp->t_state&TS_NBIO)) {
1054*7502Sroot 				(void) spl0();
1055*7502Sroot 				return (0);
1056*7502Sroot 			}
1057*7502Sroot 			sleep((caddr_t)&tp->t_rawq, TTIPRI);
1058*7502Sroot 			(void) spl0();
1059*7502Sroot 			goto loop;
1060*7502Sroot 		}
1061*7502Sroot 		(void) spl0();
1062*7502Sroot 		first = 1;
1063*7502Sroot 		while ((c = getc(qp)) >= 0) {
1064*7502Sroot 			if (tp->t_flags&CRMOD && c == '\r')
1065*7502Sroot 				c = '\n';
1066*7502Sroot 			if (tp->t_flags&LCASE && c <= 0177)
1067*7502Sroot 				if (tp->t_lstate&LSBKSL) {
1068*7502Sroot 					if (maptab[c])
1069*7502Sroot 						c = maptab[c];
1070*7502Sroot 					tp->t_lstate &= ~LSBKSL;
1071*7502Sroot 				} else if (c >= 'A' && c <= 'Z')
1072*7502Sroot 					c += 'a' - 'A';
1073*7502Sroot 				else if (c == '\\') {
1074*7502Sroot 					tp->t_lstate |= LSBKSL;
1075*7502Sroot 					continue;
1076*7502Sroot 				}
1077*7502Sroot 			if (c == tlun.t_dsuspc) {
1078*7502Sroot 				ttsignal(tp, SIGTSTP);
1079*7502Sroot 				if (first) {
1080*7502Sroot 					sleep((caddr_t)&lbolt, TTIPRI);
1081*7502Sroot 					goto loop;
1082*7502Sroot 				}
1083*7502Sroot 				break;
1084*7502Sroot 			}
1085*7502Sroot 			if (c == tun.t_eofc && (tp->t_flags&CBREAK)==0)
1086*7502Sroot 				break;
1087*7502Sroot 			if (passc(c & 0177) < 0)
1088*7502Sroot 				break;
1089*7502Sroot 			if ((tp->t_flags&CBREAK)==0 && ttbreakc(c, tp))
1090*7502Sroot 				break;
1091*7502Sroot 			first = 0;
1092*7502Sroot 		}
1093*7502Sroot 		tp->t_lstate &= ~LSBKSL;
1094*7502Sroot 	}
1095*7502Sroot 
1096*7502Sroot 	if (tp->t_state&TS_TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) {
1097*7502Sroot 		if (putc(tun.t_startc, &tp->t_outq)==0) {
1098*7502Sroot 			tp->t_state &= ~TS_TBLOCK;
1099*7502Sroot 			ttstart(tp);
1100*7502Sroot 		}
1101*7502Sroot 		tp->t_char = 0;
1102*7502Sroot 	}
1103*7502Sroot 
1104*7502Sroot 	return (tp->t_rawq.c_cc + tp->t_canq.c_cc);
1105*7502Sroot }
1106*7502Sroot 
1107*7502Sroot /*
1108*7502Sroot  * Called from the device's write routine after it has
1109*7502Sroot  * calculated the tty-structure given as argument.
1110*7502Sroot  */
1111*7502Sroot caddr_t
1112*7502Sroot ttwrite(tp)
1113*7502Sroot register struct tty *tp;
1114*7502Sroot {
1115*7502Sroot #ifdef vax
1116*7502Sroot 	/*
1117*7502Sroot 	 * THE POSITIONING OF CP, CC, AND CE ARE CRITICAL
1118*7502Sroot 	 * AND MUST NOT BE CHANGED WITHOUT PATCHING
1119*7502Sroot 	 * THE 'ASM' INLINES BELOW.  WATCH OUT.
1120*7502Sroot 	 */
1121*7502Sroot #endif
1122*7502Sroot 	register char *cp;
1123*7502Sroot 	register int cc, ce;
1124*7502Sroot 	register i;
1125*7502Sroot 	char obuf[OBUFSIZ];
1126*7502Sroot 	register c;
1127*7502Sroot 	int hiwat = TTHIWAT(tp);
1128*7502Sroot 	int cnt = u.u_count;
1129*7502Sroot 
1130*7502Sroot 	if ((tp->t_state&TS_CARR_ON)==0)
1131*7502Sroot 		return (NULL);
1132*7502Sroot loop:
1133*7502Sroot 	while (u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp &&
1134*7502Sroot 	    (tp->t_local&LTOSTOP) && (u.u_procp->p_flag&SVFORK)==0 &&
1135*7502Sroot 	    u.u_signal[SIGTTOU] != SIG_IGN &&
1136*7502Sroot 	    u.u_signal[SIGTTOU] != SIG_HOLD
1137*7502Sroot /*
1138*7502Sroot 					     &&
1139*7502Sroot 	    (u.u_procp->p_flag&SDETACH)==0) {
1140*7502Sroot */
1141*7502Sroot 	    ) {
1142*7502Sroot 		gsignal(u.u_procp->p_pgrp, SIGTTOU);
1143*7502Sroot 		sleep((caddr_t)&lbolt, TTIPRI);
1144*7502Sroot 	}
1145*7502Sroot 	while (u.u_count) {
1146*7502Sroot 		cc = MIN(u.u_count, OBUFSIZ);
1147*7502Sroot 		cp = obuf;
1148*7502Sroot 		iomove(cp, (unsigned)cc, B_WRITE);
1149*7502Sroot 		if (u.u_error)
1150*7502Sroot 			break;
1151*7502Sroot 		if (tp->t_outq.c_cc > hiwat)
1152*7502Sroot 			goto ovhiwat;
1153*7502Sroot 		if (tp->t_local&LFLUSHO)
1154*7502Sroot 			continue;
1155*7502Sroot 		if (tp->t_flags&LCASE || tp->t_local&LTILDE) {
1156*7502Sroot 			while (cc) {
1157*7502Sroot 				c = *cp++;
1158*7502Sroot 				tp->t_rocount = 0;
1159*7502Sroot 				while((c = ttyoutput(c, tp)) >= 0) {
1160*7502Sroot 					/* out of clists, wait a bit */
1161*7502Sroot 					ttstart(tp);
1162*7502Sroot 					sleep((caddr_t)&lbolt, TTOPRI);
1163*7502Sroot 					tp->t_rocount = 0;
1164*7502Sroot 				}
1165*7502Sroot 				--cc;
1166*7502Sroot 				if (tp->t_outq.c_cc > hiwat)
1167*7502Sroot 					goto ovhiwat;
1168*7502Sroot 			}
1169*7502Sroot 			continue;
1170*7502Sroot 		}
1171*7502Sroot 		while (cc) {
1172*7502Sroot 			if (tp->t_flags&RAW || tp->t_local&LLITOUT)
1173*7502Sroot 				ce = cc;
1174*7502Sroot 			else {
1175*7502Sroot #ifdef vax
1176*7502Sroot 				asm("	scanc	r9,(r10),_partab,$077");
1177*7502Sroot 				asm("	subl3	r0,r9,r8");
1178*7502Sroot #else
1179*7502Sroot 				ce=0;
1180*7502Sroot 				while(((partab[*(unsigned char *)(cp+ce)]&077)==0)&&(ce<cc))
1181*7502Sroot 					ce++;
1182*7502Sroot #endif
1183*7502Sroot 				if (ce==0) {
1184*7502Sroot 					tp->t_rocount = 0;
1185*7502Sroot 					if (ttyoutput(*cp, tp) >= 0) {
1186*7502Sroot 						ttstart(tp);
1187*7502Sroot 						sleep((caddr_t)&lbolt, TTOPRI);
1188*7502Sroot 						continue;
1189*7502Sroot 					}
1190*7502Sroot 					cp++;
1191*7502Sroot 					cc--;
1192*7502Sroot 					if (tp->t_outq.c_cc > hiwat)
1193*7502Sroot 						goto ovhiwat;
1194*7502Sroot 				}
1195*7502Sroot 			}
1196*7502Sroot 			tp->t_rocount = 0;
1197*7502Sroot 			i=b_to_q(cp,ce,&tp->t_outq);
1198*7502Sroot 			ce-=i;
1199*7502Sroot 			tk_nout+=ce;
1200*7502Sroot 			tp->t_col+=ce;
1201*7502Sroot 			cp+=ce;
1202*7502Sroot 			cc-=ce;
1203*7502Sroot 			if (i) {
1204*7502Sroot 				ttstart(tp);
1205*7502Sroot 				sleep((caddr_t)&lbolt, TTOPRI);
1206*7502Sroot 			}
1207*7502Sroot 			if (ce || tp->t_outq.c_cc > hiwat)
1208*7502Sroot 				goto ovhiwat;
1209*7502Sroot 		}
1210*7502Sroot 	}
1211*7502Sroot 	ttstart(tp);
1212*7502Sroot 	return(NULL);
1213*7502Sroot 
1214*7502Sroot ovhiwat:
1215*7502Sroot 	(void) spl5();
1216*7502Sroot 	u.u_base -= cc;
1217*7502Sroot 	u.u_offset -= cc;
1218*7502Sroot 	u.u_count += cc;
1219*7502Sroot 	if (tp->t_outq.c_cc <= hiwat) {
1220*7502Sroot 		(void) spl0();
1221*7502Sroot 		goto loop;
1222*7502Sroot 	}
1223*7502Sroot 	ttstart(tp);
1224*7502Sroot 	if (tp->t_state & TS_NBIO) {
1225*7502Sroot 		if (u.u_count == cnt)
1226*7502Sroot 			u.u_error = EWOULDBLOCK;
1227*7502Sroot 		return (NULL);
1228*7502Sroot 	}
1229*7502Sroot 	tp->t_state |= TS_ASLEEP;
1230*7502Sroot 	sleep((caddr_t)&tp->t_outq, TTOPRI);
1231*7502Sroot 	(void) spl0();
1232*7502Sroot 	goto loop;
1233*7502Sroot }
1234*7502Sroot 
1235*7502Sroot /*
1236*7502Sroot  * Rubout one character from the rawq of tp
1237*7502Sroot  * as cleanly as possible.
1238*7502Sroot  */
1239*7502Sroot ttyrub(c, tp)
1240*7502Sroot register c;
1241*7502Sroot register struct tty *tp;
1242*7502Sroot {
1243*7502Sroot 	register char *cp;
1244*7502Sroot 	register int savecol;
1245*7502Sroot 	int s;
1246*7502Sroot 	char *nextc();
1247*7502Sroot 
1248*7502Sroot 	if ((tp->t_flags&ECHO)==0)
1249*7502Sroot 		return;
1250*7502Sroot 	tp->t_local &= ~LFLUSHO;
1251*7502Sroot 	c &= 0377;
1252*7502Sroot 	if (tp->t_local&LCRTBS) {
1253*7502Sroot 		if (tp->t_rocount == 0) {
1254*7502Sroot 			/*
1255*7502Sroot 			 * Screwed by ttwrite; retype
1256*7502Sroot 			 */
1257*7502Sroot 			ttyretype(tp);
1258*7502Sroot 			return;
1259*7502Sroot 		}
1260*7502Sroot 		if (c==('\t'|0200) || c==('\n'|0200))
1261*7502Sroot 			ttyrubo(tp, 2);
1262*7502Sroot 		else switch(partab[c&=0177] & 0177) {
1263*7502Sroot 
1264*7502Sroot 		case ORDINARY:
1265*7502Sroot 			if (tp->t_flags&LCASE && c >= 'A' && c <= 'Z')
1266*7502Sroot 				ttyrubo(tp, 2);
1267*7502Sroot 			else
1268*7502Sroot 				ttyrubo(tp, 1);
1269*7502Sroot 			break;
1270*7502Sroot 
1271*7502Sroot 		case VTAB:
1272*7502Sroot 		case BACKSPACE:
1273*7502Sroot 		case CONTROL:
1274*7502Sroot 		case RETURN:
1275*7502Sroot 			if (tp->t_local & LCTLECH)
1276*7502Sroot 				ttyrubo(tp, 2);
1277*7502Sroot 			break;
1278*7502Sroot 
1279*7502Sroot 		case TAB:
1280*7502Sroot 			if (tp->t_rocount < tp->t_rawq.c_cc) {
1281*7502Sroot 				ttyretype(tp);
1282*7502Sroot 				return;
1283*7502Sroot 			}
1284*7502Sroot 			s = spl5();
1285*7502Sroot 			savecol = tp->t_col;
1286*7502Sroot 			tp->t_lstate |= LSCNTTB;
1287*7502Sroot 			tp->t_local |= LFLUSHO;
1288*7502Sroot 			tp->t_col = tp->t_rocol;
1289*7502Sroot 			for (cp = tp->t_rawq.c_cf; cp; cp = nextc(&tp->t_rawq, cp))
1290*7502Sroot 				ttyecho(*cp, tp);
1291*7502Sroot 			tp->t_local &= ~LFLUSHO;
1292*7502Sroot 			tp->t_lstate &= ~LSCNTTB;
1293*7502Sroot 			splx(s);
1294*7502Sroot 			/*
1295*7502Sroot 			 * savecol will now be length of the tab
1296*7502Sroot 			 */
1297*7502Sroot 			savecol -= tp->t_col;
1298*7502Sroot 			tp->t_col += savecol;
1299*7502Sroot 			if (savecol > 8)
1300*7502Sroot 				savecol = 8;		/* overflow screw */
1301*7502Sroot 			while (--savecol >= 0)
1302*7502Sroot 				(void) ttyoutput('\b', tp);
1303*7502Sroot 			break;
1304*7502Sroot 
1305*7502Sroot 		default:
1306*7502Sroot 			panic("ttyrub");
1307*7502Sroot 		}
1308*7502Sroot 	} else if (tp->t_local&LPRTERA) {
1309*7502Sroot 		if ((tp->t_lstate&LSERASE) == 0) {
1310*7502Sroot 			(void) ttyoutput('\\', tp);
1311*7502Sroot 			tp->t_lstate |= LSERASE;
1312*7502Sroot 		}
1313*7502Sroot 		ttyecho(c, tp);
1314*7502Sroot 	} else
1315*7502Sroot 		ttyecho(tp->t_erase, tp);
1316*7502Sroot 	tp->t_rocount--;
1317*7502Sroot }
1318*7502Sroot 
1319*7502Sroot /*
1320*7502Sroot  * Crt back over cnt chars perhaps
1321*7502Sroot  * erasing them.
1322*7502Sroot  */
1323*7502Sroot ttyrubo(tp, cnt)
1324*7502Sroot register struct tty *tp;
1325*7502Sroot int cnt;
1326*7502Sroot {
1327*7502Sroot 
1328*7502Sroot 	while (--cnt >= 0)
1329*7502Sroot 		ttyout(tp->t_local&LCRTERA ? "\b \b" : "\b", tp);
1330*7502Sroot }
1331*7502Sroot 
1332*7502Sroot /*
1333*7502Sroot  * Reprint the rawq line.
1334*7502Sroot  * We assume c_cc has already been checked.
1335*7502Sroot  */
1336*7502Sroot ttyretype(tp)
1337*7502Sroot register struct tty *tp;
1338*7502Sroot {
1339*7502Sroot 	register char *cp;
1340*7502Sroot 	char *nextc();
1341*7502Sroot 	int s;
1342*7502Sroot 
1343*7502Sroot 	if (tlun.t_rprntc != 0377)
1344*7502Sroot 		ttyecho(tlun.t_rprntc, tp);
1345*7502Sroot 	(void) ttyoutput('\n', tp);
1346*7502Sroot 	s = spl5();
1347*7502Sroot 	for (cp = tp->t_canq.c_cf; cp; cp = nextc(&tp->t_canq, cp))
1348*7502Sroot 		ttyecho(*cp, tp);
1349*7502Sroot 	for (cp = tp->t_rawq.c_cf; cp; cp = nextc(&tp->t_rawq, cp))
1350*7502Sroot 		ttyecho(*cp, tp);
1351*7502Sroot 	tp->t_lstate &= ~LSERASE;
1352*7502Sroot 	splx(s);
1353*7502Sroot 	tp->t_rocount = tp->t_rawq.c_cc;
1354*7502Sroot 	tp->t_rocol = 0;
1355*7502Sroot }
1356*7502Sroot 
1357*7502Sroot /*
1358*7502Sroot  * Echo a typed character to the terminal
1359*7502Sroot  */
1360*7502Sroot ttyecho(c, tp)
1361*7502Sroot register c;
1362*7502Sroot register struct tty *tp;
1363*7502Sroot {
1364*7502Sroot 
1365*7502Sroot 	if ((tp->t_lstate & LSCNTTB) == 0)
1366*7502Sroot 		tp->t_local &= ~LFLUSHO;
1367*7502Sroot 	if ((tp->t_flags&ECHO) == 0)
1368*7502Sroot 		return;
1369*7502Sroot 	c &= 0377;
1370*7502Sroot 	if (tp->t_flags&RAW) {
1371*7502Sroot 		(void) ttyoutput(c, tp);
1372*7502Sroot 		return;
1373*7502Sroot 	}
1374*7502Sroot 	if (c == '\r' && tp->t_flags&CRMOD)
1375*7502Sroot 		c = '\n';
1376*7502Sroot 	if (tp->t_local&LCTLECH) {
1377*7502Sroot 		if ((c&0177) <= 037 && c!='\t' && c!='\n' || (c&0177)==0177) {
1378*7502Sroot 			(void) ttyoutput('^', tp);
1379*7502Sroot 			c &= 0177;
1380*7502Sroot 			if (c == 0177)
1381*7502Sroot 				c = '?';
1382*7502Sroot 			else if (tp->t_flags&LCASE)
1383*7502Sroot 				c += 'a' - 1;
1384*7502Sroot 			else
1385*7502Sroot 				c += 'A' - 1;
1386*7502Sroot 		}
1387*7502Sroot 	}
1388*7502Sroot 	if ((tp->t_flags&LCASE) && (c >= 'A' && c <= 'Z'))
1389*7502Sroot 		c += 'a' - 'A';
1390*7502Sroot 	(void) ttyoutput(c & 0177, tp);
1391*7502Sroot }
1392*7502Sroot 
1393*7502Sroot /*
1394*7502Sroot  * Is c a break char for tp?
1395*7502Sroot  */
1396*7502Sroot ttbreakc(c, tp)
1397*7502Sroot register c;
1398*7502Sroot register struct tty *tp;
1399*7502Sroot {
1400*7502Sroot 	return (c == '\n' || c == tun.t_eofc || c == tun.t_brkc ||
1401*7502Sroot 		c == '\r' && (tp->t_flags&CRMOD));
1402*7502Sroot }
1403*7502Sroot 
1404*7502Sroot /*
1405*7502Sroot  * send string cp to tp
1406*7502Sroot  */
1407*7502Sroot ttyout(cp, tp)
1408*7502Sroot register char *cp;
1409*7502Sroot register struct tty *tp;
1410*7502Sroot {
1411*7502Sroot 	register char c;
1412*7502Sroot 
1413*7502Sroot 	while (c = *cp++)
1414*7502Sroot 		(void) ttyoutput(c, tp);
1415*7502Sroot }
1416*7502Sroot 
1417*7502Sroot ttwakeup(tp)
1418*7502Sroot 	struct tty *tp;
1419*7502Sroot {
1420*7502Sroot 
1421*7502Sroot 	if (tp->t_rsel) {
1422*7502Sroot 		selwakeup(tp->t_rsel, tp->t_state&TS_RCOLL);
1423*7502Sroot 		tp->t_state &= ~TS_RCOLL;
1424*7502Sroot 		tp->t_rsel = 0;
1425*7502Sroot 	}
1426*7502Sroot 	wakeup((caddr_t)&tp->t_rawq);
1427*7502Sroot }
1428*7502Sroot 
1429*7502Sroot ttsignal(tp, signo)
1430*7502Sroot 	struct tty *tp;
1431*7502Sroot 	int signo;
1432*7502Sroot {
1433*7502Sroot 
1434*7502Sroot 	gsignal(tp->t_pgrp, signo);
1435*7502Sroot }
1436