xref: /csrg-svn/sys/kern/tty.c (revision 1904)
1 /*	tty.c	4.3	12/17/80	*/
2 
3 /*
4  * TTY subroutines common to more than one line discipline
5  */
6 #include "../h/param.h"
7 #include "../h/systm.h"
8 #include "../h/dir.h"
9 #include "../h/user.h"
10 #include "../h/tty.h"
11 #include "../h/proc.h"
12 #include "../h/mx.h"
13 #include "../h/inode.h"
14 #include "../h/file.h"
15 #include "../h/reg.h"
16 #include "../h/conf.h"
17 #include "../h/buf.h"
18 #include "../h/dk.h"
19 
20 char	partab[];
21 
22 /*
23  * When running dz's using only SAE (silo alarm) on input
24  * it is necessary to call dzrint() at clock interrupt time.
25  * This is unsafe unless spl5()s in tty code are changed to
26  * spl6()s to block clock interrupts.  Note that the dh driver
27  * currently in use works the same way as the dz, even though
28  * we could try to more intelligently manage its silo.
29  * Thus don't take this out if you have no dz's unless you
30  * change clock.c and dhtimer().
31  */
32 #define	spl5	spl6
33 
34 /*
35  * Input mapping table-- if an entry is non-zero, when the
36  * corresponding character is typed preceded by "\" the escape
37  * sequence is replaced by the table value.  Mostly used for
38  * upper-case only terminals.
39  */
40 
41 char	maptab[] ={
42 	000,000,000,000,000,000,000,000,
43 	000,000,000,000,000,000,000,000,
44 	000,000,000,000,000,000,000,000,
45 	000,000,000,000,000,000,000,000,
46 	000,'|',000,000,000,000,000,'`',
47 	'{','}',000,000,000,000,000,000,
48 	000,000,000,000,000,000,000,000,
49 	000,000,000,000,000,000,000,000,
50 	000,000,000,000,000,000,000,000,
51 	000,000,000,000,000,000,000,000,
52 	000,000,000,000,000,000,000,000,
53 	000,000,000,000,000,000,'~',000,
54 	000,'A','B','C','D','E','F','G',
55 	'H','I','J','K','L','M','N','O',
56 	'P','Q','R','S','T','U','V','W',
57 	'X','Y','Z',000,000,000,000,000,
58 };
59 
60 short	tthiwat[16] =
61    { 100,100,100,100,100,100,100,200,200,400,400,400,650,650,650,650 };
62 short	ttlowat[16] =
63    {  30, 30, 30, 30, 30, 30, 30, 50, 50,120,120,120,125,125,125,125 };
64 
65 #define	OBUFSIZ	100
66 
67 /*
68  * set default control characters.
69  */
70 ttychars(tp)
71 register struct tty *tp;
72 {
73 
74 	tun.t_intrc = CINTR;
75 	tun.t_quitc = CQUIT;
76 	tun.t_startc = CSTART;
77 	tun.t_stopc = CSTOP;
78 	tun.t_eofc = CEOT;
79 	tun.t_brkc = CBRK;
80 	tp->t_erase = CERASE;
81 	tp->t_kill = CKILL;
82 /* begin local */
83 	tlun.t_suspc = CTRL(z);
84 	tlun.t_dsuspc = CTRL(y);
85 	tlun.t_rprntc = CTRL(r);
86 	tlun.t_flushc = CTRL(o);
87 	tlun.t_werasc = CTRL(w);
88 	tlun.t_lnextc = CTRL(v);
89 	tp->t_local = 0;
90 	tp->t_lstate = 0;
91 /* end local */
92 }
93 
94 /*
95  * Wait for output to drain, then flush input waiting.
96  */
97 wflushtty(tp)
98 register struct tty *tp;
99 {
100 
101 	(void) spl5();
102 	while (tp->t_outq.c_cc && tp->t_state&CARR_ON) {
103 		(*tp->t_oproc)(tp);
104 		tp->t_state |= ASLEEP;
105 		sleep((caddr_t)&tp->t_outq, TTOPRI);
106 	}
107 	flushtty(tp, FREAD|FWRITE);
108 	(void) spl0();
109 }
110 
111 /*
112  * flush all TTY queues
113  */
114 flushtty(tp, rw)
115 register struct tty *tp;
116 {
117 	register s;
118 
119 	if (tp->t_line == NETLDISC)
120 		return;
121 	s = spl6();
122 	if (rw & FREAD) {
123 		while (getc(&tp->t_canq) >= 0)
124 			;
125 		wakeup((caddr_t)&tp->t_rawq);
126 	}
127 	if (rw & FWRITE) {
128 		wakeup((caddr_t)&tp->t_outq);
129 		tp->t_state &= ~TTSTOP;
130 		(*cdevsw[major(tp->t_dev)].d_stop)(tp);
131 		while (getc(&tp->t_outq) >= 0)
132 			;
133 	}
134 	if (rw & FREAD) {
135 		while (getc(&tp->t_rawq) >= 0)
136 			;
137 		tp->t_delct = 0;
138 		tp->t_rocount = 0;		/* local */
139 		tp->t_rocol = 0;
140 		tp->t_lstate = 0;
141 	}
142 	splx(s);
143 }
144 
145 /*
146  * Send stop character on input overflow.
147  */
148 ttyblock(tp)
149 register struct tty *tp;
150 {
151 	register x;
152 	x = tp->t_rawq.c_cc + tp->t_canq.c_cc;
153 	if (tp->t_rawq.c_cc > TTYHOG) {
154 		flushtty(tp, FREAD|FWRITE);
155 		tp->t_state &= ~TBLOCK;
156 	}
157 	if (x >= TTYHOG/2) {
158 		if (putc(tun.t_stopc, &tp->t_outq)==0) {
159 			tp->t_state |= TBLOCK;
160 			tp->t_char++;
161 			ttstart(tp);
162 		}
163 	}
164 }
165 
166 /*
167  * Restart typewriter output following a delay
168  * timeout.
169  * The name of the routine is passed to the timeout
170  * subroutine and it is called during a clock interrupt.
171  */
172 ttrstrt(tp)
173 register struct tty *tp;
174 {
175 
176 	tp->t_state &= ~TIMEOUT;
177 	ttstart(tp);
178 }
179 
180 /*
181  * Start output on the typewriter. It is used from the top half
182  * after some characters have been put on the output queue,
183  * from the interrupt routine to transmit the next
184  * character, and after a timeout has finished.
185  */
186 ttstart(tp)
187 register struct tty *tp;
188 {
189 	register s;
190 
191 	s = spl5();
192 	if((tp->t_state&(TIMEOUT|TTSTOP|BUSY)) == 0)
193 		(*tp->t_oproc)(tp);
194 	splx(s);
195 }
196 
197 /*
198  * Common code for tty ioctls.
199  */
200 /*ARGSUSED*/
201 ttioctl(tp, com, addr, flag)
202 register struct tty *tp;
203 caddr_t addr;
204 {
205 	int dev;
206 	unsigned t;
207 	struct sgttyb iocb;
208 	struct clist tq;
209 	extern int nldisp;
210 	register c;
211 	int temp;
212 
213 	/*
214 	 * This is especially so that isatty() will
215 	 * fail when carrier is gone.
216 	 */
217 	if ((tp->t_state&CARR_ON) == 0) {
218 		u.u_error = EBADF;
219 		return (1);
220 	}
221 
222 	dev = tp->t_dev;
223 	/*
224 	 * If the ioctl involves modification,
225 	 * insist on being able to write the device,
226 	 * and hang if in the background.
227 	 */
228 	switch(com) {
229 
230 	case TIOCSETD:
231 	case TIOCSETP:
232 	case TIOCSETN:
233 	case TIOCFLUSH:
234 	case TIOCSETC:
235 	case TIOCSLTC:
236 	case TIOCSPGRP:
237 	case TIOCLBIS:
238 	case TIOCLBIC:
239 	case TIOCLSET:
240 	case TIOCSTI:
241 /* this is reasonable, but impractical...
242 		if ((flag & FWRITE) == 0) {
243 			u.u_error = EBADF;
244 			return (1);
245 		}
246  */
247 		while (tp->t_line == NTTYDISC &&
248 		   u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp &&
249 		   (u.u_procp->p_flag&SVFORK) == 0 &&
250 		   u.u_signal[SIGTTOU] != SIG_IGN &&
251 		   u.u_signal[SIGTTOU] != SIG_HOLD &&
252 		   (u.u_procp->p_flag&SDETACH)==0) {
253 			gsignal(u.u_procp->p_pgrp, SIGTTOU);
254 			sleep((caddr_t)&lbolt, TTOPRI);
255 		}
256 		break;
257 	}
258 
259 	/*
260 	 * Process the ioctl.
261 	 */
262 	switch(com) {
263 
264 	/*
265 	 * Get discipline number
266 	 */
267 	case TIOCGETD:
268 		t = tp->t_line;
269 		if (copyout((caddr_t)&t, addr, sizeof(t)))
270 			u.u_error = EFAULT;
271 		break;
272 
273 	/*
274 	 * Set line discipline
275 	 */
276 	case TIOCSETD:
277 		if (copyin(addr, (caddr_t)&t, sizeof(t))) {
278 			u.u_error = EFAULT;
279 			break;
280 		}
281 		if (t >= nldisp) {
282 			u.u_error = ENXIO;
283 			break;
284 		}
285 		(void) spl5();
286 		if (tp->t_line)
287 			(*linesw[tp->t_line].l_close)(tp);
288 		if (t)
289 			(*linesw[t].l_open)(dev, tp, addr);
290 		if (u.u_error==0)
291 			tp->t_line = t;
292 		(void) spl0();
293 		break;
294 
295 	/*
296 	 * Prevent more opens on channel
297 	 */
298 	case TIOCEXCL:
299 		tp->t_state |= XCLUDE;
300 		break;
301 
302 	case TIOCNXCL:
303 		tp->t_state &= ~XCLUDE;
304 		break;
305 
306 	/*
307 	 * Set new parameters
308 	 */
309 	case TIOCSETP:
310 	case TIOCSETN:
311 		if (copyin(addr, (caddr_t)&iocb, sizeof(iocb))) {
312 			u.u_error = EFAULT;
313 			return(1);
314 		}
315 		(void) spl5();
316 		if (tp->t_line == 0) {
317 			if (com == TIOCSETP)
318 				wflushtty(tp);
319 			while (canon(tp)>=0)
320 				;
321 #ifdef notdef
322 			wakeup((caddr_t)&tp->t_rawq);
323 #endif
324 		} else if (tp->t_line == NTTYDISC) {
325 			if (tp->t_flags&RAW || iocb.sg_flags&RAW ||
326 			    com == TIOCSETP)
327 				wflushtty(tp);
328 			else if ((tp->t_flags&CBREAK) != (iocb.sg_flags&CBREAK)) {
329 				if (iocb.sg_flags & CBREAK) {
330 					catq(&tp->t_rawq, &tp->t_canq);
331 					tq = tp->t_rawq;
332 					tp->t_rawq = tp->t_canq;
333 					tp->t_canq = tq;
334 				} else {
335 					tp->t_local |= LPENDIN;
336 					if (tp->t_canq.c_cc)
337 						panic("ioccom canq");
338 #ifdef notdef
339 					if (tp->t_chan)
340 						(void) sdata(tp->t_chan);
341 					else
342 #endif
343 						wakeup((caddr_t)&tp->t_rawq);
344 				}
345 			}
346 		}
347 		if ((tp->t_state&SPEEDS)==0) {
348 			tp->t_ispeed = iocb.sg_ispeed;
349 			tp->t_ospeed = iocb.sg_ospeed;
350 		}
351 		tp->t_erase = iocb.sg_erase;
352 		tp->t_kill = iocb.sg_kill;
353 		tp->t_flags = iocb.sg_flags;
354 		(void) spl0();
355 		break;
356 
357 	/*
358 	 * Send current parameters to user
359 	 */
360 	case TIOCGETP:
361 		iocb.sg_ispeed = tp->t_ispeed;
362 		iocb.sg_ospeed = tp->t_ospeed;
363 		iocb.sg_erase = tp->t_erase;
364 		iocb.sg_kill = tp->t_kill;
365 		iocb.sg_flags = tp->t_flags;
366 		if (copyout((caddr_t)&iocb, addr, sizeof(iocb)))
367 			u.u_error = EFAULT;
368 		break;
369 
370 	/*
371 	 * Hang up line on last close
372 	 */
373 	case TIOCHPCL:
374 		tp->t_state |= HUPCLS;
375 		break;
376 
377 	case TIOCFLUSH:
378 		flushtty(tp, FREAD|FWRITE);
379 		break;
380 
381 	/*
382 	 * Set and fetch special characters
383 	 */
384 	case TIOCSETC:
385 		if (copyin(addr, (caddr_t)&tun, sizeof(struct tchars)))
386 			u.u_error = EFAULT;
387 		break;
388 
389 	case TIOCGETC:
390 		if (copyout((caddr_t)&tun, addr, sizeof(struct tchars)))
391 			u.u_error = EFAULT;
392 		break;
393 
394 /* local ioctls */
395 	/*
396 	 * Set/get local special characters.
397 	 */
398 	case TIOCSLTC:
399 		if (copyin(addr, (caddr_t)&tlun, sizeof (struct ltchars)))
400 			u.u_error = EFAULT;
401 		break;
402 
403 	case TIOCGLTC:
404 		if (copyout((caddr_t)&tlun, addr, sizeof (struct ltchars)))
405 			u.u_error = EFAULT;
406 		break;
407 
408 	/*
409 	 * Return number of characters immediately available.
410 	 */
411 	case FIONREAD: {
412 		off_t nread;
413 
414 		switch (tp->t_line) {
415 
416 		case NETLDISC:
417 			nread = tp->t_rec ? tp->t_inbuf : 0;
418 			break;
419 
420 		case 0:
421 			(void) spl5();
422 			while (canon(tp)>=0)
423 				;
424 			(void) spl0();
425 			/* fall into ... */
426 
427 		case NTTYDISC:
428 			nread = tp->t_canq.c_cc;
429 			if (tp->t_flags & (RAW|CBREAK))
430 				nread += tp->t_rawq.c_cc;
431 			break;
432 
433 		}
434 		if (copyout((caddr_t)&nread, addr, sizeof (off_t)))
435 			u.u_error = EFAULT;
436 		break;
437 		}
438 
439 	/*
440 	 * Should allow SPGRP and GPGRP only if tty open for reading.
441 	 */
442 	case TIOCSPGRP:
443 		if (copyin(addr, (caddr_t)&tp->t_pgrp, sizeof (tp->t_pgrp)))
444 			u.u_error = EFAULT;
445 		break;
446 
447 	case TIOCGPGRP:
448 		if (copyout((caddr_t)&tp->t_pgrp, addr, sizeof(tp->t_pgrp)))
449 			u.u_error = EFAULT;
450 		break;
451 
452 	/*
453 	 * Modify local mode word.
454 	 */
455 	case TIOCLBIS:
456 		if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local)))
457 			u.u_error = EFAULT;
458 		else
459 			tp->t_local |= temp;
460 		break;
461 
462 	case TIOCLBIC:
463 		if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local)))
464 			u.u_error = EFAULT;
465 		else
466 			tp->t_local &= ~temp;
467 		break;
468 
469 	case TIOCLSET:
470 		if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local)))
471 			u.u_error = EFAULT;
472 		else
473 			tp->t_local = temp;
474 		break;
475 
476 	case TIOCLGET:
477 		if (copyout((caddr_t)&tp->t_local, addr, sizeof(tp->t_local)))
478 			u.u_error = EFAULT;
479 		break;
480 
481 	/*
482 	 * Return number of characters in
483 	 * the output.
484 	 */
485 	case TIOCOUTQ:
486 		if (copyout((caddr_t)&tp->t_outq.c_cc, addr, sizeof(tp->t_outq.c_cc)))
487 			u.u_error = EFAULT;
488 		break;
489 
490 	/*
491 	 * Simulate typing of a character at the terminal.
492 	 */
493 	case TIOCSTI:
494 		c = fubyte(addr);
495 		if (u.u_uid && u.u_ttyp != tp || c < 0)
496 			u.u_error = EFAULT;
497 		else
498 			(*linesw[tp->t_line].l_rint)(c, tp);
499 		break;
500 /* end of locals */
501 
502 	default:
503 		return(0);
504 	}
505 	return(1);
506 }
507