xref: /csrg-svn/sys/kern/tty.c (revision 5408)
1 /*	tty.c	4.15	82/01/14	*/
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|FWRITE);
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);
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 	 * Set new parameters
286 	 */
287 	case TIOCSETP:
288 	case TIOCSETN:
289 		if (copyin(addr, (caddr_t)&iocb, sizeof(iocb))) {
290 			u.u_error = EFAULT;
291 			return(1);
292 		}
293 		(void) spl5();
294 		if (tp->t_flags&RAW || iocb.sg_flags&RAW ||
295 		    com == TIOCSETP)
296 			wflushtty(tp);
297 		else if ((tp->t_flags&CBREAK) != (iocb.sg_flags&CBREAK)) {
298 			if (iocb.sg_flags & CBREAK) {
299 				catq(&tp->t_rawq, &tp->t_canq);
300 				tq = tp->t_rawq;
301 				tp->t_rawq = tp->t_canq;
302 				tp->t_canq = tq;
303 			} else {
304 				tp->t_local |= LPENDIN;
305 				ttwakeup(tp);
306 			}
307 		}
308 		tp->t_ispeed = iocb.sg_ispeed;
309 		tp->t_ospeed = iocb.sg_ospeed;
310 		tp->t_erase = iocb.sg_erase;
311 		tp->t_kill = iocb.sg_kill;
312 		tp->t_flags = iocb.sg_flags;
313 		if (tp->t_flags & RAW) {
314 			tp->t_state &= ~TS_TTSTOP;
315 			ttstart(tp);
316 		}
317 		(void) spl0();
318 		break;
319 
320 	/*
321 	 * Send current parameters to user
322 	 */
323 	case TIOCGETP:
324 		iocb.sg_ispeed = tp->t_ispeed;
325 		iocb.sg_ospeed = tp->t_ospeed;
326 		iocb.sg_erase = tp->t_erase;
327 		iocb.sg_kill = tp->t_kill;
328 		iocb.sg_flags = tp->t_flags;
329 		if (copyout((caddr_t)&iocb, addr, sizeof(iocb)))
330 			u.u_error = EFAULT;
331 		break;
332 
333 	/*
334 	 * Hang up line on last close
335 	 */
336 	case TIOCHPCL:
337 		tp->t_state |= TS_HUPCLS;
338 		break;
339 
340 	case TIOCFLUSH: {
341 		int flags;
342 		if (addr == 0)
343 			flags = FREAD|FWRITE;
344 		else if (copyin(addr, (caddr_t)&flags, sizeof (flags))) {
345 			u.u_error = EFAULT;
346 			return(1);
347 		}
348 		flushtty(tp, flags);
349 		break;
350 	}
351 
352 	case FIONBIO: {
353 		int nbio;
354 		if (copyin(addr, (caddr_t)&nbio, sizeof (nbio))) {
355 			u.u_error = EFAULT;
356 			return(1);
357 		}
358 		if (nbio)
359 			tp->t_state |= TS_NBIO;
360 		else
361 			tp->t_state &= ~TS_NBIO;
362 		break;
363 	}
364 
365 	/*
366 	 * Set and fetch special characters
367 	 */
368 	case TIOCSETC:
369 		if (copyin(addr, (caddr_t)&tun, sizeof(struct tchars)))
370 			u.u_error = EFAULT;
371 		break;
372 
373 	case TIOCGETC:
374 		if (copyout((caddr_t)&tun, addr, sizeof(struct tchars)))
375 			u.u_error = EFAULT;
376 		break;
377 
378 /* local ioctls */
379 	/*
380 	 * Set/get local special characters.
381 	 */
382 	case TIOCSLTC:
383 		if (copyin(addr, (caddr_t)&tlun, sizeof (struct ltchars)))
384 			u.u_error = EFAULT;
385 		break;
386 
387 	case TIOCGLTC:
388 		if (copyout((caddr_t)&tlun, addr, sizeof (struct ltchars)))
389 			u.u_error = EFAULT;
390 		break;
391 
392 	/*
393 	 * Return number of characters immediately available.
394 	 */
395 	case FIONREAD: {
396 		off_t nread = ttnread(tp);
397 		if (copyout((caddr_t)&nread, addr, sizeof (off_t)))
398 			u.u_error = EFAULT;
399 		break;
400 		}
401 
402 	/*
403 	 * Should allow SPGRP and GPGRP only if tty open for reading.
404 	 */
405 	case TIOCSPGRP:
406 		if (copyin(addr, (caddr_t)&tp->t_pgrp, sizeof (tp->t_pgrp)))
407 			u.u_error = EFAULT;
408 		break;
409 
410 	case TIOCGPGRP:
411 		if (copyout((caddr_t)&tp->t_pgrp, addr, sizeof(tp->t_pgrp)))
412 			u.u_error = EFAULT;
413 		break;
414 
415 	/*
416 	 * Modify local mode word.
417 	 */
418 	case TIOCLBIS:
419 		if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local)))
420 			u.u_error = EFAULT;
421 		else
422 			tp->t_local |= temp;
423 		break;
424 
425 	case TIOCLBIC:
426 		if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local)))
427 			u.u_error = EFAULT;
428 		else
429 			tp->t_local &= ~temp;
430 		break;
431 
432 	case TIOCLSET:
433 		if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local)))
434 			u.u_error = EFAULT;
435 		else
436 			tp->t_local = temp;
437 		break;
438 
439 	case TIOCLGET:
440 		if (copyout((caddr_t)&tp->t_local, addr, sizeof(tp->t_local)))
441 			u.u_error = EFAULT;
442 		break;
443 
444 	/*
445 	 * Return number of characters in
446 	 * the output.
447 	 */
448 	case TIOCOUTQ:
449 		if (copyout((caddr_t)&tp->t_outq.c_cc, addr, sizeof(tp->t_outq.c_cc)))
450 			u.u_error = EFAULT;
451 		break;
452 
453 	/*
454 	 * Simulate typing of a character at the terminal.
455 	 */
456 	case TIOCSTI:
457 		c = fubyte(addr);
458 		if (u.u_uid && u.u_ttyp != tp || c < 0)
459 			u.u_error = EFAULT;
460 		else
461 			(*linesw[tp->t_line].l_rint)(c, tp);
462 		break;
463 /* end of locals */
464 
465 	default:
466 		return(0);
467 	}
468 	return(1);
469 }
470 
471 ttnread(tp)
472 	struct tty *tp;
473 {
474 	int nread = 0;
475 
476 	if (tp->t_local & LPENDIN)
477 		ttypend(tp);
478 	nread = tp->t_canq.c_cc;
479 	if (tp->t_flags & (RAW|CBREAK))
480 		nread += tp->t_rawq.c_cc;
481 	return (nread);
482 }
483 
484 ttselect(dev, rw)
485 	dev_t dev;
486 	int rw;
487 {
488 	register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)];
489 	int nread;
490 	int s = spl5();
491 
492 	switch (rw) {
493 
494 	case FREAD:
495 		nread = ttnread(tp);
496 		if (nread > 0)
497 			goto win;
498 		if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait)
499 			tp->t_state |= TS_RCOLL;
500 		else
501 			tp->t_rsel = u.u_procp;
502 		break;
503 
504 	case FWRITE:
505 		if (tp->t_outq.c_cc <= TTLOWAT(tp))
506 			goto win;
507 printf("wsel block\n");
508 		if (tp->t_wsel && tp->t_wsel->p_wchan == (caddr_t)&selwait)
509 			tp->t_state |= TS_WCOLL;
510 		else
511 			tp->t_wsel = u.u_procp;
512 		break;
513 	}
514 	splx(s);
515 	return (0);
516 win:
517 	splx(s);
518 	return (1);
519 }
520