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