xref: /csrg-svn/sys/kern/tty.c (revision 146)
1*146Sbill /*	tty.c	3.3	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 
21*146Sbill /*
22*146Sbill  * When running dz's using only SAE (silo alarm) on input
23*146Sbill  * it is necessary to call dzrint() at clock interrupt time.
24*146Sbill  * This is unsafe unless spl5()s in tty code are changed to
25*146Sbill  * spl6()s to block clock interrupts.  Note that the dh driver
26*146Sbill  * currently in use works the same way as the dz, even though
27*146Sbill  * we could try to more intelligently manage its silo.
28*146Sbill  * Thus don't take this out if you have no dz's unless you
29*146Sbill  * change clock.c and dhtimer().
30*146Sbill  */
31*146Sbill #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;
8639Sbill 		if (tp->t_pgrp==0)
8739Sbill 			tp->t_pgrp = pp->p_pid;
8839Sbill 		pp->p_pgrp = tp->t_pgrp;
8939Sbill 	}
9039Sbill 	tp->t_state &= ~WOPEN;
9139Sbill 	tp->t_state |= ISOPEN;
9239Sbill }
9339Sbill 
9439Sbill 
9539Sbill /*
9639Sbill  * set default control characters.
9739Sbill  */
9839Sbill ttychars(tp)
9939Sbill register struct tty *tp;
10039Sbill {
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;
10939Sbill }
11039Sbill 
11139Sbill /*
11239Sbill  * clean tp on last close
11339Sbill  */
11439Sbill ttyclose(tp)
11539Sbill register struct tty *tp;
11639Sbill {
11739Sbill 
11839Sbill 	tp->t_pgrp = 0;
11939Sbill 	wflushtty(tp);
12039Sbill 	tp->t_state = 0;
12139Sbill }
12239Sbill 
12339Sbill /*
12439Sbill  * stty/gtty writearound
12539Sbill  */
12639Sbill stty()
12739Sbill {
12839Sbill 	u.u_arg[2] = u.u_arg[1];
12939Sbill 	u.u_arg[1] = TIOCSETP;
13039Sbill 	ioctl();
13139Sbill }
13239Sbill 
13339Sbill gtty()
13439Sbill {
13539Sbill 	u.u_arg[2] = u.u_arg[1];
13639Sbill 	u.u_arg[1] = TIOCGETP;
13739Sbill 	ioctl();
13839Sbill }
13939Sbill 
14039Sbill /*
141121Sbill  * Do nothing specific version of line
142121Sbill  * discipline specific ioctl command.
143121Sbill  */
144121Sbill nullioctl(tp, cmd, addr)
145121Sbill register struct tty *tp;
146121Sbill caddr_t addr;
147121Sbill {
148121Sbill 
149121Sbill 	return (cmd);
150121Sbill }
151121Sbill 
152121Sbill /*
15339Sbill  * ioctl system call
15439Sbill  * Check legality, execute common code, and switch out to individual
15539Sbill  * device routine.
15639Sbill  */
15739Sbill ioctl()
15839Sbill {
15939Sbill 	register struct file *fp;
16039Sbill 	register struct inode *ip;
16139Sbill 	register struct a {
16239Sbill 		int	fdes;
16339Sbill 		int	cmd;
16439Sbill 		caddr_t	cmarg;
16539Sbill 	} *uap;
16639Sbill 	register dev_t dev;
16739Sbill 	register fmt;
16839Sbill 
16939Sbill 	uap = (struct a *)u.u_ap;
17039Sbill 	if ((fp = getf(uap->fdes)) == NULL)
17139Sbill 		return;
17239Sbill 	if (uap->cmd==FIOCLEX) {
17339Sbill 		u.u_pofile[uap->fdes] |= EXCLOSE;
17439Sbill 		return;
17539Sbill 	}
17639Sbill 	if (uap->cmd==FIONCLEX) {
17739Sbill 		u.u_pofile[uap->fdes] &= ~EXCLOSE;
17839Sbill 		return;
17939Sbill 	}
18039Sbill 	ip = fp->f_inode;
18139Sbill 	fmt = ip->i_mode & IFMT;
18239Sbill 	if (fmt != IFCHR && fmt != IFMPC) {
18339Sbill 		u.u_error = ENOTTY;
18439Sbill 		return;
18539Sbill 	}
18639Sbill 	dev = ip->i_un.i_rdev;
18739Sbill 	u.u_r.r_val1 = 0;
18839Sbill 	(*cdevsw[major(dev)].d_ioctl)(dev, uap->cmd, uap->cmarg, fp->f_flag);
18939Sbill }
19039Sbill 
19139Sbill /*
19239Sbill  * Common code for several tty ioctl commands
19339Sbill  */
19439Sbill ttioccomm(com, tp, addr, dev)
19539Sbill register struct tty *tp;
19639Sbill caddr_t addr;
19739Sbill {
19839Sbill 	unsigned t;
19939Sbill 	struct ttiocb iocb;
20039Sbill 	extern int nldisp;
201121Sbill 	register s;
20239Sbill 
20339Sbill 	switch(com) {
20439Sbill 
20539Sbill 	/*
20639Sbill 	 * get discipline number
20739Sbill 	 */
20839Sbill 	case TIOCGETD:
20939Sbill 		t = tp->t_line;
21039Sbill 		if (copyout((caddr_t)&t, addr, sizeof(t)))
21139Sbill 			u.u_error = EFAULT;
21239Sbill 		break;
21339Sbill 
21439Sbill 	/*
21539Sbill 	 * set line discipline
21639Sbill 	 */
21739Sbill 	case TIOCSETD:
21839Sbill 		if (copyin(addr, (caddr_t)&t, sizeof(t))) {
21939Sbill 			u.u_error = EFAULT;
22039Sbill 			break;
22139Sbill 		}
22239Sbill 		if (t >= nldisp) {
22339Sbill 			u.u_error = ENXIO;
22439Sbill 			break;
22539Sbill 		}
226121Sbill 		s = spl5();
22739Sbill 		if (tp->t_line)
22839Sbill 			(*linesw[tp->t_line].l_close)(tp);
22939Sbill 		if (t)
23039Sbill 			(*linesw[t].l_open)(dev, tp, addr);
23139Sbill 		if (u.u_error==0)
23239Sbill 			tp->t_line = t;
233121Sbill 		splx(s);
23439Sbill 		break;
23539Sbill 
23639Sbill 	/*
23739Sbill 	 * prevent more opens on channel
23839Sbill 	 */
23939Sbill 	case TIOCEXCL:
24039Sbill 		tp->t_state |= XCLUDE;
24139Sbill 		break;
24239Sbill 
24339Sbill 	case TIOCNXCL:
24439Sbill 		tp->t_state &= ~XCLUDE;
24539Sbill 		break;
24639Sbill 
24739Sbill 	/*
24839Sbill 	 * Set new parameters
24939Sbill 	 */
25039Sbill 	case TIOCSETP:
25139Sbill 		wflushtty(tp);
25239Sbill 	case TIOCSETN:
25339Sbill 		if (copyin(addr, (caddr_t)&iocb, sizeof(iocb))) {
25439Sbill 			u.u_error = EFAULT;
25539Sbill 			return(1);
25639Sbill 		}
257121Sbill 		(void) spl5();
25839Sbill 		while (canon(tp)>=0)
25939Sbill 			;
26039Sbill 		if ((tp->t_state&SPEEDS)==0) {
26139Sbill 			tp->t_ispeed = iocb.ioc_ispeed;
26239Sbill 			tp->t_ospeed = iocb.ioc_ospeed;
26339Sbill 		}
26439Sbill 		tp->t_erase = iocb.ioc_erase;
26539Sbill 		tp->t_kill = iocb.ioc_kill;
26639Sbill 		tp->t_flags = iocb.ioc_flags;
267121Sbill 		(void) spl0();
26839Sbill 		break;
26939Sbill 
27039Sbill 	/*
27139Sbill 	 * send current parameters to user
27239Sbill 	 */
27339Sbill 	case TIOCGETP:
27439Sbill 		iocb.ioc_ispeed = tp->t_ispeed;
27539Sbill 		iocb.ioc_ospeed = tp->t_ospeed;
27639Sbill 		iocb.ioc_erase = tp->t_erase;
27739Sbill 		iocb.ioc_kill = tp->t_kill;
27839Sbill 		iocb.ioc_flags = tp->t_flags;
27939Sbill 		if (copyout((caddr_t)&iocb, addr, sizeof(iocb)))
28039Sbill 			u.u_error = EFAULT;
28139Sbill 		break;
28239Sbill 
28339Sbill 	/*
28439Sbill 	 * Hang up line on last close
28539Sbill 	 */
28639Sbill 
28739Sbill 	case TIOCHPCL:
28839Sbill 		tp->t_state |= HUPCLS;
28939Sbill 		break;
29039Sbill 
29139Sbill 	case TIOCFLUSH:
29239Sbill 		flushtty(tp);
29339Sbill 		break;
29439Sbill 
29539Sbill 	/*
29639Sbill 	 * ioctl entries to line discipline
29739Sbill 	 */
29839Sbill 	case DIOCSETP:
29939Sbill 	case DIOCGETP:
300121Sbill 		if ((*linesw[tp->t_line].l_ioctl)(com, tp, addr))
301121Sbill 			u.u_error = ENOTTY;
30239Sbill 		break;
30339Sbill 
30439Sbill 	/*
30539Sbill 	 * set and fetch special characters
30639Sbill 	 */
30739Sbill 	case TIOCSETC:
30839Sbill 		if (copyin(addr, (caddr_t)&tun, sizeof(struct tc)))
30939Sbill 			u.u_error = EFAULT;
31039Sbill 		break;
31139Sbill 
31239Sbill 	case TIOCGETC:
31339Sbill 		if (copyout((caddr_t)&tun, addr, sizeof(struct tc)))
31439Sbill 			u.u_error = EFAULT;
31539Sbill 		break;
31639Sbill 
31739Sbill 	default:
31839Sbill 		return(0);
31939Sbill 	}
32039Sbill 	return(1);
32139Sbill }
32239Sbill 
32339Sbill /*
32439Sbill  * Wait for output to drain, then flush input waiting.
32539Sbill  */
32639Sbill wflushtty(tp)
32739Sbill register struct tty *tp;
32839Sbill {
32939Sbill 
330121Sbill 	(void) spl5();
33139Sbill 	while (tp->t_outq.c_cc && tp->t_state&CARR_ON) {
33239Sbill 		(*tp->t_oproc)(tp);
33339Sbill 		tp->t_state |= ASLEEP;
33439Sbill 		sleep((caddr_t)&tp->t_outq, TTOPRI);
33539Sbill 	}
33639Sbill 	flushtty(tp);
337121Sbill 	(void) spl0();
33839Sbill }
33939Sbill 
34039Sbill /*
34139Sbill  * flush all TTY queues
34239Sbill  */
34339Sbill flushtty(tp)
34439Sbill register struct tty *tp;
34539Sbill {
34639Sbill 	register s;
34739Sbill 
348121Sbill 	s = spl6();
34939Sbill 	while (getc(&tp->t_canq) >= 0)
35039Sbill 		;
35139Sbill 	wakeup((caddr_t)&tp->t_rawq);
35239Sbill 	wakeup((caddr_t)&tp->t_outq);
35339Sbill 	tp->t_state &= ~TTSTOP;
35439Sbill 	(*cdevsw[major(tp->t_dev)].d_stop)(tp);
35539Sbill 	while (getc(&tp->t_outq) >= 0)
35639Sbill 		;
35739Sbill 	while (getc(&tp->t_rawq) >= 0)
35839Sbill 		;
35939Sbill 	tp->t_delct = 0;
36039Sbill 	splx(s);
36139Sbill }
36239Sbill 
36339Sbill 
36439Sbill 
36539Sbill /*
36639Sbill  * transfer raw input list to canonical list,
36739Sbill  * doing erase-kill processing and handling escapes.
36839Sbill  * It waits until a full line has been typed in cooked mode,
36939Sbill  * or until any character has been typed in raw mode.
37039Sbill  */
37139Sbill canon(tp)
37239Sbill register struct tty *tp;
37339Sbill {
37439Sbill 	register char *bp;
37539Sbill 	char *bp1;
37639Sbill 	register int c;
37739Sbill 	int mc;
37839Sbill 	int s;
37939Sbill 
38039Sbill 	if ((tp->t_flags&(RAW|CBREAK))==0 && tp->t_delct==0
38139Sbill 	    || (tp->t_flags&(RAW|CBREAK))!=0 && tp->t_rawq.c_cc==0) {
38239Sbill 		return(-1);
38339Sbill 	}
38439Sbill 	s = spl0();
38539Sbill loop:
38639Sbill 	bp = &canonb[2];
38739Sbill 	while ((c=getc(&tp->t_rawq)) >= 0) {
38839Sbill 		if ((tp->t_flags&(RAW|CBREAK))==0) {
38939Sbill 			if (c==0377) {
39039Sbill 				tp->t_delct--;
39139Sbill 				break;
39239Sbill 			}
39339Sbill 			if (bp[-1]!='\\') {
39439Sbill 				if (c==tp->t_erase) {
39539Sbill 					if (bp > &canonb[2])
39639Sbill 						bp--;
39739Sbill 					continue;
39839Sbill 				}
39939Sbill 				if (c==tp->t_kill)
40039Sbill 					goto loop;
40139Sbill 				if (c==tun.t_eofc)
40239Sbill 					continue;
40339Sbill 			} else {
40439Sbill 				mc = maptab[c];
40539Sbill 				if (c==tp->t_erase || c==tp->t_kill)
40639Sbill 					mc = c;
40739Sbill 				if (mc && (mc==c || (tp->t_flags&LCASE))) {
40839Sbill 					if (bp[-2] != '\\')
40939Sbill 						c = mc;
41039Sbill 					bp--;
41139Sbill 				}
41239Sbill 			}
41339Sbill 		}
41439Sbill 		*bp++ = c;
41539Sbill 		if (bp>=canonb+CANBSIZ)
41639Sbill 			break;
41739Sbill 	}
41839Sbill 	bp1 = &canonb[2];
419121Sbill 	(void) b_to_q(bp1, bp-bp1, &tp->t_canq);
42039Sbill 
42139Sbill 	if (tp->t_state&TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) {
42239Sbill 		if (putc(tun.t_startc, &tp->t_outq)==0) {
42339Sbill 			tp->t_state &= ~TBLOCK;
42439Sbill 			ttstart(tp);
42539Sbill 		}
42639Sbill 		tp->t_char = 0;
42739Sbill 	}
42839Sbill 
42939Sbill 	splx(s);
43039Sbill 	return(0);
43139Sbill }
43239Sbill 
43339Sbill 
43439Sbill /*
43539Sbill  * block transfer input handler.
43639Sbill  */
43739Sbill ttyrend(tp, pb, pe)
43839Sbill register struct tty *tp;
43939Sbill register char *pb, *pe;
44039Sbill {
44139Sbill 	int	tandem;
44239Sbill 
44339Sbill 	tandem = tp->t_flags&TANDEM;
44439Sbill 	if (tp->t_flags&RAW) {
445121Sbill 		(void) b_to_q(pb, pe-pb, &tp->t_rawq);
44639Sbill 		if (tp->t_chan)
447121Sbill 			(void) sdata(tp->t_chan); else
44839Sbill 			wakeup((caddr_t)&tp->t_rawq);
44939Sbill 	} else {
45039Sbill 		tp->t_flags &= ~TANDEM;
45139Sbill 		while (pb < pe)
45239Sbill 			ttyinput(*pb++, tp);
45339Sbill 		tp->t_flags |= tandem;
45439Sbill 	}
45539Sbill 	if (tandem)
45639Sbill 		ttyblock(tp);
45739Sbill }
45839Sbill 
45939Sbill /*
46039Sbill  * Place a character on raw TTY input queue, putting in delimiters
46139Sbill  * and waking up top half as needed.
46239Sbill  * Also echo if required.
46339Sbill  * The arguments are the character and the appropriate
46439Sbill  * tty structure.
46539Sbill  */
46639Sbill ttyinput(c, tp)
46739Sbill register c;
46839Sbill register struct tty *tp;
46939Sbill {
47039Sbill 	register int t_flags;
47139Sbill 	register struct chan *cp;
47239Sbill 
47339Sbill 	tk_nin += 1;
47439Sbill 	c &= 0377;
47539Sbill 	t_flags = tp->t_flags;
47639Sbill 	if (t_flags&TANDEM)
47739Sbill 		ttyblock(tp);
47839Sbill 	if ((t_flags&RAW)==0) {
47939Sbill 		c &= 0177;
48039Sbill 		if (tp->t_state&TTSTOP) {
48139Sbill 			if (c==tun.t_startc) {
48239Sbill 				tp->t_state &= ~TTSTOP;
48339Sbill 				ttstart(tp);
48439Sbill 				return;
48539Sbill 			}
48639Sbill 			if (c==tun.t_stopc)
48739Sbill 				return;
48839Sbill 			tp->t_state &= ~TTSTOP;
48939Sbill 			ttstart(tp);
49039Sbill 		} else {
49139Sbill 			if (c==tun.t_stopc) {
49239Sbill 				tp->t_state |= TTSTOP;
49339Sbill 				(*cdevsw[major(tp->t_dev)].d_stop)(tp);
49439Sbill 				return;
49539Sbill 			}
49639Sbill 			if (c==tun.t_startc)
49739Sbill 				return;
49839Sbill 		}
49939Sbill 		if (c==tun.t_quitc || c==tun.t_intrc) {
50039Sbill 			flushtty(tp);
50139Sbill 			c = (c==tun.t_intrc) ? SIGINT:SIGQUIT;
50239Sbill 			if (tp->t_chan)
50339Sbill 				scontrol(tp->t_chan, M_SIG, c);
50439Sbill 			else
50539Sbill 				signal(tp->t_pgrp, c);
50639Sbill 			return;
50739Sbill 		}
50839Sbill 		if (c=='\r' && t_flags&CRMOD)
50939Sbill 			c = '\n';
51039Sbill 	}
51139Sbill 	if (tp->t_rawq.c_cc>TTYHOG) {
51239Sbill 		flushtty(tp);
51339Sbill 		return;
51439Sbill 	}
51539Sbill 	if (t_flags&LCASE && c>='A' && c<='Z')
51639Sbill 		c += 'a'-'A';
517121Sbill 	(void) putc(c, &tp->t_rawq);
51839Sbill 	if (t_flags&(RAW|CBREAK)||(c=='\n'||c==tun.t_eofc||c==tun.t_brkc)) {
51939Sbill 		if ((t_flags&(RAW|CBREAK))==0 && putc(0377, &tp->t_rawq)==0)
52039Sbill 			tp->t_delct++;
52139Sbill 		if ((cp=tp->t_chan)!=NULL)
522121Sbill 			(void) sdata(cp); else
52339Sbill 			wakeup((caddr_t)&tp->t_rawq);
52439Sbill 	}
52539Sbill 	if (t_flags&ECHO) {
52639Sbill 		ttyoutput(c, tp);
52739Sbill 		if (c==tp->t_kill && (t_flags&(RAW|CBREAK))==0)
52839Sbill 			ttyoutput('\n', tp);
52939Sbill 		ttstart(tp);
53039Sbill 	}
53139Sbill }
53239Sbill 
53339Sbill 
53439Sbill /*
53539Sbill  * Send stop character on input overflow.
53639Sbill  */
53739Sbill ttyblock(tp)
53839Sbill register struct tty *tp;
53939Sbill {
54039Sbill 	register x;
54139Sbill 	x = q1.c_cc + q2.c_cc;
54239Sbill 	if (q1.c_cc > TTYHOG) {
54339Sbill 		flushtty(tp);
54439Sbill 		tp->t_state &= ~TBLOCK;
54539Sbill 	}
54639Sbill 	if (x >= TTYHOG/2) {
54739Sbill 		if (putc(tun.t_stopc, &tp->t_outq)==0) {
54839Sbill 			tp->t_state |= TBLOCK;
54939Sbill 			tp->t_char++;
55039Sbill 			ttstart(tp);
55139Sbill 		}
55239Sbill 	}
55339Sbill }
55439Sbill 
55539Sbill /*
55639Sbill  * put character on TTY output queue, adding delays,
55739Sbill  * expanding tabs, and handling the CR/NL bit.
55839Sbill  * It is called both from the top half for output, and from
55939Sbill  * interrupt level for echoing.
56039Sbill  * The arguments are the character and the tty structure.
56139Sbill  */
56239Sbill ttyoutput(c, tp)
56339Sbill register c;
56439Sbill register struct tty *tp;
56539Sbill {
56639Sbill 	register char *colp;
56739Sbill 	register ctype;
56839Sbill 
56939Sbill 	/*
57039Sbill 	 * Ignore EOT in normal mode to avoid hanging up
57139Sbill 	 * certain terminals.
57239Sbill 	 * In raw mode dump the char unchanged.
57339Sbill 	 */
57439Sbill 	if ((tp->t_flags&RAW)==0) {
57539Sbill 		c &= 0177;
57639Sbill 		if ((tp->t_flags&CBREAK)==0 && c==CEOT)
57739Sbill 			return;
57839Sbill 	} else {
579121Sbill 		tk_nout++;
580121Sbill 		(void) putc(c, &tp->t_outq);
58139Sbill 		return;
58239Sbill 	}
58339Sbill 
58439Sbill 	/*
58539Sbill 	 * Turn tabs to spaces as required
58639Sbill 	 */
58739Sbill 	if (c=='\t' && (tp->t_flags&TBDELAY)==XTABS) {
588121Sbill 		c = 8 - (tp->t_col & 7);
589121Sbill 		(void) b_to_q("        ", c, &tp->t_outq);
590121Sbill 		tp->t_col += c;
591121Sbill 		tk_nout += c;
59239Sbill 		return;
59339Sbill 	}
594121Sbill 	tk_nout++;
59539Sbill 	/*
59639Sbill 	 * for upper-case-only terminals,
59739Sbill 	 * generate escapes.
59839Sbill 	 */
59939Sbill 	if (tp->t_flags&LCASE) {
60039Sbill 		colp = "({)}!|^~'`";
60139Sbill 		while(*colp++)
60239Sbill 			if(c == *colp++) {
60339Sbill 				ttyoutput('\\', tp);
60439Sbill 				c = colp[-2];
60539Sbill 				break;
60639Sbill 			}
60739Sbill 		if ('a'<=c && c<='z')
60839Sbill 			c += 'A' - 'a';
60939Sbill 	}
61039Sbill 	/*
61139Sbill 	 * turn <nl> to <cr><lf> if desired.
61239Sbill 	 */
61339Sbill 	if (c=='\n' && tp->t_flags&CRMOD)
61439Sbill 		ttyoutput('\r', tp);
615121Sbill 	(void) putc(c, &tp->t_outq);
61639Sbill 	/*
61739Sbill 	 * Calculate delays.
61839Sbill 	 * The numbers here represent clock ticks
61939Sbill 	 * and are not necessarily optimal for all terminals.
62039Sbill 	 * The delays are indicated by characters above 0200.
62139Sbill 	 * In raw mode there are no delays and the
62239Sbill 	 * transmission path is 8 bits wide.
62339Sbill 	 */
62439Sbill 	colp = &tp->t_col;
62539Sbill 	ctype = partab[c];
62639Sbill 	c = 0;
62739Sbill 	switch (ctype&077) {
62839Sbill 
62939Sbill 	/* ordinary */
63039Sbill 	case 0:
63139Sbill 		(*colp)++;
63239Sbill 
63339Sbill 	/* non-printing */
63439Sbill 	case 1:
63539Sbill 		break;
63639Sbill 
63739Sbill 	/* backspace */
63839Sbill 	case 2:
63939Sbill 		if (*colp)
64039Sbill 			(*colp)--;
64139Sbill 		break;
64239Sbill 
64339Sbill 	/* newline */
64439Sbill 	case 3:
64539Sbill 		ctype = (tp->t_flags >> 8) & 03;
64639Sbill 		if(ctype == 1) { /* tty 37 */
64739Sbill 			if (*colp)
64839Sbill 				c = max(((unsigned)*colp>>4) + 3, (unsigned)6);
64939Sbill 		} else
65039Sbill 		if(ctype == 2) { /* vt05 */
65139Sbill 			c = 6;
65239Sbill 		}
65339Sbill 		*colp = 0;
65439Sbill 		break;
65539Sbill 
65639Sbill 	/* tab */
65739Sbill 	case 4:
65839Sbill 		ctype = (tp->t_flags >> 10) & 03;
65939Sbill 		if(ctype == 1) { /* tty 37 */
66039Sbill 			c = 1 - (*colp | ~07);
66139Sbill 			if(c < 5)
66239Sbill 				c = 0;
66339Sbill 		}
66439Sbill 		*colp |= 07;
66539Sbill 		(*colp)++;
66639Sbill 		break;
66739Sbill 
66839Sbill 	/* vertical motion */
66939Sbill 	case 5:
67039Sbill 		if(tp->t_flags & VTDELAY) /* tty 37 */
67139Sbill 			c = 0177;
67239Sbill 		break;
67339Sbill 
67439Sbill 	/* carriage return */
67539Sbill 	case 6:
67639Sbill 		ctype = (tp->t_flags >> 12) & 03;
67739Sbill 		if(ctype == 1) { /* tn 300 */
67839Sbill 			c = 5;
67939Sbill 		} else if(ctype == 2) { /* ti 700 */
68039Sbill 			c = 10;
68139Sbill 		} else if(ctype == 3) { /* concept 100 */
68239Sbill 			int i;
68339Sbill 			for (i= *colp; i<9; i++)
684121Sbill 				(void) putc(0177, &tp->t_outq);
68539Sbill 		}
68639Sbill 		*colp = 0;
68739Sbill 	}
68839Sbill 	if(c)
689121Sbill 		(void) putc(c|0200, &tp->t_outq);
69039Sbill }
69139Sbill 
69239Sbill /*
69339Sbill  * Restart typewriter output following a delay
69439Sbill  * timeout.
69539Sbill  * The name of the routine is passed to the timeout
69639Sbill  * subroutine and it is called during a clock interrupt.
69739Sbill  */
69839Sbill ttrstrt(tp)
69939Sbill register struct tty *tp;
70039Sbill {
70139Sbill 
70239Sbill 	tp->t_state &= ~TIMEOUT;
70339Sbill 	ttstart(tp);
70439Sbill }
70539Sbill 
70639Sbill /*
70739Sbill  * Start output on the typewriter. It is used from the top half
70839Sbill  * after some characters have been put on the output queue,
70939Sbill  * from the interrupt routine to transmit the next
71039Sbill  * character, and after a timeout has finished.
71139Sbill  */
71239Sbill ttstart(tp)
71339Sbill register struct tty *tp;
71439Sbill {
71539Sbill 	register s;
71639Sbill 
71739Sbill 	s = spl5();
71839Sbill 	if((tp->t_state&(TIMEOUT|TTSTOP|BUSY)) == 0)
71939Sbill 		(*tp->t_oproc)(tp);
72039Sbill 	splx(s);
72139Sbill }
72239Sbill 
72339Sbill /*
72439Sbill  * Called from device's read routine after it has
72539Sbill  * calculated the tty-structure given as argument.
72639Sbill  */
72739Sbill ttread(tp)
72839Sbill register struct tty *tp;
72939Sbill {
73039Sbill register s;
73139Sbill 
73239Sbill 	if ((tp->t_state&CARR_ON)==0)
73339Sbill 		return(-1);
73439Sbill 	s = spl5();
73539Sbill 	if (tp->t_canq.c_cc==0)
73639Sbill 		while (canon(tp)<0)
73739Sbill 			if (tp->t_chan==NULL) {
73839Sbill 				sleep((caddr_t)&tp->t_rawq, TTIPRI);
73939Sbill 			} else {
74039Sbill 				splx(s);
74139Sbill 				return(0);
74239Sbill 			}
74339Sbill 	splx(s);
74439Sbill 	while (tp->t_canq.c_cc && passc(getc(&tp->t_canq))>=0)
74539Sbill 			;
74639Sbill 	return(tp->t_rawq.c_cc+tp->t_canq.c_cc);
74739Sbill }
74839Sbill 
74939Sbill /*
75039Sbill  * Called from the device's write routine after it has
75139Sbill  * calculated the tty-structure given as argument.
75239Sbill  */
75339Sbill caddr_t
75439Sbill ttwrite(tp)
75539Sbill register struct tty *tp;
75639Sbill {
75739Sbill 	/*
75839Sbill 	 * THE POSITIONING OF CP, CC, AND CE ARE CRITICAL
75939Sbill 	 * AND MUST NOT BE CHANGED WITHOUT PATCHING
76039Sbill 	 * THE 'ASM' INLINES BELOW.  WATCH OUT.
76139Sbill 	 */
76239Sbill 	register char *cp;
76339Sbill 	register int cc, ce;
76439Sbill 	register i;
76539Sbill 	char obuf[OBUFSIZ];
76639Sbill 
76739Sbill 	if ((tp->t_state&CARR_ON)==0)
76839Sbill 		return(NULL);
76939Sbill 	while (u.u_count) {
77039Sbill 		cc = MIN(u.u_count, OBUFSIZ);
77139Sbill 		cp = obuf;
77239Sbill 		iomove(cp, (unsigned)cc, B_WRITE);
77339Sbill 		if (u.u_error)
77439Sbill 			break;
775121Sbill 		(void) spl5();
77639Sbill 		while (tp->t_outq.c_cc > TTHIWAT) {
77739Sbill 			ttstart(tp);
77839Sbill 			tp->t_state |= ASLEEP;
77939Sbill 			if (tp->t_chan) {
78039Sbill 				u.u_base -= cc;
78139Sbill 				u.u_offset -= cc;
78239Sbill 				u.u_count += cc;
783121Sbill 				(void) spl0();
78439Sbill 				return((caddr_t)&tp->t_outq);
78539Sbill 			}
78639Sbill 			sleep((caddr_t)&tp->t_outq, TTOPRI);
78739Sbill 		}
788121Sbill 		(void) spl0();
78939Sbill 		if (tp->t_flags&LCASE) {
79039Sbill 			while (cc--)
79139Sbill 				ttyoutput(*cp++,tp);
79239Sbill 			continue;
79339Sbill 		}
79439Sbill 		while (cc) {
79539Sbill 			if (tp->t_flags&RAW)
79639Sbill 				ce=cc;
79739Sbill 			else {
79839Sbill #ifdef VAX
79939Sbill 				asm("	scanc	r9,(r10),_partab,$077");
80039Sbill 				asm("	subl3	r0,r9,r8");
80139Sbill #else
80239Sbill 				ce=0;
80339Sbill 				while(((partab[*(cp+ce)]&077)==0)&&(ce<cc))
80439Sbill 					ce++;
80539Sbill #endif
80639Sbill 				if (ce==0) {
80739Sbill 					ttyoutput(*cp++,tp);
80839Sbill 					cc--;
809121Sbill 					goto check;
81039Sbill 				}
81139Sbill 			}
81239Sbill 			i=b_to_q(cp,ce,&tp->t_outq);
81339Sbill 			ce-=i;
81439Sbill 			tk_nout+=ce;
81539Sbill 			tp->t_col+=ce;
81639Sbill 			cp+=ce;
81739Sbill 			cc-=ce;
818121Sbill 			if (i == 0)
819121Sbill 				continue;
820121Sbill check:
821121Sbill 			if (tp->t_outq.c_cc > TTHIWAT) {
822121Sbill 				(void) spl5();
82339Sbill 				while (tp->t_outq.c_cc > TTHIWAT) {
82439Sbill 					ttstart(tp);
82539Sbill 					tp->t_state |= ASLEEP;
82639Sbill 					sleep((caddr_t)&tp->t_outq, TTOPRI);
82739Sbill 				}
828121Sbill 				(void) spl0();
82939Sbill 			}
83039Sbill 		}
83139Sbill 	}
83239Sbill 	ttstart(tp);
83339Sbill 	return(NULL);
83439Sbill }
835