xref: /original-bsd/sys/kern/tty.c (revision 6c57d260)
1 /*	tty.c	4.6	81/03/22	*/
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 		(void) spl0();
347 		break;
348 
349 	/*
350 	 * Send current parameters to user
351 	 */
352 	case TIOCGETP:
353 		iocb.sg_ispeed = tp->t_ispeed;
354 		iocb.sg_ospeed = tp->t_ospeed;
355 		iocb.sg_erase = tp->t_erase;
356 		iocb.sg_kill = tp->t_kill;
357 		iocb.sg_flags = tp->t_flags;
358 		if (copyout((caddr_t)&iocb, addr, sizeof(iocb)))
359 			u.u_error = EFAULT;
360 		break;
361 
362 	/*
363 	 * Hang up line on last close
364 	 */
365 	case TIOCHPCL:
366 		tp->t_state |= HUPCLS;
367 		break;
368 
369 	case TIOCFLUSH:
370 		flushtty(tp, FREAD|FWRITE);
371 		break;
372 
373 	/*
374 	 * Set and fetch special characters
375 	 */
376 	case TIOCSETC:
377 		if (copyin(addr, (caddr_t)&tun, sizeof(struct tchars)))
378 			u.u_error = EFAULT;
379 		break;
380 
381 	case TIOCGETC:
382 		if (copyout((caddr_t)&tun, addr, sizeof(struct tchars)))
383 			u.u_error = EFAULT;
384 		break;
385 
386 /* local ioctls */
387 	/*
388 	 * Set/get local special characters.
389 	 */
390 	case TIOCSLTC:
391 		if (copyin(addr, (caddr_t)&tlun, sizeof (struct ltchars)))
392 			u.u_error = EFAULT;
393 		break;
394 
395 	case TIOCGLTC:
396 		if (copyout((caddr_t)&tlun, addr, sizeof (struct ltchars)))
397 			u.u_error = EFAULT;
398 		break;
399 
400 	/*
401 	 * Return number of characters immediately available.
402 	 */
403 	case FIONREAD: {
404 		off_t nread;
405 
406 		switch (tp->t_line) {
407 
408 		case NETLDISC:
409 			nread = tp->t_rec ? tp->t_inbuf : 0;
410 			break;
411 
412 		case 0:
413 			(void) spl5();
414 			while (canon(tp)>=0)
415 				;
416 			(void) spl0();
417 			/* fall into ... */
418 
419 		case NTTYDISC:
420 			nread = tp->t_canq.c_cc;
421 			if (tp->t_flags & (RAW|CBREAK))
422 				nread += tp->t_rawq.c_cc;
423 			break;
424 
425 		}
426 		if (copyout((caddr_t)&nread, addr, sizeof (off_t)))
427 			u.u_error = EFAULT;
428 		break;
429 		}
430 
431 	/*
432 	 * Should allow SPGRP and GPGRP only if tty open for reading.
433 	 */
434 	case TIOCSPGRP:
435 		if (copyin(addr, (caddr_t)&tp->t_pgrp, sizeof (tp->t_pgrp)))
436 			u.u_error = EFAULT;
437 		break;
438 
439 	case TIOCGPGRP:
440 		if (copyout((caddr_t)&tp->t_pgrp, addr, sizeof(tp->t_pgrp)))
441 			u.u_error = EFAULT;
442 		break;
443 
444 	/*
445 	 * Modify local mode word.
446 	 */
447 	case TIOCLBIS:
448 		if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local)))
449 			u.u_error = EFAULT;
450 		else
451 			tp->t_local |= temp;
452 		break;
453 
454 	case TIOCLBIC:
455 		if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local)))
456 			u.u_error = EFAULT;
457 		else
458 			tp->t_local &= ~temp;
459 		break;
460 
461 	case TIOCLSET:
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 TIOCLGET:
469 		if (copyout((caddr_t)&tp->t_local, addr, sizeof(tp->t_local)))
470 			u.u_error = EFAULT;
471 		break;
472 
473 	/*
474 	 * Return number of characters in
475 	 * the output.
476 	 */
477 	case TIOCOUTQ:
478 		if (copyout((caddr_t)&tp->t_outq.c_cc, addr, sizeof(tp->t_outq.c_cc)))
479 			u.u_error = EFAULT;
480 		break;
481 
482 	/*
483 	 * Simulate typing of a character at the terminal.
484 	 */
485 	case TIOCSTI:
486 		c = fubyte(addr);
487 		if (u.u_uid && u.u_ttyp != tp || c < 0)
488 			u.u_error = EFAULT;
489 		else
490 			(*linesw[tp->t_line].l_rint)(c, tp);
491 		break;
492 /* end of locals */
493 
494 	default:
495 		return(0);
496 	}
497 	return(1);
498 }
499