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