xref: /csrg-svn/sys/kern/tty.c (revision 903)
1*903Sbill /*	tty.c	3.17	09/20/80	*/
239Sbill 
339Sbill /*
4*903Sbill  * 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 
6039Sbill #define	OBUFSIZ	100
6139Sbill 
6239Sbill /*
6339Sbill  * set default control characters.
6439Sbill  */
6539Sbill ttychars(tp)
6639Sbill register struct tty *tp;
6739Sbill {
68174Sbill 
6939Sbill 	tun.t_intrc = CINTR;
7039Sbill 	tun.t_quitc = CQUIT;
7139Sbill 	tun.t_startc = CSTART;
7239Sbill 	tun.t_stopc = CSTOP;
7339Sbill 	tun.t_eofc = CEOT;
7439Sbill 	tun.t_brkc = CBRK;
7539Sbill 	tp->t_erase = CERASE;
7639Sbill 	tp->t_kill = CKILL;
77174Sbill /* begin local */
78208Sbill 	tlun.t_suspc = CTRL(z);
79208Sbill 	tlun.t_dsuspc = CTRL(y);
80174Sbill 	tlun.t_rprntc = CTRL(r);
81174Sbill 	tlun.t_flushc = CTRL(o);
82174Sbill 	tlun.t_werasc = CTRL(w);
83174Sbill 	tlun.t_lnextc = CTRL(v);
84174Sbill 	tlun.t_lintr = CTRL(c);
85174Sbill 	tlun.t_lerase = CTRL(h);
86174Sbill 	tlun.t_lkill = CTRL(u);
87174Sbill 	tp->t_local = 0;
88174Sbill 	tp->t_lstate = 0;
89174Sbill /* end local */
9039Sbill }
9139Sbill 
9239Sbill /*
93*903Sbill  * Wait for output to drain, then flush input waiting.
9439Sbill  */
95*903Sbill wflushtty(tp)
9639Sbill register struct tty *tp;
9739Sbill {
9839Sbill 
99*903Sbill 	(void) spl5();
100*903Sbill 	while (tp->t_outq.c_cc && tp->t_state&CARR_ON) {
101*903Sbill 		(*tp->t_oproc)(tp);
102*903Sbill 		tp->t_state |= ASLEEP;
103*903Sbill 		sleep((caddr_t)&tp->t_outq, TTOPRI);
104*903Sbill 	}
105*903Sbill 	flushtty(tp, FREAD|FWRITE);
106*903Sbill 	(void) spl0();
10739Sbill }
10839Sbill 
10939Sbill /*
110*903Sbill  * flush all TTY queues
11139Sbill  */
112*903Sbill flushtty(tp, rw)
113*903Sbill register struct tty *tp;
11439Sbill {
115*903Sbill 	register s;
116*903Sbill 
117*903Sbill 	if (tp->t_line == NETLDISC)
118*903Sbill 		return;
119*903Sbill 	s = spl6();
120*903Sbill 	if (rw & FREAD) {
121*903Sbill 		while (getc(&tp->t_canq) >= 0)
122*903Sbill 			;
123*903Sbill 		wakeup((caddr_t)&tp->t_rawq);
124*903Sbill 	}
125*903Sbill 	if (rw & FWRITE) {
126*903Sbill 		wakeup((caddr_t)&tp->t_outq);
127*903Sbill 		tp->t_state &= ~TTSTOP;
128*903Sbill 		(*cdevsw[major(tp->t_dev)].d_stop)(tp);
129*903Sbill 		while (getc(&tp->t_outq) >= 0)
130*903Sbill 			;
131*903Sbill 	}
132*903Sbill 	if (rw & FREAD) {
133*903Sbill 		while (getc(&tp->t_rawq) >= 0)
134*903Sbill 			;
135*903Sbill 		tp->t_delct = 0;
136*903Sbill 		tp->t_rocount = 0;		/* local */
137*903Sbill 		tp->t_rocol = 0;
138*903Sbill 		tp->t_lstate = 0;
139*903Sbill 	}
140*903Sbill 	splx(s);
14139Sbill }
14239Sbill 
143*903Sbill /*
144*903Sbill  * Send stop character on input overflow.
145*903Sbill  */
146*903Sbill ttyblock(tp)
147*903Sbill register struct tty *tp;
14839Sbill {
149*903Sbill 	register x;
150*903Sbill 	x = tp->t_rawq.c_cc + tp->t_canq.c_cc;
151*903Sbill 	if (tp->t_rawq.c_cc > TTYHOG) {
152*903Sbill 		flushtty(tp, FREAD|FWRITE);
153*903Sbill 		tp->t_state &= ~TBLOCK;
154*903Sbill 	}
155*903Sbill 	if (x >= TTYHOG/2) {
156*903Sbill 		if (putc(tun.t_stopc, &tp->t_outq)==0) {
157*903Sbill 			tp->t_state |= TBLOCK;
158*903Sbill 			tp->t_char++;
159*903Sbill 			ttstart(tp);
160*903Sbill 		}
161*903Sbill 	}
16239Sbill }
16339Sbill 
16439Sbill /*
165*903Sbill  * Restart typewriter output following a delay
166*903Sbill  * timeout.
167*903Sbill  * The name of the routine is passed to the timeout
168*903Sbill  * subroutine and it is called during a clock interrupt.
169121Sbill  */
170*903Sbill ttrstrt(tp)
171121Sbill register struct tty *tp;
172121Sbill {
173121Sbill 
174*903Sbill 	tp->t_state &= ~TIMEOUT;
175*903Sbill 	ttstart(tp);
176121Sbill }
177121Sbill 
178121Sbill /*
179*903Sbill  * Start output on the typewriter. It is used from the top half
180*903Sbill  * after some characters have been put on the output queue,
181*903Sbill  * from the interrupt routine to transmit the next
182*903Sbill  * character, and after a timeout has finished.
18339Sbill  */
184*903Sbill ttstart(tp)
185*903Sbill register struct tty *tp;
18639Sbill {
187*903Sbill 	register s;
18839Sbill 
189*903Sbill 	s = spl5();
190*903Sbill 	if((tp->t_state&(TIMEOUT|TTSTOP|BUSY)) == 0)
191*903Sbill 		(*tp->t_oproc)(tp);
192*903Sbill 	splx(s);
19339Sbill }
19439Sbill 
19539Sbill /*
196*903Sbill  * Common code for tty ioctls.
19739Sbill  */
198*903Sbill ttioctl(com, tp, addr, dev, flag)
19939Sbill register struct tty *tp;
20039Sbill caddr_t addr;
20139Sbill {
20239Sbill 	unsigned t;
203174Sbill 	struct sgttyb iocb;
204191Sbill 	struct clist tq;
20539Sbill 	extern int nldisp;
206887Sbill 	register c;
207728Sbill 	int temp;
20839Sbill 
209*903Sbill 	/*
210*903Sbill 	 * If the ioctl involves modification,
211*903Sbill 	 * insist on being able to write the device,
212*903Sbill 	 * and hang if in the background.
213*903Sbill 	 */
21439Sbill 	switch(com) {
21539Sbill 
216*903Sbill 	case TIOCHPCL:
217*903Sbill 	case TIOCFLUSH:
218*903Sbill 	case TIOCSETC:
219*903Sbill 	case TIOCSLTC:
220*903Sbill 	case TIOCSPGRP:
221*903Sbill 	case TIOCLBIS:
222*903Sbill 	case TIOCLBIC:
223*903Sbill 	case TIOCLSET:
224*903Sbill 	case TIOCSTI:
225*903Sbill 		if ((flag & FWRITE) == 0) {
226*903Sbill 			u.u_error = EBADF;
227*903Sbill 			return (1);
228*903Sbill 		}
229*903Sbill 		while (tp->t_line == NTTYDISC &&
230*903Sbill 		   u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp &&
231*903Sbill 		   (u.u_procp->p_flag&SVFORK) == 0 &&
232*903Sbill 		   u.u_signal[SIGTTOU] != SIG_IGN &&
233*903Sbill 		   u.u_signal[SIGTTOU] != SIG_HOLD &&
234*903Sbill 		   (u.u_procp->p_flag&SDETACH)==0) {
235*903Sbill 			gsignal(u.u_procp->p_pgrp, SIGTTOU);
236*903Sbill 			sleep((caddr_t)&lbolt, TTOPRI);
237*903Sbill 		}
238*903Sbill 		break;
239*903Sbill 	}
240*903Sbill 
24139Sbill 	/*
242*903Sbill 	 * Process the ioctl.
24339Sbill 	 */
244*903Sbill 	switch(com) {
245*903Sbill 
246*903Sbill 	/*
247*903Sbill 	 * Get discipline number
248*903Sbill 	 */
24939Sbill 	case TIOCGETD:
25039Sbill 		t = tp->t_line;
25139Sbill 		if (copyout((caddr_t)&t, addr, sizeof(t)))
25239Sbill 			u.u_error = EFAULT;
25339Sbill 		break;
25439Sbill 
25539Sbill 	/*
256*903Sbill 	 * Set line discipline
25739Sbill 	 */
25839Sbill 	case TIOCSETD:
25939Sbill 		if (copyin(addr, (caddr_t)&t, sizeof(t))) {
26039Sbill 			u.u_error = EFAULT;
26139Sbill 			break;
26239Sbill 		}
26339Sbill 		if (t >= nldisp) {
26439Sbill 			u.u_error = ENXIO;
26539Sbill 			break;
26639Sbill 		}
267174Sbill 		(void) spl5();
26839Sbill 		if (tp->t_line)
26939Sbill 			(*linesw[tp->t_line].l_close)(tp);
27039Sbill 		if (t)
27139Sbill 			(*linesw[t].l_open)(dev, tp, addr);
27239Sbill 		if (u.u_error==0)
27339Sbill 			tp->t_line = t;
274174Sbill 		(void) spl0();
27539Sbill 		break;
27639Sbill 
27739Sbill 	/*
278*903Sbill 	 * Prevent more opens on channel
27939Sbill 	 */
28039Sbill 	case TIOCEXCL:
28139Sbill 		tp->t_state |= XCLUDE;
28239Sbill 		break;
28339Sbill 
28439Sbill 	case TIOCNXCL:
28539Sbill 		tp->t_state &= ~XCLUDE;
28639Sbill 		break;
28739Sbill 
28839Sbill 	/*
28939Sbill 	 * Set new parameters
29039Sbill 	 */
29139Sbill 	case TIOCSETP:
292191Sbill 	case TIOCSETN:
29339Sbill 		if (copyin(addr, (caddr_t)&iocb, sizeof(iocb))) {
29439Sbill 			u.u_error = EFAULT;
29539Sbill 			return(1);
29639Sbill 		}
297121Sbill 		(void) spl5();
298174Sbill 		if (tp->t_line == 0) {
299174Sbill 			if (com == TIOCSETP)
300174Sbill 				wflushtty(tp);
301174Sbill 			while (canon(tp)>=0)
302174Sbill 				;
303174Sbill 		} else if (tp->t_line == NTTYDISC) {
304174Sbill 			if (tp->t_flags&RAW || iocb.sg_flags&RAW ||
305174Sbill 			    com == TIOCSETP)
306174Sbill 				wflushtty(tp);
307174Sbill 			else if ((tp->t_flags&CBREAK) != (iocb.sg_flags&CBREAK)) {
308174Sbill 				if (iocb.sg_flags & CBREAK) {
309174Sbill 					catq(&tp->t_rawq, &tp->t_canq);
310174Sbill 					tq = tp->t_rawq;
311174Sbill 					tp->t_rawq = tp->t_canq;
312174Sbill 					tp->t_canq = tq;
313174Sbill 				} else {
314174Sbill 					tp->t_local |= LPENDIN;
315174Sbill 					if (tp->t_canq.c_cc)
316174Sbill 						panic("ioccom canq");
317174Sbill 					if (tp->t_chan)
318174Sbill 						(void) sdata(tp->t_chan);
319174Sbill 					else
320174Sbill 						wakeup((caddr_t)&tp->t_rawq);
321174Sbill 				}
322174Sbill 			}
323174Sbill 		}
32439Sbill 		if ((tp->t_state&SPEEDS)==0) {
325174Sbill 			tp->t_ispeed = iocb.sg_ispeed;
326174Sbill 			tp->t_ospeed = iocb.sg_ospeed;
32739Sbill 		}
328174Sbill 		tp->t_erase = iocb.sg_erase;
329174Sbill 		tp->t_kill = iocb.sg_kill;
330174Sbill 		tp->t_flags = iocb.sg_flags;
331121Sbill 		(void) spl0();
33239Sbill 		break;
33339Sbill 
33439Sbill 	/*
335*903Sbill 	 * Send current parameters to user
33639Sbill 	 */
33739Sbill 	case TIOCGETP:
338174Sbill 		iocb.sg_ispeed = tp->t_ispeed;
339174Sbill 		iocb.sg_ospeed = tp->t_ospeed;
340174Sbill 		iocb.sg_erase = tp->t_erase;
341174Sbill 		iocb.sg_kill = tp->t_kill;
342174Sbill 		iocb.sg_flags = tp->t_flags;
34339Sbill 		if (copyout((caddr_t)&iocb, addr, sizeof(iocb)))
34439Sbill 			u.u_error = EFAULT;
34539Sbill 		break;
34639Sbill 
34739Sbill 	/*
34839Sbill 	 * Hang up line on last close
34939Sbill 	 */
35039Sbill 	case TIOCHPCL:
35139Sbill 		tp->t_state |= HUPCLS;
35239Sbill 		break;
35339Sbill 
35439Sbill 	case TIOCFLUSH:
355872Sbill 		flushtty(tp, FREAD|FWRITE);
35639Sbill 		break;
35739Sbill 
35839Sbill 	/*
359*903Sbill 	 * Ioctl entries to line discipline
36039Sbill 	 */
36139Sbill 	case DIOCSETP:
36239Sbill 	case DIOCGETP:
363121Sbill 		if ((*linesw[tp->t_line].l_ioctl)(com, tp, addr))
364121Sbill 			u.u_error = ENOTTY;
36539Sbill 		break;
36639Sbill 
36739Sbill 	/*
368*903Sbill 	 * Set and fetch special characters
36939Sbill 	 */
37039Sbill 	case TIOCSETC:
371174Sbill 		if (copyin(addr, (caddr_t)&tun, sizeof(struct tchars)))
37239Sbill 			u.u_error = EFAULT;
37339Sbill 		break;
37439Sbill 
37539Sbill 	case TIOCGETC:
376174Sbill 		if (copyout((caddr_t)&tun, addr, sizeof(struct tchars)))
37739Sbill 			u.u_error = EFAULT;
37839Sbill 		break;
37939Sbill 
380174Sbill /* local ioctls */
381*903Sbill 	/*
382*903Sbill 	 * Set/get local special characters.
383*903Sbill 	 */
384174Sbill 	case TIOCSLTC:
385174Sbill 		if (copyin(addr, (caddr_t)&tlun, sizeof (struct ltchars)))
386174Sbill 			u.u_error = EFAULT;
387174Sbill 		break;
388174Sbill 
389174Sbill 	case TIOCGLTC:
390174Sbill 		if (copyout((caddr_t)&tlun, addr, sizeof (struct ltchars)))
391174Sbill 			u.u_error = EFAULT;
392174Sbill 		break;
393174Sbill 
394*903Sbill 	/*
395*903Sbill 	 * Return number of characters immediately available.
396*903Sbill 	 */
397174Sbill 	case FIONREAD: {
398340Sbill 		off_t nread;
399174Sbill 
400340Sbill 		switch (tp->t_line) {
401340Sbill 
402340Sbill 		case NETLDISC:
403340Sbill 			nread = tp->t_rec ? tp->t_inbuf : 0;
404340Sbill 			break;
405340Sbill 
406894Sbill 		case 0:
407894Sbill 			(void) spl5();
408894Sbill 			while (canon(tp)>=0)
409894Sbill 				;
410894Sbill 			(void) spl0();
411894Sbill 			/* fall into ... */
412894Sbill 
413340Sbill 		case NTTYDISC:
414340Sbill 			nread = tp->t_canq.c_cc;
415340Sbill 			if (tp->t_flags & (RAW|CBREAK))
416340Sbill 				nread += tp->t_rawq.c_cc;
417340Sbill 			break;
418340Sbill 
419340Sbill 		}
420174Sbill 		if (copyout((caddr_t)&nread, addr, sizeof (off_t)))
421174Sbill 			u.u_error = EFAULT;
422174Sbill 		break;
423174Sbill 		}
424174Sbill 
425174Sbill 	/*
426174Sbill 	 * Should allow SPGRP and GPGRP only if tty open for reading.
427174Sbill 	 */
428174Sbill 	case TIOCSPGRP:
429728Sbill 		if (copyin(addr, (caddr_t)&tp->t_pgrp, sizeof (tp->t_pgrp)))
430728Sbill 			u.u_error = EFAULT;
431174Sbill 		break;
432174Sbill 
433174Sbill 	case TIOCGPGRP:
434174Sbill 		if (copyout((caddr_t)&tp->t_pgrp, addr, sizeof(tp->t_pgrp)))
435174Sbill 			u.u_error = EFAULT;
436174Sbill 		break;
437174Sbill 
438174Sbill 	/*
439174Sbill 	 * Modify local mode word.
440174Sbill 	 */
441174Sbill 	case TIOCLBIS:
442728Sbill 		if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local)))
443728Sbill 			u.u_error = EFAULT;
444728Sbill 		else
445728Sbill 			tp->t_local |= temp;
446174Sbill 		break;
447174Sbill 
448174Sbill 	case TIOCLBIC:
449728Sbill 		if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local)))
450728Sbill 			u.u_error = EFAULT;
451728Sbill 		else
452728Sbill 			tp->t_local &= ~temp;
453174Sbill 		break;
454174Sbill 
455174Sbill 	case TIOCLSET:
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 TIOCLGET:
463174Sbill 		if (copyout((caddr_t)&tp->t_local, addr, sizeof(tp->t_local)))
464174Sbill 			u.u_error = EFAULT;
465174Sbill 		break;
466174Sbill 
467*903Sbill 	/*
468*903Sbill 	 * Return number of characters in
469*903Sbill 	 * the output.
470*903Sbill 	 */
471213Sbill 	case TIOCOUTQ:
472213Sbill 		if (copyout((caddr_t)&tp->t_outq.c_cc, addr, sizeof(tp->t_outq.c_cc)))
473213Sbill 			u.u_error = EFAULT;
474213Sbill 		break;
475213Sbill 
476*903Sbill 	/*
477*903Sbill 	 * Simulate typing of a character at the terminal.
478*903Sbill 	 */
479887Sbill 	case TIOCSTI:
480887Sbill 		c = fubyte(addr);
481887Sbill 		if (u.u_uid && u.u_ttyp != tp || c < 0)
482887Sbill 			u.u_error = EFAULT;
483887Sbill 		else
484887Sbill 			(*linesw[tp->t_line].l_rint)(c, tp);
485887Sbill 		break;
486174Sbill /* end of locals */
487887Sbill 
48839Sbill 	default:
48939Sbill 		return(0);
49039Sbill 	}
49139Sbill 	return(1);
49239Sbill }
493