xref: /csrg-svn/sys/kern/tty.c (revision 1780)
1 /*	tty.c	4.2	11/09/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(com, tp, addr, dev, flag)
202 register struct tty *tp;
203 caddr_t addr;
204 {
205 	unsigned t;
206 	struct sgttyb iocb;
207 	struct clist tq;
208 	extern int nldisp;
209 	register c;
210 	int temp;
211 
212 	/*
213 	 * This is especially so that isatty() will
214 	 * fail when carrier is gone.
215 	 */
216 	if ((tp->t_state&CARR_ON) == 0) {
217 		u.u_error = EBADF;
218 		return (1);
219 	}
220 
221 	/*
222 	 * If the ioctl involves modification,
223 	 * insist on being able to write the device,
224 	 * and hang if in the background.
225 	 */
226 	switch(com) {
227 
228 	case TIOCSETD:
229 	case TIOCSETP:
230 	case TIOCSETN:
231 	case TIOCFLUSH:
232 	case TIOCSETC:
233 	case TIOCSLTC:
234 	case TIOCSPGRP:
235 	case TIOCLBIS:
236 	case TIOCLBIC:
237 	case TIOCLSET:
238 	case TIOCSTI:
239 /* this is reasonable, but impractical...
240 		if ((flag & FWRITE) == 0) {
241 			u.u_error = EBADF;
242 			return (1);
243 		}
244  */
245 		while (tp->t_line == NTTYDISC &&
246 		   u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp &&
247 		   (u.u_procp->p_flag&SVFORK) == 0 &&
248 		   u.u_signal[SIGTTOU] != SIG_IGN &&
249 		   u.u_signal[SIGTTOU] != SIG_HOLD &&
250 		   (u.u_procp->p_flag&SDETACH)==0) {
251 			gsignal(u.u_procp->p_pgrp, SIGTTOU);
252 			sleep((caddr_t)&lbolt, TTOPRI);
253 		}
254 		break;
255 	}
256 
257 	/*
258 	 * Process the ioctl.
259 	 */
260 	switch(com) {
261 
262 	/*
263 	 * Get discipline number
264 	 */
265 	case TIOCGETD:
266 		t = tp->t_line;
267 		if (copyout((caddr_t)&t, addr, sizeof(t)))
268 			u.u_error = EFAULT;
269 		break;
270 
271 	/*
272 	 * Set line discipline
273 	 */
274 	case TIOCSETD:
275 		if (copyin(addr, (caddr_t)&t, sizeof(t))) {
276 			u.u_error = EFAULT;
277 			break;
278 		}
279 		if (t >= nldisp) {
280 			u.u_error = ENXIO;
281 			break;
282 		}
283 		(void) spl5();
284 		if (tp->t_line)
285 			(*linesw[tp->t_line].l_close)(tp);
286 		if (t)
287 			(*linesw[t].l_open)(dev, tp, addr);
288 		if (u.u_error==0)
289 			tp->t_line = t;
290 		(void) spl0();
291 		break;
292 
293 	/*
294 	 * Prevent more opens on channel
295 	 */
296 	case TIOCEXCL:
297 		tp->t_state |= XCLUDE;
298 		break;
299 
300 	case TIOCNXCL:
301 		tp->t_state &= ~XCLUDE;
302 		break;
303 
304 	/*
305 	 * Set new parameters
306 	 */
307 	case TIOCSETP:
308 	case TIOCSETN:
309 		if (copyin(addr, (caddr_t)&iocb, sizeof(iocb))) {
310 			u.u_error = EFAULT;
311 			return(1);
312 		}
313 		(void) spl5();
314 		if (tp->t_line == 0) {
315 			if (com == TIOCSETP)
316 				wflushtty(tp);
317 			while (canon(tp)>=0)
318 				;
319 #ifdef notdef
320 			wakeup((caddr_t)&tp->t_rawq);
321 #endif
322 		} else if (tp->t_line == NTTYDISC) {
323 			if (tp->t_flags&RAW || iocb.sg_flags&RAW ||
324 			    com == TIOCSETP)
325 				wflushtty(tp);
326 			else if ((tp->t_flags&CBREAK) != (iocb.sg_flags&CBREAK)) {
327 				if (iocb.sg_flags & CBREAK) {
328 					catq(&tp->t_rawq, &tp->t_canq);
329 					tq = tp->t_rawq;
330 					tp->t_rawq = tp->t_canq;
331 					tp->t_canq = tq;
332 				} else {
333 					tp->t_local |= LPENDIN;
334 					if (tp->t_canq.c_cc)
335 						panic("ioccom canq");
336 #ifdef notdef
337 					if (tp->t_chan)
338 						(void) sdata(tp->t_chan);
339 					else
340 #endif
341 						wakeup((caddr_t)&tp->t_rawq);
342 				}
343 			}
344 		}
345 		if ((tp->t_state&SPEEDS)==0) {
346 			tp->t_ispeed = iocb.sg_ispeed;
347 			tp->t_ospeed = iocb.sg_ospeed;
348 		}
349 		tp->t_erase = iocb.sg_erase;
350 		tp->t_kill = iocb.sg_kill;
351 		tp->t_flags = iocb.sg_flags;
352 		(void) spl0();
353 		break;
354 
355 	/*
356 	 * Send current parameters to user
357 	 */
358 	case TIOCGETP:
359 		iocb.sg_ispeed = tp->t_ispeed;
360 		iocb.sg_ospeed = tp->t_ospeed;
361 		iocb.sg_erase = tp->t_erase;
362 		iocb.sg_kill = tp->t_kill;
363 		iocb.sg_flags = tp->t_flags;
364 		if (copyout((caddr_t)&iocb, addr, sizeof(iocb)))
365 			u.u_error = EFAULT;
366 		break;
367 
368 	/*
369 	 * Hang up line on last close
370 	 */
371 	case TIOCHPCL:
372 		tp->t_state |= HUPCLS;
373 		break;
374 
375 	case TIOCFLUSH:
376 		flushtty(tp, FREAD|FWRITE);
377 		break;
378 
379 	/*
380 	 * Ioctl entries to line discipline
381 	 */
382 	case DIOCSETP:
383 	case DIOCGETP:
384 		if ((*linesw[tp->t_line].l_ioctl)(com, tp, addr))
385 			u.u_error = ENOTTY;
386 		break;
387 
388 	/*
389 	 * Set and fetch special characters
390 	 */
391 	case TIOCSETC:
392 		if (copyin(addr, (caddr_t)&tun, sizeof(struct tchars)))
393 			u.u_error = EFAULT;
394 		break;
395 
396 	case TIOCGETC:
397 		if (copyout((caddr_t)&tun, addr, sizeof(struct tchars)))
398 			u.u_error = EFAULT;
399 		break;
400 
401 /* local ioctls */
402 	/*
403 	 * Set/get local special characters.
404 	 */
405 	case TIOCSLTC:
406 		if (copyin(addr, (caddr_t)&tlun, sizeof (struct ltchars)))
407 			u.u_error = EFAULT;
408 		break;
409 
410 	case TIOCGLTC:
411 		if (copyout((caddr_t)&tlun, addr, sizeof (struct ltchars)))
412 			u.u_error = EFAULT;
413 		break;
414 
415 	/*
416 	 * Return number of characters immediately available.
417 	 */
418 	case FIONREAD: {
419 		off_t nread;
420 
421 		switch (tp->t_line) {
422 
423 		case NETLDISC:
424 			nread = tp->t_rec ? tp->t_inbuf : 0;
425 			break;
426 
427 		case 0:
428 			(void) spl5();
429 			while (canon(tp)>=0)
430 				;
431 			(void) spl0();
432 			/* fall into ... */
433 
434 		case NTTYDISC:
435 			nread = tp->t_canq.c_cc;
436 			if (tp->t_flags & (RAW|CBREAK))
437 				nread += tp->t_rawq.c_cc;
438 			break;
439 
440 		}
441 		if (copyout((caddr_t)&nread, addr, sizeof (off_t)))
442 			u.u_error = EFAULT;
443 		break;
444 		}
445 
446 	/*
447 	 * Should allow SPGRP and GPGRP only if tty open for reading.
448 	 */
449 	case TIOCSPGRP:
450 		if (copyin(addr, (caddr_t)&tp->t_pgrp, sizeof (tp->t_pgrp)))
451 			u.u_error = EFAULT;
452 		break;
453 
454 	case TIOCGPGRP:
455 		if (copyout((caddr_t)&tp->t_pgrp, addr, sizeof(tp->t_pgrp)))
456 			u.u_error = EFAULT;
457 		break;
458 
459 	/*
460 	 * Modify local mode word.
461 	 */
462 	case TIOCLBIS:
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 TIOCLBIC:
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 TIOCLSET:
477 		if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local)))
478 			u.u_error = EFAULT;
479 		else
480 			tp->t_local = temp;
481 		break;
482 
483 	case TIOCLGET:
484 		if (copyout((caddr_t)&tp->t_local, addr, sizeof(tp->t_local)))
485 			u.u_error = EFAULT;
486 		break;
487 
488 	/*
489 	 * Return number of characters in
490 	 * the output.
491 	 */
492 	case TIOCOUTQ:
493 		if (copyout((caddr_t)&tp->t_outq.c_cc, addr, sizeof(tp->t_outq.c_cc)))
494 			u.u_error = EFAULT;
495 		break;
496 
497 	/*
498 	 * Simulate typing of a character at the terminal.
499 	 */
500 	case TIOCSTI:
501 		c = fubyte(addr);
502 		if (u.u_uid && u.u_ttyp != tp || c < 0)
503 			u.u_error = EFAULT;
504 		else
505 			(*linesw[tp->t_line].l_rint)(c, tp);
506 		break;
507 /* end of locals */
508 
509 	default:
510 		return(0);
511 	}
512 	return(1);
513 }
514