xref: /original-bsd/sys/kern/tty.c (revision 1f3a482a)
1 /*	tty.c	4.10	81/07/08	*/
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 	/*
386 	 * Set and fetch special characters
387 	 */
388 	case TIOCSETC:
389 		if (copyin(addr, (caddr_t)&tun, sizeof(struct tchars)))
390 			u.u_error = EFAULT;
391 		break;
392 
393 	case TIOCGETC:
394 		if (copyout((caddr_t)&tun, addr, sizeof(struct tchars)))
395 			u.u_error = EFAULT;
396 		break;
397 
398 /* local ioctls */
399 	/*
400 	 * Set/get local special characters.
401 	 */
402 	case TIOCSLTC:
403 		if (copyin(addr, (caddr_t)&tlun, sizeof (struct ltchars)))
404 			u.u_error = EFAULT;
405 		break;
406 
407 	case TIOCGLTC:
408 		if (copyout((caddr_t)&tlun, addr, sizeof (struct ltchars)))
409 			u.u_error = EFAULT;
410 		break;
411 
412 	/*
413 	 * Return number of characters immediately available.
414 	 */
415 	case FIONREAD: {
416 		off_t nread;
417 
418 		switch (tp->t_line) {
419 
420 		case NETLDISC:
421 			nread = tp->t_rec ? tp->t_inbuf : 0;
422 			break;
423 
424 		case 0:
425 			(void) spl5();
426 			while (canon(tp)>=0)
427 				;
428 			(void) spl0();
429 			/* fall into ... */
430 
431 		case NTTYDISC:
432 			if (tp->t_local & LPENDIN)
433 				ntypend(tp);
434 			nread = tp->t_canq.c_cc;
435 			if (tp->t_flags & (RAW|CBREAK))
436 				nread += tp->t_rawq.c_cc;
437 			break;
438 
439 		}
440 		if (copyout((caddr_t)&nread, addr, sizeof (off_t)))
441 			u.u_error = EFAULT;
442 		break;
443 		}
444 
445 	/*
446 	 * Should allow SPGRP and GPGRP only if tty open for reading.
447 	 */
448 	case TIOCSPGRP:
449 		if (copyin(addr, (caddr_t)&tp->t_pgrp, sizeof (tp->t_pgrp)))
450 			u.u_error = EFAULT;
451 		break;
452 
453 	case TIOCGPGRP:
454 		if (copyout((caddr_t)&tp->t_pgrp, addr, sizeof(tp->t_pgrp)))
455 			u.u_error = EFAULT;
456 		break;
457 
458 	/*
459 	 * Modify local mode word.
460 	 */
461 	case TIOCLBIS:
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 TIOCLBIC:
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 TIOCLSET:
476 		if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local)))
477 			u.u_error = EFAULT;
478 		else
479 			tp->t_local = temp;
480 		break;
481 
482 	case TIOCLGET:
483 		if (copyout((caddr_t)&tp->t_local, addr, sizeof(tp->t_local)))
484 			u.u_error = EFAULT;
485 		break;
486 
487 	/*
488 	 * Return number of characters in
489 	 * the output.
490 	 */
491 	case TIOCOUTQ:
492 		if (copyout((caddr_t)&tp->t_outq.c_cc, addr, sizeof(tp->t_outq.c_cc)))
493 			u.u_error = EFAULT;
494 		break;
495 
496 	/*
497 	 * Simulate typing of a character at the terminal.
498 	 */
499 	case TIOCSTI:
500 		c = fubyte(addr);
501 		if (u.u_uid && u.u_ttyp != tp || c < 0)
502 			u.u_error = EFAULT;
503 		else
504 			(*linesw[tp->t_line].l_rint)(c, tp);
505 		break;
506 /* end of locals */
507 
508 	default:
509 		return(0);
510 	}
511 	return(1);
512 }
513