xref: /original-bsd/sys/kern/tty.c (revision e5dafb11)
1 /*	tty.c	4.22	82/03/15	*/
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/inode.h"
13 #include "../h/file.h"
14 #include "../h/reg.h"
15 #include "../h/conf.h"
16 #include "../h/buf.h"
17 #include "../h/dk.h"
18 
19 char	partab[];
20 
21 /*
22  * Input mapping table-- if an entry is non-zero, when the
23  * corresponding character is typed preceded by "\" the escape
24  * sequence is replaced by the table value.  Mostly used for
25  * upper-case only terminals.
26  */
27 
28 char	maptab[] ={
29 	000,000,000,000,000,000,000,000,
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,'`',
34 	'{','}',000,000,000,000,000,000,
35 	000,000,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,
41 	000,'A','B','C','D','E','F','G',
42 	'H','I','J','K','L','M','N','O',
43 	'P','Q','R','S','T','U','V','W',
44 	'X','Y','Z',000,000,000,000,000,
45 };
46 
47 short	tthiwat[16] =
48    { 100,100,100,100,100,100,100,200,200,400,400,400,650,650,650,650 };
49 short	ttlowat[16] =
50    {  30, 30, 30, 30, 30, 30, 30, 50, 50,120,120,120,125,125,125,125 };
51 
52 #define	OBUFSIZ	100
53 
54 /*
55  * set default control characters.
56  */
57 ttychars(tp)
58 register struct tty *tp;
59 {
60 
61 	tun.t_intrc = CINTR;
62 	tun.t_quitc = CQUIT;
63 	tun.t_startc = CSTART;
64 	tun.t_stopc = CSTOP;
65 	tun.t_eofc = CEOT;
66 	tun.t_brkc = CBRK;
67 	tp->t_erase = CERASE;
68 	tp->t_kill = CKILL;
69 /* begin local */
70 	tlun.t_suspc = CTRL(z);
71 	tlun.t_dsuspc = CTRL(y);
72 	tlun.t_rprntc = CTRL(r);
73 	tlun.t_flushc = CTRL(o);
74 	tlun.t_werasc = CTRL(w);
75 	tlun.t_lnextc = CTRL(v);
76 	tp->t_local = 0;
77 	tp->t_lstate = 0;
78 /* end local */
79 }
80 
81 /*
82  * Wait for output to drain, then flush input waiting.
83  */
84 wflushtty(tp)
85 	register struct tty *tp;
86 {
87 
88 	(void) spl5();
89 	while (tp->t_outq.c_cc && tp->t_state&TS_CARR_ON
90 	    && tp->t_oproc) {		/* kludge for pty */
91 		(*tp->t_oproc)(tp);
92 		tp->t_state |= TS_ASLEEP;
93 		sleep((caddr_t)&tp->t_outq, TTOPRI);
94 	}
95 	flushtty(tp, FREAD);
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 	s = spl6();
108 	if (rw & FREAD) {
109 		while (getc(&tp->t_canq) >= 0)
110 			;
111 		wakeup((caddr_t)&tp->t_rawq);
112 	}
113 	if (rw & FWRITE) {
114 		wakeup((caddr_t)&tp->t_outq);
115 		tp->t_state &= ~TS_TTSTOP;
116 		(*cdevsw[major(tp->t_dev)].d_stop)(tp, rw);
117 		while (getc(&tp->t_outq) >= 0)
118 			;
119 	}
120 	if (rw & FREAD) {
121 		while (getc(&tp->t_rawq) >= 0)
122 			;
123 		tp->t_delct = 0;
124 		tp->t_rocount = 0;		/* local */
125 		tp->t_rocol = 0;
126 		tp->t_lstate = 0;
127 	}
128 	splx(s);
129 }
130 
131 /*
132  * Send stop character on input overflow.
133  */
134 ttyblock(tp)
135 register struct tty *tp;
136 {
137 	register x;
138 	x = tp->t_rawq.c_cc + tp->t_canq.c_cc;
139 	if (tp->t_rawq.c_cc > TTYHOG) {
140 		flushtty(tp, FREAD|FWRITE);
141 		tp->t_state &= ~TS_TBLOCK;
142 	}
143 	if (x >= TTYHOG/2) {
144 		if (putc(tun.t_stopc, &tp->t_outq)==0) {
145 			tp->t_state |= TS_TBLOCK;
146 			tp->t_char++;
147 			ttstart(tp);
148 		}
149 	}
150 }
151 
152 /*
153  * Restart typewriter output following a delay
154  * timeout.
155  * The name of the routine is passed to the timeout
156  * subroutine and it is called during a clock interrupt.
157  */
158 ttrstrt(tp)
159 register struct tty *tp;
160 {
161 
162 	if (tp == 0) {
163 		printf("ttrstrt: arg was 0!\n");
164 		return;
165 	}
166 	tp->t_state &= ~TS_TIMEOUT;
167 	ttstart(tp);
168 }
169 
170 /*
171  * Start output on the typewriter. It is used from the top half
172  * after some characters have been put on the output queue,
173  * from the interrupt routine to transmit the next
174  * character, and after a timeout has finished.
175  */
176 ttstart(tp)
177 register struct tty *tp;
178 {
179 	register s;
180 
181 	s = spl5();
182 	if((tp->t_state&(TS_TIMEOUT|TS_TTSTOP|TS_BUSY)) == 0 &&
183 	    tp->t_oproc)		/* kludge for pty */
184 		(*tp->t_oproc)(tp);
185 	splx(s);
186 }
187 
188 /*
189  * Common code for tty ioctls.
190  */
191 /*ARGSUSED*/
192 ttioctl(tp, com, addr, flag)
193 register struct tty *tp;
194 caddr_t addr;
195 {
196 	int dev;
197 	unsigned t;
198 	struct sgttyb iocb;
199 	struct clist tq;
200 	extern int nldisp;
201 	register c;
202 	int temp;
203 
204 	/*
205 	 * This is especially so that isatty() will
206 	 * fail when carrier is gone.
207 	 */
208 	if ((tp->t_state&TS_CARR_ON) == 0) {
209 		u.u_error = EBADF;
210 		return (1);
211 	}
212 
213 	dev = tp->t_dev;
214 	/*
215 	 * If the ioctl involves modification,
216 	 * insist on being able to write the device,
217 	 * and hang if in the background.
218 	 */
219 	switch(com) {
220 
221 	case TIOCSETD:
222 	case TIOCSETP:
223 	case TIOCSETN:
224 	case TIOCFLUSH:
225 	case TIOCSETC:
226 	case TIOCSLTC:
227 	case TIOCSPGRP:
228 	case TIOCLBIS:
229 	case TIOCLBIC:
230 	case TIOCLSET:
231 	case TIOCSTI:
232 /* this is reasonable, but impractical...
233 		if ((flag & FWRITE) == 0) {
234 			u.u_error = EBADF;
235 			return (1);
236 		}
237  */
238 		while (tp->t_line == NTTYDISC &&
239 		   u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp &&
240 		   (u.u_procp->p_flag&SVFORK) == 0 &&
241 		   u.u_signal[SIGTTOU] != SIG_IGN &&
242 		   u.u_signal[SIGTTOU] != SIG_HOLD
243 /*
244 						   &&
245 		   (u.u_procp->p_flag&SDETACH)==0) {
246 */
247 		   ) {
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 |= TS_XCLUDE;
295 		break;
296 
297 	case TIOCNXCL:
298 		tp->t_state &= ~TS_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_flags&RAW || iocb.sg_flags&RAW ||
312 		    com == TIOCSETP)
313 			wflushtty(tp);
314 		else if ((tp->t_flags&CBREAK) != (iocb.sg_flags&CBREAK)) {
315 			if (iocb.sg_flags & CBREAK) {
316 				catq(&tp->t_rawq, &tp->t_canq);
317 				tq = tp->t_rawq;
318 				tp->t_rawq = tp->t_canq;
319 				tp->t_canq = tq;
320 			} else {
321 				tp->t_local |= LPENDIN;
322 				ttwakeup(tp);
323 			}
324 		}
325 		tp->t_ispeed = iocb.sg_ispeed;
326 		tp->t_ospeed = iocb.sg_ospeed;
327 		tp->t_erase = iocb.sg_erase;
328 		tp->t_kill = iocb.sg_kill;
329 		tp->t_flags = iocb.sg_flags;
330 		if (tp->t_flags & RAW) {
331 			tp->t_state &= ~TS_TTSTOP;
332 			ttstart(tp);
333 		}
334 		(void) spl0();
335 		break;
336 
337 	/*
338 	 * Send current parameters to user
339 	 */
340 	case TIOCGETP:
341 		iocb.sg_ispeed = tp->t_ispeed;
342 		iocb.sg_ospeed = tp->t_ospeed;
343 		iocb.sg_erase = tp->t_erase;
344 		iocb.sg_kill = tp->t_kill;
345 		iocb.sg_flags = tp->t_flags;
346 		if (copyout((caddr_t)&iocb, addr, sizeof(iocb)))
347 			u.u_error = EFAULT;
348 		break;
349 
350 	/*
351 	 * Hang up line on last close
352 	 */
353 	case TIOCHPCL:
354 		tp->t_state |= TS_HUPCLS;
355 		break;
356 
357 	case TIOCFLUSH: {
358 		int flags;
359 		if (addr == 0)
360 			flags = FREAD|FWRITE;
361 		else if (copyin(addr, (caddr_t)&flags, sizeof (flags))) {
362 			u.u_error = EFAULT;
363 			return(1);
364 		}
365 		flushtty(tp, flags);
366 		break;
367 	}
368 
369 	case FIONBIO: {
370 		int nbio;
371 		if (copyin(addr, (caddr_t)&nbio, sizeof (nbio))) {
372 			u.u_error = EFAULT;
373 			return(1);
374 		}
375 		if (nbio)
376 			tp->t_state |= TS_NBIO;
377 		else
378 			tp->t_state &= ~TS_NBIO;
379 		break;
380 	}
381 
382 	case FIOASYNC: {
383 		int async;
384 		if (copyin(addr, (caddr_t)&async, sizeof (async))) {
385 			u.u_error = EFAULT;
386 			return(1);
387 		}
388 		if (async)
389 			tp->t_state |= TS_ASYNC;
390 		else
391 			tp->t_state &= ~TS_ASYNC;
392 		break;
393 	}
394 
395 	/*
396 	 * Set and fetch special characters
397 	 */
398 	case TIOCSETC:
399 		if (copyin(addr, (caddr_t)&tun, sizeof(struct tchars)))
400 			u.u_error = EFAULT;
401 		break;
402 
403 	case TIOCGETC:
404 		if (copyout((caddr_t)&tun, addr, sizeof(struct tchars)))
405 			u.u_error = EFAULT;
406 		break;
407 
408 /* local ioctls */
409 	/*
410 	 * Set/get local special characters.
411 	 */
412 	case TIOCSLTC:
413 		if (copyin(addr, (caddr_t)&tlun, sizeof (struct ltchars)))
414 			u.u_error = EFAULT;
415 		break;
416 
417 	case TIOCGLTC:
418 		if (copyout((caddr_t)&tlun, addr, sizeof (struct ltchars)))
419 			u.u_error = EFAULT;
420 		break;
421 
422 	/*
423 	 * Return number of characters immediately available.
424 	 */
425 	case FIONREAD: {
426 		off_t nread = ttnread(tp);
427 		if (copyout((caddr_t)&nread, addr, sizeof (off_t)))
428 			u.u_error = EFAULT;
429 		break;
430 		}
431 
432 	/*
433 	 * Should allow SPGRP and GPGRP only if tty open for reading.
434 	 */
435 	case TIOCSPGRP:
436 		if (copyin(addr, (caddr_t)&tp->t_pgrp, sizeof (tp->t_pgrp)))
437 			u.u_error = EFAULT;
438 		break;
439 
440 	case TIOCGPGRP:
441 		if (copyout((caddr_t)&tp->t_pgrp, addr, sizeof(tp->t_pgrp)))
442 			u.u_error = EFAULT;
443 		break;
444 
445 	/*
446 	 * Modify local mode word.
447 	 */
448 	case TIOCLBIS:
449 		if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local)))
450 			u.u_error = EFAULT;
451 		else
452 			tp->t_local |= temp;
453 		break;
454 
455 	case TIOCLBIC:
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 TIOCLSET:
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 TIOCLGET:
470 		if (copyout((caddr_t)&tp->t_local, addr, sizeof(tp->t_local)))
471 			u.u_error = EFAULT;
472 		break;
473 
474 	/*
475 	 * Return number of characters in
476 	 * the output.
477 	 */
478 	case TIOCOUTQ:
479 		if (copyout((caddr_t)&tp->t_outq.c_cc, addr, sizeof(tp->t_outq.c_cc)))
480 			u.u_error = EFAULT;
481 		break;
482 
483 	/*
484 	 * Simulate typing of a character at the terminal.
485 	 */
486 	case TIOCSTI:
487 		c = fubyte(addr);
488 		if (u.u_uid && u.u_ttyp != tp || c < 0)
489 			u.u_error = EFAULT;
490 		else
491 			(*linesw[tp->t_line].l_rint)(c, tp);
492 		break;
493 
494 	case TIOCSTOP:
495 		c = spl5();
496 		if ((tp->t_state & TS_TTSTOP) == 0) {
497 			tp->t_state |= TS_TTSTOP;
498 			(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
499 		}
500 		splx(c);
501 		break;
502 
503 	case TIOCSTART:
504 		c = spl5();
505 		if ((tp->t_state & TS_TTSTOP) || (tp->t_local & LFLUSHO)) {
506 			tp->t_state &= ~TS_TTSTOP;
507 			tp->t_local &= ~LFLUSHO;
508 			ttstart(tp);
509 		}
510 		splx(c);
511 		break;
512 
513 /* end of locals */
514 
515 	default:
516 		return(0);
517 	}
518 	return(1);
519 }
520 
521 ttnread(tp)
522 	struct tty *tp;
523 {
524 	int nread = 0;
525 
526 	if (tp->t_local & LPENDIN)
527 		ttypend(tp);
528 	nread = tp->t_canq.c_cc;
529 	if (tp->t_flags & (RAW|CBREAK))
530 		nread += tp->t_rawq.c_cc;
531 	return (nread);
532 }
533 
534 ttselect(dev, rw)
535 	dev_t dev;
536 	int rw;
537 {
538 	register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)];
539 	int nread;
540 	int s = spl5();
541 
542 	switch (rw) {
543 
544 	case FREAD:
545 		nread = ttnread(tp);
546 		if (nread > 0)
547 			goto win;
548 		if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait)
549 			tp->t_state |= TS_RCOLL;
550 		else
551 			tp->t_rsel = u.u_procp;
552 		break;
553 
554 	case FWRITE:
555 		if (tp->t_outq.c_cc <= TTLOWAT(tp))
556 			goto win;
557 		if (tp->t_wsel && tp->t_wsel->p_wchan == (caddr_t)&selwait)
558 			tp->t_state |= TS_WCOLL;
559 		else
560 			tp->t_wsel = u.u_procp;
561 		break;
562 	}
563 	splx(s);
564 	return (0);
565 win:
566 	splx(s);
567 	return (1);
568 }
569