xref: /csrg-svn/sys/kern/tty.c (revision 1780)
1*1780Sbill /*	tty.c	4.2	11/09/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  */
200*1780Sbill /*ARGSUSED*/
201903Sbill ttioctl(com, tp, addr, dev, flag)
20239Sbill register struct tty *tp;
20339Sbill caddr_t addr;
20439Sbill {
20539Sbill 	unsigned t;
206174Sbill 	struct sgttyb iocb;
207191Sbill 	struct clist tq;
20839Sbill 	extern int nldisp;
209887Sbill 	register c;
210728Sbill 	int temp;
21139Sbill 
212903Sbill 	/*
213915Sbill 	 * This is especially so that isatty() will
214915Sbill 	 * fail when carrier is gone.
215915Sbill 	 */
216915Sbill 	if ((tp->t_state&CARR_ON) == 0) {
217915Sbill 		u.u_error = EBADF;
218915Sbill 		return (1);
219915Sbill 	}
220915Sbill 
221915Sbill 	/*
222903Sbill 	 * If the ioctl involves modification,
223903Sbill 	 * insist on being able to write the device,
224903Sbill 	 * and hang if in the background.
225903Sbill 	 */
22639Sbill 	switch(com) {
22739Sbill 
228915Sbill 	case TIOCSETD:
229915Sbill 	case TIOCSETP:
230915Sbill 	case TIOCSETN:
231903Sbill 	case TIOCFLUSH:
232903Sbill 	case TIOCSETC:
233903Sbill 	case TIOCSLTC:
234903Sbill 	case TIOCSPGRP:
235903Sbill 	case TIOCLBIS:
236903Sbill 	case TIOCLBIC:
237903Sbill 	case TIOCLSET:
238903Sbill 	case TIOCSTI:
239915Sbill /* this is reasonable, but impractical...
240903Sbill 		if ((flag & FWRITE) == 0) {
241903Sbill 			u.u_error = EBADF;
242903Sbill 			return (1);
243903Sbill 		}
244915Sbill  */
245903Sbill 		while (tp->t_line == NTTYDISC &&
246903Sbill 		   u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp &&
247903Sbill 		   (u.u_procp->p_flag&SVFORK) == 0 &&
248903Sbill 		   u.u_signal[SIGTTOU] != SIG_IGN &&
249903Sbill 		   u.u_signal[SIGTTOU] != SIG_HOLD &&
250903Sbill 		   (u.u_procp->p_flag&SDETACH)==0) {
251903Sbill 			gsignal(u.u_procp->p_pgrp, SIGTTOU);
252903Sbill 			sleep((caddr_t)&lbolt, TTOPRI);
253903Sbill 		}
254903Sbill 		break;
255903Sbill 	}
256903Sbill 
25739Sbill 	/*
258903Sbill 	 * Process the ioctl.
25939Sbill 	 */
260903Sbill 	switch(com) {
261903Sbill 
262903Sbill 	/*
263903Sbill 	 * Get discipline number
264903Sbill 	 */
26539Sbill 	case TIOCGETD:
26639Sbill 		t = tp->t_line;
26739Sbill 		if (copyout((caddr_t)&t, addr, sizeof(t)))
26839Sbill 			u.u_error = EFAULT;
26939Sbill 		break;
27039Sbill 
27139Sbill 	/*
272903Sbill 	 * Set line discipline
27339Sbill 	 */
27439Sbill 	case TIOCSETD:
27539Sbill 		if (copyin(addr, (caddr_t)&t, sizeof(t))) {
27639Sbill 			u.u_error = EFAULT;
27739Sbill 			break;
27839Sbill 		}
27939Sbill 		if (t >= nldisp) {
28039Sbill 			u.u_error = ENXIO;
28139Sbill 			break;
28239Sbill 		}
283174Sbill 		(void) spl5();
28439Sbill 		if (tp->t_line)
28539Sbill 			(*linesw[tp->t_line].l_close)(tp);
28639Sbill 		if (t)
28739Sbill 			(*linesw[t].l_open)(dev, tp, addr);
28839Sbill 		if (u.u_error==0)
28939Sbill 			tp->t_line = t;
290174Sbill 		(void) spl0();
29139Sbill 		break;
29239Sbill 
29339Sbill 	/*
294903Sbill 	 * Prevent more opens on channel
29539Sbill 	 */
29639Sbill 	case TIOCEXCL:
29739Sbill 		tp->t_state |= XCLUDE;
29839Sbill 		break;
29939Sbill 
30039Sbill 	case TIOCNXCL:
30139Sbill 		tp->t_state &= ~XCLUDE;
30239Sbill 		break;
30339Sbill 
30439Sbill 	/*
30539Sbill 	 * Set new parameters
30639Sbill 	 */
30739Sbill 	case TIOCSETP:
308191Sbill 	case TIOCSETN:
30939Sbill 		if (copyin(addr, (caddr_t)&iocb, sizeof(iocb))) {
31039Sbill 			u.u_error = EFAULT;
31139Sbill 			return(1);
31239Sbill 		}
313121Sbill 		(void) spl5();
314174Sbill 		if (tp->t_line == 0) {
315174Sbill 			if (com == TIOCSETP)
316174Sbill 				wflushtty(tp);
317174Sbill 			while (canon(tp)>=0)
318174Sbill 				;
319933Sbill #ifdef notdef
320933Sbill 			wakeup((caddr_t)&tp->t_rawq);
321933Sbill #endif
322174Sbill 		} else if (tp->t_line == NTTYDISC) {
323174Sbill 			if (tp->t_flags&RAW || iocb.sg_flags&RAW ||
324174Sbill 			    com == TIOCSETP)
325174Sbill 				wflushtty(tp);
326174Sbill 			else if ((tp->t_flags&CBREAK) != (iocb.sg_flags&CBREAK)) {
327174Sbill 				if (iocb.sg_flags & CBREAK) {
328174Sbill 					catq(&tp->t_rawq, &tp->t_canq);
329174Sbill 					tq = tp->t_rawq;
330174Sbill 					tp->t_rawq = tp->t_canq;
331174Sbill 					tp->t_canq = tq;
332174Sbill 				} else {
333174Sbill 					tp->t_local |= LPENDIN;
334174Sbill 					if (tp->t_canq.c_cc)
335174Sbill 						panic("ioccom canq");
336933Sbill #ifdef notdef
337174Sbill 					if (tp->t_chan)
338174Sbill 						(void) sdata(tp->t_chan);
339174Sbill 					else
340933Sbill #endif
341174Sbill 						wakeup((caddr_t)&tp->t_rawq);
342174Sbill 				}
343174Sbill 			}
344174Sbill 		}
34539Sbill 		if ((tp->t_state&SPEEDS)==0) {
346174Sbill 			tp->t_ispeed = iocb.sg_ispeed;
347174Sbill 			tp->t_ospeed = iocb.sg_ospeed;
34839Sbill 		}
349174Sbill 		tp->t_erase = iocb.sg_erase;
350174Sbill 		tp->t_kill = iocb.sg_kill;
351174Sbill 		tp->t_flags = iocb.sg_flags;
352121Sbill 		(void) spl0();
35339Sbill 		break;
35439Sbill 
35539Sbill 	/*
356903Sbill 	 * Send current parameters to user
35739Sbill 	 */
35839Sbill 	case TIOCGETP:
359174Sbill 		iocb.sg_ispeed = tp->t_ispeed;
360174Sbill 		iocb.sg_ospeed = tp->t_ospeed;
361174Sbill 		iocb.sg_erase = tp->t_erase;
362174Sbill 		iocb.sg_kill = tp->t_kill;
363174Sbill 		iocb.sg_flags = tp->t_flags;
36439Sbill 		if (copyout((caddr_t)&iocb, addr, sizeof(iocb)))
36539Sbill 			u.u_error = EFAULT;
36639Sbill 		break;
36739Sbill 
36839Sbill 	/*
36939Sbill 	 * Hang up line on last close
37039Sbill 	 */
37139Sbill 	case TIOCHPCL:
37239Sbill 		tp->t_state |= HUPCLS;
37339Sbill 		break;
37439Sbill 
37539Sbill 	case TIOCFLUSH:
376872Sbill 		flushtty(tp, FREAD|FWRITE);
37739Sbill 		break;
37839Sbill 
37939Sbill 	/*
380903Sbill 	 * Ioctl entries to line discipline
38139Sbill 	 */
38239Sbill 	case DIOCSETP:
38339Sbill 	case DIOCGETP:
384121Sbill 		if ((*linesw[tp->t_line].l_ioctl)(com, tp, addr))
385121Sbill 			u.u_error = ENOTTY;
38639Sbill 		break;
38739Sbill 
38839Sbill 	/*
389903Sbill 	 * Set and fetch special characters
39039Sbill 	 */
39139Sbill 	case TIOCSETC:
392174Sbill 		if (copyin(addr, (caddr_t)&tun, sizeof(struct tchars)))
39339Sbill 			u.u_error = EFAULT;
39439Sbill 		break;
39539Sbill 
39639Sbill 	case TIOCGETC:
397174Sbill 		if (copyout((caddr_t)&tun, addr, sizeof(struct tchars)))
39839Sbill 			u.u_error = EFAULT;
39939Sbill 		break;
40039Sbill 
401174Sbill /* local ioctls */
402903Sbill 	/*
403903Sbill 	 * Set/get local special characters.
404903Sbill 	 */
405174Sbill 	case TIOCSLTC:
406174Sbill 		if (copyin(addr, (caddr_t)&tlun, sizeof (struct ltchars)))
407174Sbill 			u.u_error = EFAULT;
408174Sbill 		break;
409174Sbill 
410174Sbill 	case TIOCGLTC:
411174Sbill 		if (copyout((caddr_t)&tlun, addr, sizeof (struct ltchars)))
412174Sbill 			u.u_error = EFAULT;
413174Sbill 		break;
414174Sbill 
415903Sbill 	/*
416903Sbill 	 * Return number of characters immediately available.
417903Sbill 	 */
418174Sbill 	case FIONREAD: {
419340Sbill 		off_t nread;
420174Sbill 
421340Sbill 		switch (tp->t_line) {
422340Sbill 
423340Sbill 		case NETLDISC:
424340Sbill 			nread = tp->t_rec ? tp->t_inbuf : 0;
425340Sbill 			break;
426340Sbill 
427894Sbill 		case 0:
428894Sbill 			(void) spl5();
429894Sbill 			while (canon(tp)>=0)
430894Sbill 				;
431894Sbill 			(void) spl0();
432894Sbill 			/* fall into ... */
433894Sbill 
434340Sbill 		case NTTYDISC:
435340Sbill 			nread = tp->t_canq.c_cc;
436340Sbill 			if (tp->t_flags & (RAW|CBREAK))
437340Sbill 				nread += tp->t_rawq.c_cc;
438340Sbill 			break;
439340Sbill 
440340Sbill 		}
441174Sbill 		if (copyout((caddr_t)&nread, addr, sizeof (off_t)))
442174Sbill 			u.u_error = EFAULT;
443174Sbill 		break;
444174Sbill 		}
445174Sbill 
446174Sbill 	/*
447174Sbill 	 * Should allow SPGRP and GPGRP only if tty open for reading.
448174Sbill 	 */
449174Sbill 	case TIOCSPGRP:
450728Sbill 		if (copyin(addr, (caddr_t)&tp->t_pgrp, sizeof (tp->t_pgrp)))
451728Sbill 			u.u_error = EFAULT;
452174Sbill 		break;
453174Sbill 
454174Sbill 	case TIOCGPGRP:
455174Sbill 		if (copyout((caddr_t)&tp->t_pgrp, addr, sizeof(tp->t_pgrp)))
456174Sbill 			u.u_error = EFAULT;
457174Sbill 		break;
458174Sbill 
459174Sbill 	/*
460174Sbill 	 * Modify local mode word.
461174Sbill 	 */
462174Sbill 	case TIOCLBIS:
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 TIOCLBIC:
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 TIOCLSET:
477728Sbill 		if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local)))
478728Sbill 			u.u_error = EFAULT;
479728Sbill 		else
480728Sbill 			tp->t_local = temp;
481174Sbill 		break;
482174Sbill 
483174Sbill 	case TIOCLGET:
484174Sbill 		if (copyout((caddr_t)&tp->t_local, addr, sizeof(tp->t_local)))
485174Sbill 			u.u_error = EFAULT;
486174Sbill 		break;
487174Sbill 
488903Sbill 	/*
489903Sbill 	 * Return number of characters in
490903Sbill 	 * the output.
491903Sbill 	 */
492213Sbill 	case TIOCOUTQ:
493213Sbill 		if (copyout((caddr_t)&tp->t_outq.c_cc, addr, sizeof(tp->t_outq.c_cc)))
494213Sbill 			u.u_error = EFAULT;
495213Sbill 		break;
496213Sbill 
497903Sbill 	/*
498903Sbill 	 * Simulate typing of a character at the terminal.
499903Sbill 	 */
500887Sbill 	case TIOCSTI:
501887Sbill 		c = fubyte(addr);
502887Sbill 		if (u.u_uid && u.u_ttyp != tp || c < 0)
503887Sbill 			u.u_error = EFAULT;
504887Sbill 		else
505887Sbill 			(*linesw[tp->t_line].l_rint)(c, tp);
506887Sbill 		break;
507174Sbill /* end of locals */
508887Sbill 
50939Sbill 	default:
51039Sbill 		return(0);
51139Sbill 	}
51239Sbill 	return(1);
51339Sbill }
514