xref: /csrg-svn/sys/kern/tty.c (revision 5573)
1*5573Swnj /*	tty.c	4.18	82/01/19	*/
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/inode.h"
1339Sbill #include "../h/file.h"
1439Sbill #include "../h/reg.h"
1539Sbill #include "../h/conf.h"
1639Sbill #include "../h/buf.h"
17340Sbill #include "../h/dk.h"
1839Sbill 
1939Sbill char	partab[];
2039Sbill 
21146Sbill /*
2239Sbill  * Input mapping table-- if an entry is non-zero, when the
2339Sbill  * corresponding character is typed preceded by "\" the escape
2439Sbill  * sequence is replaced by the table value.  Mostly used for
2539Sbill  * upper-case only terminals.
2639Sbill  */
2739Sbill 
2839Sbill char	maptab[] ={
2939Sbill 	000,000,000,000,000,000,000,000,
3039Sbill 	000,000,000,000,000,000,000,000,
3139Sbill 	000,000,000,000,000,000,000,000,
3239Sbill 	000,000,000,000,000,000,000,000,
3339Sbill 	000,'|',000,000,000,000,000,'`',
3439Sbill 	'{','}',000,000,000,000,000,000,
3539Sbill 	000,000,000,000,000,000,000,000,
3639Sbill 	000,000,000,000,000,000,000,000,
3739Sbill 	000,000,000,000,000,000,000,000,
3839Sbill 	000,000,000,000,000,000,000,000,
3939Sbill 	000,000,000,000,000,000,000,000,
4039Sbill 	000,000,000,000,000,000,'~',000,
4139Sbill 	000,'A','B','C','D','E','F','G',
4239Sbill 	'H','I','J','K','L','M','N','O',
4339Sbill 	'P','Q','R','S','T','U','V','W',
4439Sbill 	'X','Y','Z',000,000,000,000,000,
4539Sbill };
4639Sbill 
47925Sbill short	tthiwat[16] =
48925Sbill    { 100,100,100,100,100,100,100,200,200,400,400,400,650,650,650,650 };
49925Sbill short	ttlowat[16] =
50925Sbill    {  30, 30, 30, 30, 30, 30, 30, 50, 50,120,120,120,125,125,125,125 };
51925Sbill 
5239Sbill #define	OBUFSIZ	100
5339Sbill 
5439Sbill /*
5539Sbill  * set default control characters.
5639Sbill  */
5739Sbill ttychars(tp)
5839Sbill register struct tty *tp;
5939Sbill {
60174Sbill 
6139Sbill 	tun.t_intrc = CINTR;
6239Sbill 	tun.t_quitc = CQUIT;
6339Sbill 	tun.t_startc = CSTART;
6439Sbill 	tun.t_stopc = CSTOP;
6539Sbill 	tun.t_eofc = CEOT;
6639Sbill 	tun.t_brkc = CBRK;
6739Sbill 	tp->t_erase = CERASE;
6839Sbill 	tp->t_kill = CKILL;
69174Sbill /* begin local */
70208Sbill 	tlun.t_suspc = CTRL(z);
71208Sbill 	tlun.t_dsuspc = CTRL(y);
72174Sbill 	tlun.t_rprntc = CTRL(r);
73174Sbill 	tlun.t_flushc = CTRL(o);
74174Sbill 	tlun.t_werasc = CTRL(w);
75174Sbill 	tlun.t_lnextc = CTRL(v);
76174Sbill 	tp->t_local = 0;
77174Sbill 	tp->t_lstate = 0;
78174Sbill /* end local */
7939Sbill }
8039Sbill 
8139Sbill /*
82903Sbill  * Wait for output to drain, then flush input waiting.
8339Sbill  */
84903Sbill wflushtty(tp)
855408Swnj 	register struct tty *tp;
8639Sbill {
8739Sbill 
88903Sbill 	(void) spl5();
895408Swnj 	while (tp->t_outq.c_cc && tp->t_state&TS_CARR_ON) {
90903Sbill 		(*tp->t_oproc)(tp);
915408Swnj 		tp->t_state |= TS_ASLEEP;
92903Sbill 		sleep((caddr_t)&tp->t_outq, TTOPRI);
93903Sbill 	}
945426Swnj 	flushtty(tp, FREAD);
95903Sbill 	(void) spl0();
9639Sbill }
9739Sbill 
9839Sbill /*
99903Sbill  * flush all TTY queues
10039Sbill  */
101903Sbill flushtty(tp, rw)
102903Sbill register struct tty *tp;
10339Sbill {
104903Sbill 	register s;
105903Sbill 
106903Sbill 	s = spl6();
107903Sbill 	if (rw & FREAD) {
108903Sbill 		while (getc(&tp->t_canq) >= 0)
109903Sbill 			;
110903Sbill 		wakeup((caddr_t)&tp->t_rawq);
111903Sbill 	}
112903Sbill 	if (rw & FWRITE) {
113903Sbill 		wakeup((caddr_t)&tp->t_outq);
1145408Swnj 		tp->t_state &= ~TS_TTSTOP;
1155426Swnj 		(*cdevsw[major(tp->t_dev)].d_stop)(tp, rw);
116903Sbill 		while (getc(&tp->t_outq) >= 0)
117903Sbill 			;
118903Sbill 	}
119903Sbill 	if (rw & FREAD) {
120903Sbill 		while (getc(&tp->t_rawq) >= 0)
121903Sbill 			;
122903Sbill 		tp->t_delct = 0;
123903Sbill 		tp->t_rocount = 0;		/* local */
124903Sbill 		tp->t_rocol = 0;
125903Sbill 		tp->t_lstate = 0;
126903Sbill 	}
127903Sbill 	splx(s);
12839Sbill }
12939Sbill 
130903Sbill /*
131903Sbill  * Send stop character on input overflow.
132903Sbill  */
133903Sbill ttyblock(tp)
134903Sbill register struct tty *tp;
13539Sbill {
136903Sbill 	register x;
137903Sbill 	x = tp->t_rawq.c_cc + tp->t_canq.c_cc;
138903Sbill 	if (tp->t_rawq.c_cc > TTYHOG) {
139903Sbill 		flushtty(tp, FREAD|FWRITE);
1405408Swnj 		tp->t_state &= ~TS_TBLOCK;
141903Sbill 	}
142903Sbill 	if (x >= TTYHOG/2) {
143903Sbill 		if (putc(tun.t_stopc, &tp->t_outq)==0) {
1445408Swnj 			tp->t_state |= TS_TBLOCK;
145903Sbill 			tp->t_char++;
146903Sbill 			ttstart(tp);
147903Sbill 		}
148903Sbill 	}
14939Sbill }
15039Sbill 
15139Sbill /*
152903Sbill  * Restart typewriter output following a delay
153903Sbill  * timeout.
154903Sbill  * The name of the routine is passed to the timeout
155903Sbill  * subroutine and it is called during a clock interrupt.
156121Sbill  */
157903Sbill ttrstrt(tp)
158121Sbill register struct tty *tp;
159121Sbill {
160121Sbill 
1613351Swnj 	if (tp == 0) {
1623351Swnj 		printf("ttrstrt: arg was 0!\n");
1633351Swnj 		return;
1643351Swnj 	}
1655408Swnj 	tp->t_state &= ~TS_TIMEOUT;
166903Sbill 	ttstart(tp);
167121Sbill }
168121Sbill 
169121Sbill /*
170903Sbill  * Start output on the typewriter. It is used from the top half
171903Sbill  * after some characters have been put on the output queue,
172903Sbill  * from the interrupt routine to transmit the next
173903Sbill  * character, and after a timeout has finished.
17439Sbill  */
175903Sbill ttstart(tp)
176903Sbill register struct tty *tp;
17739Sbill {
178903Sbill 	register s;
17939Sbill 
180903Sbill 	s = spl5();
1815408Swnj 	if((tp->t_state&(TS_TIMEOUT|TS_TTSTOP|TS_BUSY)) == 0)
182903Sbill 		(*tp->t_oproc)(tp);
183903Sbill 	splx(s);
18439Sbill }
18539Sbill 
18639Sbill /*
187903Sbill  * Common code for tty ioctls.
18839Sbill  */
1891780Sbill /*ARGSUSED*/
1901904Swnj ttioctl(tp, com, addr, flag)
19139Sbill register struct tty *tp;
19239Sbill caddr_t addr;
19339Sbill {
1941904Swnj 	int dev;
19539Sbill 	unsigned t;
196174Sbill 	struct sgttyb iocb;
197191Sbill 	struct clist tq;
19839Sbill 	extern int nldisp;
199887Sbill 	register c;
200728Sbill 	int temp;
20139Sbill 
202903Sbill 	/*
203915Sbill 	 * This is especially so that isatty() will
204915Sbill 	 * fail when carrier is gone.
205915Sbill 	 */
2065408Swnj 	if ((tp->t_state&TS_CARR_ON) == 0) {
207915Sbill 		u.u_error = EBADF;
208915Sbill 		return (1);
209915Sbill 	}
210915Sbill 
2111904Swnj 	dev = tp->t_dev;
212915Sbill 	/*
213903Sbill 	 * If the ioctl involves modification,
214903Sbill 	 * insist on being able to write the device,
215903Sbill 	 * and hang if in the background.
216903Sbill 	 */
21739Sbill 	switch(com) {
21839Sbill 
219915Sbill 	case TIOCSETD:
220915Sbill 	case TIOCSETP:
221915Sbill 	case TIOCSETN:
222903Sbill 	case TIOCFLUSH:
223903Sbill 	case TIOCSETC:
224903Sbill 	case TIOCSLTC:
225903Sbill 	case TIOCSPGRP:
226903Sbill 	case TIOCLBIS:
227903Sbill 	case TIOCLBIC:
228903Sbill 	case TIOCLSET:
229903Sbill 	case TIOCSTI:
230915Sbill /* this is reasonable, but impractical...
231903Sbill 		if ((flag & FWRITE) == 0) {
232903Sbill 			u.u_error = EBADF;
233903Sbill 			return (1);
234903Sbill 		}
235915Sbill  */
236903Sbill 		while (tp->t_line == NTTYDISC &&
237903Sbill 		   u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp &&
238903Sbill 		   (u.u_procp->p_flag&SVFORK) == 0 &&
239903Sbill 		   u.u_signal[SIGTTOU] != SIG_IGN &&
240903Sbill 		   u.u_signal[SIGTTOU] != SIG_HOLD &&
241903Sbill 		   (u.u_procp->p_flag&SDETACH)==0) {
242903Sbill 			gsignal(u.u_procp->p_pgrp, SIGTTOU);
243903Sbill 			sleep((caddr_t)&lbolt, TTOPRI);
244903Sbill 		}
245903Sbill 		break;
246903Sbill 	}
247903Sbill 
24839Sbill 	/*
249903Sbill 	 * Process the ioctl.
25039Sbill 	 */
251903Sbill 	switch(com) {
252903Sbill 
253903Sbill 	/*
254903Sbill 	 * Get discipline number
255903Sbill 	 */
25639Sbill 	case TIOCGETD:
25739Sbill 		t = tp->t_line;
25839Sbill 		if (copyout((caddr_t)&t, addr, sizeof(t)))
25939Sbill 			u.u_error = EFAULT;
26039Sbill 		break;
26139Sbill 
26239Sbill 	/*
263903Sbill 	 * Set line discipline
26439Sbill 	 */
26539Sbill 	case TIOCSETD:
26639Sbill 		if (copyin(addr, (caddr_t)&t, sizeof(t))) {
26739Sbill 			u.u_error = EFAULT;
26839Sbill 			break;
26939Sbill 		}
27039Sbill 		if (t >= nldisp) {
27139Sbill 			u.u_error = ENXIO;
27239Sbill 			break;
27339Sbill 		}
274174Sbill 		(void) spl5();
27539Sbill 		if (tp->t_line)
27639Sbill 			(*linesw[tp->t_line].l_close)(tp);
27739Sbill 		if (t)
27839Sbill 			(*linesw[t].l_open)(dev, tp, addr);
27939Sbill 		if (u.u_error==0)
28039Sbill 			tp->t_line = t;
281174Sbill 		(void) spl0();
28239Sbill 		break;
28339Sbill 
28439Sbill 	/*
28539Sbill 	 * Set new parameters
28639Sbill 	 */
28739Sbill 	case TIOCSETP:
288191Sbill 	case TIOCSETN:
28939Sbill 		if (copyin(addr, (caddr_t)&iocb, sizeof(iocb))) {
29039Sbill 			u.u_error = EFAULT;
29139Sbill 			return(1);
29239Sbill 		}
293121Sbill 		(void) spl5();
2944484Swnj 		if (tp->t_flags&RAW || iocb.sg_flags&RAW ||
2954484Swnj 		    com == TIOCSETP)
2964484Swnj 			wflushtty(tp);
2974484Swnj 		else if ((tp->t_flags&CBREAK) != (iocb.sg_flags&CBREAK)) {
2984484Swnj 			if (iocb.sg_flags & CBREAK) {
2994484Swnj 				catq(&tp->t_rawq, &tp->t_canq);
3004484Swnj 				tq = tp->t_rawq;
3014484Swnj 				tp->t_rawq = tp->t_canq;
3024484Swnj 				tp->t_canq = tq;
3034484Swnj 			} else {
3044484Swnj 				tp->t_local |= LPENDIN;
3054484Swnj 				ttwakeup(tp);
306174Sbill 			}
307174Sbill 		}
3084484Swnj 		tp->t_ispeed = iocb.sg_ispeed;
3094484Swnj 		tp->t_ospeed = iocb.sg_ospeed;
310174Sbill 		tp->t_erase = iocb.sg_erase;
311174Sbill 		tp->t_kill = iocb.sg_kill;
312174Sbill 		tp->t_flags = iocb.sg_flags;
3133941Sbugs 		if (tp->t_flags & RAW) {
3145408Swnj 			tp->t_state &= ~TS_TTSTOP;
3153941Sbugs 			ttstart(tp);
3163941Sbugs 		}
317121Sbill 		(void) spl0();
31839Sbill 		break;
31939Sbill 
32039Sbill 	/*
321903Sbill 	 * Send current parameters to user
32239Sbill 	 */
32339Sbill 	case TIOCGETP:
324174Sbill 		iocb.sg_ispeed = tp->t_ispeed;
325174Sbill 		iocb.sg_ospeed = tp->t_ospeed;
326174Sbill 		iocb.sg_erase = tp->t_erase;
327174Sbill 		iocb.sg_kill = tp->t_kill;
328174Sbill 		iocb.sg_flags = tp->t_flags;
32939Sbill 		if (copyout((caddr_t)&iocb, addr, sizeof(iocb)))
33039Sbill 			u.u_error = EFAULT;
33139Sbill 		break;
33239Sbill 
33339Sbill 	/*
33439Sbill 	 * Hang up line on last close
33539Sbill 	 */
33639Sbill 	case TIOCHPCL:
3375408Swnj 		tp->t_state |= TS_HUPCLS;
33839Sbill 		break;
33939Sbill 
3403942Sbugs 	case TIOCFLUSH: {
3413942Sbugs 		int flags;
3423942Sbugs 		if (addr == 0)
3433942Sbugs 			flags = FREAD|FWRITE;
3443942Sbugs 		else if (copyin(addr, (caddr_t)&flags, sizeof (flags))) {
3453942Sbugs 			u.u_error = EFAULT;
3463983Sroot 			return(1);
3473942Sbugs 		}
3483942Sbugs 		flushtty(tp, flags);
34939Sbill 		break;
3503944Sbugs 	}
35139Sbill 
3525408Swnj 	case FIONBIO: {
3535408Swnj 		int nbio;
3545408Swnj 		if (copyin(addr, (caddr_t)&nbio, sizeof (nbio))) {
3555408Swnj 			u.u_error = EFAULT;
3565408Swnj 			return(1);
3575408Swnj 		}
3585408Swnj 		if (nbio)
3595408Swnj 			tp->t_state |= TS_NBIO;
3605408Swnj 		else
3615408Swnj 			tp->t_state &= ~TS_NBIO;
3625408Swnj 		break;
3635408Swnj 	}
3645408Swnj 
36539Sbill 	/*
366903Sbill 	 * Set and fetch special characters
36739Sbill 	 */
36839Sbill 	case TIOCSETC:
369174Sbill 		if (copyin(addr, (caddr_t)&tun, sizeof(struct tchars)))
37039Sbill 			u.u_error = EFAULT;
37139Sbill 		break;
37239Sbill 
37339Sbill 	case TIOCGETC:
374174Sbill 		if (copyout((caddr_t)&tun, addr, sizeof(struct tchars)))
37539Sbill 			u.u_error = EFAULT;
37639Sbill 		break;
37739Sbill 
378174Sbill /* local ioctls */
379903Sbill 	/*
380903Sbill 	 * Set/get local special characters.
381903Sbill 	 */
382174Sbill 	case TIOCSLTC:
383174Sbill 		if (copyin(addr, (caddr_t)&tlun, sizeof (struct ltchars)))
384174Sbill 			u.u_error = EFAULT;
385174Sbill 		break;
386174Sbill 
387174Sbill 	case TIOCGLTC:
388174Sbill 		if (copyout((caddr_t)&tlun, addr, sizeof (struct ltchars)))
389174Sbill 			u.u_error = EFAULT;
390174Sbill 		break;
391174Sbill 
392903Sbill 	/*
393903Sbill 	 * Return number of characters immediately available.
394903Sbill 	 */
395174Sbill 	case FIONREAD: {
3964484Swnj 		off_t nread = ttnread(tp);
397174Sbill 		if (copyout((caddr_t)&nread, addr, sizeof (off_t)))
398174Sbill 			u.u_error = EFAULT;
399174Sbill 		break;
400174Sbill 		}
401174Sbill 
402174Sbill 	/*
403174Sbill 	 * Should allow SPGRP and GPGRP only if tty open for reading.
404174Sbill 	 */
405174Sbill 	case TIOCSPGRP:
406728Sbill 		if (copyin(addr, (caddr_t)&tp->t_pgrp, sizeof (tp->t_pgrp)))
407728Sbill 			u.u_error = EFAULT;
408174Sbill 		break;
409174Sbill 
410174Sbill 	case TIOCGPGRP:
411174Sbill 		if (copyout((caddr_t)&tp->t_pgrp, addr, sizeof(tp->t_pgrp)))
412174Sbill 			u.u_error = EFAULT;
413174Sbill 		break;
414174Sbill 
415174Sbill 	/*
416174Sbill 	 * Modify local mode word.
417174Sbill 	 */
418174Sbill 	case TIOCLBIS:
419728Sbill 		if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local)))
420728Sbill 			u.u_error = EFAULT;
421728Sbill 		else
422728Sbill 			tp->t_local |= temp;
423174Sbill 		break;
424174Sbill 
425174Sbill 	case TIOCLBIC:
426728Sbill 		if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local)))
427728Sbill 			u.u_error = EFAULT;
428728Sbill 		else
429728Sbill 			tp->t_local &= ~temp;
430174Sbill 		break;
431174Sbill 
432174Sbill 	case TIOCLSET:
433728Sbill 		if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local)))
434728Sbill 			u.u_error = EFAULT;
435728Sbill 		else
436728Sbill 			tp->t_local = temp;
437174Sbill 		break;
438174Sbill 
439174Sbill 	case TIOCLGET:
440174Sbill 		if (copyout((caddr_t)&tp->t_local, addr, sizeof(tp->t_local)))
441174Sbill 			u.u_error = EFAULT;
442174Sbill 		break;
443174Sbill 
444903Sbill 	/*
445903Sbill 	 * Return number of characters in
446903Sbill 	 * the output.
447903Sbill 	 */
448213Sbill 	case TIOCOUTQ:
449213Sbill 		if (copyout((caddr_t)&tp->t_outq.c_cc, addr, sizeof(tp->t_outq.c_cc)))
450213Sbill 			u.u_error = EFAULT;
451213Sbill 		break;
452213Sbill 
453903Sbill 	/*
454903Sbill 	 * Simulate typing of a character at the terminal.
455903Sbill 	 */
456887Sbill 	case TIOCSTI:
457887Sbill 		c = fubyte(addr);
458887Sbill 		if (u.u_uid && u.u_ttyp != tp || c < 0)
459887Sbill 			u.u_error = EFAULT;
460887Sbill 		else
461887Sbill 			(*linesw[tp->t_line].l_rint)(c, tp);
462887Sbill 		break;
463*5573Swnj 
464*5573Swnj 	case TIOCSTOP:
465*5573Swnj 		c = spl5();
466*5573Swnj 		if ((tp->t_state & TS_TTSTOP) == 0) {
467*5573Swnj 			tp->t_state |= TS_TTSTOP;
468*5573Swnj 			(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
469*5573Swnj 		}
470*5573Swnj 		splx(c);
471*5573Swnj 		break;
472*5573Swnj 
473*5573Swnj 	case TIOCSTART:
474*5573Swnj 		c = spl5();
475*5573Swnj 		if ((tp->t_state & TS_TTSTOP) || (tp->t_local & LFLUSHO)) {
476*5573Swnj 			tp->t_state &= ~TS_TTSTOP;
477*5573Swnj 			tp->t_local &= ~LFLUSHO;
478*5573Swnj 			ttstart(tp);
479*5573Swnj 		}
480*5573Swnj 		splx(c);
481*5573Swnj 		break;
482*5573Swnj 
483174Sbill /* end of locals */
484887Sbill 
48539Sbill 	default:
48639Sbill 		return(0);
48739Sbill 	}
48839Sbill 	return(1);
48939Sbill }
4904484Swnj 
4914484Swnj ttnread(tp)
4924484Swnj 	struct tty *tp;
4934484Swnj {
4944484Swnj 	int nread = 0;
4954484Swnj 
4964484Swnj 	if (tp->t_local & LPENDIN)
4974484Swnj 		ttypend(tp);
4984484Swnj 	nread = tp->t_canq.c_cc;
4994484Swnj 	if (tp->t_flags & (RAW|CBREAK))
5004484Swnj 		nread += tp->t_rawq.c_cc;
5014484Swnj 	return (nread);
5024484Swnj }
5034484Swnj 
5045408Swnj ttselect(dev, rw)
5054484Swnj 	dev_t dev;
5065408Swnj 	int rw;
5074484Swnj {
5084484Swnj 	register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)];
5094484Swnj 	int nread;
5105408Swnj 	int s = spl5();
5114484Swnj 
5125408Swnj 	switch (rw) {
5134484Swnj 
5144484Swnj 	case FREAD:
5154484Swnj 		nread = ttnread(tp);
5164484Swnj 		if (nread > 0)
5175408Swnj 			goto win;
5184938Swnj 		if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait)
5195408Swnj 			tp->t_state |= TS_RCOLL;
5204484Swnj 		else
5214484Swnj 			tp->t_rsel = u.u_procp;
5225408Swnj 		break;
5234484Swnj 
5245408Swnj 	case FWRITE:
5255408Swnj 		if (tp->t_outq.c_cc <= TTLOWAT(tp))
5265408Swnj 			goto win;
5275408Swnj 		if (tp->t_wsel && tp->t_wsel->p_wchan == (caddr_t)&selwait)
5285408Swnj 			tp->t_state |= TS_WCOLL;
5295408Swnj 		else
5305408Swnj 			tp->t_wsel = u.u_procp;
5315408Swnj 		break;
5324484Swnj 	}
5335408Swnj 	splx(s);
5345408Swnj 	return (0);
5355408Swnj win:
5365408Swnj 	splx(s);
5375408Swnj 	return (1);
5384484Swnj }
539