xref: /csrg-svn/sys/kern/tty.c (revision 3351)
1*3351Swnj /*	tty.c	4.6	81/03/22	*/
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 /*
2339Sbill  * Input mapping table-- if an entry is non-zero, when the
2439Sbill  * corresponding character is typed preceded by "\" the escape
2539Sbill  * sequence is replaced by the table value.  Mostly used for
2639Sbill  * upper-case only terminals.
2739Sbill  */
2839Sbill 
2939Sbill char	maptab[] ={
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,000,000,
3439Sbill 	000,'|',000,000,000,000,000,'`',
3539Sbill 	'{','}',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,000,
4139Sbill 	000,000,000,000,000,000,'~',000,
4239Sbill 	000,'A','B','C','D','E','F','G',
4339Sbill 	'H','I','J','K','L','M','N','O',
4439Sbill 	'P','Q','R','S','T','U','V','W',
4539Sbill 	'X','Y','Z',000,000,000,000,000,
4639Sbill };
4739Sbill 
48925Sbill short	tthiwat[16] =
49925Sbill    { 100,100,100,100,100,100,100,200,200,400,400,400,650,650,650,650 };
50925Sbill short	ttlowat[16] =
51925Sbill    {  30, 30, 30, 30, 30, 30, 30, 50, 50,120,120,120,125,125,125,125 };
52925Sbill 
5339Sbill #define	OBUFSIZ	100
5439Sbill 
5539Sbill /*
5639Sbill  * set default control characters.
5739Sbill  */
5839Sbill ttychars(tp)
5939Sbill register struct tty *tp;
6039Sbill {
61174Sbill 
6239Sbill 	tun.t_intrc = CINTR;
6339Sbill 	tun.t_quitc = CQUIT;
6439Sbill 	tun.t_startc = CSTART;
6539Sbill 	tun.t_stopc = CSTOP;
6639Sbill 	tun.t_eofc = CEOT;
6739Sbill 	tun.t_brkc = CBRK;
6839Sbill 	tp->t_erase = CERASE;
6939Sbill 	tp->t_kill = CKILL;
70174Sbill /* begin local */
71208Sbill 	tlun.t_suspc = CTRL(z);
72208Sbill 	tlun.t_dsuspc = CTRL(y);
73174Sbill 	tlun.t_rprntc = CTRL(r);
74174Sbill 	tlun.t_flushc = CTRL(o);
75174Sbill 	tlun.t_werasc = CTRL(w);
76174Sbill 	tlun.t_lnextc = CTRL(v);
77174Sbill 	tp->t_local = 0;
78174Sbill 	tp->t_lstate = 0;
79174Sbill /* end local */
8039Sbill }
8139Sbill 
8239Sbill /*
83903Sbill  * Wait for output to drain, then flush input waiting.
8439Sbill  */
85903Sbill wflushtty(tp)
8639Sbill register struct tty *tp;
8739Sbill {
8839Sbill 
89903Sbill 	(void) spl5();
90903Sbill 	while (tp->t_outq.c_cc && tp->t_state&CARR_ON) {
91903Sbill 		(*tp->t_oproc)(tp);
92903Sbill 		tp->t_state |= ASLEEP;
93903Sbill 		sleep((caddr_t)&tp->t_outq, TTOPRI);
94903Sbill 	}
95903Sbill 	flushtty(tp, FREAD|FWRITE);
96903Sbill 	(void) spl0();
9739Sbill }
9839Sbill 
9939Sbill /*
100903Sbill  * flush all TTY queues
10139Sbill  */
102903Sbill flushtty(tp, rw)
103903Sbill register struct tty *tp;
10439Sbill {
105903Sbill 	register s;
106903Sbill 
107903Sbill 	if (tp->t_line == NETLDISC)
108903Sbill 		return;
109903Sbill 	s = spl6();
110903Sbill 	if (rw & FREAD) {
111903Sbill 		while (getc(&tp->t_canq) >= 0)
112903Sbill 			;
113903Sbill 		wakeup((caddr_t)&tp->t_rawq);
114903Sbill 	}
115903Sbill 	if (rw & FWRITE) {
116903Sbill 		wakeup((caddr_t)&tp->t_outq);
117903Sbill 		tp->t_state &= ~TTSTOP;
118903Sbill 		(*cdevsw[major(tp->t_dev)].d_stop)(tp);
119903Sbill 		while (getc(&tp->t_outq) >= 0)
120903Sbill 			;
121903Sbill 	}
122903Sbill 	if (rw & FREAD) {
123903Sbill 		while (getc(&tp->t_rawq) >= 0)
124903Sbill 			;
125903Sbill 		tp->t_delct = 0;
126903Sbill 		tp->t_rocount = 0;		/* local */
127903Sbill 		tp->t_rocol = 0;
128903Sbill 		tp->t_lstate = 0;
129903Sbill 	}
130903Sbill 	splx(s);
13139Sbill }
13239Sbill 
133903Sbill /*
134903Sbill  * Send stop character on input overflow.
135903Sbill  */
136903Sbill ttyblock(tp)
137903Sbill register struct tty *tp;
13839Sbill {
139903Sbill 	register x;
140903Sbill 	x = tp->t_rawq.c_cc + tp->t_canq.c_cc;
141903Sbill 	if (tp->t_rawq.c_cc > TTYHOG) {
142903Sbill 		flushtty(tp, FREAD|FWRITE);
143903Sbill 		tp->t_state &= ~TBLOCK;
144903Sbill 	}
145903Sbill 	if (x >= TTYHOG/2) {
146903Sbill 		if (putc(tun.t_stopc, &tp->t_outq)==0) {
147903Sbill 			tp->t_state |= TBLOCK;
148903Sbill 			tp->t_char++;
149903Sbill 			ttstart(tp);
150903Sbill 		}
151903Sbill 	}
15239Sbill }
15339Sbill 
15439Sbill /*
155903Sbill  * Restart typewriter output following a delay
156903Sbill  * timeout.
157903Sbill  * The name of the routine is passed to the timeout
158903Sbill  * subroutine and it is called during a clock interrupt.
159121Sbill  */
160903Sbill ttrstrt(tp)
161121Sbill register struct tty *tp;
162121Sbill {
163121Sbill 
164*3351Swnj 	if (tp == 0) {
165*3351Swnj 		printf("ttrstrt: arg was 0!\n");
166*3351Swnj 		return;
167*3351Swnj 	}
168903Sbill 	tp->t_state &= ~TIMEOUT;
169903Sbill 	ttstart(tp);
170121Sbill }
171121Sbill 
172121Sbill /*
173903Sbill  * Start output on the typewriter. It is used from the top half
174903Sbill  * after some characters have been put on the output queue,
175903Sbill  * from the interrupt routine to transmit the next
176903Sbill  * character, and after a timeout has finished.
17739Sbill  */
178903Sbill ttstart(tp)
179903Sbill register struct tty *tp;
18039Sbill {
181903Sbill 	register s;
18239Sbill 
183903Sbill 	s = spl5();
184903Sbill 	if((tp->t_state&(TIMEOUT|TTSTOP|BUSY)) == 0)
185903Sbill 		(*tp->t_oproc)(tp);
186903Sbill 	splx(s);
18739Sbill }
18839Sbill 
18939Sbill /*
190903Sbill  * Common code for tty ioctls.
19139Sbill  */
1921780Sbill /*ARGSUSED*/
1931904Swnj ttioctl(tp, com, addr, flag)
19439Sbill register struct tty *tp;
19539Sbill caddr_t addr;
19639Sbill {
1971904Swnj 	int dev;
19839Sbill 	unsigned t;
199174Sbill 	struct sgttyb iocb;
200191Sbill 	struct clist tq;
20139Sbill 	extern int nldisp;
202887Sbill 	register c;
203728Sbill 	int temp;
20439Sbill 
205903Sbill 	/*
206915Sbill 	 * This is especially so that isatty() will
207915Sbill 	 * fail when carrier is gone.
208915Sbill 	 */
209915Sbill 	if ((tp->t_state&CARR_ON) == 0) {
210915Sbill 		u.u_error = EBADF;
211915Sbill 		return (1);
212915Sbill 	}
213915Sbill 
2141904Swnj 	dev = tp->t_dev;
215915Sbill 	/*
216903Sbill 	 * If the ioctl involves modification,
217903Sbill 	 * insist on being able to write the device,
218903Sbill 	 * and hang if in the background.
219903Sbill 	 */
22039Sbill 	switch(com) {
22139Sbill 
222915Sbill 	case TIOCSETD:
223915Sbill 	case TIOCSETP:
224915Sbill 	case TIOCSETN:
225903Sbill 	case TIOCFLUSH:
226903Sbill 	case TIOCSETC:
227903Sbill 	case TIOCSLTC:
228903Sbill 	case TIOCSPGRP:
229903Sbill 	case TIOCLBIS:
230903Sbill 	case TIOCLBIC:
231903Sbill 	case TIOCLSET:
232903Sbill 	case TIOCSTI:
233915Sbill /* this is reasonable, but impractical...
234903Sbill 		if ((flag & FWRITE) == 0) {
235903Sbill 			u.u_error = EBADF;
236903Sbill 			return (1);
237903Sbill 		}
238915Sbill  */
239903Sbill 		while (tp->t_line == NTTYDISC &&
240903Sbill 		   u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp &&
241903Sbill 		   (u.u_procp->p_flag&SVFORK) == 0 &&
242903Sbill 		   u.u_signal[SIGTTOU] != SIG_IGN &&
243903Sbill 		   u.u_signal[SIGTTOU] != SIG_HOLD &&
244903Sbill 		   (u.u_procp->p_flag&SDETACH)==0) {
245903Sbill 			gsignal(u.u_procp->p_pgrp, SIGTTOU);
246903Sbill 			sleep((caddr_t)&lbolt, TTOPRI);
247903Sbill 		}
248903Sbill 		break;
249903Sbill 	}
250903Sbill 
25139Sbill 	/*
252903Sbill 	 * Process the ioctl.
25339Sbill 	 */
254903Sbill 	switch(com) {
255903Sbill 
256903Sbill 	/*
257903Sbill 	 * Get discipline number
258903Sbill 	 */
25939Sbill 	case TIOCGETD:
26039Sbill 		t = tp->t_line;
26139Sbill 		if (copyout((caddr_t)&t, addr, sizeof(t)))
26239Sbill 			u.u_error = EFAULT;
26339Sbill 		break;
26439Sbill 
26539Sbill 	/*
266903Sbill 	 * Set line discipline
26739Sbill 	 */
26839Sbill 	case TIOCSETD:
26939Sbill 		if (copyin(addr, (caddr_t)&t, sizeof(t))) {
27039Sbill 			u.u_error = EFAULT;
27139Sbill 			break;
27239Sbill 		}
27339Sbill 		if (t >= nldisp) {
27439Sbill 			u.u_error = ENXIO;
27539Sbill 			break;
27639Sbill 		}
277174Sbill 		(void) spl5();
27839Sbill 		if (tp->t_line)
27939Sbill 			(*linesw[tp->t_line].l_close)(tp);
28039Sbill 		if (t)
28139Sbill 			(*linesw[t].l_open)(dev, tp, addr);
28239Sbill 		if (u.u_error==0)
28339Sbill 			tp->t_line = t;
284174Sbill 		(void) spl0();
28539Sbill 		break;
28639Sbill 
28739Sbill 	/*
288903Sbill 	 * Prevent more opens on channel
28939Sbill 	 */
29039Sbill 	case TIOCEXCL:
29139Sbill 		tp->t_state |= XCLUDE;
29239Sbill 		break;
29339Sbill 
29439Sbill 	case TIOCNXCL:
29539Sbill 		tp->t_state &= ~XCLUDE;
29639Sbill 		break;
29739Sbill 
29839Sbill 	/*
29939Sbill 	 * Set new parameters
30039Sbill 	 */
30139Sbill 	case TIOCSETP:
302191Sbill 	case TIOCSETN:
30339Sbill 		if (copyin(addr, (caddr_t)&iocb, sizeof(iocb))) {
30439Sbill 			u.u_error = EFAULT;
30539Sbill 			return(1);
30639Sbill 		}
307121Sbill 		(void) spl5();
308174Sbill 		if (tp->t_line == 0) {
309174Sbill 			if (com == TIOCSETP)
310174Sbill 				wflushtty(tp);
311174Sbill 			while (canon(tp)>=0)
312174Sbill 				;
313933Sbill #ifdef notdef
314933Sbill 			wakeup((caddr_t)&tp->t_rawq);
315933Sbill #endif
316174Sbill 		} else if (tp->t_line == NTTYDISC) {
317174Sbill 			if (tp->t_flags&RAW || iocb.sg_flags&RAW ||
318174Sbill 			    com == TIOCSETP)
319174Sbill 				wflushtty(tp);
320174Sbill 			else if ((tp->t_flags&CBREAK) != (iocb.sg_flags&CBREAK)) {
321174Sbill 				if (iocb.sg_flags & CBREAK) {
322174Sbill 					catq(&tp->t_rawq, &tp->t_canq);
323174Sbill 					tq = tp->t_rawq;
324174Sbill 					tp->t_rawq = tp->t_canq;
325174Sbill 					tp->t_canq = tq;
326174Sbill 				} else {
327174Sbill 					tp->t_local |= LPENDIN;
328174Sbill 					if (tp->t_canq.c_cc)
329174Sbill 						panic("ioccom canq");
330933Sbill #ifdef notdef
331174Sbill 					if (tp->t_chan)
332174Sbill 						(void) sdata(tp->t_chan);
333174Sbill 					else
334933Sbill #endif
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 	 * Set and fetch special characters
37539Sbill 	 */
37639Sbill 	case TIOCSETC:
377174Sbill 		if (copyin(addr, (caddr_t)&tun, sizeof(struct tchars)))
37839Sbill 			u.u_error = EFAULT;
37939Sbill 		break;
38039Sbill 
38139Sbill 	case TIOCGETC:
382174Sbill 		if (copyout((caddr_t)&tun, addr, sizeof(struct tchars)))
38339Sbill 			u.u_error = EFAULT;
38439Sbill 		break;
38539Sbill 
386174Sbill /* local ioctls */
387903Sbill 	/*
388903Sbill 	 * Set/get local special characters.
389903Sbill 	 */
390174Sbill 	case TIOCSLTC:
391174Sbill 		if (copyin(addr, (caddr_t)&tlun, sizeof (struct ltchars)))
392174Sbill 			u.u_error = EFAULT;
393174Sbill 		break;
394174Sbill 
395174Sbill 	case TIOCGLTC:
396174Sbill 		if (copyout((caddr_t)&tlun, addr, sizeof (struct ltchars)))
397174Sbill 			u.u_error = EFAULT;
398174Sbill 		break;
399174Sbill 
400903Sbill 	/*
401903Sbill 	 * Return number of characters immediately available.
402903Sbill 	 */
403174Sbill 	case FIONREAD: {
404340Sbill 		off_t nread;
405174Sbill 
406340Sbill 		switch (tp->t_line) {
407340Sbill 
408340Sbill 		case NETLDISC:
409340Sbill 			nread = tp->t_rec ? tp->t_inbuf : 0;
410340Sbill 			break;
411340Sbill 
412894Sbill 		case 0:
413894Sbill 			(void) spl5();
414894Sbill 			while (canon(tp)>=0)
415894Sbill 				;
416894Sbill 			(void) spl0();
417894Sbill 			/* fall into ... */
418894Sbill 
419340Sbill 		case NTTYDISC:
420340Sbill 			nread = tp->t_canq.c_cc;
421340Sbill 			if (tp->t_flags & (RAW|CBREAK))
422340Sbill 				nread += tp->t_rawq.c_cc;
423340Sbill 			break;
424340Sbill 
425340Sbill 		}
426174Sbill 		if (copyout((caddr_t)&nread, addr, sizeof (off_t)))
427174Sbill 			u.u_error = EFAULT;
428174Sbill 		break;
429174Sbill 		}
430174Sbill 
431174Sbill 	/*
432174Sbill 	 * Should allow SPGRP and GPGRP only if tty open for reading.
433174Sbill 	 */
434174Sbill 	case TIOCSPGRP:
435728Sbill 		if (copyin(addr, (caddr_t)&tp->t_pgrp, sizeof (tp->t_pgrp)))
436728Sbill 			u.u_error = EFAULT;
437174Sbill 		break;
438174Sbill 
439174Sbill 	case TIOCGPGRP:
440174Sbill 		if (copyout((caddr_t)&tp->t_pgrp, addr, sizeof(tp->t_pgrp)))
441174Sbill 			u.u_error = EFAULT;
442174Sbill 		break;
443174Sbill 
444174Sbill 	/*
445174Sbill 	 * Modify local mode word.
446174Sbill 	 */
447174Sbill 	case TIOCLBIS:
448728Sbill 		if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local)))
449728Sbill 			u.u_error = EFAULT;
450728Sbill 		else
451728Sbill 			tp->t_local |= temp;
452174Sbill 		break;
453174Sbill 
454174Sbill 	case TIOCLBIC:
455728Sbill 		if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local)))
456728Sbill 			u.u_error = EFAULT;
457728Sbill 		else
458728Sbill 			tp->t_local &= ~temp;
459174Sbill 		break;
460174Sbill 
461174Sbill 	case TIOCLSET:
462728Sbill 		if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local)))
463728Sbill 			u.u_error = EFAULT;
464728Sbill 		else
465728Sbill 			tp->t_local = temp;
466174Sbill 		break;
467174Sbill 
468174Sbill 	case TIOCLGET:
469174Sbill 		if (copyout((caddr_t)&tp->t_local, addr, sizeof(tp->t_local)))
470174Sbill 			u.u_error = EFAULT;
471174Sbill 		break;
472174Sbill 
473903Sbill 	/*
474903Sbill 	 * Return number of characters in
475903Sbill 	 * the output.
476903Sbill 	 */
477213Sbill 	case TIOCOUTQ:
478213Sbill 		if (copyout((caddr_t)&tp->t_outq.c_cc, addr, sizeof(tp->t_outq.c_cc)))
479213Sbill 			u.u_error = EFAULT;
480213Sbill 		break;
481213Sbill 
482903Sbill 	/*
483903Sbill 	 * Simulate typing of a character at the terminal.
484903Sbill 	 */
485887Sbill 	case TIOCSTI:
486887Sbill 		c = fubyte(addr);
487887Sbill 		if (u.u_uid && u.u_ttyp != tp || c < 0)
488887Sbill 			u.u_error = EFAULT;
489887Sbill 		else
490887Sbill 			(*linesw[tp->t_line].l_rint)(c, tp);
491887Sbill 		break;
492174Sbill /* end of locals */
493887Sbill 
49439Sbill 	default:
49539Sbill 		return(0);
49639Sbill 	}
49739Sbill 	return(1);
49839Sbill }
499