xref: /csrg-svn/sys/kern/tty.c (revision 121)
1*121Sbill /*	tty.c	3.2	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 
2139Sbill 
2239Sbill /*
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 
4839Sbill 
4939Sbill /*
5039Sbill  * shorthand
5139Sbill  */
5239Sbill #define	q1	tp->t_rawq
5339Sbill #define	q2	tp->t_canq
5439Sbill #define	q3	tp->t_outq
5539Sbill #define	q4	tp->t_un.t_ctlq
5639Sbill 
5739Sbill #define	OBUFSIZ	100
5839Sbill 
5939Sbill /*
6039Sbill  * routine called on first teletype open.
6139Sbill  * establishes a process group for distribution
6239Sbill  * of quits and interrupts from the tty.
6339Sbill  */
6439Sbill ttyopen(dev, tp)
6539Sbill dev_t dev;
6639Sbill register struct tty *tp;
6739Sbill {
6839Sbill 	register struct proc *pp;
6939Sbill 
7039Sbill 	pp = u.u_procp;
7139Sbill 	tp->t_dev = dev;
7239Sbill 	if(pp->p_pgrp == 0) {
7339Sbill 		u.u_ttyp = tp;
7439Sbill 		u.u_ttyd = dev;
7539Sbill 		if (tp->t_pgrp==0)
7639Sbill 			tp->t_pgrp = pp->p_pid;
7739Sbill 		pp->p_pgrp = tp->t_pgrp;
7839Sbill 	}
7939Sbill 	tp->t_state &= ~WOPEN;
8039Sbill 	tp->t_state |= ISOPEN;
8139Sbill }
8239Sbill 
8339Sbill 
8439Sbill /*
8539Sbill  * set default control characters.
8639Sbill  */
8739Sbill ttychars(tp)
8839Sbill register struct tty *tp;
8939Sbill {
9039Sbill 	tun.t_intrc = CINTR;
9139Sbill 	tun.t_quitc = CQUIT;
9239Sbill 	tun.t_startc = CSTART;
9339Sbill 	tun.t_stopc = CSTOP;
9439Sbill 	tun.t_eofc = CEOT;
9539Sbill 	tun.t_brkc = CBRK;
9639Sbill 	tp->t_erase = CERASE;
9739Sbill 	tp->t_kill = CKILL;
9839Sbill }
9939Sbill 
10039Sbill /*
10139Sbill  * clean tp on last close
10239Sbill  */
10339Sbill ttyclose(tp)
10439Sbill register struct tty *tp;
10539Sbill {
10639Sbill 
10739Sbill 	tp->t_pgrp = 0;
10839Sbill 	wflushtty(tp);
10939Sbill 	tp->t_state = 0;
11039Sbill }
11139Sbill 
11239Sbill /*
11339Sbill  * stty/gtty writearound
11439Sbill  */
11539Sbill stty()
11639Sbill {
11739Sbill 	u.u_arg[2] = u.u_arg[1];
11839Sbill 	u.u_arg[1] = TIOCSETP;
11939Sbill 	ioctl();
12039Sbill }
12139Sbill 
12239Sbill gtty()
12339Sbill {
12439Sbill 	u.u_arg[2] = u.u_arg[1];
12539Sbill 	u.u_arg[1] = TIOCGETP;
12639Sbill 	ioctl();
12739Sbill }
12839Sbill 
12939Sbill /*
130*121Sbill  * Do nothing specific version of line
131*121Sbill  * discipline specific ioctl command.
132*121Sbill  */
133*121Sbill nullioctl(tp, cmd, addr)
134*121Sbill register struct tty *tp;
135*121Sbill caddr_t addr;
136*121Sbill {
137*121Sbill 
138*121Sbill 	return (cmd);
139*121Sbill }
140*121Sbill 
141*121Sbill /*
14239Sbill  * ioctl system call
14339Sbill  * Check legality, execute common code, and switch out to individual
14439Sbill  * device routine.
14539Sbill  */
14639Sbill ioctl()
14739Sbill {
14839Sbill 	register struct file *fp;
14939Sbill 	register struct inode *ip;
15039Sbill 	register struct a {
15139Sbill 		int	fdes;
15239Sbill 		int	cmd;
15339Sbill 		caddr_t	cmarg;
15439Sbill 	} *uap;
15539Sbill 	register dev_t dev;
15639Sbill 	register fmt;
15739Sbill 
15839Sbill 	uap = (struct a *)u.u_ap;
15939Sbill 	if ((fp = getf(uap->fdes)) == NULL)
16039Sbill 		return;
16139Sbill 	if (uap->cmd==FIOCLEX) {
16239Sbill 		u.u_pofile[uap->fdes] |= EXCLOSE;
16339Sbill 		return;
16439Sbill 	}
16539Sbill 	if (uap->cmd==FIONCLEX) {
16639Sbill 		u.u_pofile[uap->fdes] &= ~EXCLOSE;
16739Sbill 		return;
16839Sbill 	}
16939Sbill 	ip = fp->f_inode;
17039Sbill 	fmt = ip->i_mode & IFMT;
17139Sbill 	if (fmt != IFCHR && fmt != IFMPC) {
17239Sbill 		u.u_error = ENOTTY;
17339Sbill 		return;
17439Sbill 	}
17539Sbill 	dev = ip->i_un.i_rdev;
17639Sbill 	u.u_r.r_val1 = 0;
17739Sbill 	(*cdevsw[major(dev)].d_ioctl)(dev, uap->cmd, uap->cmarg, fp->f_flag);
17839Sbill }
17939Sbill 
18039Sbill /*
18139Sbill  * Common code for several tty ioctl commands
18239Sbill  */
18339Sbill ttioccomm(com, tp, addr, dev)
18439Sbill register struct tty *tp;
18539Sbill caddr_t addr;
18639Sbill {
18739Sbill 	unsigned t;
18839Sbill 	struct ttiocb iocb;
18939Sbill 	extern int nldisp;
190*121Sbill 	register s;
19139Sbill 
19239Sbill 	switch(com) {
19339Sbill 
19439Sbill 	/*
19539Sbill 	 * get discipline number
19639Sbill 	 */
19739Sbill 	case TIOCGETD:
19839Sbill 		t = tp->t_line;
19939Sbill 		if (copyout((caddr_t)&t, addr, sizeof(t)))
20039Sbill 			u.u_error = EFAULT;
20139Sbill 		break;
20239Sbill 
20339Sbill 	/*
20439Sbill 	 * set line discipline
20539Sbill 	 */
20639Sbill 	case TIOCSETD:
20739Sbill 		if (copyin(addr, (caddr_t)&t, sizeof(t))) {
20839Sbill 			u.u_error = EFAULT;
20939Sbill 			break;
21039Sbill 		}
21139Sbill 		if (t >= nldisp) {
21239Sbill 			u.u_error = ENXIO;
21339Sbill 			break;
21439Sbill 		}
215*121Sbill 		s = spl5();
21639Sbill 		if (tp->t_line)
21739Sbill 			(*linesw[tp->t_line].l_close)(tp);
21839Sbill 		if (t)
21939Sbill 			(*linesw[t].l_open)(dev, tp, addr);
22039Sbill 		if (u.u_error==0)
22139Sbill 			tp->t_line = t;
222*121Sbill 		splx(s);
22339Sbill 		break;
22439Sbill 
22539Sbill 	/*
22639Sbill 	 * prevent more opens on channel
22739Sbill 	 */
22839Sbill 	case TIOCEXCL:
22939Sbill 		tp->t_state |= XCLUDE;
23039Sbill 		break;
23139Sbill 
23239Sbill 	case TIOCNXCL:
23339Sbill 		tp->t_state &= ~XCLUDE;
23439Sbill 		break;
23539Sbill 
23639Sbill 	/*
23739Sbill 	 * Set new parameters
23839Sbill 	 */
23939Sbill 	case TIOCSETP:
24039Sbill 		wflushtty(tp);
24139Sbill 	case TIOCSETN:
24239Sbill 		if (copyin(addr, (caddr_t)&iocb, sizeof(iocb))) {
24339Sbill 			u.u_error = EFAULT;
24439Sbill 			return(1);
24539Sbill 		}
246*121Sbill 		(void) spl5();
24739Sbill 		while (canon(tp)>=0)
24839Sbill 			;
24939Sbill 		if ((tp->t_state&SPEEDS)==0) {
25039Sbill 			tp->t_ispeed = iocb.ioc_ispeed;
25139Sbill 			tp->t_ospeed = iocb.ioc_ospeed;
25239Sbill 		}
25339Sbill 		tp->t_erase = iocb.ioc_erase;
25439Sbill 		tp->t_kill = iocb.ioc_kill;
25539Sbill 		tp->t_flags = iocb.ioc_flags;
256*121Sbill 		(void) spl0();
25739Sbill 		break;
25839Sbill 
25939Sbill 	/*
26039Sbill 	 * send current parameters to user
26139Sbill 	 */
26239Sbill 	case TIOCGETP:
26339Sbill 		iocb.ioc_ispeed = tp->t_ispeed;
26439Sbill 		iocb.ioc_ospeed = tp->t_ospeed;
26539Sbill 		iocb.ioc_erase = tp->t_erase;
26639Sbill 		iocb.ioc_kill = tp->t_kill;
26739Sbill 		iocb.ioc_flags = tp->t_flags;
26839Sbill 		if (copyout((caddr_t)&iocb, addr, sizeof(iocb)))
26939Sbill 			u.u_error = EFAULT;
27039Sbill 		break;
27139Sbill 
27239Sbill 	/*
27339Sbill 	 * Hang up line on last close
27439Sbill 	 */
27539Sbill 
27639Sbill 	case TIOCHPCL:
27739Sbill 		tp->t_state |= HUPCLS;
27839Sbill 		break;
27939Sbill 
28039Sbill 	case TIOCFLUSH:
28139Sbill 		flushtty(tp);
28239Sbill 		break;
28339Sbill 
28439Sbill 	/*
28539Sbill 	 * ioctl entries to line discipline
28639Sbill 	 */
28739Sbill 	case DIOCSETP:
28839Sbill 	case DIOCGETP:
289*121Sbill 		if ((*linesw[tp->t_line].l_ioctl)(com, tp, addr))
290*121Sbill 			u.u_error = ENOTTY;
29139Sbill 		break;
29239Sbill 
29339Sbill 	/*
29439Sbill 	 * set and fetch special characters
29539Sbill 	 */
29639Sbill 	case TIOCSETC:
29739Sbill 		if (copyin(addr, (caddr_t)&tun, sizeof(struct tc)))
29839Sbill 			u.u_error = EFAULT;
29939Sbill 		break;
30039Sbill 
30139Sbill 	case TIOCGETC:
30239Sbill 		if (copyout((caddr_t)&tun, addr, sizeof(struct tc)))
30339Sbill 			u.u_error = EFAULT;
30439Sbill 		break;
30539Sbill 
30639Sbill 	default:
30739Sbill 		return(0);
30839Sbill 	}
30939Sbill 	return(1);
31039Sbill }
31139Sbill 
31239Sbill /*
31339Sbill  * Wait for output to drain, then flush input waiting.
31439Sbill  */
31539Sbill wflushtty(tp)
31639Sbill register struct tty *tp;
31739Sbill {
31839Sbill 
319*121Sbill 	(void) spl5();
32039Sbill 	while (tp->t_outq.c_cc && tp->t_state&CARR_ON) {
32139Sbill 		(*tp->t_oproc)(tp);
32239Sbill 		tp->t_state |= ASLEEP;
32339Sbill 		sleep((caddr_t)&tp->t_outq, TTOPRI);
32439Sbill 	}
32539Sbill 	flushtty(tp);
326*121Sbill 	(void) spl0();
32739Sbill }
32839Sbill 
32939Sbill /*
33039Sbill  * flush all TTY queues
33139Sbill  */
33239Sbill flushtty(tp)
33339Sbill register struct tty *tp;
33439Sbill {
33539Sbill 	register s;
33639Sbill 
337*121Sbill 	s = spl6();
33839Sbill 	while (getc(&tp->t_canq) >= 0)
33939Sbill 		;
34039Sbill 	wakeup((caddr_t)&tp->t_rawq);
34139Sbill 	wakeup((caddr_t)&tp->t_outq);
34239Sbill 	tp->t_state &= ~TTSTOP;
34339Sbill 	(*cdevsw[major(tp->t_dev)].d_stop)(tp);
34439Sbill 	while (getc(&tp->t_outq) >= 0)
34539Sbill 		;
34639Sbill 	while (getc(&tp->t_rawq) >= 0)
34739Sbill 		;
34839Sbill 	tp->t_delct = 0;
34939Sbill 	splx(s);
35039Sbill }
35139Sbill 
35239Sbill 
35339Sbill 
35439Sbill /*
35539Sbill  * transfer raw input list to canonical list,
35639Sbill  * doing erase-kill processing and handling escapes.
35739Sbill  * It waits until a full line has been typed in cooked mode,
35839Sbill  * or until any character has been typed in raw mode.
35939Sbill  */
36039Sbill canon(tp)
36139Sbill register struct tty *tp;
36239Sbill {
36339Sbill 	register char *bp;
36439Sbill 	char *bp1;
36539Sbill 	register int c;
36639Sbill 	int mc;
36739Sbill 	int s;
36839Sbill 
36939Sbill 	if ((tp->t_flags&(RAW|CBREAK))==0 && tp->t_delct==0
37039Sbill 	    || (tp->t_flags&(RAW|CBREAK))!=0 && tp->t_rawq.c_cc==0) {
37139Sbill 		return(-1);
37239Sbill 	}
37339Sbill 	s = spl0();
37439Sbill loop:
37539Sbill 	bp = &canonb[2];
37639Sbill 	while ((c=getc(&tp->t_rawq)) >= 0) {
37739Sbill 		if ((tp->t_flags&(RAW|CBREAK))==0) {
37839Sbill 			if (c==0377) {
37939Sbill 				tp->t_delct--;
38039Sbill 				break;
38139Sbill 			}
38239Sbill 			if (bp[-1]!='\\') {
38339Sbill 				if (c==tp->t_erase) {
38439Sbill 					if (bp > &canonb[2])
38539Sbill 						bp--;
38639Sbill 					continue;
38739Sbill 				}
38839Sbill 				if (c==tp->t_kill)
38939Sbill 					goto loop;
39039Sbill 				if (c==tun.t_eofc)
39139Sbill 					continue;
39239Sbill 			} else {
39339Sbill 				mc = maptab[c];
39439Sbill 				if (c==tp->t_erase || c==tp->t_kill)
39539Sbill 					mc = c;
39639Sbill 				if (mc && (mc==c || (tp->t_flags&LCASE))) {
39739Sbill 					if (bp[-2] != '\\')
39839Sbill 						c = mc;
39939Sbill 					bp--;
40039Sbill 				}
40139Sbill 			}
40239Sbill 		}
40339Sbill 		*bp++ = c;
40439Sbill 		if (bp>=canonb+CANBSIZ)
40539Sbill 			break;
40639Sbill 	}
40739Sbill 	bp1 = &canonb[2];
408*121Sbill 	(void) b_to_q(bp1, bp-bp1, &tp->t_canq);
40939Sbill 
41039Sbill 	if (tp->t_state&TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) {
41139Sbill 		if (putc(tun.t_startc, &tp->t_outq)==0) {
41239Sbill 			tp->t_state &= ~TBLOCK;
41339Sbill 			ttstart(tp);
41439Sbill 		}
41539Sbill 		tp->t_char = 0;
41639Sbill 	}
41739Sbill 
41839Sbill 	splx(s);
41939Sbill 	return(0);
42039Sbill }
42139Sbill 
42239Sbill 
42339Sbill /*
42439Sbill  * block transfer input handler.
42539Sbill  */
42639Sbill ttyrend(tp, pb, pe)
42739Sbill register struct tty *tp;
42839Sbill register char *pb, *pe;
42939Sbill {
43039Sbill 	int	tandem;
43139Sbill 
43239Sbill 	tandem = tp->t_flags&TANDEM;
43339Sbill 	if (tp->t_flags&RAW) {
434*121Sbill 		(void) b_to_q(pb, pe-pb, &tp->t_rawq);
43539Sbill 		if (tp->t_chan)
436*121Sbill 			(void) sdata(tp->t_chan); else
43739Sbill 			wakeup((caddr_t)&tp->t_rawq);
43839Sbill 	} else {
43939Sbill 		tp->t_flags &= ~TANDEM;
44039Sbill 		while (pb < pe)
44139Sbill 			ttyinput(*pb++, tp);
44239Sbill 		tp->t_flags |= tandem;
44339Sbill 	}
44439Sbill 	if (tandem)
44539Sbill 		ttyblock(tp);
44639Sbill }
44739Sbill 
44839Sbill /*
44939Sbill  * Place a character on raw TTY input queue, putting in delimiters
45039Sbill  * and waking up top half as needed.
45139Sbill  * Also echo if required.
45239Sbill  * The arguments are the character and the appropriate
45339Sbill  * tty structure.
45439Sbill  */
45539Sbill ttyinput(c, tp)
45639Sbill register c;
45739Sbill register struct tty *tp;
45839Sbill {
45939Sbill 	register int t_flags;
46039Sbill 	register struct chan *cp;
46139Sbill 
46239Sbill 	tk_nin += 1;
46339Sbill 	c &= 0377;
46439Sbill 	t_flags = tp->t_flags;
46539Sbill 	if (t_flags&TANDEM)
46639Sbill 		ttyblock(tp);
46739Sbill 	if ((t_flags&RAW)==0) {
46839Sbill 		c &= 0177;
46939Sbill 		if (tp->t_state&TTSTOP) {
47039Sbill 			if (c==tun.t_startc) {
47139Sbill 				tp->t_state &= ~TTSTOP;
47239Sbill 				ttstart(tp);
47339Sbill 				return;
47439Sbill 			}
47539Sbill 			if (c==tun.t_stopc)
47639Sbill 				return;
47739Sbill 			tp->t_state &= ~TTSTOP;
47839Sbill 			ttstart(tp);
47939Sbill 		} else {
48039Sbill 			if (c==tun.t_stopc) {
48139Sbill 				tp->t_state |= TTSTOP;
48239Sbill 				(*cdevsw[major(tp->t_dev)].d_stop)(tp);
48339Sbill 				return;
48439Sbill 			}
48539Sbill 			if (c==tun.t_startc)
48639Sbill 				return;
48739Sbill 		}
48839Sbill 		if (c==tun.t_quitc || c==tun.t_intrc) {
48939Sbill 			flushtty(tp);
49039Sbill 			c = (c==tun.t_intrc) ? SIGINT:SIGQUIT;
49139Sbill 			if (tp->t_chan)
49239Sbill 				scontrol(tp->t_chan, M_SIG, c);
49339Sbill 			else
49439Sbill 				signal(tp->t_pgrp, c);
49539Sbill 			return;
49639Sbill 		}
49739Sbill 		if (c=='\r' && t_flags&CRMOD)
49839Sbill 			c = '\n';
49939Sbill 	}
50039Sbill 	if (tp->t_rawq.c_cc>TTYHOG) {
50139Sbill 		flushtty(tp);
50239Sbill 		return;
50339Sbill 	}
50439Sbill 	if (t_flags&LCASE && c>='A' && c<='Z')
50539Sbill 		c += 'a'-'A';
506*121Sbill 	(void) putc(c, &tp->t_rawq);
50739Sbill 	if (t_flags&(RAW|CBREAK)||(c=='\n'||c==tun.t_eofc||c==tun.t_brkc)) {
50839Sbill 		if ((t_flags&(RAW|CBREAK))==0 && putc(0377, &tp->t_rawq)==0)
50939Sbill 			tp->t_delct++;
51039Sbill 		if ((cp=tp->t_chan)!=NULL)
511*121Sbill 			(void) sdata(cp); else
51239Sbill 			wakeup((caddr_t)&tp->t_rawq);
51339Sbill 	}
51439Sbill 	if (t_flags&ECHO) {
51539Sbill 		ttyoutput(c, tp);
51639Sbill 		if (c==tp->t_kill && (t_flags&(RAW|CBREAK))==0)
51739Sbill 			ttyoutput('\n', tp);
51839Sbill 		ttstart(tp);
51939Sbill 	}
52039Sbill }
52139Sbill 
52239Sbill 
52339Sbill /*
52439Sbill  * Send stop character on input overflow.
52539Sbill  */
52639Sbill ttyblock(tp)
52739Sbill register struct tty *tp;
52839Sbill {
52939Sbill 	register x;
53039Sbill 	x = q1.c_cc + q2.c_cc;
53139Sbill 	if (q1.c_cc > TTYHOG) {
53239Sbill 		flushtty(tp);
53339Sbill 		tp->t_state &= ~TBLOCK;
53439Sbill 	}
53539Sbill 	if (x >= TTYHOG/2) {
53639Sbill 		if (putc(tun.t_stopc, &tp->t_outq)==0) {
53739Sbill 			tp->t_state |= TBLOCK;
53839Sbill 			tp->t_char++;
53939Sbill 			ttstart(tp);
54039Sbill 		}
54139Sbill 	}
54239Sbill }
54339Sbill 
54439Sbill /*
54539Sbill  * put character on TTY output queue, adding delays,
54639Sbill  * expanding tabs, and handling the CR/NL bit.
54739Sbill  * It is called both from the top half for output, and from
54839Sbill  * interrupt level for echoing.
54939Sbill  * The arguments are the character and the tty structure.
55039Sbill  */
55139Sbill ttyoutput(c, tp)
55239Sbill register c;
55339Sbill register struct tty *tp;
55439Sbill {
55539Sbill 	register char *colp;
55639Sbill 	register ctype;
55739Sbill 
55839Sbill 	/*
55939Sbill 	 * Ignore EOT in normal mode to avoid hanging up
56039Sbill 	 * certain terminals.
56139Sbill 	 * In raw mode dump the char unchanged.
56239Sbill 	 */
56339Sbill 	if ((tp->t_flags&RAW)==0) {
56439Sbill 		c &= 0177;
56539Sbill 		if ((tp->t_flags&CBREAK)==0 && c==CEOT)
56639Sbill 			return;
56739Sbill 	} else {
568*121Sbill 		tk_nout++;
569*121Sbill 		(void) putc(c, &tp->t_outq);
57039Sbill 		return;
57139Sbill 	}
57239Sbill 
57339Sbill 	/*
57439Sbill 	 * Turn tabs to spaces as required
57539Sbill 	 */
57639Sbill 	if (c=='\t' && (tp->t_flags&TBDELAY)==XTABS) {
577*121Sbill 		c = 8 - (tp->t_col & 7);
578*121Sbill 		(void) b_to_q("        ", c, &tp->t_outq);
579*121Sbill 		tp->t_col += c;
580*121Sbill 		tk_nout += c;
58139Sbill 		return;
58239Sbill 	}
583*121Sbill 	tk_nout++;
58439Sbill 	/*
58539Sbill 	 * for upper-case-only terminals,
58639Sbill 	 * generate escapes.
58739Sbill 	 */
58839Sbill 	if (tp->t_flags&LCASE) {
58939Sbill 		colp = "({)}!|^~'`";
59039Sbill 		while(*colp++)
59139Sbill 			if(c == *colp++) {
59239Sbill 				ttyoutput('\\', tp);
59339Sbill 				c = colp[-2];
59439Sbill 				break;
59539Sbill 			}
59639Sbill 		if ('a'<=c && c<='z')
59739Sbill 			c += 'A' - 'a';
59839Sbill 	}
59939Sbill 	/*
60039Sbill 	 * turn <nl> to <cr><lf> if desired.
60139Sbill 	 */
60239Sbill 	if (c=='\n' && tp->t_flags&CRMOD)
60339Sbill 		ttyoutput('\r', tp);
604*121Sbill 	(void) putc(c, &tp->t_outq);
60539Sbill 	/*
60639Sbill 	 * Calculate delays.
60739Sbill 	 * The numbers here represent clock ticks
60839Sbill 	 * and are not necessarily optimal for all terminals.
60939Sbill 	 * The delays are indicated by characters above 0200.
61039Sbill 	 * In raw mode there are no delays and the
61139Sbill 	 * transmission path is 8 bits wide.
61239Sbill 	 */
61339Sbill 	colp = &tp->t_col;
61439Sbill 	ctype = partab[c];
61539Sbill 	c = 0;
61639Sbill 	switch (ctype&077) {
61739Sbill 
61839Sbill 	/* ordinary */
61939Sbill 	case 0:
62039Sbill 		(*colp)++;
62139Sbill 
62239Sbill 	/* non-printing */
62339Sbill 	case 1:
62439Sbill 		break;
62539Sbill 
62639Sbill 	/* backspace */
62739Sbill 	case 2:
62839Sbill 		if (*colp)
62939Sbill 			(*colp)--;
63039Sbill 		break;
63139Sbill 
63239Sbill 	/* newline */
63339Sbill 	case 3:
63439Sbill 		ctype = (tp->t_flags >> 8) & 03;
63539Sbill 		if(ctype == 1) { /* tty 37 */
63639Sbill 			if (*colp)
63739Sbill 				c = max(((unsigned)*colp>>4) + 3, (unsigned)6);
63839Sbill 		} else
63939Sbill 		if(ctype == 2) { /* vt05 */
64039Sbill 			c = 6;
64139Sbill 		}
64239Sbill 		*colp = 0;
64339Sbill 		break;
64439Sbill 
64539Sbill 	/* tab */
64639Sbill 	case 4:
64739Sbill 		ctype = (tp->t_flags >> 10) & 03;
64839Sbill 		if(ctype == 1) { /* tty 37 */
64939Sbill 			c = 1 - (*colp | ~07);
65039Sbill 			if(c < 5)
65139Sbill 				c = 0;
65239Sbill 		}
65339Sbill 		*colp |= 07;
65439Sbill 		(*colp)++;
65539Sbill 		break;
65639Sbill 
65739Sbill 	/* vertical motion */
65839Sbill 	case 5:
65939Sbill 		if(tp->t_flags & VTDELAY) /* tty 37 */
66039Sbill 			c = 0177;
66139Sbill 		break;
66239Sbill 
66339Sbill 	/* carriage return */
66439Sbill 	case 6:
66539Sbill 		ctype = (tp->t_flags >> 12) & 03;
66639Sbill 		if(ctype == 1) { /* tn 300 */
66739Sbill 			c = 5;
66839Sbill 		} else if(ctype == 2) { /* ti 700 */
66939Sbill 			c = 10;
67039Sbill 		} else if(ctype == 3) { /* concept 100 */
67139Sbill 			int i;
67239Sbill 			for (i= *colp; i<9; i++)
673*121Sbill 				(void) putc(0177, &tp->t_outq);
67439Sbill 		}
67539Sbill 		*colp = 0;
67639Sbill 	}
67739Sbill 	if(c)
678*121Sbill 		(void) putc(c|0200, &tp->t_outq);
67939Sbill }
68039Sbill 
68139Sbill /*
68239Sbill  * Restart typewriter output following a delay
68339Sbill  * timeout.
68439Sbill  * The name of the routine is passed to the timeout
68539Sbill  * subroutine and it is called during a clock interrupt.
68639Sbill  */
68739Sbill ttrstrt(tp)
68839Sbill register struct tty *tp;
68939Sbill {
69039Sbill 
69139Sbill 	tp->t_state &= ~TIMEOUT;
69239Sbill 	ttstart(tp);
69339Sbill }
69439Sbill 
69539Sbill /*
69639Sbill  * Start output on the typewriter. It is used from the top half
69739Sbill  * after some characters have been put on the output queue,
69839Sbill  * from the interrupt routine to transmit the next
69939Sbill  * character, and after a timeout has finished.
70039Sbill  */
70139Sbill ttstart(tp)
70239Sbill register struct tty *tp;
70339Sbill {
70439Sbill 	register s;
70539Sbill 
70639Sbill 	s = spl5();
70739Sbill 	if((tp->t_state&(TIMEOUT|TTSTOP|BUSY)) == 0)
70839Sbill 		(*tp->t_oproc)(tp);
70939Sbill 	splx(s);
71039Sbill }
71139Sbill 
71239Sbill /*
71339Sbill  * Called from device's read routine after it has
71439Sbill  * calculated the tty-structure given as argument.
71539Sbill  */
71639Sbill ttread(tp)
71739Sbill register struct tty *tp;
71839Sbill {
71939Sbill register s;
72039Sbill 
72139Sbill 	if ((tp->t_state&CARR_ON)==0)
72239Sbill 		return(-1);
72339Sbill 	s = spl5();
72439Sbill 	if (tp->t_canq.c_cc==0)
72539Sbill 		while (canon(tp)<0)
72639Sbill 			if (tp->t_chan==NULL) {
72739Sbill 				sleep((caddr_t)&tp->t_rawq, TTIPRI);
72839Sbill 			} else {
72939Sbill 				splx(s);
73039Sbill 				return(0);
73139Sbill 			}
73239Sbill 	splx(s);
73339Sbill 	while (tp->t_canq.c_cc && passc(getc(&tp->t_canq))>=0)
73439Sbill 			;
73539Sbill 	return(tp->t_rawq.c_cc+tp->t_canq.c_cc);
73639Sbill }
73739Sbill 
73839Sbill /*
73939Sbill  * Called from the device's write routine after it has
74039Sbill  * calculated the tty-structure given as argument.
74139Sbill  */
74239Sbill caddr_t
74339Sbill ttwrite(tp)
74439Sbill register struct tty *tp;
74539Sbill {
74639Sbill 	/*
74739Sbill 	 * THE POSITIONING OF CP, CC, AND CE ARE CRITICAL
74839Sbill 	 * AND MUST NOT BE CHANGED WITHOUT PATCHING
74939Sbill 	 * THE 'ASM' INLINES BELOW.  WATCH OUT.
75039Sbill 	 */
75139Sbill 	register char *cp;
75239Sbill 	register int cc, ce;
75339Sbill 	register i;
75439Sbill 	char obuf[OBUFSIZ];
75539Sbill 
75639Sbill 	if ((tp->t_state&CARR_ON)==0)
75739Sbill 		return(NULL);
75839Sbill 	while (u.u_count) {
75939Sbill 		cc = MIN(u.u_count, OBUFSIZ);
76039Sbill 		cp = obuf;
76139Sbill 		iomove(cp, (unsigned)cc, B_WRITE);
76239Sbill 		if (u.u_error)
76339Sbill 			break;
764*121Sbill 		(void) spl5();
76539Sbill 		while (tp->t_outq.c_cc > TTHIWAT) {
76639Sbill 			ttstart(tp);
76739Sbill 			tp->t_state |= ASLEEP;
76839Sbill 			if (tp->t_chan) {
76939Sbill 				u.u_base -= cc;
77039Sbill 				u.u_offset -= cc;
77139Sbill 				u.u_count += cc;
772*121Sbill 				(void) spl0();
77339Sbill 				return((caddr_t)&tp->t_outq);
77439Sbill 			}
77539Sbill 			sleep((caddr_t)&tp->t_outq, TTOPRI);
77639Sbill 		}
777*121Sbill 		(void) spl0();
77839Sbill 		if (tp->t_flags&LCASE) {
77939Sbill 			while (cc--)
78039Sbill 				ttyoutput(*cp++,tp);
78139Sbill 			continue;
78239Sbill 		}
78339Sbill 		while (cc) {
78439Sbill 			if (tp->t_flags&RAW)
78539Sbill 				ce=cc;
78639Sbill 			else {
78739Sbill #ifdef VAX
78839Sbill 				asm("	scanc	r9,(r10),_partab,$077");
78939Sbill 				asm("	subl3	r0,r9,r8");
79039Sbill #else
79139Sbill 				ce=0;
79239Sbill 				while(((partab[*(cp+ce)]&077)==0)&&(ce<cc))
79339Sbill 					ce++;
79439Sbill #endif
79539Sbill 				if (ce==0) {
79639Sbill 					ttyoutput(*cp++,tp);
79739Sbill 					cc--;
798*121Sbill 					goto check;
79939Sbill 				}
80039Sbill 			}
80139Sbill 			i=b_to_q(cp,ce,&tp->t_outq);
80239Sbill 			ce-=i;
80339Sbill 			tk_nout+=ce;
80439Sbill 			tp->t_col+=ce;
80539Sbill 			cp+=ce;
80639Sbill 			cc-=ce;
807*121Sbill 			if (i == 0)
808*121Sbill 				continue;
809*121Sbill check:
810*121Sbill 			if (tp->t_outq.c_cc > TTHIWAT) {
811*121Sbill 				(void) spl5();
81239Sbill 				while (tp->t_outq.c_cc > TTHIWAT) {
81339Sbill 					ttstart(tp);
81439Sbill 					tp->t_state |= ASLEEP;
81539Sbill 					sleep((caddr_t)&tp->t_outq, TTOPRI);
81639Sbill 				}
817*121Sbill 				(void) spl0();
81839Sbill 			}
81939Sbill 		}
82039Sbill 	}
82139Sbill 	ttstart(tp);
82239Sbill 	return(NULL);
82339Sbill }
824