xref: /csrg-svn/sys/kern/tty.c (revision 925)
1*925Sbill /*	tty.c	3.19	09/27/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 
60*925Sbill short	tthiwat[16] =
61*925Sbill    { 100,100,100,100,100,100,100,200,200,400,400,400,650,650,650,650 };
62*925Sbill short	ttlowat[16] =
63*925Sbill    {  30, 30, 30, 30, 30, 30, 30, 50, 50,120,120,120,125,125,125,125 };
64*925Sbill 
6539Sbill #define	OBUFSIZ	100
6639Sbill 
6739Sbill /*
6839Sbill  * set default control characters.
6939Sbill  */
7039Sbill ttychars(tp)
7139Sbill register struct tty *tp;
7239Sbill {
73174Sbill 
7439Sbill 	tun.t_intrc = CINTR;
7539Sbill 	tun.t_quitc = CQUIT;
7639Sbill 	tun.t_startc = CSTART;
7739Sbill 	tun.t_stopc = CSTOP;
7839Sbill 	tun.t_eofc = CEOT;
7939Sbill 	tun.t_brkc = CBRK;
8039Sbill 	tp->t_erase = CERASE;
8139Sbill 	tp->t_kill = CKILL;
82174Sbill /* begin local */
83208Sbill 	tlun.t_suspc = CTRL(z);
84208Sbill 	tlun.t_dsuspc = CTRL(y);
85174Sbill 	tlun.t_rprntc = CTRL(r);
86174Sbill 	tlun.t_flushc = CTRL(o);
87174Sbill 	tlun.t_werasc = CTRL(w);
88174Sbill 	tlun.t_lnextc = CTRL(v);
89174Sbill 	tp->t_local = 0;
90174Sbill 	tp->t_lstate = 0;
91174Sbill /* end local */
9239Sbill }
9339Sbill 
9439Sbill /*
95903Sbill  * Wait for output to drain, then flush input waiting.
9639Sbill  */
97903Sbill wflushtty(tp)
9839Sbill register struct tty *tp;
9939Sbill {
10039Sbill 
101903Sbill 	(void) spl5();
102903Sbill 	while (tp->t_outq.c_cc && tp->t_state&CARR_ON) {
103903Sbill 		(*tp->t_oproc)(tp);
104903Sbill 		tp->t_state |= ASLEEP;
105903Sbill 		sleep((caddr_t)&tp->t_outq, TTOPRI);
106903Sbill 	}
107903Sbill 	flushtty(tp, FREAD|FWRITE);
108903Sbill 	(void) spl0();
10939Sbill }
11039Sbill 
11139Sbill /*
112903Sbill  * flush all TTY queues
11339Sbill  */
114903Sbill flushtty(tp, rw)
115903Sbill register struct tty *tp;
11639Sbill {
117903Sbill 	register s;
118903Sbill 
119903Sbill 	if (tp->t_line == NETLDISC)
120903Sbill 		return;
121903Sbill 	s = spl6();
122903Sbill 	if (rw & FREAD) {
123903Sbill 		while (getc(&tp->t_canq) >= 0)
124903Sbill 			;
125903Sbill 		wakeup((caddr_t)&tp->t_rawq);
126903Sbill 	}
127903Sbill 	if (rw & FWRITE) {
128903Sbill 		wakeup((caddr_t)&tp->t_outq);
129903Sbill 		tp->t_state &= ~TTSTOP;
130903Sbill 		(*cdevsw[major(tp->t_dev)].d_stop)(tp);
131903Sbill 		while (getc(&tp->t_outq) >= 0)
132903Sbill 			;
133903Sbill 	}
134903Sbill 	if (rw & FREAD) {
135903Sbill 		while (getc(&tp->t_rawq) >= 0)
136903Sbill 			;
137903Sbill 		tp->t_delct = 0;
138903Sbill 		tp->t_rocount = 0;		/* local */
139903Sbill 		tp->t_rocol = 0;
140903Sbill 		tp->t_lstate = 0;
141903Sbill 	}
142903Sbill 	splx(s);
14339Sbill }
14439Sbill 
145903Sbill /*
146903Sbill  * Send stop character on input overflow.
147903Sbill  */
148903Sbill ttyblock(tp)
149903Sbill register struct tty *tp;
15039Sbill {
151903Sbill 	register x;
152903Sbill 	x = tp->t_rawq.c_cc + tp->t_canq.c_cc;
153903Sbill 	if (tp->t_rawq.c_cc > TTYHOG) {
154903Sbill 		flushtty(tp, FREAD|FWRITE);
155903Sbill 		tp->t_state &= ~TBLOCK;
156903Sbill 	}
157903Sbill 	if (x >= TTYHOG/2) {
158903Sbill 		if (putc(tun.t_stopc, &tp->t_outq)==0) {
159903Sbill 			tp->t_state |= TBLOCK;
160903Sbill 			tp->t_char++;
161903Sbill 			ttstart(tp);
162903Sbill 		}
163903Sbill 	}
16439Sbill }
16539Sbill 
16639Sbill /*
167903Sbill  * Restart typewriter output following a delay
168903Sbill  * timeout.
169903Sbill  * The name of the routine is passed to the timeout
170903Sbill  * subroutine and it is called during a clock interrupt.
171121Sbill  */
172903Sbill ttrstrt(tp)
173121Sbill register struct tty *tp;
174121Sbill {
175121Sbill 
176903Sbill 	tp->t_state &= ~TIMEOUT;
177903Sbill 	ttstart(tp);
178121Sbill }
179121Sbill 
180121Sbill /*
181903Sbill  * Start output on the typewriter. It is used from the top half
182903Sbill  * after some characters have been put on the output queue,
183903Sbill  * from the interrupt routine to transmit the next
184903Sbill  * character, and after a timeout has finished.
18539Sbill  */
186903Sbill ttstart(tp)
187903Sbill register struct tty *tp;
18839Sbill {
189903Sbill 	register s;
19039Sbill 
191903Sbill 	s = spl5();
192903Sbill 	if((tp->t_state&(TIMEOUT|TTSTOP|BUSY)) == 0)
193903Sbill 		(*tp->t_oproc)(tp);
194903Sbill 	splx(s);
19539Sbill }
19639Sbill 
19739Sbill /*
198903Sbill  * Common code for tty ioctls.
19939Sbill  */
200903Sbill ttioctl(com, tp, addr, dev, flag)
20139Sbill register struct tty *tp;
20239Sbill caddr_t addr;
20339Sbill {
20439Sbill 	unsigned t;
205174Sbill 	struct sgttyb iocb;
206191Sbill 	struct clist tq;
20739Sbill 	extern int nldisp;
208887Sbill 	register c;
209728Sbill 	int temp;
21039Sbill 
211903Sbill 	/*
212915Sbill 	 * This is especially so that isatty() will
213915Sbill 	 * fail when carrier is gone.
214915Sbill 	 */
215915Sbill 	if ((tp->t_state&CARR_ON) == 0) {
216915Sbill 		u.u_error = EBADF;
217915Sbill 		return (1);
218915Sbill 	}
219915Sbill 
220915Sbill 	/*
221903Sbill 	 * If the ioctl involves modification,
222903Sbill 	 * insist on being able to write the device,
223903Sbill 	 * and hang if in the background.
224903Sbill 	 */
22539Sbill 	switch(com) {
22639Sbill 
227915Sbill 	case TIOCSETD:
228915Sbill 	case TIOCSETP:
229915Sbill 	case TIOCSETN:
230903Sbill 	case TIOCFLUSH:
231903Sbill 	case TIOCSETC:
232903Sbill 	case TIOCSLTC:
233903Sbill 	case TIOCSPGRP:
234903Sbill 	case TIOCLBIS:
235903Sbill 	case TIOCLBIC:
236903Sbill 	case TIOCLSET:
237903Sbill 	case TIOCSTI:
238915Sbill /* this is reasonable, but impractical...
239903Sbill 		if ((flag & FWRITE) == 0) {
240903Sbill 			u.u_error = EBADF;
241903Sbill 			return (1);
242903Sbill 		}
243915Sbill  */
244903Sbill 		while (tp->t_line == NTTYDISC &&
245903Sbill 		   u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp &&
246903Sbill 		   (u.u_procp->p_flag&SVFORK) == 0 &&
247903Sbill 		   u.u_signal[SIGTTOU] != SIG_IGN &&
248903Sbill 		   u.u_signal[SIGTTOU] != SIG_HOLD &&
249903Sbill 		   (u.u_procp->p_flag&SDETACH)==0) {
250903Sbill 			gsignal(u.u_procp->p_pgrp, SIGTTOU);
251903Sbill 			sleep((caddr_t)&lbolt, TTOPRI);
252903Sbill 		}
253903Sbill 		break;
254903Sbill 	}
255903Sbill 
25639Sbill 	/*
257903Sbill 	 * Process the ioctl.
25839Sbill 	 */
259903Sbill 	switch(com) {
260903Sbill 
261903Sbill 	/*
262903Sbill 	 * Get discipline number
263903Sbill 	 */
26439Sbill 	case TIOCGETD:
26539Sbill 		t = tp->t_line;
26639Sbill 		if (copyout((caddr_t)&t, addr, sizeof(t)))
26739Sbill 			u.u_error = EFAULT;
26839Sbill 		break;
26939Sbill 
27039Sbill 	/*
271903Sbill 	 * Set line discipline
27239Sbill 	 */
27339Sbill 	case TIOCSETD:
27439Sbill 		if (copyin(addr, (caddr_t)&t, sizeof(t))) {
27539Sbill 			u.u_error = EFAULT;
27639Sbill 			break;
27739Sbill 		}
27839Sbill 		if (t >= nldisp) {
27939Sbill 			u.u_error = ENXIO;
28039Sbill 			break;
28139Sbill 		}
282174Sbill 		(void) spl5();
28339Sbill 		if (tp->t_line)
28439Sbill 			(*linesw[tp->t_line].l_close)(tp);
28539Sbill 		if (t)
28639Sbill 			(*linesw[t].l_open)(dev, tp, addr);
28739Sbill 		if (u.u_error==0)
28839Sbill 			tp->t_line = t;
289174Sbill 		(void) spl0();
29039Sbill 		break;
29139Sbill 
29239Sbill 	/*
293903Sbill 	 * Prevent more opens on channel
29439Sbill 	 */
29539Sbill 	case TIOCEXCL:
29639Sbill 		tp->t_state |= XCLUDE;
29739Sbill 		break;
29839Sbill 
29939Sbill 	case TIOCNXCL:
30039Sbill 		tp->t_state &= ~XCLUDE;
30139Sbill 		break;
30239Sbill 
30339Sbill 	/*
30439Sbill 	 * Set new parameters
30539Sbill 	 */
30639Sbill 	case TIOCSETP:
307191Sbill 	case TIOCSETN:
30839Sbill 		if (copyin(addr, (caddr_t)&iocb, sizeof(iocb))) {
30939Sbill 			u.u_error = EFAULT;
31039Sbill 			return(1);
31139Sbill 		}
312121Sbill 		(void) spl5();
313174Sbill 		if (tp->t_line == 0) {
314174Sbill 			if (com == TIOCSETP)
315174Sbill 				wflushtty(tp);
316174Sbill 			while (canon(tp)>=0)
317174Sbill 				;
318174Sbill 		} else if (tp->t_line == NTTYDISC) {
319174Sbill 			if (tp->t_flags&RAW || iocb.sg_flags&RAW ||
320174Sbill 			    com == TIOCSETP)
321174Sbill 				wflushtty(tp);
322174Sbill 			else if ((tp->t_flags&CBREAK) != (iocb.sg_flags&CBREAK)) {
323174Sbill 				if (iocb.sg_flags & CBREAK) {
324174Sbill 					catq(&tp->t_rawq, &tp->t_canq);
325174Sbill 					tq = tp->t_rawq;
326174Sbill 					tp->t_rawq = tp->t_canq;
327174Sbill 					tp->t_canq = tq;
328174Sbill 				} else {
329174Sbill 					tp->t_local |= LPENDIN;
330174Sbill 					if (tp->t_canq.c_cc)
331174Sbill 						panic("ioccom canq");
332174Sbill 					if (tp->t_chan)
333174Sbill 						(void) sdata(tp->t_chan);
334174Sbill 					else
335174Sbill 						wakeup((caddr_t)&tp->t_rawq);
336174Sbill 				}
337174Sbill 			}
338174Sbill 		}
33939Sbill 		if ((tp->t_state&SPEEDS)==0) {
340174Sbill 			tp->t_ispeed = iocb.sg_ispeed;
341174Sbill 			tp->t_ospeed = iocb.sg_ospeed;
34239Sbill 		}
343174Sbill 		tp->t_erase = iocb.sg_erase;
344174Sbill 		tp->t_kill = iocb.sg_kill;
345174Sbill 		tp->t_flags = iocb.sg_flags;
346121Sbill 		(void) spl0();
34739Sbill 		break;
34839Sbill 
34939Sbill 	/*
350903Sbill 	 * Send current parameters to user
35139Sbill 	 */
35239Sbill 	case TIOCGETP:
353174Sbill 		iocb.sg_ispeed = tp->t_ispeed;
354174Sbill 		iocb.sg_ospeed = tp->t_ospeed;
355174Sbill 		iocb.sg_erase = tp->t_erase;
356174Sbill 		iocb.sg_kill = tp->t_kill;
357174Sbill 		iocb.sg_flags = tp->t_flags;
35839Sbill 		if (copyout((caddr_t)&iocb, addr, sizeof(iocb)))
35939Sbill 			u.u_error = EFAULT;
36039Sbill 		break;
36139Sbill 
36239Sbill 	/*
36339Sbill 	 * Hang up line on last close
36439Sbill 	 */
36539Sbill 	case TIOCHPCL:
36639Sbill 		tp->t_state |= HUPCLS;
36739Sbill 		break;
36839Sbill 
36939Sbill 	case TIOCFLUSH:
370872Sbill 		flushtty(tp, FREAD|FWRITE);
37139Sbill 		break;
37239Sbill 
37339Sbill 	/*
374903Sbill 	 * Ioctl entries to line discipline
37539Sbill 	 */
37639Sbill 	case DIOCSETP:
37739Sbill 	case DIOCGETP:
378121Sbill 		if ((*linesw[tp->t_line].l_ioctl)(com, tp, addr))
379121Sbill 			u.u_error = ENOTTY;
38039Sbill 		break;
38139Sbill 
38239Sbill 	/*
383903Sbill 	 * Set and fetch special characters
38439Sbill 	 */
38539Sbill 	case TIOCSETC:
386174Sbill 		if (copyin(addr, (caddr_t)&tun, sizeof(struct tchars)))
38739Sbill 			u.u_error = EFAULT;
38839Sbill 		break;
38939Sbill 
39039Sbill 	case TIOCGETC:
391174Sbill 		if (copyout((caddr_t)&tun, addr, sizeof(struct tchars)))
39239Sbill 			u.u_error = EFAULT;
39339Sbill 		break;
39439Sbill 
395174Sbill /* local ioctls */
396903Sbill 	/*
397903Sbill 	 * Set/get local special characters.
398903Sbill 	 */
399174Sbill 	case TIOCSLTC:
400174Sbill 		if (copyin(addr, (caddr_t)&tlun, sizeof (struct ltchars)))
401174Sbill 			u.u_error = EFAULT;
402174Sbill 		break;
403174Sbill 
404174Sbill 	case TIOCGLTC:
405174Sbill 		if (copyout((caddr_t)&tlun, addr, sizeof (struct ltchars)))
406174Sbill 			u.u_error = EFAULT;
407174Sbill 		break;
408174Sbill 
409903Sbill 	/*
410903Sbill 	 * Return number of characters immediately available.
411903Sbill 	 */
412174Sbill 	case FIONREAD: {
413340Sbill 		off_t nread;
414174Sbill 
415340Sbill 		switch (tp->t_line) {
416340Sbill 
417340Sbill 		case NETLDISC:
418340Sbill 			nread = tp->t_rec ? tp->t_inbuf : 0;
419340Sbill 			break;
420340Sbill 
421894Sbill 		case 0:
422894Sbill 			(void) spl5();
423894Sbill 			while (canon(tp)>=0)
424894Sbill 				;
425894Sbill 			(void) spl0();
426894Sbill 			/* fall into ... */
427894Sbill 
428340Sbill 		case NTTYDISC:
429340Sbill 			nread = tp->t_canq.c_cc;
430340Sbill 			if (tp->t_flags & (RAW|CBREAK))
431340Sbill 				nread += tp->t_rawq.c_cc;
432340Sbill 			break;
433340Sbill 
434340Sbill 		}
435174Sbill 		if (copyout((caddr_t)&nread, addr, sizeof (off_t)))
436174Sbill 			u.u_error = EFAULT;
437174Sbill 		break;
438174Sbill 		}
439174Sbill 
440174Sbill 	/*
441174Sbill 	 * Should allow SPGRP and GPGRP only if tty open for reading.
442174Sbill 	 */
443174Sbill 	case TIOCSPGRP:
444728Sbill 		if (copyin(addr, (caddr_t)&tp->t_pgrp, sizeof (tp->t_pgrp)))
445728Sbill 			u.u_error = EFAULT;
446174Sbill 		break;
447174Sbill 
448174Sbill 	case TIOCGPGRP:
449174Sbill 		if (copyout((caddr_t)&tp->t_pgrp, addr, sizeof(tp->t_pgrp)))
450174Sbill 			u.u_error = EFAULT;
451174Sbill 		break;
452174Sbill 
453174Sbill 	/*
454174Sbill 	 * Modify local mode word.
455174Sbill 	 */
456174Sbill 	case TIOCLBIS:
457728Sbill 		if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local)))
458728Sbill 			u.u_error = EFAULT;
459728Sbill 		else
460728Sbill 			tp->t_local |= temp;
461174Sbill 		break;
462174Sbill 
463174Sbill 	case TIOCLBIC:
464728Sbill 		if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local)))
465728Sbill 			u.u_error = EFAULT;
466728Sbill 		else
467728Sbill 			tp->t_local &= ~temp;
468174Sbill 		break;
469174Sbill 
470174Sbill 	case TIOCLSET:
471728Sbill 		if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local)))
472728Sbill 			u.u_error = EFAULT;
473728Sbill 		else
474728Sbill 			tp->t_local = temp;
475174Sbill 		break;
476174Sbill 
477174Sbill 	case TIOCLGET:
478174Sbill 		if (copyout((caddr_t)&tp->t_local, addr, sizeof(tp->t_local)))
479174Sbill 			u.u_error = EFAULT;
480174Sbill 		break;
481174Sbill 
482903Sbill 	/*
483903Sbill 	 * Return number of characters in
484903Sbill 	 * the output.
485903Sbill 	 */
486213Sbill 	case TIOCOUTQ:
487213Sbill 		if (copyout((caddr_t)&tp->t_outq.c_cc, addr, sizeof(tp->t_outq.c_cc)))
488213Sbill 			u.u_error = EFAULT;
489213Sbill 		break;
490213Sbill 
491903Sbill 	/*
492903Sbill 	 * Simulate typing of a character at the terminal.
493903Sbill 	 */
494887Sbill 	case TIOCSTI:
495887Sbill 		c = fubyte(addr);
496887Sbill 		if (u.u_uid && u.u_ttyp != tp || c < 0)
497887Sbill 			u.u_error = EFAULT;
498887Sbill 		else
499887Sbill 			(*linesw[tp->t_line].l_rint)(c, tp);
500887Sbill 		break;
501174Sbill /* end of locals */
502887Sbill 
50339Sbill 	default:
50439Sbill 		return(0);
50539Sbill 	}
50639Sbill 	return(1);
50739Sbill }
508