xref: /csrg-svn/sys/kern/tty.c (revision 5614)
1 /*	tty.c	4.19	82/01/24	*/
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)(tp);
91 		tp->t_state |= TS_ASLEEP;
92 		sleep((caddr_t)&tp->t_outq, TTOPRI);
93 	}
94 	flushtty(tp, FREAD);
95 	(void) spl0();
96 }
97 
98 /*
99  * flush all TTY queues
100  */
101 flushtty(tp, rw)
102 register struct tty *tp;
103 {
104 	register s;
105 
106 	s = spl6();
107 	if (rw & FREAD) {
108 		while (getc(&tp->t_canq) >= 0)
109 			;
110 		wakeup((caddr_t)&tp->t_rawq);
111 	}
112 	if (rw & FWRITE) {
113 		wakeup((caddr_t)&tp->t_outq);
114 		tp->t_state &= ~TS_TTSTOP;
115 		(*cdevsw[major(tp->t_dev)].d_stop)(tp, rw);
116 		while (getc(&tp->t_outq) >= 0)
117 			;
118 	}
119 	if (rw & FREAD) {
120 		while (getc(&tp->t_rawq) >= 0)
121 			;
122 		tp->t_delct = 0;
123 		tp->t_rocount = 0;		/* local */
124 		tp->t_rocol = 0;
125 		tp->t_lstate = 0;
126 	}
127 	splx(s);
128 }
129 
130 /*
131  * Send stop character on input overflow.
132  */
133 ttyblock(tp)
134 register struct tty *tp;
135 {
136 	register x;
137 	x = tp->t_rawq.c_cc + tp->t_canq.c_cc;
138 	if (tp->t_rawq.c_cc > TTYHOG) {
139 		flushtty(tp, FREAD|FWRITE);
140 		tp->t_state &= ~TS_TBLOCK;
141 	}
142 	if (x >= TTYHOG/2) {
143 		if (putc(tun.t_stopc, &tp->t_outq)==0) {
144 			tp->t_state |= TS_TBLOCK;
145 			tp->t_char++;
146 			ttstart(tp);
147 		}
148 	}
149 }
150 
151 /*
152  * Restart typewriter output following a delay
153  * timeout.
154  * The name of the routine is passed to the timeout
155  * subroutine and it is called during a clock interrupt.
156  */
157 ttrstrt(tp)
158 register struct tty *tp;
159 {
160 
161 	if (tp == 0) {
162 		printf("ttrstrt: arg was 0!\n");
163 		return;
164 	}
165 	tp->t_state &= ~TS_TIMEOUT;
166 	ttstart(tp);
167 }
168 
169 /*
170  * Start output on the typewriter. It is used from the top half
171  * after some characters have been put on the output queue,
172  * from the interrupt routine to transmit the next
173  * character, and after a timeout has finished.
174  */
175 ttstart(tp)
176 register struct tty *tp;
177 {
178 	register s;
179 
180 	s = spl5();
181 	if((tp->t_state&(TS_TIMEOUT|TS_TTSTOP|TS_BUSY)) == 0)
182 		(*tp->t_oproc)(tp);
183 	splx(s);
184 }
185 
186 /*
187  * Common code for tty ioctls.
188  */
189 /*ARGSUSED*/
190 ttioctl(tp, com, addr, flag)
191 register struct tty *tp;
192 caddr_t addr;
193 {
194 	int dev;
195 	unsigned t;
196 	struct sgttyb iocb;
197 	struct clist tq;
198 	extern int nldisp;
199 	register c;
200 	int temp;
201 
202 	/*
203 	 * This is especially so that isatty() will
204 	 * fail when carrier is gone.
205 	 */
206 	if ((tp->t_state&TS_CARR_ON) == 0) {
207 		u.u_error = EBADF;
208 		return (1);
209 	}
210 
211 	dev = tp->t_dev;
212 	/*
213 	 * If the ioctl involves modification,
214 	 * insist on being able to write the device,
215 	 * and hang if in the background.
216 	 */
217 	switch(com) {
218 
219 	case TIOCSETD:
220 	case TIOCSETP:
221 	case TIOCSETN:
222 	case TIOCFLUSH:
223 	case TIOCSETC:
224 	case TIOCSLTC:
225 	case TIOCSPGRP:
226 	case TIOCLBIS:
227 	case TIOCLBIC:
228 	case TIOCLSET:
229 	case TIOCSTI:
230 /* this is reasonable, but impractical...
231 		if ((flag & FWRITE) == 0) {
232 			u.u_error = EBADF;
233 			return (1);
234 		}
235  */
236 		while (tp->t_line == NTTYDISC &&
237 		   u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp &&
238 		   (u.u_procp->p_flag&SVFORK) == 0 &&
239 		   u.u_signal[SIGTTOU] != SIG_IGN &&
240 		   u.u_signal[SIGTTOU] != SIG_HOLD &&
241 		   (u.u_procp->p_flag&SDETACH)==0) {
242 			gsignal(u.u_procp->p_pgrp, SIGTTOU);
243 			sleep((caddr_t)&lbolt, TTOPRI);
244 		}
245 		break;
246 	}
247 
248 	/*
249 	 * Process the ioctl.
250 	 */
251 	switch(com) {
252 
253 	/*
254 	 * Get discipline number
255 	 */
256 	case TIOCGETD:
257 		t = tp->t_line;
258 		if (copyout((caddr_t)&t, addr, sizeof(t)))
259 			u.u_error = EFAULT;
260 		break;
261 
262 	/*
263 	 * Set line discipline
264 	 */
265 	case TIOCSETD:
266 		if (copyin(addr, (caddr_t)&t, sizeof(t))) {
267 			u.u_error = EFAULT;
268 			break;
269 		}
270 		if (t >= nldisp) {
271 			u.u_error = ENXIO;
272 			break;
273 		}
274 		(void) spl5();
275 		if (tp->t_line)
276 			(*linesw[tp->t_line].l_close)(tp);
277 		if (t)
278 			(*linesw[t].l_open)(dev, tp, addr);
279 		if (u.u_error==0)
280 			tp->t_line = t;
281 		(void) spl0();
282 		break;
283 
284 	/*
285 	 * Prevent more opens on channel
286 	 */
287 	case TIOCEXCL:
288 		tp->t_state |= TS_XCLUDE;
289 		break;
290 
291 	case TIOCNXCL:
292 		tp->t_state &= ~TS_XCLUDE;
293 		break;
294 
295 	/*
296 	 * Set new parameters
297 	 */
298 	case TIOCSETP:
299 	case TIOCSETN:
300 		if (copyin(addr, (caddr_t)&iocb, sizeof(iocb))) {
301 			u.u_error = EFAULT;
302 			return(1);
303 		}
304 		(void) spl5();
305 		if (tp->t_flags&RAW || iocb.sg_flags&RAW ||
306 		    com == TIOCSETP)
307 			wflushtty(tp);
308 		else if ((tp->t_flags&CBREAK) != (iocb.sg_flags&CBREAK)) {
309 			if (iocb.sg_flags & CBREAK) {
310 				catq(&tp->t_rawq, &tp->t_canq);
311 				tq = tp->t_rawq;
312 				tp->t_rawq = tp->t_canq;
313 				tp->t_canq = tq;
314 			} else {
315 				tp->t_local |= LPENDIN;
316 				ttwakeup(tp);
317 			}
318 		}
319 		tp->t_ispeed = iocb.sg_ispeed;
320 		tp->t_ospeed = iocb.sg_ospeed;
321 		tp->t_erase = iocb.sg_erase;
322 		tp->t_kill = iocb.sg_kill;
323 		tp->t_flags = iocb.sg_flags;
324 		if (tp->t_flags & RAW) {
325 			tp->t_state &= ~TS_TTSTOP;
326 			ttstart(tp);
327 		}
328 		(void) spl0();
329 		break;
330 
331 	/*
332 	 * Send current parameters to user
333 	 */
334 	case TIOCGETP:
335 		iocb.sg_ispeed = tp->t_ispeed;
336 		iocb.sg_ospeed = tp->t_ospeed;
337 		iocb.sg_erase = tp->t_erase;
338 		iocb.sg_kill = tp->t_kill;
339 		iocb.sg_flags = tp->t_flags;
340 		if (copyout((caddr_t)&iocb, addr, sizeof(iocb)))
341 			u.u_error = EFAULT;
342 		break;
343 
344 	/*
345 	 * Hang up line on last close
346 	 */
347 	case TIOCHPCL:
348 		tp->t_state |= TS_HUPCLS;
349 		break;
350 
351 	case TIOCFLUSH: {
352 		int flags;
353 		if (addr == 0)
354 			flags = FREAD|FWRITE;
355 		else if (copyin(addr, (caddr_t)&flags, sizeof (flags))) {
356 			u.u_error = EFAULT;
357 			return(1);
358 		}
359 		flushtty(tp, flags);
360 		break;
361 	}
362 
363 	case FIONBIO: {
364 		int nbio;
365 		if (copyin(addr, (caddr_t)&nbio, sizeof (nbio))) {
366 			u.u_error = EFAULT;
367 			return(1);
368 		}
369 		if (nbio)
370 			tp->t_state |= TS_NBIO;
371 		else
372 			tp->t_state &= ~TS_NBIO;
373 		break;
374 	}
375 
376 	/*
377 	 * Set and fetch special characters
378 	 */
379 	case TIOCSETC:
380 		if (copyin(addr, (caddr_t)&tun, sizeof(struct tchars)))
381 			u.u_error = EFAULT;
382 		break;
383 
384 	case TIOCGETC:
385 		if (copyout((caddr_t)&tun, addr, sizeof(struct tchars)))
386 			u.u_error = EFAULT;
387 		break;
388 
389 /* local ioctls */
390 	/*
391 	 * Set/get local special characters.
392 	 */
393 	case TIOCSLTC:
394 		if (copyin(addr, (caddr_t)&tlun, sizeof (struct ltchars)))
395 			u.u_error = EFAULT;
396 		break;
397 
398 	case TIOCGLTC:
399 		if (copyout((caddr_t)&tlun, addr, sizeof (struct ltchars)))
400 			u.u_error = EFAULT;
401 		break;
402 
403 	/*
404 	 * Return number of characters immediately available.
405 	 */
406 	case FIONREAD: {
407 		off_t nread = ttnread(tp);
408 		if (copyout((caddr_t)&nread, addr, sizeof (off_t)))
409 			u.u_error = EFAULT;
410 		break;
411 		}
412 
413 	/*
414 	 * Should allow SPGRP and GPGRP only if tty open for reading.
415 	 */
416 	case TIOCSPGRP:
417 		if (copyin(addr, (caddr_t)&tp->t_pgrp, sizeof (tp->t_pgrp)))
418 			u.u_error = EFAULT;
419 		break;
420 
421 	case TIOCGPGRP:
422 		if (copyout((caddr_t)&tp->t_pgrp, addr, sizeof(tp->t_pgrp)))
423 			u.u_error = EFAULT;
424 		break;
425 
426 	/*
427 	 * Modify local mode word.
428 	 */
429 	case TIOCLBIS:
430 		if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local)))
431 			u.u_error = EFAULT;
432 		else
433 			tp->t_local |= temp;
434 		break;
435 
436 	case TIOCLBIC:
437 		if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local)))
438 			u.u_error = EFAULT;
439 		else
440 			tp->t_local &= ~temp;
441 		break;
442 
443 	case TIOCLSET:
444 		if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local)))
445 			u.u_error = EFAULT;
446 		else
447 			tp->t_local = temp;
448 		break;
449 
450 	case TIOCLGET:
451 		if (copyout((caddr_t)&tp->t_local, addr, sizeof(tp->t_local)))
452 			u.u_error = EFAULT;
453 		break;
454 
455 	/*
456 	 * Return number of characters in
457 	 * the output.
458 	 */
459 	case TIOCOUTQ:
460 		if (copyout((caddr_t)&tp->t_outq.c_cc, addr, sizeof(tp->t_outq.c_cc)))
461 			u.u_error = EFAULT;
462 		break;
463 
464 	/*
465 	 * Simulate typing of a character at the terminal.
466 	 */
467 	case TIOCSTI:
468 		c = fubyte(addr);
469 		if (u.u_uid && u.u_ttyp != tp || c < 0)
470 			u.u_error = EFAULT;
471 		else
472 			(*linesw[tp->t_line].l_rint)(c, tp);
473 		break;
474 
475 	case TIOCSTOP:
476 		c = spl5();
477 		if ((tp->t_state & TS_TTSTOP) == 0) {
478 			tp->t_state |= TS_TTSTOP;
479 			(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
480 		}
481 		splx(c);
482 		break;
483 
484 	case TIOCSTART:
485 		c = spl5();
486 		if ((tp->t_state & TS_TTSTOP) || (tp->t_local & LFLUSHO)) {
487 			tp->t_state &= ~TS_TTSTOP;
488 			tp->t_local &= ~LFLUSHO;
489 			ttstart(tp);
490 		}
491 		splx(c);
492 		break;
493 
494 /* end of locals */
495 
496 	default:
497 		return(0);
498 	}
499 	return(1);
500 }
501 
502 ttnread(tp)
503 	struct tty *tp;
504 {
505 	int nread = 0;
506 
507 	if (tp->t_local & LPENDIN)
508 		ttypend(tp);
509 	nread = tp->t_canq.c_cc;
510 	if (tp->t_flags & (RAW|CBREAK))
511 		nread += tp->t_rawq.c_cc;
512 	return (nread);
513 }
514 
515 ttselect(dev, rw)
516 	dev_t dev;
517 	int rw;
518 {
519 	register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)];
520 	int nread;
521 	int s = spl5();
522 
523 	switch (rw) {
524 
525 	case FREAD:
526 		nread = ttnread(tp);
527 		if (nread > 0)
528 			goto win;
529 		if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait)
530 			tp->t_state |= TS_RCOLL;
531 		else
532 			tp->t_rsel = u.u_procp;
533 		break;
534 
535 	case FWRITE:
536 		if (tp->t_outq.c_cc <= TTLOWAT(tp))
537 			goto win;
538 		if (tp->t_wsel && tp->t_wsel->p_wchan == (caddr_t)&selwait)
539 			tp->t_state |= TS_WCOLL;
540 		else
541 			tp->t_wsel = u.u_procp;
542 		break;
543 	}
544 	splx(s);
545 	return (0);
546 win:
547 	splx(s);
548 	return (1);
549 }
550