xref: /csrg-svn/sys/kern/tty.c (revision 174)
1*174Sbill /*	tty.c	3.4	10/14/12	*/
239Sbill 
339Sbill /*
439Sbill  * general TTY subroutines
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"
1839Sbill 
1939Sbill char	partab[];
2039Sbill 
21146Sbill /*
22146Sbill  * When running dz's using only SAE (silo alarm) on input
23146Sbill  * it is necessary to call dzrint() at clock interrupt time.
24146Sbill  * This is unsafe unless spl5()s in tty code are changed to
25146Sbill  * spl6()s to block clock interrupts.  Note that the dh driver
26146Sbill  * currently in use works the same way as the dz, even though
27146Sbill  * we could try to more intelligently manage its silo.
28146Sbill  * Thus don't take this out if you have no dz's unless you
29146Sbill  * change clock.c and dhtimer().
30146Sbill  */
31146Sbill #define	spl5	spl6
3239Sbill 
3339Sbill /*
3439Sbill  * Input mapping table-- if an entry is non-zero, when the
3539Sbill  * corresponding character is typed preceded by "\" the escape
3639Sbill  * sequence is replaced by the table value.  Mostly used for
3739Sbill  * upper-case only terminals.
3839Sbill  */
3939Sbill 
4039Sbill char	maptab[] ={
4139Sbill 	000,000,000,000,000,000,000,000,
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,'`',
4639Sbill 	'{','}',000,000,000,000,000,000,
4739Sbill 	000,000,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,
5339Sbill 	000,'A','B','C','D','E','F','G',
5439Sbill 	'H','I','J','K','L','M','N','O',
5539Sbill 	'P','Q','R','S','T','U','V','W',
5639Sbill 	'X','Y','Z',000,000,000,000,000,
5739Sbill };
5839Sbill 
5939Sbill 
6039Sbill /*
6139Sbill  * shorthand
6239Sbill  */
6339Sbill #define	q1	tp->t_rawq
6439Sbill #define	q2	tp->t_canq
6539Sbill #define	q3	tp->t_outq
6639Sbill #define	q4	tp->t_un.t_ctlq
6739Sbill 
6839Sbill #define	OBUFSIZ	100
6939Sbill 
7039Sbill /*
7139Sbill  * routine called on first teletype open.
7239Sbill  * establishes a process group for distribution
7339Sbill  * of quits and interrupts from the tty.
7439Sbill  */
7539Sbill ttyopen(dev, tp)
7639Sbill dev_t dev;
7739Sbill register struct tty *tp;
7839Sbill {
7939Sbill 	register struct proc *pp;
8039Sbill 
8139Sbill 	pp = u.u_procp;
8239Sbill 	tp->t_dev = dev;
8339Sbill 	if(pp->p_pgrp == 0) {
8439Sbill 		u.u_ttyp = tp;
8539Sbill 		u.u_ttyd = dev;
86*174Sbill 		tp->t_pgrp = pp->p_pid;
8739Sbill 		pp->p_pgrp = tp->t_pgrp;
8839Sbill 	}
8939Sbill 	tp->t_state &= ~WOPEN;
9039Sbill 	tp->t_state |= ISOPEN;
91*174Sbill 	tp->t_line = 0;		/* conservative */
9239Sbill }
9339Sbill 
9439Sbill /*
9539Sbill  * set default control characters.
9639Sbill  */
9739Sbill ttychars(tp)
9839Sbill register struct tty *tp;
9939Sbill {
100*174Sbill 
10139Sbill 	tun.t_intrc = CINTR;
10239Sbill 	tun.t_quitc = CQUIT;
10339Sbill 	tun.t_startc = CSTART;
10439Sbill 	tun.t_stopc = CSTOP;
10539Sbill 	tun.t_eofc = CEOT;
10639Sbill 	tun.t_brkc = CBRK;
10739Sbill 	tp->t_erase = CERASE;
10839Sbill 	tp->t_kill = CKILL;
109*174Sbill /* begin local */
110*174Sbill 	tlun.t_suspc = 0377;
111*174Sbill 	tlun.t_dstopc = 0377;
112*174Sbill 	tlun.t_rprntc = CTRL(r);
113*174Sbill 	tlun.t_flushc = CTRL(o);
114*174Sbill 	tlun.t_werasc = CTRL(w);
115*174Sbill 	tlun.t_lnextc = CTRL(v);
116*174Sbill 	tlun.t_lintr = CTRL(c);
117*174Sbill 	tlun.t_lerase = CTRL(h);
118*174Sbill 	tlun.t_lkill = CTRL(u);
119*174Sbill 	tp->t_local = 0;
120*174Sbill 	tp->t_lstate = 0;
121*174Sbill /* end local */
12239Sbill }
12339Sbill 
12439Sbill /*
12539Sbill  * clean tp on last close
12639Sbill  */
12739Sbill ttyclose(tp)
12839Sbill register struct tty *tp;
12939Sbill {
13039Sbill 
13139Sbill 	tp->t_pgrp = 0;
13239Sbill 	wflushtty(tp);
13339Sbill 	tp->t_state = 0;
134*174Sbill 	tp->t_line = 0;
13539Sbill }
13639Sbill 
13739Sbill /*
13839Sbill  * stty/gtty writearound
13939Sbill  */
14039Sbill stty()
14139Sbill {
14239Sbill 	u.u_arg[2] = u.u_arg[1];
14339Sbill 	u.u_arg[1] = TIOCSETP;
14439Sbill 	ioctl();
14539Sbill }
14639Sbill 
14739Sbill gtty()
14839Sbill {
14939Sbill 	u.u_arg[2] = u.u_arg[1];
15039Sbill 	u.u_arg[1] = TIOCGETP;
15139Sbill 	ioctl();
15239Sbill }
15339Sbill 
15439Sbill /*
155121Sbill  * Do nothing specific version of line
156121Sbill  * discipline specific ioctl command.
157121Sbill  */
158121Sbill nullioctl(tp, cmd, addr)
159121Sbill register struct tty *tp;
160121Sbill caddr_t addr;
161121Sbill {
162121Sbill 
163121Sbill 	return (cmd);
164121Sbill }
165121Sbill 
166121Sbill /*
16739Sbill  * ioctl system call
16839Sbill  * Check legality, execute common code, and switch out to individual
16939Sbill  * device routine.
17039Sbill  */
17139Sbill ioctl()
17239Sbill {
17339Sbill 	register struct file *fp;
17439Sbill 	register struct inode *ip;
17539Sbill 	register struct a {
17639Sbill 		int	fdes;
17739Sbill 		int	cmd;
17839Sbill 		caddr_t	cmarg;
17939Sbill 	} *uap;
18039Sbill 	register dev_t dev;
18139Sbill 	register fmt;
18239Sbill 
18339Sbill 	uap = (struct a *)u.u_ap;
18439Sbill 	if ((fp = getf(uap->fdes)) == NULL)
18539Sbill 		return;
18639Sbill 	if (uap->cmd==FIOCLEX) {
18739Sbill 		u.u_pofile[uap->fdes] |= EXCLOSE;
18839Sbill 		return;
18939Sbill 	}
19039Sbill 	if (uap->cmd==FIONCLEX) {
19139Sbill 		u.u_pofile[uap->fdes] &= ~EXCLOSE;
19239Sbill 		return;
19339Sbill 	}
19439Sbill 	ip = fp->f_inode;
19539Sbill 	fmt = ip->i_mode & IFMT;
19639Sbill 	if (fmt != IFCHR && fmt != IFMPC) {
197*174Sbill /* begin local */
198*174Sbill 		if (uap->cmd==FIONREAD && (fmt == IFREG || fmt == IFDIR)) {
199*174Sbill 			off_t nread = ip->i_size - fp->f_un.f_offset;
200*174Sbill 
201*174Sbill 			if (copyout((caddr_t)&nread, uap->cmarg, sizeof(off_t)))
202*174Sbill 				u.u_error = EFAULT;
203*174Sbill 		} else
204*174Sbill /* end local */
205*174Sbill 			u.u_error = ENOTTY;
20639Sbill 		return;
20739Sbill 	}
20839Sbill 	dev = ip->i_un.i_rdev;
20939Sbill 	u.u_r.r_val1 = 0;
21039Sbill 	(*cdevsw[major(dev)].d_ioctl)(dev, uap->cmd, uap->cmarg, fp->f_flag);
21139Sbill }
21239Sbill 
21339Sbill /*
21439Sbill  * Common code for several tty ioctl commands
21539Sbill  */
21639Sbill ttioccomm(com, tp, addr, dev)
21739Sbill register struct tty *tp;
21839Sbill caddr_t addr;
21939Sbill {
22039Sbill 	unsigned t;
221*174Sbill 	struct sgttyb iocb;
22239Sbill 	extern int nldisp;
22339Sbill 
22439Sbill 	switch(com) {
22539Sbill 
22639Sbill 	/*
22739Sbill 	 * get discipline number
22839Sbill 	 */
22939Sbill 	case TIOCGETD:
23039Sbill 		t = tp->t_line;
23139Sbill 		if (copyout((caddr_t)&t, addr, sizeof(t)))
23239Sbill 			u.u_error = EFAULT;
23339Sbill 		break;
23439Sbill 
23539Sbill 	/*
23639Sbill 	 * set line discipline
23739Sbill 	 */
23839Sbill 	case TIOCSETD:
23939Sbill 		if (copyin(addr, (caddr_t)&t, sizeof(t))) {
24039Sbill 			u.u_error = EFAULT;
24139Sbill 			break;
24239Sbill 		}
24339Sbill 		if (t >= nldisp) {
24439Sbill 			u.u_error = ENXIO;
24539Sbill 			break;
24639Sbill 		}
247*174Sbill 		(void) spl5();
24839Sbill 		if (tp->t_line)
24939Sbill 			(*linesw[tp->t_line].l_close)(tp);
25039Sbill 		if (t)
25139Sbill 			(*linesw[t].l_open)(dev, tp, addr);
25239Sbill 		if (u.u_error==0)
25339Sbill 			tp->t_line = t;
254*174Sbill 		(void) spl0();
25539Sbill 		break;
25639Sbill 
25739Sbill 	/*
25839Sbill 	 * prevent more opens on channel
25939Sbill 	 */
26039Sbill 	case TIOCEXCL:
26139Sbill 		tp->t_state |= XCLUDE;
26239Sbill 		break;
26339Sbill 
26439Sbill 	case TIOCNXCL:
26539Sbill 		tp->t_state &= ~XCLUDE;
26639Sbill 		break;
26739Sbill 
26839Sbill 	/*
26939Sbill 	 * Set new parameters
27039Sbill 	 */
27139Sbill 	case TIOCSETP:
272*174Sbill 	case TIOCSETN: {
273*174Sbill 		struct clist tq;
274*174Sbill 		register c;
275*174Sbill 
27639Sbill 		if (copyin(addr, (caddr_t)&iocb, sizeof(iocb))) {
27739Sbill 			u.u_error = EFAULT;
27839Sbill 			return(1);
27939Sbill 		}
280121Sbill 		(void) spl5();
281*174Sbill 		if (tp->t_line == 0) {
282*174Sbill 			if (com == TIOCSETP)
283*174Sbill 				wflushtty(tp);
284*174Sbill 			while (canon(tp)>=0)
285*174Sbill 				;
286*174Sbill 		} else if (tp->t_line == NTTYDISC) {
287*174Sbill 			if (tp->t_flags&RAW || iocb.sg_flags&RAW ||
288*174Sbill 			    com == TIOCSETP)
289*174Sbill 				wflushtty(tp);
290*174Sbill 			else if ((tp->t_flags&CBREAK) != (iocb.sg_flags&CBREAK)) {
291*174Sbill 				if (iocb.sg_flags & CBREAK) {
292*174Sbill 					catq(&tp->t_rawq, &tp->t_canq);
293*174Sbill 					tq = tp->t_rawq;
294*174Sbill 					tp->t_rawq = tp->t_canq;
295*174Sbill 					tp->t_canq = tq;
296*174Sbill 				} else {
297*174Sbill 					tp->t_local |= LPENDIN;
298*174Sbill 					if (tp->t_canq.c_cc)
299*174Sbill 						panic("ioccom canq");
300*174Sbill 					if (tp->t_chan)
301*174Sbill 						(void) sdata(tp->t_chan);
302*174Sbill 					else
303*174Sbill 						wakeup((caddr_t)&tp->t_rawq);
304*174Sbill 				}
305*174Sbill 			}
306*174Sbill 		}
30739Sbill 		if ((tp->t_state&SPEEDS)==0) {
308*174Sbill 			tp->t_ispeed = iocb.sg_ispeed;
309*174Sbill 			tp->t_ospeed = iocb.sg_ospeed;
31039Sbill 		}
311*174Sbill 		tp->t_erase = iocb.sg_erase;
312*174Sbill 		tp->t_kill = iocb.sg_kill;
313*174Sbill 		tp->t_flags = iocb.sg_flags;
314121Sbill 		(void) spl0();
31539Sbill 		break;
316*174Sbill 		}
31739Sbill 
31839Sbill 	/*
31939Sbill 	 * send current parameters to user
32039Sbill 	 */
32139Sbill 	case TIOCGETP:
322*174Sbill 		iocb.sg_ispeed = tp->t_ispeed;
323*174Sbill 		iocb.sg_ospeed = tp->t_ospeed;
324*174Sbill 		iocb.sg_erase = tp->t_erase;
325*174Sbill 		iocb.sg_kill = tp->t_kill;
326*174Sbill 		iocb.sg_flags = tp->t_flags;
32739Sbill 		if (copyout((caddr_t)&iocb, addr, sizeof(iocb)))
32839Sbill 			u.u_error = EFAULT;
32939Sbill 		break;
33039Sbill 
33139Sbill 	/*
33239Sbill 	 * Hang up line on last close
33339Sbill 	 */
33439Sbill 
33539Sbill 	case TIOCHPCL:
33639Sbill 		tp->t_state |= HUPCLS;
33739Sbill 		break;
33839Sbill 
33939Sbill 	case TIOCFLUSH:
34039Sbill 		flushtty(tp);
34139Sbill 		break;
34239Sbill 
34339Sbill 	/*
34439Sbill 	 * ioctl entries to line discipline
34539Sbill 	 */
34639Sbill 	case DIOCSETP:
34739Sbill 	case DIOCGETP:
348121Sbill 		if ((*linesw[tp->t_line].l_ioctl)(com, tp, addr))
349121Sbill 			u.u_error = ENOTTY;
35039Sbill 		break;
35139Sbill 
35239Sbill 	/*
35339Sbill 	 * set and fetch special characters
35439Sbill 	 */
35539Sbill 	case TIOCSETC:
356*174Sbill 		if (copyin(addr, (caddr_t)&tun, sizeof(struct tchars)))
35739Sbill 			u.u_error = EFAULT;
35839Sbill 		break;
35939Sbill 
36039Sbill 	case TIOCGETC:
361*174Sbill 		if (copyout((caddr_t)&tun, addr, sizeof(struct tchars)))
36239Sbill 			u.u_error = EFAULT;
36339Sbill 		break;
36439Sbill 
365*174Sbill /* local ioctls */
366*174Sbill 	case TIOCSLTC:
367*174Sbill 		if (copyin(addr, (caddr_t)&tlun, sizeof (struct ltchars)))
368*174Sbill 			u.u_error = EFAULT;
369*174Sbill 		break;
370*174Sbill 
371*174Sbill 	case TIOCGLTC:
372*174Sbill 		if (copyout((caddr_t)&tlun, addr, sizeof (struct ltchars)))
373*174Sbill 			u.u_error = EFAULT;
374*174Sbill 		break;
375*174Sbill 
376*174Sbill 	case FIONREAD: {
377*174Sbill 		off_t nread = tp->t_canq.c_cc;
378*174Sbill 
379*174Sbill 		if (tp->t_flags & (RAW|CBREAK))
380*174Sbill 			nread += tp->t_rawq.c_cc;
381*174Sbill 		if (copyout((caddr_t)&nread, addr, sizeof (off_t)))
382*174Sbill 			u.u_error = EFAULT;
383*174Sbill 		break;
384*174Sbill 		}
385*174Sbill 
386*174Sbill 	/*
387*174Sbill 	 * Should allow SPGRP and GPGRP only if tty open for reading.
388*174Sbill 	 */
389*174Sbill 	case TIOCSPGRP:
390*174Sbill 		tp->t_pgrp = (int)addr;
391*174Sbill 		break;
392*174Sbill 
393*174Sbill 	case TIOCGPGRP:
394*174Sbill 		if (copyout((caddr_t)&tp->t_pgrp, addr, sizeof(tp->t_pgrp)))
395*174Sbill 			u.u_error = EFAULT;
396*174Sbill 		break;
397*174Sbill 
398*174Sbill 	/*
399*174Sbill 	 * Modify local mode word.
400*174Sbill 	 */
401*174Sbill 	case TIOCLBIS:
402*174Sbill 		tp->t_local |= (int)addr;
403*174Sbill 		break;
404*174Sbill 
405*174Sbill 	case TIOCLBIC:
406*174Sbill 		tp->t_local &= ~(int)addr;
407*174Sbill 		break;
408*174Sbill 
409*174Sbill 	case TIOCLSET:
410*174Sbill 		tp->t_local = (int)addr;
411*174Sbill 		break;
412*174Sbill 
413*174Sbill 	case TIOCLGET:
414*174Sbill 		if (copyout((caddr_t)&tp->t_local, addr, sizeof(tp->t_local)))
415*174Sbill 			u.u_error = EFAULT;
416*174Sbill 		break;
417*174Sbill 
418*174Sbill /* end of locals */
41939Sbill 	default:
42039Sbill 		return(0);
42139Sbill 	}
42239Sbill 	return(1);
42339Sbill }
42439Sbill 
42539Sbill /*
42639Sbill  * Wait for output to drain, then flush input waiting.
42739Sbill  */
42839Sbill wflushtty(tp)
42939Sbill register struct tty *tp;
43039Sbill {
43139Sbill 
432121Sbill 	(void) spl5();
43339Sbill 	while (tp->t_outq.c_cc && tp->t_state&CARR_ON) {
43439Sbill 		(*tp->t_oproc)(tp);
43539Sbill 		tp->t_state |= ASLEEP;
43639Sbill 		sleep((caddr_t)&tp->t_outq, TTOPRI);
43739Sbill 	}
43839Sbill 	flushtty(tp);
439121Sbill 	(void) spl0();
44039Sbill }
44139Sbill 
44239Sbill /*
44339Sbill  * flush all TTY queues
44439Sbill  */
44539Sbill flushtty(tp)
44639Sbill register struct tty *tp;
44739Sbill {
44839Sbill 	register s;
44939Sbill 
450121Sbill 	s = spl6();
45139Sbill 	while (getc(&tp->t_canq) >= 0)
45239Sbill 		;
45339Sbill 	wakeup((caddr_t)&tp->t_rawq);
45439Sbill 	wakeup((caddr_t)&tp->t_outq);
45539Sbill 	tp->t_state &= ~TTSTOP;
45639Sbill 	(*cdevsw[major(tp->t_dev)].d_stop)(tp);
45739Sbill 	while (getc(&tp->t_outq) >= 0)
45839Sbill 		;
45939Sbill 	while (getc(&tp->t_rawq) >= 0)
46039Sbill 		;
46139Sbill 	tp->t_delct = 0;
462*174Sbill 	tp->t_rocount = 0;		/* local */
463*174Sbill 	tp->t_lstate = 0;	/* reset */
46439Sbill 	splx(s);
46539Sbill }
46639Sbill 
46739Sbill 
46839Sbill 
46939Sbill /*
47039Sbill  * transfer raw input list to canonical list,
47139Sbill  * doing erase-kill processing and handling escapes.
47239Sbill  * It waits until a full line has been typed in cooked mode,
47339Sbill  * or until any character has been typed in raw mode.
47439Sbill  */
47539Sbill canon(tp)
47639Sbill register struct tty *tp;
47739Sbill {
47839Sbill 	register char *bp;
47939Sbill 	char *bp1;
48039Sbill 	register int c;
48139Sbill 	int mc;
48239Sbill 	int s;
48339Sbill 
48439Sbill 	if ((tp->t_flags&(RAW|CBREAK))==0 && tp->t_delct==0
48539Sbill 	    || (tp->t_flags&(RAW|CBREAK))!=0 && tp->t_rawq.c_cc==0) {
48639Sbill 		return(-1);
48739Sbill 	}
48839Sbill 	s = spl0();
48939Sbill loop:
49039Sbill 	bp = &canonb[2];
49139Sbill 	while ((c=getc(&tp->t_rawq)) >= 0) {
49239Sbill 		if ((tp->t_flags&(RAW|CBREAK))==0) {
49339Sbill 			if (c==0377) {
49439Sbill 				tp->t_delct--;
49539Sbill 				break;
49639Sbill 			}
49739Sbill 			if (bp[-1]!='\\') {
49839Sbill 				if (c==tp->t_erase) {
49939Sbill 					if (bp > &canonb[2])
50039Sbill 						bp--;
50139Sbill 					continue;
50239Sbill 				}
50339Sbill 				if (c==tp->t_kill)
50439Sbill 					goto loop;
50539Sbill 				if (c==tun.t_eofc)
50639Sbill 					continue;
50739Sbill 			} else {
50839Sbill 				mc = maptab[c];
50939Sbill 				if (c==tp->t_erase || c==tp->t_kill)
51039Sbill 					mc = c;
51139Sbill 				if (mc && (mc==c || (tp->t_flags&LCASE))) {
51239Sbill 					if (bp[-2] != '\\')
51339Sbill 						c = mc;
51439Sbill 					bp--;
51539Sbill 				}
51639Sbill 			}
51739Sbill 		}
51839Sbill 		*bp++ = c;
51939Sbill 		if (bp>=canonb+CANBSIZ)
52039Sbill 			break;
52139Sbill 	}
52239Sbill 	bp1 = &canonb[2];
523121Sbill 	(void) b_to_q(bp1, bp-bp1, &tp->t_canq);
52439Sbill 
52539Sbill 	if (tp->t_state&TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) {
52639Sbill 		if (putc(tun.t_startc, &tp->t_outq)==0) {
52739Sbill 			tp->t_state &= ~TBLOCK;
52839Sbill 			ttstart(tp);
52939Sbill 		}
53039Sbill 		tp->t_char = 0;
53139Sbill 	}
53239Sbill 
53339Sbill 	splx(s);
53439Sbill 	return(0);
53539Sbill }
53639Sbill 
53739Sbill 
53839Sbill /*
53939Sbill  * block transfer input handler.
54039Sbill  */
54139Sbill ttyrend(tp, pb, pe)
54239Sbill register struct tty *tp;
54339Sbill register char *pb, *pe;
54439Sbill {
54539Sbill 	int	tandem;
54639Sbill 
54739Sbill 	tandem = tp->t_flags&TANDEM;
54839Sbill 	if (tp->t_flags&RAW) {
549121Sbill 		(void) b_to_q(pb, pe-pb, &tp->t_rawq);
55039Sbill 		if (tp->t_chan)
551121Sbill 			(void) sdata(tp->t_chan); else
55239Sbill 			wakeup((caddr_t)&tp->t_rawq);
55339Sbill 	} else {
55439Sbill 		tp->t_flags &= ~TANDEM;
55539Sbill 		while (pb < pe)
55639Sbill 			ttyinput(*pb++, tp);
55739Sbill 		tp->t_flags |= tandem;
55839Sbill 	}
55939Sbill 	if (tandem)
56039Sbill 		ttyblock(tp);
56139Sbill }
56239Sbill 
56339Sbill /*
56439Sbill  * Place a character on raw TTY input queue, putting in delimiters
56539Sbill  * and waking up top half as needed.
56639Sbill  * Also echo if required.
56739Sbill  * The arguments are the character and the appropriate
56839Sbill  * tty structure.
56939Sbill  */
57039Sbill ttyinput(c, tp)
57139Sbill register c;
57239Sbill register struct tty *tp;
57339Sbill {
57439Sbill 	register int t_flags;
57539Sbill 	register struct chan *cp;
57639Sbill 
57739Sbill 	tk_nin += 1;
57839Sbill 	c &= 0377;
57939Sbill 	t_flags = tp->t_flags;
58039Sbill 	if (t_flags&TANDEM)
58139Sbill 		ttyblock(tp);
58239Sbill 	if ((t_flags&RAW)==0) {
58339Sbill 		c &= 0177;
58439Sbill 		if (tp->t_state&TTSTOP) {
58539Sbill 			if (c==tun.t_startc) {
58639Sbill 				tp->t_state &= ~TTSTOP;
58739Sbill 				ttstart(tp);
58839Sbill 				return;
58939Sbill 			}
59039Sbill 			if (c==tun.t_stopc)
59139Sbill 				return;
59239Sbill 			tp->t_state &= ~TTSTOP;
59339Sbill 			ttstart(tp);
59439Sbill 		} else {
59539Sbill 			if (c==tun.t_stopc) {
59639Sbill 				tp->t_state |= TTSTOP;
59739Sbill 				(*cdevsw[major(tp->t_dev)].d_stop)(tp);
59839Sbill 				return;
59939Sbill 			}
60039Sbill 			if (c==tun.t_startc)
60139Sbill 				return;
60239Sbill 		}
60339Sbill 		if (c==tun.t_quitc || c==tun.t_intrc) {
60439Sbill 			flushtty(tp);
60539Sbill 			c = (c==tun.t_intrc) ? SIGINT:SIGQUIT;
60639Sbill 			if (tp->t_chan)
60739Sbill 				scontrol(tp->t_chan, M_SIG, c);
60839Sbill 			else
609*174Sbill 				gsignal(tp->t_pgrp, c);
61039Sbill 			return;
61139Sbill 		}
61239Sbill 		if (c=='\r' && t_flags&CRMOD)
61339Sbill 			c = '\n';
61439Sbill 	}
61539Sbill 	if (tp->t_rawq.c_cc>TTYHOG) {
61639Sbill 		flushtty(tp);
61739Sbill 		return;
61839Sbill 	}
61939Sbill 	if (t_flags&LCASE && c>='A' && c<='Z')
62039Sbill 		c += 'a'-'A';
621121Sbill 	(void) putc(c, &tp->t_rawq);
62239Sbill 	if (t_flags&(RAW|CBREAK)||(c=='\n'||c==tun.t_eofc||c==tun.t_brkc)) {
62339Sbill 		if ((t_flags&(RAW|CBREAK))==0 && putc(0377, &tp->t_rawq)==0)
62439Sbill 			tp->t_delct++;
62539Sbill 		if ((cp=tp->t_chan)!=NULL)
626121Sbill 			(void) sdata(cp); else
62739Sbill 			wakeup((caddr_t)&tp->t_rawq);
62839Sbill 	}
62939Sbill 	if (t_flags&ECHO) {
63039Sbill 		ttyoutput(c, tp);
63139Sbill 		if (c==tp->t_kill && (t_flags&(RAW|CBREAK))==0)
63239Sbill 			ttyoutput('\n', tp);
63339Sbill 		ttstart(tp);
63439Sbill 	}
63539Sbill }
63639Sbill 
63739Sbill 
63839Sbill /*
63939Sbill  * Send stop character on input overflow.
64039Sbill  */
64139Sbill ttyblock(tp)
64239Sbill register struct tty *tp;
64339Sbill {
64439Sbill 	register x;
64539Sbill 	x = q1.c_cc + q2.c_cc;
64639Sbill 	if (q1.c_cc > TTYHOG) {
64739Sbill 		flushtty(tp);
64839Sbill 		tp->t_state &= ~TBLOCK;
64939Sbill 	}
65039Sbill 	if (x >= TTYHOG/2) {
65139Sbill 		if (putc(tun.t_stopc, &tp->t_outq)==0) {
65239Sbill 			tp->t_state |= TBLOCK;
65339Sbill 			tp->t_char++;
65439Sbill 			ttstart(tp);
65539Sbill 		}
65639Sbill 	}
65739Sbill }
65839Sbill 
65939Sbill /*
66039Sbill  * put character on TTY output queue, adding delays,
66139Sbill  * expanding tabs, and handling the CR/NL bit.
66239Sbill  * It is called both from the top half for output, and from
66339Sbill  * interrupt level for echoing.
66439Sbill  * The arguments are the character and the tty structure.
66539Sbill  */
66639Sbill ttyoutput(c, tp)
66739Sbill register c;
66839Sbill register struct tty *tp;
66939Sbill {
67039Sbill 	register char *colp;
67139Sbill 	register ctype;
67239Sbill 
67339Sbill 	/*
67439Sbill 	 * Ignore EOT in normal mode to avoid hanging up
67539Sbill 	 * certain terminals.
67639Sbill 	 * In raw mode dump the char unchanged.
67739Sbill 	 */
67839Sbill 	if ((tp->t_flags&RAW)==0) {
67939Sbill 		c &= 0177;
68039Sbill 		if ((tp->t_flags&CBREAK)==0 && c==CEOT)
68139Sbill 			return;
68239Sbill 	} else {
683121Sbill 		tk_nout++;
684121Sbill 		(void) putc(c, &tp->t_outq);
68539Sbill 		return;
68639Sbill 	}
68739Sbill 
68839Sbill 	/*
68939Sbill 	 * Turn tabs to spaces as required
69039Sbill 	 */
69139Sbill 	if (c=='\t' && (tp->t_flags&TBDELAY)==XTABS) {
692121Sbill 		c = 8 - (tp->t_col & 7);
693121Sbill 		(void) b_to_q("        ", c, &tp->t_outq);
694121Sbill 		tp->t_col += c;
695121Sbill 		tk_nout += c;
69639Sbill 		return;
69739Sbill 	}
698121Sbill 	tk_nout++;
69939Sbill 	/*
70039Sbill 	 * for upper-case-only terminals,
70139Sbill 	 * generate escapes.
70239Sbill 	 */
70339Sbill 	if (tp->t_flags&LCASE) {
70439Sbill 		colp = "({)}!|^~'`";
70539Sbill 		while(*colp++)
70639Sbill 			if(c == *colp++) {
70739Sbill 				ttyoutput('\\', tp);
70839Sbill 				c = colp[-2];
70939Sbill 				break;
71039Sbill 			}
71139Sbill 		if ('a'<=c && c<='z')
71239Sbill 			c += 'A' - 'a';
71339Sbill 	}
71439Sbill 	/*
71539Sbill 	 * turn <nl> to <cr><lf> if desired.
71639Sbill 	 */
71739Sbill 	if (c=='\n' && tp->t_flags&CRMOD)
71839Sbill 		ttyoutput('\r', tp);
719121Sbill 	(void) putc(c, &tp->t_outq);
72039Sbill 	/*
72139Sbill 	 * Calculate delays.
72239Sbill 	 * The numbers here represent clock ticks
72339Sbill 	 * and are not necessarily optimal for all terminals.
72439Sbill 	 * The delays are indicated by characters above 0200.
72539Sbill 	 * In raw mode there are no delays and the
72639Sbill 	 * transmission path is 8 bits wide.
72739Sbill 	 */
72839Sbill 	colp = &tp->t_col;
72939Sbill 	ctype = partab[c];
73039Sbill 	c = 0;
73139Sbill 	switch (ctype&077) {
73239Sbill 
73339Sbill 	/* ordinary */
73439Sbill 	case 0:
73539Sbill 		(*colp)++;
73639Sbill 
73739Sbill 	/* non-printing */
73839Sbill 	case 1:
73939Sbill 		break;
74039Sbill 
74139Sbill 	/* backspace */
74239Sbill 	case 2:
74339Sbill 		if (*colp)
74439Sbill 			(*colp)--;
74539Sbill 		break;
74639Sbill 
74739Sbill 	/* newline */
74839Sbill 	case 3:
74939Sbill 		ctype = (tp->t_flags >> 8) & 03;
75039Sbill 		if(ctype == 1) { /* tty 37 */
75139Sbill 			if (*colp)
75239Sbill 				c = max(((unsigned)*colp>>4) + 3, (unsigned)6);
75339Sbill 		} else
75439Sbill 		if(ctype == 2) { /* vt05 */
75539Sbill 			c = 6;
75639Sbill 		}
75739Sbill 		*colp = 0;
75839Sbill 		break;
75939Sbill 
76039Sbill 	/* tab */
76139Sbill 	case 4:
76239Sbill 		ctype = (tp->t_flags >> 10) & 03;
76339Sbill 		if(ctype == 1) { /* tty 37 */
76439Sbill 			c = 1 - (*colp | ~07);
76539Sbill 			if(c < 5)
76639Sbill 				c = 0;
76739Sbill 		}
76839Sbill 		*colp |= 07;
76939Sbill 		(*colp)++;
77039Sbill 		break;
77139Sbill 
77239Sbill 	/* vertical motion */
77339Sbill 	case 5:
77439Sbill 		if(tp->t_flags & VTDELAY) /* tty 37 */
77539Sbill 			c = 0177;
77639Sbill 		break;
77739Sbill 
77839Sbill 	/* carriage return */
77939Sbill 	case 6:
78039Sbill 		ctype = (tp->t_flags >> 12) & 03;
78139Sbill 		if(ctype == 1) { /* tn 300 */
78239Sbill 			c = 5;
78339Sbill 		} else if(ctype == 2) { /* ti 700 */
78439Sbill 			c = 10;
78539Sbill 		} else if(ctype == 3) { /* concept 100 */
78639Sbill 			int i;
78739Sbill 			for (i= *colp; i<9; i++)
788121Sbill 				(void) putc(0177, &tp->t_outq);
78939Sbill 		}
79039Sbill 		*colp = 0;
79139Sbill 	}
79239Sbill 	if(c)
793121Sbill 		(void) putc(c|0200, &tp->t_outq);
79439Sbill }
79539Sbill 
79639Sbill /*
79739Sbill  * Restart typewriter output following a delay
79839Sbill  * timeout.
79939Sbill  * The name of the routine is passed to the timeout
80039Sbill  * subroutine and it is called during a clock interrupt.
80139Sbill  */
80239Sbill ttrstrt(tp)
80339Sbill register struct tty *tp;
80439Sbill {
80539Sbill 
80639Sbill 	tp->t_state &= ~TIMEOUT;
80739Sbill 	ttstart(tp);
80839Sbill }
80939Sbill 
81039Sbill /*
81139Sbill  * Start output on the typewriter. It is used from the top half
81239Sbill  * after some characters have been put on the output queue,
81339Sbill  * from the interrupt routine to transmit the next
81439Sbill  * character, and after a timeout has finished.
81539Sbill  */
81639Sbill ttstart(tp)
81739Sbill register struct tty *tp;
81839Sbill {
81939Sbill 	register s;
82039Sbill 
82139Sbill 	s = spl5();
82239Sbill 	if((tp->t_state&(TIMEOUT|TTSTOP|BUSY)) == 0)
82339Sbill 		(*tp->t_oproc)(tp);
82439Sbill 	splx(s);
82539Sbill }
82639Sbill 
82739Sbill /*
82839Sbill  * Called from device's read routine after it has
82939Sbill  * calculated the tty-structure given as argument.
83039Sbill  */
83139Sbill ttread(tp)
83239Sbill register struct tty *tp;
83339Sbill {
83439Sbill register s;
83539Sbill 
83639Sbill 	if ((tp->t_state&CARR_ON)==0)
83739Sbill 		return(-1);
83839Sbill 	s = spl5();
83939Sbill 	if (tp->t_canq.c_cc==0)
84039Sbill 		while (canon(tp)<0)
84139Sbill 			if (tp->t_chan==NULL) {
84239Sbill 				sleep((caddr_t)&tp->t_rawq, TTIPRI);
84339Sbill 			} else {
84439Sbill 				splx(s);
84539Sbill 				return(0);
84639Sbill 			}
84739Sbill 	splx(s);
84839Sbill 	while (tp->t_canq.c_cc && passc(getc(&tp->t_canq))>=0)
84939Sbill 			;
85039Sbill 	return(tp->t_rawq.c_cc+tp->t_canq.c_cc);
85139Sbill }
85239Sbill 
85339Sbill /*
85439Sbill  * Called from the device's write routine after it has
85539Sbill  * calculated the tty-structure given as argument.
85639Sbill  */
85739Sbill caddr_t
85839Sbill ttwrite(tp)
85939Sbill register struct tty *tp;
86039Sbill {
86139Sbill 	/*
86239Sbill 	 * THE POSITIONING OF CP, CC, AND CE ARE CRITICAL
86339Sbill 	 * AND MUST NOT BE CHANGED WITHOUT PATCHING
86439Sbill 	 * THE 'ASM' INLINES BELOW.  WATCH OUT.
86539Sbill 	 */
86639Sbill 	register char *cp;
86739Sbill 	register int cc, ce;
86839Sbill 	register i;
86939Sbill 	char obuf[OBUFSIZ];
87039Sbill 
87139Sbill 	if ((tp->t_state&CARR_ON)==0)
87239Sbill 		return(NULL);
87339Sbill 	while (u.u_count) {
87439Sbill 		cc = MIN(u.u_count, OBUFSIZ);
87539Sbill 		cp = obuf;
87639Sbill 		iomove(cp, (unsigned)cc, B_WRITE);
87739Sbill 		if (u.u_error)
87839Sbill 			break;
879121Sbill 		(void) spl5();
88039Sbill 		while (tp->t_outq.c_cc > TTHIWAT) {
88139Sbill 			ttstart(tp);
88239Sbill 			tp->t_state |= ASLEEP;
88339Sbill 			if (tp->t_chan) {
88439Sbill 				u.u_base -= cc;
88539Sbill 				u.u_offset -= cc;
88639Sbill 				u.u_count += cc;
887121Sbill 				(void) spl0();
88839Sbill 				return((caddr_t)&tp->t_outq);
88939Sbill 			}
89039Sbill 			sleep((caddr_t)&tp->t_outq, TTOPRI);
89139Sbill 		}
892121Sbill 		(void) spl0();
89339Sbill 		if (tp->t_flags&LCASE) {
89439Sbill 			while (cc--)
89539Sbill 				ttyoutput(*cp++,tp);
89639Sbill 			continue;
89739Sbill 		}
89839Sbill 		while (cc) {
89939Sbill 			if (tp->t_flags&RAW)
90039Sbill 				ce=cc;
90139Sbill 			else {
90239Sbill #ifdef VAX
90339Sbill 				asm("	scanc	r9,(r10),_partab,$077");
90439Sbill 				asm("	subl3	r0,r9,r8");
90539Sbill #else
90639Sbill 				ce=0;
90739Sbill 				while(((partab[*(cp+ce)]&077)==0)&&(ce<cc))
90839Sbill 					ce++;
90939Sbill #endif
91039Sbill 				if (ce==0) {
91139Sbill 					ttyoutput(*cp++,tp);
91239Sbill 					cc--;
913121Sbill 					goto check;
91439Sbill 				}
91539Sbill 			}
91639Sbill 			i=b_to_q(cp,ce,&tp->t_outq);
91739Sbill 			ce-=i;
91839Sbill 			tk_nout+=ce;
91939Sbill 			tp->t_col+=ce;
92039Sbill 			cp+=ce;
92139Sbill 			cc-=ce;
922121Sbill check:
923121Sbill 			if (tp->t_outq.c_cc > TTHIWAT) {
924121Sbill 				(void) spl5();
92539Sbill 				while (tp->t_outq.c_cc > TTHIWAT) {
92639Sbill 					ttstart(tp);
92739Sbill 					tp->t_state |= ASLEEP;
92839Sbill 					sleep((caddr_t)&tp->t_outq, TTOPRI);
92939Sbill 				}
930121Sbill 				(void) spl0();
93139Sbill 			}
93239Sbill 		}
93339Sbill 	}
93439Sbill 	ttstart(tp);
93539Sbill 	return(NULL);
93639Sbill }
937