xref: /csrg-svn/sys/kern/tty.c (revision 3132)
1 /*	tty.c	4.5	81/03/09	*/
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 	tp->t_state &= ~TIMEOUT;
165 	ttstart(tp);
166 }
167 
168 /*
169  * Start output on the typewriter. It is used from the top half
170  * after some characters have been put on the output queue,
171  * from the interrupt routine to transmit the next
172  * character, and after a timeout has finished.
173  */
174 ttstart(tp)
175 register struct tty *tp;
176 {
177 	register s;
178 
179 	s = spl5();
180 	if((tp->t_state&(TIMEOUT|TTSTOP|BUSY)) == 0)
181 		(*tp->t_oproc)(tp);
182 	splx(s);
183 }
184 
185 /*
186  * Common code for tty ioctls.
187  */
188 /*ARGSUSED*/
189 ttioctl(tp, com, addr, flag)
190 register struct tty *tp;
191 caddr_t addr;
192 {
193 	int dev;
194 	unsigned t;
195 	struct sgttyb iocb;
196 	struct clist tq;
197 	extern int nldisp;
198 	register c;
199 	int temp;
200 
201 	/*
202 	 * This is especially so that isatty() will
203 	 * fail when carrier is gone.
204 	 */
205 	if ((tp->t_state&CARR_ON) == 0) {
206 		u.u_error = EBADF;
207 		return (1);
208 	}
209 
210 	dev = tp->t_dev;
211 	/*
212 	 * If the ioctl involves modification,
213 	 * insist on being able to write the device,
214 	 * and hang if in the background.
215 	 */
216 	switch(com) {
217 
218 	case TIOCSETD:
219 	case TIOCSETP:
220 	case TIOCSETN:
221 	case TIOCFLUSH:
222 	case TIOCSETC:
223 	case TIOCSLTC:
224 	case TIOCSPGRP:
225 	case TIOCLBIS:
226 	case TIOCLBIC:
227 	case TIOCLSET:
228 	case TIOCSTI:
229 /* this is reasonable, but impractical...
230 		if ((flag & FWRITE) == 0) {
231 			u.u_error = EBADF;
232 			return (1);
233 		}
234  */
235 		while (tp->t_line == NTTYDISC &&
236 		   u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp &&
237 		   (u.u_procp->p_flag&SVFORK) == 0 &&
238 		   u.u_signal[SIGTTOU] != SIG_IGN &&
239 		   u.u_signal[SIGTTOU] != SIG_HOLD &&
240 		   (u.u_procp->p_flag&SDETACH)==0) {
241 			gsignal(u.u_procp->p_pgrp, SIGTTOU);
242 			sleep((caddr_t)&lbolt, TTOPRI);
243 		}
244 		break;
245 	}
246 
247 	/*
248 	 * Process the ioctl.
249 	 */
250 	switch(com) {
251 
252 	/*
253 	 * Get discipline number
254 	 */
255 	case TIOCGETD:
256 		t = tp->t_line;
257 		if (copyout((caddr_t)&t, addr, sizeof(t)))
258 			u.u_error = EFAULT;
259 		break;
260 
261 	/*
262 	 * Set line discipline
263 	 */
264 	case TIOCSETD:
265 		if (copyin(addr, (caddr_t)&t, sizeof(t))) {
266 			u.u_error = EFAULT;
267 			break;
268 		}
269 		if (t >= nldisp) {
270 			u.u_error = ENXIO;
271 			break;
272 		}
273 		(void) spl5();
274 		if (tp->t_line)
275 			(*linesw[tp->t_line].l_close)(tp);
276 		if (t)
277 			(*linesw[t].l_open)(dev, tp, addr);
278 		if (u.u_error==0)
279 			tp->t_line = t;
280 		(void) spl0();
281 		break;
282 
283 	/*
284 	 * Prevent more opens on channel
285 	 */
286 	case TIOCEXCL:
287 		tp->t_state |= XCLUDE;
288 		break;
289 
290 	case TIOCNXCL:
291 		tp->t_state &= ~XCLUDE;
292 		break;
293 
294 	/*
295 	 * Set new parameters
296 	 */
297 	case TIOCSETP:
298 	case TIOCSETN:
299 		if (copyin(addr, (caddr_t)&iocb, sizeof(iocb))) {
300 			u.u_error = EFAULT;
301 			return(1);
302 		}
303 		(void) spl5();
304 		if (tp->t_line == 0) {
305 			if (com == TIOCSETP)
306 				wflushtty(tp);
307 			while (canon(tp)>=0)
308 				;
309 #ifdef notdef
310 			wakeup((caddr_t)&tp->t_rawq);
311 #endif
312 		} else if (tp->t_line == NTTYDISC) {
313 			if (tp->t_flags&RAW || iocb.sg_flags&RAW ||
314 			    com == TIOCSETP)
315 				wflushtty(tp);
316 			else if ((tp->t_flags&CBREAK) != (iocb.sg_flags&CBREAK)) {
317 				if (iocb.sg_flags & CBREAK) {
318 					catq(&tp->t_rawq, &tp->t_canq);
319 					tq = tp->t_rawq;
320 					tp->t_rawq = tp->t_canq;
321 					tp->t_canq = tq;
322 				} else {
323 					tp->t_local |= LPENDIN;
324 					if (tp->t_canq.c_cc)
325 						panic("ioccom canq");
326 #ifdef notdef
327 					if (tp->t_chan)
328 						(void) sdata(tp->t_chan);
329 					else
330 #endif
331 						wakeup((caddr_t)&tp->t_rawq);
332 				}
333 			}
334 		}
335 		if ((tp->t_state&SPEEDS)==0) {
336 			tp->t_ispeed = iocb.sg_ispeed;
337 			tp->t_ospeed = iocb.sg_ospeed;
338 		}
339 		tp->t_erase = iocb.sg_erase;
340 		tp->t_kill = iocb.sg_kill;
341 		tp->t_flags = iocb.sg_flags;
342 		(void) spl0();
343 		break;
344 
345 	/*
346 	 * Send current parameters to user
347 	 */
348 	case TIOCGETP:
349 		iocb.sg_ispeed = tp->t_ispeed;
350 		iocb.sg_ospeed = tp->t_ospeed;
351 		iocb.sg_erase = tp->t_erase;
352 		iocb.sg_kill = tp->t_kill;
353 		iocb.sg_flags = tp->t_flags;
354 		if (copyout((caddr_t)&iocb, addr, sizeof(iocb)))
355 			u.u_error = EFAULT;
356 		break;
357 
358 	/*
359 	 * Hang up line on last close
360 	 */
361 	case TIOCHPCL:
362 		tp->t_state |= HUPCLS;
363 		break;
364 
365 	case TIOCFLUSH:
366 		flushtty(tp, FREAD|FWRITE);
367 		break;
368 
369 	/*
370 	 * Set and fetch special characters
371 	 */
372 	case TIOCSETC:
373 		if (copyin(addr, (caddr_t)&tun, sizeof(struct tchars)))
374 			u.u_error = EFAULT;
375 		break;
376 
377 	case TIOCGETC:
378 		if (copyout((caddr_t)&tun, addr, sizeof(struct tchars)))
379 			u.u_error = EFAULT;
380 		break;
381 
382 /* local ioctls */
383 	/*
384 	 * Set/get local special characters.
385 	 */
386 	case TIOCSLTC:
387 		if (copyin(addr, (caddr_t)&tlun, sizeof (struct ltchars)))
388 			u.u_error = EFAULT;
389 		break;
390 
391 	case TIOCGLTC:
392 		if (copyout((caddr_t)&tlun, addr, sizeof (struct ltchars)))
393 			u.u_error = EFAULT;
394 		break;
395 
396 	/*
397 	 * Return number of characters immediately available.
398 	 */
399 	case FIONREAD: {
400 		off_t nread;
401 
402 		switch (tp->t_line) {
403 
404 		case NETLDISC:
405 			nread = tp->t_rec ? tp->t_inbuf : 0;
406 			break;
407 
408 		case 0:
409 			(void) spl5();
410 			while (canon(tp)>=0)
411 				;
412 			(void) spl0();
413 			/* fall into ... */
414 
415 		case NTTYDISC:
416 			nread = tp->t_canq.c_cc;
417 			if (tp->t_flags & (RAW|CBREAK))
418 				nread += tp->t_rawq.c_cc;
419 			break;
420 
421 		}
422 		if (copyout((caddr_t)&nread, addr, sizeof (off_t)))
423 			u.u_error = EFAULT;
424 		break;
425 		}
426 
427 	/*
428 	 * Should allow SPGRP and GPGRP only if tty open for reading.
429 	 */
430 	case TIOCSPGRP:
431 		if (copyin(addr, (caddr_t)&tp->t_pgrp, sizeof (tp->t_pgrp)))
432 			u.u_error = EFAULT;
433 		break;
434 
435 	case TIOCGPGRP:
436 		if (copyout((caddr_t)&tp->t_pgrp, addr, sizeof(tp->t_pgrp)))
437 			u.u_error = EFAULT;
438 		break;
439 
440 	/*
441 	 * Modify local mode word.
442 	 */
443 	case TIOCLBIS:
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 TIOCLBIC:
451 		if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local)))
452 			u.u_error = EFAULT;
453 		else
454 			tp->t_local &= ~temp;
455 		break;
456 
457 	case TIOCLSET:
458 		if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local)))
459 			u.u_error = EFAULT;
460 		else
461 			tp->t_local = temp;
462 		break;
463 
464 	case TIOCLGET:
465 		if (copyout((caddr_t)&tp->t_local, addr, sizeof(tp->t_local)))
466 			u.u_error = EFAULT;
467 		break;
468 
469 	/*
470 	 * Return number of characters in
471 	 * the output.
472 	 */
473 	case TIOCOUTQ:
474 		if (copyout((caddr_t)&tp->t_outq.c_cc, addr, sizeof(tp->t_outq.c_cc)))
475 			u.u_error = EFAULT;
476 		break;
477 
478 	/*
479 	 * Simulate typing of a character at the terminal.
480 	 */
481 	case TIOCSTI:
482 		c = fubyte(addr);
483 		if (u.u_uid && u.u_ttyp != tp || c < 0)
484 			u.u_error = EFAULT;
485 		else
486 			(*linesw[tp->t_line].l_rint)(c, tp);
487 		break;
488 /* end of locals */
489 
490 	default:
491 		return(0);
492 	}
493 	return(1);
494 }
495