xref: /csrg-svn/sys/kern/tty.c (revision 915)
1*915Sbill /*	tty.c	3.18	09/25/80	*/
239Sbill 
339Sbill /*
4903Sbill  * TTY subroutines common to more than one line discipline
539Sbill  */
639Sbill #include "../h/param.h"
739Sbill #include "../h/systm.h"
839Sbill #include "../h/dir.h"
939Sbill #include "../h/user.h"
1039Sbill #include "../h/tty.h"
1139Sbill #include "../h/proc.h"
1239Sbill #include "../h/mx.h"
1339Sbill #include "../h/inode.h"
1439Sbill #include "../h/file.h"
1539Sbill #include "../h/reg.h"
1639Sbill #include "../h/conf.h"
1739Sbill #include "../h/buf.h"
18340Sbill #include "../h/dk.h"
1939Sbill 
2039Sbill char	partab[];
2139Sbill 
22146Sbill /*
23146Sbill  * When running dz's using only SAE (silo alarm) on input
24146Sbill  * it is necessary to call dzrint() at clock interrupt time.
25146Sbill  * This is unsafe unless spl5()s in tty code are changed to
26146Sbill  * spl6()s to block clock interrupts.  Note that the dh driver
27146Sbill  * currently in use works the same way as the dz, even though
28146Sbill  * we could try to more intelligently manage its silo.
29146Sbill  * Thus don't take this out if you have no dz's unless you
30146Sbill  * change clock.c and dhtimer().
31146Sbill  */
32146Sbill #define	spl5	spl6
3339Sbill 
3439Sbill /*
3539Sbill  * Input mapping table-- if an entry is non-zero, when the
3639Sbill  * corresponding character is typed preceded by "\" the escape
3739Sbill  * sequence is replaced by the table value.  Mostly used for
3839Sbill  * upper-case only terminals.
3939Sbill  */
4039Sbill 
4139Sbill char	maptab[] ={
4239Sbill 	000,000,000,000,000,000,000,000,
4339Sbill 	000,000,000,000,000,000,000,000,
4439Sbill 	000,000,000,000,000,000,000,000,
4539Sbill 	000,000,000,000,000,000,000,000,
4639Sbill 	000,'|',000,000,000,000,000,'`',
4739Sbill 	'{','}',000,000,000,000,000,000,
4839Sbill 	000,000,000,000,000,000,000,000,
4939Sbill 	000,000,000,000,000,000,000,000,
5039Sbill 	000,000,000,000,000,000,000,000,
5139Sbill 	000,000,000,000,000,000,000,000,
5239Sbill 	000,000,000,000,000,000,000,000,
5339Sbill 	000,000,000,000,000,000,'~',000,
5439Sbill 	000,'A','B','C','D','E','F','G',
5539Sbill 	'H','I','J','K','L','M','N','O',
5639Sbill 	'P','Q','R','S','T','U','V','W',
5739Sbill 	'X','Y','Z',000,000,000,000,000,
5839Sbill };
5939Sbill 
6039Sbill #define	OBUFSIZ	100
6139Sbill 
6239Sbill /*
6339Sbill  * set default control characters.
6439Sbill  */
6539Sbill ttychars(tp)
6639Sbill register struct tty *tp;
6739Sbill {
68174Sbill 
6939Sbill 	tun.t_intrc = CINTR;
7039Sbill 	tun.t_quitc = CQUIT;
7139Sbill 	tun.t_startc = CSTART;
7239Sbill 	tun.t_stopc = CSTOP;
7339Sbill 	tun.t_eofc = CEOT;
7439Sbill 	tun.t_brkc = CBRK;
7539Sbill 	tp->t_erase = CERASE;
7639Sbill 	tp->t_kill = CKILL;
77174Sbill /* begin local */
78208Sbill 	tlun.t_suspc = CTRL(z);
79208Sbill 	tlun.t_dsuspc = CTRL(y);
80174Sbill 	tlun.t_rprntc = CTRL(r);
81174Sbill 	tlun.t_flushc = CTRL(o);
82174Sbill 	tlun.t_werasc = CTRL(w);
83174Sbill 	tlun.t_lnextc = CTRL(v);
84174Sbill 	tlun.t_lintr = CTRL(c);
85174Sbill 	tlun.t_lerase = CTRL(h);
86174Sbill 	tlun.t_lkill = CTRL(u);
87174Sbill 	tp->t_local = 0;
88174Sbill 	tp->t_lstate = 0;
89174Sbill /* end local */
9039Sbill }
9139Sbill 
9239Sbill /*
93903Sbill  * Wait for output to drain, then flush input waiting.
9439Sbill  */
95903Sbill wflushtty(tp)
9639Sbill register struct tty *tp;
9739Sbill {
9839Sbill 
99903Sbill 	(void) spl5();
100903Sbill 	while (tp->t_outq.c_cc && tp->t_state&CARR_ON) {
101903Sbill 		(*tp->t_oproc)(tp);
102903Sbill 		tp->t_state |= ASLEEP;
103903Sbill 		sleep((caddr_t)&tp->t_outq, TTOPRI);
104903Sbill 	}
105903Sbill 	flushtty(tp, FREAD|FWRITE);
106903Sbill 	(void) spl0();
10739Sbill }
10839Sbill 
10939Sbill /*
110903Sbill  * flush all TTY queues
11139Sbill  */
112903Sbill flushtty(tp, rw)
113903Sbill register struct tty *tp;
11439Sbill {
115903Sbill 	register s;
116903Sbill 
117903Sbill 	if (tp->t_line == NETLDISC)
118903Sbill 		return;
119903Sbill 	s = spl6();
120903Sbill 	if (rw & FREAD) {
121903Sbill 		while (getc(&tp->t_canq) >= 0)
122903Sbill 			;
123903Sbill 		wakeup((caddr_t)&tp->t_rawq);
124903Sbill 	}
125903Sbill 	if (rw & FWRITE) {
126903Sbill 		wakeup((caddr_t)&tp->t_outq);
127903Sbill 		tp->t_state &= ~TTSTOP;
128903Sbill 		(*cdevsw[major(tp->t_dev)].d_stop)(tp);
129903Sbill 		while (getc(&tp->t_outq) >= 0)
130903Sbill 			;
131903Sbill 	}
132903Sbill 	if (rw & FREAD) {
133903Sbill 		while (getc(&tp->t_rawq) >= 0)
134903Sbill 			;
135903Sbill 		tp->t_delct = 0;
136903Sbill 		tp->t_rocount = 0;		/* local */
137903Sbill 		tp->t_rocol = 0;
138903Sbill 		tp->t_lstate = 0;
139903Sbill 	}
140903Sbill 	splx(s);
14139Sbill }
14239Sbill 
143903Sbill /*
144903Sbill  * Send stop character on input overflow.
145903Sbill  */
146903Sbill ttyblock(tp)
147903Sbill register struct tty *tp;
14839Sbill {
149903Sbill 	register x;
150903Sbill 	x = tp->t_rawq.c_cc + tp->t_canq.c_cc;
151903Sbill 	if (tp->t_rawq.c_cc > TTYHOG) {
152903Sbill 		flushtty(tp, FREAD|FWRITE);
153903Sbill 		tp->t_state &= ~TBLOCK;
154903Sbill 	}
155903Sbill 	if (x >= TTYHOG/2) {
156903Sbill 		if (putc(tun.t_stopc, &tp->t_outq)==0) {
157903Sbill 			tp->t_state |= TBLOCK;
158903Sbill 			tp->t_char++;
159903Sbill 			ttstart(tp);
160903Sbill 		}
161903Sbill 	}
16239Sbill }
16339Sbill 
16439Sbill /*
165903Sbill  * Restart typewriter output following a delay
166903Sbill  * timeout.
167903Sbill  * The name of the routine is passed to the timeout
168903Sbill  * subroutine and it is called during a clock interrupt.
169121Sbill  */
170903Sbill ttrstrt(tp)
171121Sbill register struct tty *tp;
172121Sbill {
173121Sbill 
174903Sbill 	tp->t_state &= ~TIMEOUT;
175903Sbill 	ttstart(tp);
176121Sbill }
177121Sbill 
178121Sbill /*
179903Sbill  * Start output on the typewriter. It is used from the top half
180903Sbill  * after some characters have been put on the output queue,
181903Sbill  * from the interrupt routine to transmit the next
182903Sbill  * character, and after a timeout has finished.
18339Sbill  */
184903Sbill ttstart(tp)
185903Sbill register struct tty *tp;
18639Sbill {
187903Sbill 	register s;
18839Sbill 
189903Sbill 	s = spl5();
190903Sbill 	if((tp->t_state&(TIMEOUT|TTSTOP|BUSY)) == 0)
191903Sbill 		(*tp->t_oproc)(tp);
192903Sbill 	splx(s);
19339Sbill }
19439Sbill 
19539Sbill /*
196903Sbill  * Common code for tty ioctls.
19739Sbill  */
198903Sbill ttioctl(com, tp, addr, dev, flag)
19939Sbill register struct tty *tp;
20039Sbill caddr_t addr;
20139Sbill {
20239Sbill 	unsigned t;
203174Sbill 	struct sgttyb iocb;
204191Sbill 	struct clist tq;
20539Sbill 	extern int nldisp;
206887Sbill 	register c;
207728Sbill 	int temp;
20839Sbill 
209903Sbill 	/*
210*915Sbill 	 * This is especially so that isatty() will
211*915Sbill 	 * fail when carrier is gone.
212*915Sbill 	 */
213*915Sbill 	if ((tp->t_state&CARR_ON) == 0) {
214*915Sbill 		u.u_error = EBADF;
215*915Sbill 		return (1);
216*915Sbill 	}
217*915Sbill 
218*915Sbill 	/*
219903Sbill 	 * If the ioctl involves modification,
220903Sbill 	 * insist on being able to write the device,
221903Sbill 	 * and hang if in the background.
222903Sbill 	 */
22339Sbill 	switch(com) {
22439Sbill 
225*915Sbill 	case TIOCSETD:
226*915Sbill 	case TIOCSETP:
227*915Sbill 	case TIOCSETN:
228903Sbill 	case TIOCFLUSH:
229903Sbill 	case TIOCSETC:
230903Sbill 	case TIOCSLTC:
231903Sbill 	case TIOCSPGRP:
232903Sbill 	case TIOCLBIS:
233903Sbill 	case TIOCLBIC:
234903Sbill 	case TIOCLSET:
235903Sbill 	case TIOCSTI:
236*915Sbill /* this is reasonable, but impractical...
237903Sbill 		if ((flag & FWRITE) == 0) {
238903Sbill 			u.u_error = EBADF;
239903Sbill 			return (1);
240903Sbill 		}
241*915Sbill  */
242903Sbill 		while (tp->t_line == NTTYDISC &&
243903Sbill 		   u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp &&
244903Sbill 		   (u.u_procp->p_flag&SVFORK) == 0 &&
245903Sbill 		   u.u_signal[SIGTTOU] != SIG_IGN &&
246903Sbill 		   u.u_signal[SIGTTOU] != SIG_HOLD &&
247903Sbill 		   (u.u_procp->p_flag&SDETACH)==0) {
248903Sbill 			gsignal(u.u_procp->p_pgrp, SIGTTOU);
249903Sbill 			sleep((caddr_t)&lbolt, TTOPRI);
250903Sbill 		}
251903Sbill 		break;
252903Sbill 	}
253903Sbill 
25439Sbill 	/*
255903Sbill 	 * Process the ioctl.
25639Sbill 	 */
257903Sbill 	switch(com) {
258903Sbill 
259903Sbill 	/*
260903Sbill 	 * Get discipline number
261903Sbill 	 */
26239Sbill 	case TIOCGETD:
26339Sbill 		t = tp->t_line;
26439Sbill 		if (copyout((caddr_t)&t, addr, sizeof(t)))
26539Sbill 			u.u_error = EFAULT;
26639Sbill 		break;
26739Sbill 
26839Sbill 	/*
269903Sbill 	 * Set line discipline
27039Sbill 	 */
27139Sbill 	case TIOCSETD:
27239Sbill 		if (copyin(addr, (caddr_t)&t, sizeof(t))) {
27339Sbill 			u.u_error = EFAULT;
27439Sbill 			break;
27539Sbill 		}
27639Sbill 		if (t >= nldisp) {
27739Sbill 			u.u_error = ENXIO;
27839Sbill 			break;
27939Sbill 		}
280174Sbill 		(void) spl5();
28139Sbill 		if (tp->t_line)
28239Sbill 			(*linesw[tp->t_line].l_close)(tp);
28339Sbill 		if (t)
28439Sbill 			(*linesw[t].l_open)(dev, tp, addr);
28539Sbill 		if (u.u_error==0)
28639Sbill 			tp->t_line = t;
287174Sbill 		(void) spl0();
28839Sbill 		break;
28939Sbill 
29039Sbill 	/*
291903Sbill 	 * Prevent more opens on channel
29239Sbill 	 */
29339Sbill 	case TIOCEXCL:
29439Sbill 		tp->t_state |= XCLUDE;
29539Sbill 		break;
29639Sbill 
29739Sbill 	case TIOCNXCL:
29839Sbill 		tp->t_state &= ~XCLUDE;
29939Sbill 		break;
30039Sbill 
30139Sbill 	/*
30239Sbill 	 * Set new parameters
30339Sbill 	 */
30439Sbill 	case TIOCSETP:
305191Sbill 	case TIOCSETN:
30639Sbill 		if (copyin(addr, (caddr_t)&iocb, sizeof(iocb))) {
30739Sbill 			u.u_error = EFAULT;
30839Sbill 			return(1);
30939Sbill 		}
310121Sbill 		(void) spl5();
311174Sbill 		if (tp->t_line == 0) {
312174Sbill 			if (com == TIOCSETP)
313174Sbill 				wflushtty(tp);
314174Sbill 			while (canon(tp)>=0)
315174Sbill 				;
316174Sbill 		} else if (tp->t_line == NTTYDISC) {
317174Sbill 			if (tp->t_flags&RAW || iocb.sg_flags&RAW ||
318174Sbill 			    com == TIOCSETP)
319174Sbill 				wflushtty(tp);
320174Sbill 			else if ((tp->t_flags&CBREAK) != (iocb.sg_flags&CBREAK)) {
321174Sbill 				if (iocb.sg_flags & CBREAK) {
322174Sbill 					catq(&tp->t_rawq, &tp->t_canq);
323174Sbill 					tq = tp->t_rawq;
324174Sbill 					tp->t_rawq = tp->t_canq;
325174Sbill 					tp->t_canq = tq;
326174Sbill 				} else {
327174Sbill 					tp->t_local |= LPENDIN;
328174Sbill 					if (tp->t_canq.c_cc)
329174Sbill 						panic("ioccom canq");
330174Sbill 					if (tp->t_chan)
331174Sbill 						(void) sdata(tp->t_chan);
332174Sbill 					else
333174Sbill 						wakeup((caddr_t)&tp->t_rawq);
334174Sbill 				}
335174Sbill 			}
336174Sbill 		}
33739Sbill 		if ((tp->t_state&SPEEDS)==0) {
338174Sbill 			tp->t_ispeed = iocb.sg_ispeed;
339174Sbill 			tp->t_ospeed = iocb.sg_ospeed;
34039Sbill 		}
341174Sbill 		tp->t_erase = iocb.sg_erase;
342174Sbill 		tp->t_kill = iocb.sg_kill;
343174Sbill 		tp->t_flags = iocb.sg_flags;
344121Sbill 		(void) spl0();
34539Sbill 		break;
34639Sbill 
34739Sbill 	/*
348903Sbill 	 * Send current parameters to user
34939Sbill 	 */
35039Sbill 	case TIOCGETP:
351174Sbill 		iocb.sg_ispeed = tp->t_ispeed;
352174Sbill 		iocb.sg_ospeed = tp->t_ospeed;
353174Sbill 		iocb.sg_erase = tp->t_erase;
354174Sbill 		iocb.sg_kill = tp->t_kill;
355174Sbill 		iocb.sg_flags = tp->t_flags;
35639Sbill 		if (copyout((caddr_t)&iocb, addr, sizeof(iocb)))
35739Sbill 			u.u_error = EFAULT;
35839Sbill 		break;
35939Sbill 
36039Sbill 	/*
36139Sbill 	 * Hang up line on last close
36239Sbill 	 */
36339Sbill 	case TIOCHPCL:
36439Sbill 		tp->t_state |= HUPCLS;
36539Sbill 		break;
36639Sbill 
36739Sbill 	case TIOCFLUSH:
368872Sbill 		flushtty(tp, FREAD|FWRITE);
36939Sbill 		break;
37039Sbill 
37139Sbill 	/*
372903Sbill 	 * Ioctl entries to line discipline
37339Sbill 	 */
37439Sbill 	case DIOCSETP:
37539Sbill 	case DIOCGETP:
376121Sbill 		if ((*linesw[tp->t_line].l_ioctl)(com, tp, addr))
377121Sbill 			u.u_error = ENOTTY;
37839Sbill 		break;
37939Sbill 
38039Sbill 	/*
381903Sbill 	 * Set and fetch special characters
38239Sbill 	 */
38339Sbill 	case TIOCSETC:
384174Sbill 		if (copyin(addr, (caddr_t)&tun, sizeof(struct tchars)))
38539Sbill 			u.u_error = EFAULT;
38639Sbill 		break;
38739Sbill 
38839Sbill 	case TIOCGETC:
389174Sbill 		if (copyout((caddr_t)&tun, addr, sizeof(struct tchars)))
39039Sbill 			u.u_error = EFAULT;
39139Sbill 		break;
39239Sbill 
393174Sbill /* local ioctls */
394903Sbill 	/*
395903Sbill 	 * Set/get local special characters.
396903Sbill 	 */
397174Sbill 	case TIOCSLTC:
398174Sbill 		if (copyin(addr, (caddr_t)&tlun, sizeof (struct ltchars)))
399174Sbill 			u.u_error = EFAULT;
400174Sbill 		break;
401174Sbill 
402174Sbill 	case TIOCGLTC:
403174Sbill 		if (copyout((caddr_t)&tlun, addr, sizeof (struct ltchars)))
404174Sbill 			u.u_error = EFAULT;
405174Sbill 		break;
406174Sbill 
407903Sbill 	/*
408903Sbill 	 * Return number of characters immediately available.
409903Sbill 	 */
410174Sbill 	case FIONREAD: {
411340Sbill 		off_t nread;
412174Sbill 
413340Sbill 		switch (tp->t_line) {
414340Sbill 
415340Sbill 		case NETLDISC:
416340Sbill 			nread = tp->t_rec ? tp->t_inbuf : 0;
417340Sbill 			break;
418340Sbill 
419894Sbill 		case 0:
420894Sbill 			(void) spl5();
421894Sbill 			while (canon(tp)>=0)
422894Sbill 				;
423894Sbill 			(void) spl0();
424894Sbill 			/* fall into ... */
425894Sbill 
426340Sbill 		case NTTYDISC:
427340Sbill 			nread = tp->t_canq.c_cc;
428340Sbill 			if (tp->t_flags & (RAW|CBREAK))
429340Sbill 				nread += tp->t_rawq.c_cc;
430340Sbill 			break;
431340Sbill 
432340Sbill 		}
433174Sbill 		if (copyout((caddr_t)&nread, addr, sizeof (off_t)))
434174Sbill 			u.u_error = EFAULT;
435174Sbill 		break;
436174Sbill 		}
437174Sbill 
438174Sbill 	/*
439174Sbill 	 * Should allow SPGRP and GPGRP only if tty open for reading.
440174Sbill 	 */
441174Sbill 	case TIOCSPGRP:
442728Sbill 		if (copyin(addr, (caddr_t)&tp->t_pgrp, sizeof (tp->t_pgrp)))
443728Sbill 			u.u_error = EFAULT;
444174Sbill 		break;
445174Sbill 
446174Sbill 	case TIOCGPGRP:
447174Sbill 		if (copyout((caddr_t)&tp->t_pgrp, addr, sizeof(tp->t_pgrp)))
448174Sbill 			u.u_error = EFAULT;
449174Sbill 		break;
450174Sbill 
451174Sbill 	/*
452174Sbill 	 * Modify local mode word.
453174Sbill 	 */
454174Sbill 	case TIOCLBIS:
455728Sbill 		if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local)))
456728Sbill 			u.u_error = EFAULT;
457728Sbill 		else
458728Sbill 			tp->t_local |= temp;
459174Sbill 		break;
460174Sbill 
461174Sbill 	case TIOCLBIC:
462728Sbill 		if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local)))
463728Sbill 			u.u_error = EFAULT;
464728Sbill 		else
465728Sbill 			tp->t_local &= ~temp;
466174Sbill 		break;
467174Sbill 
468174Sbill 	case TIOCLSET:
469728Sbill 		if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local)))
470728Sbill 			u.u_error = EFAULT;
471728Sbill 		else
472728Sbill 			tp->t_local = temp;
473174Sbill 		break;
474174Sbill 
475174Sbill 	case TIOCLGET:
476174Sbill 		if (copyout((caddr_t)&tp->t_local, addr, sizeof(tp->t_local)))
477174Sbill 			u.u_error = EFAULT;
478174Sbill 		break;
479174Sbill 
480903Sbill 	/*
481903Sbill 	 * Return number of characters in
482903Sbill 	 * the output.
483903Sbill 	 */
484213Sbill 	case TIOCOUTQ:
485213Sbill 		if (copyout((caddr_t)&tp->t_outq.c_cc, addr, sizeof(tp->t_outq.c_cc)))
486213Sbill 			u.u_error = EFAULT;
487213Sbill 		break;
488213Sbill 
489903Sbill 	/*
490903Sbill 	 * Simulate typing of a character at the terminal.
491903Sbill 	 */
492887Sbill 	case TIOCSTI:
493887Sbill 		c = fubyte(addr);
494887Sbill 		if (u.u_uid && u.u_ttyp != tp || c < 0)
495887Sbill 			u.u_error = EFAULT;
496887Sbill 		else
497887Sbill 			(*linesw[tp->t_line].l_rint)(c, tp);
498887Sbill 		break;
499174Sbill /* end of locals */
500887Sbill 
50139Sbill 	default:
50239Sbill 		return(0);
50339Sbill 	}
50439Sbill 	return(1);
50539Sbill }
506