xref: /csrg-svn/sys/kern/tty.c (revision 7436)
1*7436Skre /*	tty.c	4.23	82/07/15	*/
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 
19*7436Skre /*
20*7436Skre  * Table giving parity for characters and indicating
21*7436Skre  * character classes to tty driver.  In particular,
22*7436Skre  * if the low 6 bits are 0, then the character needs
23*7436Skre  * no special processing on output.
24*7436Skre  */
2539Sbill 
26*7436Skre char partab[] = {
27*7436Skre 	0001,0201,0201,0001,0201,0001,0001,0201,
28*7436Skre 	0202,0004,0003,0201,0005,0206,0201,0001,
29*7436Skre 	0201,0001,0001,0201,0001,0201,0201,0001,
30*7436Skre 	0001,0201,0201,0001,0201,0001,0001,0201,
31*7436Skre 	0200,0000,0000,0200,0000,0200,0200,0000,
32*7436Skre 	0000,0200,0200,0000,0200,0000,0000,0200,
33*7436Skre 	0000,0200,0200,0000,0200,0000,0000,0200,
34*7436Skre 	0200,0000,0000,0200,0000,0200,0200,0000,
35*7436Skre 	0200,0000,0000,0200,0000,0200,0200,0000,
36*7436Skre 	0000,0200,0200,0000,0200,0000,0000,0200,
37*7436Skre 	0000,0200,0200,0000,0200,0000,0000,0200,
38*7436Skre 	0200,0000,0000,0200,0000,0200,0200,0000,
39*7436Skre 	0000,0200,0200,0000,0200,0000,0000,0200,
40*7436Skre 	0200,0000,0000,0200,0000,0200,0200,0000,
41*7436Skre 	0200,0000,0000,0200,0000,0200,0200,0000,
42*7436Skre 	0000,0200,0200,0000,0200,0000,0000,0201,
43*7436Skre 
44*7436Skre 	/*
45*7436Skre 	 * 7 bit ascii ends with the last character above,
46*7436Skre 	 * but we contine through all 256 codes for the sake
47*7436Skre 	 * of the tty output routines which use special vax
48*7436Skre 	 * instructions which need a 256 character trt table.
49*7436Skre 	 */
50*7436Skre 
51*7436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
52*7436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
53*7436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
54*7436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
55*7436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
56*7436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
57*7436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
58*7436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
59*7436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
60*7436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
61*7436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
62*7436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
63*7436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
64*7436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
65*7436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
66*7436Skre 	0007,0007,0007,0007,0007,0007,0007,0007
67*7436Skre };
68*7436Skre 
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 }
617*7436Skre 
618