xref: /csrg-svn/sys/kern/tty.c (revision 5614)
1*5614Swnj /*	tty.c	4.19	82/01/24	*/
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 	/*
285*5614Swnj 	 * Prevent more opens on channel
286*5614Swnj 	 */
287*5614Swnj 	case TIOCEXCL:
288*5614Swnj 		tp->t_state |= TS_XCLUDE;
289*5614Swnj 		break;
290*5614Swnj 
291*5614Swnj 	case TIOCNXCL:
292*5614Swnj 		tp->t_state &= ~TS_XCLUDE;
293*5614Swnj 		break;
294*5614Swnj 
295*5614Swnj 	/*
29639Sbill 	 * Set new parameters
29739Sbill 	 */
29839Sbill 	case TIOCSETP:
299191Sbill 	case TIOCSETN:
30039Sbill 		if (copyin(addr, (caddr_t)&iocb, sizeof(iocb))) {
30139Sbill 			u.u_error = EFAULT;
30239Sbill 			return(1);
30339Sbill 		}
304121Sbill 		(void) spl5();
3054484Swnj 		if (tp->t_flags&RAW || iocb.sg_flags&RAW ||
3064484Swnj 		    com == TIOCSETP)
3074484Swnj 			wflushtty(tp);
3084484Swnj 		else if ((tp->t_flags&CBREAK) != (iocb.sg_flags&CBREAK)) {
3094484Swnj 			if (iocb.sg_flags & CBREAK) {
3104484Swnj 				catq(&tp->t_rawq, &tp->t_canq);
3114484Swnj 				tq = tp->t_rawq;
3124484Swnj 				tp->t_rawq = tp->t_canq;
3134484Swnj 				tp->t_canq = tq;
3144484Swnj 			} else {
3154484Swnj 				tp->t_local |= LPENDIN;
3164484Swnj 				ttwakeup(tp);
317174Sbill 			}
318174Sbill 		}
3194484Swnj 		tp->t_ispeed = iocb.sg_ispeed;
3204484Swnj 		tp->t_ospeed = iocb.sg_ospeed;
321174Sbill 		tp->t_erase = iocb.sg_erase;
322174Sbill 		tp->t_kill = iocb.sg_kill;
323174Sbill 		tp->t_flags = iocb.sg_flags;
3243941Sbugs 		if (tp->t_flags & RAW) {
3255408Swnj 			tp->t_state &= ~TS_TTSTOP;
3263941Sbugs 			ttstart(tp);
3273941Sbugs 		}
328121Sbill 		(void) spl0();
32939Sbill 		break;
33039Sbill 
33139Sbill 	/*
332903Sbill 	 * Send current parameters to user
33339Sbill 	 */
33439Sbill 	case TIOCGETP:
335174Sbill 		iocb.sg_ispeed = tp->t_ispeed;
336174Sbill 		iocb.sg_ospeed = tp->t_ospeed;
337174Sbill 		iocb.sg_erase = tp->t_erase;
338174Sbill 		iocb.sg_kill = tp->t_kill;
339174Sbill 		iocb.sg_flags = tp->t_flags;
34039Sbill 		if (copyout((caddr_t)&iocb, addr, sizeof(iocb)))
34139Sbill 			u.u_error = EFAULT;
34239Sbill 		break;
34339Sbill 
34439Sbill 	/*
34539Sbill 	 * Hang up line on last close
34639Sbill 	 */
34739Sbill 	case TIOCHPCL:
3485408Swnj 		tp->t_state |= TS_HUPCLS;
34939Sbill 		break;
35039Sbill 
3513942Sbugs 	case TIOCFLUSH: {
3523942Sbugs 		int flags;
3533942Sbugs 		if (addr == 0)
3543942Sbugs 			flags = FREAD|FWRITE;
3553942Sbugs 		else if (copyin(addr, (caddr_t)&flags, sizeof (flags))) {
3563942Sbugs 			u.u_error = EFAULT;
3573983Sroot 			return(1);
3583942Sbugs 		}
3593942Sbugs 		flushtty(tp, flags);
36039Sbill 		break;
3613944Sbugs 	}
36239Sbill 
3635408Swnj 	case FIONBIO: {
3645408Swnj 		int nbio;
3655408Swnj 		if (copyin(addr, (caddr_t)&nbio, sizeof (nbio))) {
3665408Swnj 			u.u_error = EFAULT;
3675408Swnj 			return(1);
3685408Swnj 		}
3695408Swnj 		if (nbio)
3705408Swnj 			tp->t_state |= TS_NBIO;
3715408Swnj 		else
3725408Swnj 			tp->t_state &= ~TS_NBIO;
3735408Swnj 		break;
3745408Swnj 	}
3755408Swnj 
37639Sbill 	/*
377903Sbill 	 * Set and fetch special characters
37839Sbill 	 */
37939Sbill 	case TIOCSETC:
380174Sbill 		if (copyin(addr, (caddr_t)&tun, sizeof(struct tchars)))
38139Sbill 			u.u_error = EFAULT;
38239Sbill 		break;
38339Sbill 
38439Sbill 	case TIOCGETC:
385174Sbill 		if (copyout((caddr_t)&tun, addr, sizeof(struct tchars)))
38639Sbill 			u.u_error = EFAULT;
38739Sbill 		break;
38839Sbill 
389174Sbill /* local ioctls */
390903Sbill 	/*
391903Sbill 	 * Set/get local special characters.
392903Sbill 	 */
393174Sbill 	case TIOCSLTC:
394174Sbill 		if (copyin(addr, (caddr_t)&tlun, sizeof (struct ltchars)))
395174Sbill 			u.u_error = EFAULT;
396174Sbill 		break;
397174Sbill 
398174Sbill 	case TIOCGLTC:
399174Sbill 		if (copyout((caddr_t)&tlun, addr, sizeof (struct ltchars)))
400174Sbill 			u.u_error = EFAULT;
401174Sbill 		break;
402174Sbill 
403903Sbill 	/*
404903Sbill 	 * Return number of characters immediately available.
405903Sbill 	 */
406174Sbill 	case FIONREAD: {
4074484Swnj 		off_t nread = ttnread(tp);
408174Sbill 		if (copyout((caddr_t)&nread, addr, sizeof (off_t)))
409174Sbill 			u.u_error = EFAULT;
410174Sbill 		break;
411174Sbill 		}
412174Sbill 
413174Sbill 	/*
414174Sbill 	 * Should allow SPGRP and GPGRP only if tty open for reading.
415174Sbill 	 */
416174Sbill 	case TIOCSPGRP:
417728Sbill 		if (copyin(addr, (caddr_t)&tp->t_pgrp, sizeof (tp->t_pgrp)))
418728Sbill 			u.u_error = EFAULT;
419174Sbill 		break;
420174Sbill 
421174Sbill 	case TIOCGPGRP:
422174Sbill 		if (copyout((caddr_t)&tp->t_pgrp, addr, sizeof(tp->t_pgrp)))
423174Sbill 			u.u_error = EFAULT;
424174Sbill 		break;
425174Sbill 
426174Sbill 	/*
427174Sbill 	 * Modify local mode word.
428174Sbill 	 */
429174Sbill 	case TIOCLBIS:
430728Sbill 		if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local)))
431728Sbill 			u.u_error = EFAULT;
432728Sbill 		else
433728Sbill 			tp->t_local |= temp;
434174Sbill 		break;
435174Sbill 
436174Sbill 	case TIOCLBIC:
437728Sbill 		if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local)))
438728Sbill 			u.u_error = EFAULT;
439728Sbill 		else
440728Sbill 			tp->t_local &= ~temp;
441174Sbill 		break;
442174Sbill 
443174Sbill 	case TIOCLSET:
444728Sbill 		if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local)))
445728Sbill 			u.u_error = EFAULT;
446728Sbill 		else
447728Sbill 			tp->t_local = temp;
448174Sbill 		break;
449174Sbill 
450174Sbill 	case TIOCLGET:
451174Sbill 		if (copyout((caddr_t)&tp->t_local, addr, sizeof(tp->t_local)))
452174Sbill 			u.u_error = EFAULT;
453174Sbill 		break;
454174Sbill 
455903Sbill 	/*
456903Sbill 	 * Return number of characters in
457903Sbill 	 * the output.
458903Sbill 	 */
459213Sbill 	case TIOCOUTQ:
460213Sbill 		if (copyout((caddr_t)&tp->t_outq.c_cc, addr, sizeof(tp->t_outq.c_cc)))
461213Sbill 			u.u_error = EFAULT;
462213Sbill 		break;
463213Sbill 
464903Sbill 	/*
465903Sbill 	 * Simulate typing of a character at the terminal.
466903Sbill 	 */
467887Sbill 	case TIOCSTI:
468887Sbill 		c = fubyte(addr);
469887Sbill 		if (u.u_uid && u.u_ttyp != tp || c < 0)
470887Sbill 			u.u_error = EFAULT;
471887Sbill 		else
472887Sbill 			(*linesw[tp->t_line].l_rint)(c, tp);
473887Sbill 		break;
4745573Swnj 
4755573Swnj 	case TIOCSTOP:
4765573Swnj 		c = spl5();
4775573Swnj 		if ((tp->t_state & TS_TTSTOP) == 0) {
4785573Swnj 			tp->t_state |= TS_TTSTOP;
4795573Swnj 			(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
4805573Swnj 		}
4815573Swnj 		splx(c);
4825573Swnj 		break;
4835573Swnj 
4845573Swnj 	case TIOCSTART:
4855573Swnj 		c = spl5();
4865573Swnj 		if ((tp->t_state & TS_TTSTOP) || (tp->t_local & LFLUSHO)) {
4875573Swnj 			tp->t_state &= ~TS_TTSTOP;
4885573Swnj 			tp->t_local &= ~LFLUSHO;
4895573Swnj 			ttstart(tp);
4905573Swnj 		}
4915573Swnj 		splx(c);
4925573Swnj 		break;
4935573Swnj 
494174Sbill /* end of locals */
495887Sbill 
49639Sbill 	default:
49739Sbill 		return(0);
49839Sbill 	}
49939Sbill 	return(1);
50039Sbill }
5014484Swnj 
5024484Swnj ttnread(tp)
5034484Swnj 	struct tty *tp;
5044484Swnj {
5054484Swnj 	int nread = 0;
5064484Swnj 
5074484Swnj 	if (tp->t_local & LPENDIN)
5084484Swnj 		ttypend(tp);
5094484Swnj 	nread = tp->t_canq.c_cc;
5104484Swnj 	if (tp->t_flags & (RAW|CBREAK))
5114484Swnj 		nread += tp->t_rawq.c_cc;
5124484Swnj 	return (nread);
5134484Swnj }
5144484Swnj 
5155408Swnj ttselect(dev, rw)
5164484Swnj 	dev_t dev;
5175408Swnj 	int rw;
5184484Swnj {
5194484Swnj 	register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)];
5204484Swnj 	int nread;
5215408Swnj 	int s = spl5();
5224484Swnj 
5235408Swnj 	switch (rw) {
5244484Swnj 
5254484Swnj 	case FREAD:
5264484Swnj 		nread = ttnread(tp);
5274484Swnj 		if (nread > 0)
5285408Swnj 			goto win;
5294938Swnj 		if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait)
5305408Swnj 			tp->t_state |= TS_RCOLL;
5314484Swnj 		else
5324484Swnj 			tp->t_rsel = u.u_procp;
5335408Swnj 		break;
5344484Swnj 
5355408Swnj 	case FWRITE:
5365408Swnj 		if (tp->t_outq.c_cc <= TTLOWAT(tp))
5375408Swnj 			goto win;
5385408Swnj 		if (tp->t_wsel && tp->t_wsel->p_wchan == (caddr_t)&selwait)
5395408Swnj 			tp->t_state |= TS_WCOLL;
5405408Swnj 		else
5415408Swnj 			tp->t_wsel = u.u_procp;
5425408Swnj 		break;
5434484Swnj 	}
5445408Swnj 	splx(s);
5455408Swnj 	return (0);
5465408Swnj win:
5475408Swnj 	splx(s);
5485408Swnj 	return (1);
5494484Swnj }
550