xref: /csrg-svn/sys/kern/tty.c (revision 1904)
1*1904Swnj /*	tty.c	4.3	12/17/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 
60925Sbill short	tthiwat[16] =
61925Sbill    { 100,100,100,100,100,100,100,200,200,400,400,400,650,650,650,650 };
62925Sbill short	ttlowat[16] =
63925Sbill    {  30, 30, 30, 30, 30, 30, 30, 50, 50,120,120,120,125,125,125,125 };
64925Sbill 
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  */
2001780Sbill /*ARGSUSED*/
201*1904Swnj ttioctl(tp, com, addr, flag)
20239Sbill register struct tty *tp;
20339Sbill caddr_t addr;
20439Sbill {
205*1904Swnj 	int dev;
20639Sbill 	unsigned t;
207174Sbill 	struct sgttyb iocb;
208191Sbill 	struct clist tq;
20939Sbill 	extern int nldisp;
210887Sbill 	register c;
211728Sbill 	int temp;
21239Sbill 
213903Sbill 	/*
214915Sbill 	 * This is especially so that isatty() will
215915Sbill 	 * fail when carrier is gone.
216915Sbill 	 */
217915Sbill 	if ((tp->t_state&CARR_ON) == 0) {
218915Sbill 		u.u_error = EBADF;
219915Sbill 		return (1);
220915Sbill 	}
221915Sbill 
222*1904Swnj 	dev = tp->t_dev;
223915Sbill 	/*
224903Sbill 	 * If the ioctl involves modification,
225903Sbill 	 * insist on being able to write the device,
226903Sbill 	 * and hang if in the background.
227903Sbill 	 */
22839Sbill 	switch(com) {
22939Sbill 
230915Sbill 	case TIOCSETD:
231915Sbill 	case TIOCSETP:
232915Sbill 	case TIOCSETN:
233903Sbill 	case TIOCFLUSH:
234903Sbill 	case TIOCSETC:
235903Sbill 	case TIOCSLTC:
236903Sbill 	case TIOCSPGRP:
237903Sbill 	case TIOCLBIS:
238903Sbill 	case TIOCLBIC:
239903Sbill 	case TIOCLSET:
240903Sbill 	case TIOCSTI:
241915Sbill /* this is reasonable, but impractical...
242903Sbill 		if ((flag & FWRITE) == 0) {
243903Sbill 			u.u_error = EBADF;
244903Sbill 			return (1);
245903Sbill 		}
246915Sbill  */
247903Sbill 		while (tp->t_line == NTTYDISC &&
248903Sbill 		   u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp &&
249903Sbill 		   (u.u_procp->p_flag&SVFORK) == 0 &&
250903Sbill 		   u.u_signal[SIGTTOU] != SIG_IGN &&
251903Sbill 		   u.u_signal[SIGTTOU] != SIG_HOLD &&
252903Sbill 		   (u.u_procp->p_flag&SDETACH)==0) {
253903Sbill 			gsignal(u.u_procp->p_pgrp, SIGTTOU);
254903Sbill 			sleep((caddr_t)&lbolt, TTOPRI);
255903Sbill 		}
256903Sbill 		break;
257903Sbill 	}
258903Sbill 
25939Sbill 	/*
260903Sbill 	 * Process the ioctl.
26139Sbill 	 */
262903Sbill 	switch(com) {
263903Sbill 
264903Sbill 	/*
265903Sbill 	 * Get discipline number
266903Sbill 	 */
26739Sbill 	case TIOCGETD:
26839Sbill 		t = tp->t_line;
26939Sbill 		if (copyout((caddr_t)&t, addr, sizeof(t)))
27039Sbill 			u.u_error = EFAULT;
27139Sbill 		break;
27239Sbill 
27339Sbill 	/*
274903Sbill 	 * Set line discipline
27539Sbill 	 */
27639Sbill 	case TIOCSETD:
27739Sbill 		if (copyin(addr, (caddr_t)&t, sizeof(t))) {
27839Sbill 			u.u_error = EFAULT;
27939Sbill 			break;
28039Sbill 		}
28139Sbill 		if (t >= nldisp) {
28239Sbill 			u.u_error = ENXIO;
28339Sbill 			break;
28439Sbill 		}
285174Sbill 		(void) spl5();
28639Sbill 		if (tp->t_line)
28739Sbill 			(*linesw[tp->t_line].l_close)(tp);
28839Sbill 		if (t)
28939Sbill 			(*linesw[t].l_open)(dev, tp, addr);
29039Sbill 		if (u.u_error==0)
29139Sbill 			tp->t_line = t;
292174Sbill 		(void) spl0();
29339Sbill 		break;
29439Sbill 
29539Sbill 	/*
296903Sbill 	 * Prevent more opens on channel
29739Sbill 	 */
29839Sbill 	case TIOCEXCL:
29939Sbill 		tp->t_state |= XCLUDE;
30039Sbill 		break;
30139Sbill 
30239Sbill 	case TIOCNXCL:
30339Sbill 		tp->t_state &= ~XCLUDE;
30439Sbill 		break;
30539Sbill 
30639Sbill 	/*
30739Sbill 	 * Set new parameters
30839Sbill 	 */
30939Sbill 	case TIOCSETP:
310191Sbill 	case TIOCSETN:
31139Sbill 		if (copyin(addr, (caddr_t)&iocb, sizeof(iocb))) {
31239Sbill 			u.u_error = EFAULT;
31339Sbill 			return(1);
31439Sbill 		}
315121Sbill 		(void) spl5();
316174Sbill 		if (tp->t_line == 0) {
317174Sbill 			if (com == TIOCSETP)
318174Sbill 				wflushtty(tp);
319174Sbill 			while (canon(tp)>=0)
320174Sbill 				;
321933Sbill #ifdef notdef
322933Sbill 			wakeup((caddr_t)&tp->t_rawq);
323933Sbill #endif
324174Sbill 		} else if (tp->t_line == NTTYDISC) {
325174Sbill 			if (tp->t_flags&RAW || iocb.sg_flags&RAW ||
326174Sbill 			    com == TIOCSETP)
327174Sbill 				wflushtty(tp);
328174Sbill 			else if ((tp->t_flags&CBREAK) != (iocb.sg_flags&CBREAK)) {
329174Sbill 				if (iocb.sg_flags & CBREAK) {
330174Sbill 					catq(&tp->t_rawq, &tp->t_canq);
331174Sbill 					tq = tp->t_rawq;
332174Sbill 					tp->t_rawq = tp->t_canq;
333174Sbill 					tp->t_canq = tq;
334174Sbill 				} else {
335174Sbill 					tp->t_local |= LPENDIN;
336174Sbill 					if (tp->t_canq.c_cc)
337174Sbill 						panic("ioccom canq");
338933Sbill #ifdef notdef
339174Sbill 					if (tp->t_chan)
340174Sbill 						(void) sdata(tp->t_chan);
341174Sbill 					else
342933Sbill #endif
343174Sbill 						wakeup((caddr_t)&tp->t_rawq);
344174Sbill 				}
345174Sbill 			}
346174Sbill 		}
34739Sbill 		if ((tp->t_state&SPEEDS)==0) {
348174Sbill 			tp->t_ispeed = iocb.sg_ispeed;
349174Sbill 			tp->t_ospeed = iocb.sg_ospeed;
35039Sbill 		}
351174Sbill 		tp->t_erase = iocb.sg_erase;
352174Sbill 		tp->t_kill = iocb.sg_kill;
353174Sbill 		tp->t_flags = iocb.sg_flags;
354121Sbill 		(void) spl0();
35539Sbill 		break;
35639Sbill 
35739Sbill 	/*
358903Sbill 	 * Send current parameters to user
35939Sbill 	 */
36039Sbill 	case TIOCGETP:
361174Sbill 		iocb.sg_ispeed = tp->t_ispeed;
362174Sbill 		iocb.sg_ospeed = tp->t_ospeed;
363174Sbill 		iocb.sg_erase = tp->t_erase;
364174Sbill 		iocb.sg_kill = tp->t_kill;
365174Sbill 		iocb.sg_flags = tp->t_flags;
36639Sbill 		if (copyout((caddr_t)&iocb, addr, sizeof(iocb)))
36739Sbill 			u.u_error = EFAULT;
36839Sbill 		break;
36939Sbill 
37039Sbill 	/*
37139Sbill 	 * Hang up line on last close
37239Sbill 	 */
37339Sbill 	case TIOCHPCL:
37439Sbill 		tp->t_state |= HUPCLS;
37539Sbill 		break;
37639Sbill 
37739Sbill 	case TIOCFLUSH:
378872Sbill 		flushtty(tp, FREAD|FWRITE);
37939Sbill 		break;
38039Sbill 
38139Sbill 	/*
382903Sbill 	 * Set and fetch special characters
38339Sbill 	 */
38439Sbill 	case TIOCSETC:
385174Sbill 		if (copyin(addr, (caddr_t)&tun, sizeof(struct tchars)))
38639Sbill 			u.u_error = EFAULT;
38739Sbill 		break;
38839Sbill 
38939Sbill 	case TIOCGETC:
390174Sbill 		if (copyout((caddr_t)&tun, addr, sizeof(struct tchars)))
39139Sbill 			u.u_error = EFAULT;
39239Sbill 		break;
39339Sbill 
394174Sbill /* local ioctls */
395903Sbill 	/*
396903Sbill 	 * Set/get local special characters.
397903Sbill 	 */
398174Sbill 	case TIOCSLTC:
399174Sbill 		if (copyin(addr, (caddr_t)&tlun, sizeof (struct ltchars)))
400174Sbill 			u.u_error = EFAULT;
401174Sbill 		break;
402174Sbill 
403174Sbill 	case TIOCGLTC:
404174Sbill 		if (copyout((caddr_t)&tlun, addr, sizeof (struct ltchars)))
405174Sbill 			u.u_error = EFAULT;
406174Sbill 		break;
407174Sbill 
408903Sbill 	/*
409903Sbill 	 * Return number of characters immediately available.
410903Sbill 	 */
411174Sbill 	case FIONREAD: {
412340Sbill 		off_t nread;
413174Sbill 
414340Sbill 		switch (tp->t_line) {
415340Sbill 
416340Sbill 		case NETLDISC:
417340Sbill 			nread = tp->t_rec ? tp->t_inbuf : 0;
418340Sbill 			break;
419340Sbill 
420894Sbill 		case 0:
421894Sbill 			(void) spl5();
422894Sbill 			while (canon(tp)>=0)
423894Sbill 				;
424894Sbill 			(void) spl0();
425894Sbill 			/* fall into ... */
426894Sbill 
427340Sbill 		case NTTYDISC:
428340Sbill 			nread = tp->t_canq.c_cc;
429340Sbill 			if (tp->t_flags & (RAW|CBREAK))
430340Sbill 				nread += tp->t_rawq.c_cc;
431340Sbill 			break;
432340Sbill 
433340Sbill 		}
434174Sbill 		if (copyout((caddr_t)&nread, addr, sizeof (off_t)))
435174Sbill 			u.u_error = EFAULT;
436174Sbill 		break;
437174Sbill 		}
438174Sbill 
439174Sbill 	/*
440174Sbill 	 * Should allow SPGRP and GPGRP only if tty open for reading.
441174Sbill 	 */
442174Sbill 	case TIOCSPGRP:
443728Sbill 		if (copyin(addr, (caddr_t)&tp->t_pgrp, sizeof (tp->t_pgrp)))
444728Sbill 			u.u_error = EFAULT;
445174Sbill 		break;
446174Sbill 
447174Sbill 	case TIOCGPGRP:
448174Sbill 		if (copyout((caddr_t)&tp->t_pgrp, addr, sizeof(tp->t_pgrp)))
449174Sbill 			u.u_error = EFAULT;
450174Sbill 		break;
451174Sbill 
452174Sbill 	/*
453174Sbill 	 * Modify local mode word.
454174Sbill 	 */
455174Sbill 	case TIOCLBIS:
456728Sbill 		if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local)))
457728Sbill 			u.u_error = EFAULT;
458728Sbill 		else
459728Sbill 			tp->t_local |= temp;
460174Sbill 		break;
461174Sbill 
462174Sbill 	case TIOCLBIC:
463728Sbill 		if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local)))
464728Sbill 			u.u_error = EFAULT;
465728Sbill 		else
466728Sbill 			tp->t_local &= ~temp;
467174Sbill 		break;
468174Sbill 
469174Sbill 	case TIOCLSET:
470728Sbill 		if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local)))
471728Sbill 			u.u_error = EFAULT;
472728Sbill 		else
473728Sbill 			tp->t_local = temp;
474174Sbill 		break;
475174Sbill 
476174Sbill 	case TIOCLGET:
477174Sbill 		if (copyout((caddr_t)&tp->t_local, addr, sizeof(tp->t_local)))
478174Sbill 			u.u_error = EFAULT;
479174Sbill 		break;
480174Sbill 
481903Sbill 	/*
482903Sbill 	 * Return number of characters in
483903Sbill 	 * the output.
484903Sbill 	 */
485213Sbill 	case TIOCOUTQ:
486213Sbill 		if (copyout((caddr_t)&tp->t_outq.c_cc, addr, sizeof(tp->t_outq.c_cc)))
487213Sbill 			u.u_error = EFAULT;
488213Sbill 		break;
489213Sbill 
490903Sbill 	/*
491903Sbill 	 * Simulate typing of a character at the terminal.
492903Sbill 	 */
493887Sbill 	case TIOCSTI:
494887Sbill 		c = fubyte(addr);
495887Sbill 		if (u.u_uid && u.u_ttyp != tp || c < 0)
496887Sbill 			u.u_error = EFAULT;
497887Sbill 		else
498887Sbill 			(*linesw[tp->t_line].l_rint)(c, tp);
499887Sbill 		break;
500174Sbill /* end of locals */
501887Sbill 
50239Sbill 	default:
50339Sbill 		return(0);
50439Sbill 	}
50539Sbill 	return(1);
50639Sbill }
507