xref: /csrg-svn/sys/kern/tty.c (revision 887)
1*887Sbill /*	tty.c	3.15	09/16/80	*/
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"
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 
6139Sbill /*
6239Sbill  * shorthand
6339Sbill  */
6439Sbill #define	q1	tp->t_rawq
6539Sbill #define	q2	tp->t_canq
6639Sbill #define	q3	tp->t_outq
6739Sbill #define	q4	tp->t_un.t_ctlq
6839Sbill 
6939Sbill #define	OBUFSIZ	100
7039Sbill 
7139Sbill /*
7239Sbill  * routine called on first teletype open.
7339Sbill  * establishes a process group for distribution
7439Sbill  * of quits and interrupts from the tty.
7539Sbill  */
7639Sbill ttyopen(dev, tp)
7739Sbill dev_t dev;
7839Sbill register struct tty *tp;
7939Sbill {
8039Sbill 	register struct proc *pp;
8139Sbill 
8239Sbill 	pp = u.u_procp;
8339Sbill 	tp->t_dev = dev;
8439Sbill 	if(pp->p_pgrp == 0) {
8539Sbill 		u.u_ttyp = tp;
8639Sbill 		u.u_ttyd = dev;
87208Sbill 		if (tp->t_pgrp == 0)
88208Sbill 			tp->t_pgrp = pp->p_pid;
8939Sbill 		pp->p_pgrp = tp->t_pgrp;
9039Sbill 	}
9139Sbill 	tp->t_state &= ~WOPEN;
9239Sbill 	tp->t_state |= ISOPEN;
93384Sbill 	tp->t_line = 0;		/* conservative */
9439Sbill }
9539Sbill 
9639Sbill /*
9739Sbill  * set default control characters.
9839Sbill  */
9939Sbill ttychars(tp)
10039Sbill register struct tty *tp;
10139Sbill {
102174Sbill 
10339Sbill 	tun.t_intrc = CINTR;
10439Sbill 	tun.t_quitc = CQUIT;
10539Sbill 	tun.t_startc = CSTART;
10639Sbill 	tun.t_stopc = CSTOP;
10739Sbill 	tun.t_eofc = CEOT;
10839Sbill 	tun.t_brkc = CBRK;
10939Sbill 	tp->t_erase = CERASE;
11039Sbill 	tp->t_kill = CKILL;
111174Sbill /* begin local */
112208Sbill 	tlun.t_suspc = CTRL(z);
113208Sbill 	tlun.t_dsuspc = CTRL(y);
114174Sbill 	tlun.t_rprntc = CTRL(r);
115174Sbill 	tlun.t_flushc = CTRL(o);
116174Sbill 	tlun.t_werasc = CTRL(w);
117174Sbill 	tlun.t_lnextc = CTRL(v);
118174Sbill 	tlun.t_lintr = CTRL(c);
119174Sbill 	tlun.t_lerase = CTRL(h);
120174Sbill 	tlun.t_lkill = CTRL(u);
121174Sbill 	tp->t_local = 0;
122174Sbill 	tp->t_lstate = 0;
123174Sbill /* end local */
12439Sbill }
12539Sbill 
12639Sbill /*
12739Sbill  * clean tp on last close
12839Sbill  */
12939Sbill ttyclose(tp)
13039Sbill register struct tty *tp;
13139Sbill {
13239Sbill 
13339Sbill 	tp->t_pgrp = 0;
13439Sbill 	wflushtty(tp);
13539Sbill 	tp->t_state = 0;
136384Sbill 	tp->t_line = 0;
13739Sbill }
13839Sbill 
13939Sbill /*
14039Sbill  * stty/gtty writearound
14139Sbill  */
14239Sbill stty()
14339Sbill {
14439Sbill 	u.u_arg[2] = u.u_arg[1];
14539Sbill 	u.u_arg[1] = TIOCSETP;
14639Sbill 	ioctl();
14739Sbill }
14839Sbill 
14939Sbill gtty()
15039Sbill {
15139Sbill 	u.u_arg[2] = u.u_arg[1];
15239Sbill 	u.u_arg[1] = TIOCGETP;
15339Sbill 	ioctl();
15439Sbill }
15539Sbill 
15639Sbill /*
157121Sbill  * Do nothing specific version of line
158121Sbill  * discipline specific ioctl command.
159121Sbill  */
160191Sbill /*ARGSUSED*/
161121Sbill nullioctl(tp, cmd, addr)
162121Sbill register struct tty *tp;
163121Sbill caddr_t addr;
164121Sbill {
165121Sbill 
166121Sbill 	return (cmd);
167121Sbill }
168121Sbill 
169121Sbill /*
17039Sbill  * ioctl system call
17139Sbill  * Check legality, execute common code, and switch out to individual
17239Sbill  * device routine.
17339Sbill  */
17439Sbill ioctl()
17539Sbill {
17639Sbill 	register struct file *fp;
17739Sbill 	register struct inode *ip;
17839Sbill 	register struct a {
17939Sbill 		int	fdes;
18039Sbill 		int	cmd;
18139Sbill 		caddr_t	cmarg;
18239Sbill 	} *uap;
18339Sbill 	register dev_t dev;
18439Sbill 	register fmt;
18539Sbill 
18639Sbill 	uap = (struct a *)u.u_ap;
18739Sbill 	if ((fp = getf(uap->fdes)) == NULL)
18839Sbill 		return;
18939Sbill 	if (uap->cmd==FIOCLEX) {
19039Sbill 		u.u_pofile[uap->fdes] |= EXCLOSE;
19139Sbill 		return;
19239Sbill 	}
19339Sbill 	if (uap->cmd==FIONCLEX) {
19439Sbill 		u.u_pofile[uap->fdes] &= ~EXCLOSE;
19539Sbill 		return;
19639Sbill 	}
19739Sbill 	ip = fp->f_inode;
19839Sbill 	fmt = ip->i_mode & IFMT;
19939Sbill 	if (fmt != IFCHR && fmt != IFMPC) {
200174Sbill /* begin local */
201174Sbill 		if (uap->cmd==FIONREAD && (fmt == IFREG || fmt == IFDIR)) {
202174Sbill 			off_t nread = ip->i_size - fp->f_un.f_offset;
203174Sbill 
204174Sbill 			if (copyout((caddr_t)&nread, uap->cmarg, sizeof(off_t)))
205174Sbill 				u.u_error = EFAULT;
206174Sbill 		} else
207174Sbill /* end local */
208174Sbill 			u.u_error = ENOTTY;
20939Sbill 		return;
21039Sbill 	}
21139Sbill 	dev = ip->i_un.i_rdev;
21239Sbill 	u.u_r.r_val1 = 0;
21339Sbill 	(*cdevsw[major(dev)].d_ioctl)(dev, uap->cmd, uap->cmarg, fp->f_flag);
21439Sbill }
21539Sbill 
21639Sbill /*
21739Sbill  * Common code for several tty ioctl commands
21839Sbill  */
21939Sbill ttioccomm(com, tp, addr, dev)
22039Sbill register struct tty *tp;
22139Sbill caddr_t addr;
22239Sbill {
22339Sbill 	unsigned t;
224174Sbill 	struct sgttyb iocb;
225191Sbill 	struct clist tq;
22639Sbill 	extern int nldisp;
227*887Sbill 	register c;
228728Sbill 	int temp;
22939Sbill 
23039Sbill 	switch(com) {
23139Sbill 
23239Sbill 	/*
23339Sbill 	 * get discipline number
23439Sbill 	 */
23539Sbill 	case TIOCGETD:
23639Sbill 		t = tp->t_line;
23739Sbill 		if (copyout((caddr_t)&t, addr, sizeof(t)))
23839Sbill 			u.u_error = EFAULT;
23939Sbill 		break;
24039Sbill 
24139Sbill 	/*
24239Sbill 	 * set line discipline
24339Sbill 	 */
24439Sbill 	case TIOCSETD:
24539Sbill 		if (copyin(addr, (caddr_t)&t, sizeof(t))) {
24639Sbill 			u.u_error = EFAULT;
24739Sbill 			break;
24839Sbill 		}
24939Sbill 		if (t >= nldisp) {
25039Sbill 			u.u_error = ENXIO;
25139Sbill 			break;
25239Sbill 		}
253174Sbill 		(void) spl5();
25439Sbill 		if (tp->t_line)
25539Sbill 			(*linesw[tp->t_line].l_close)(tp);
25639Sbill 		if (t)
25739Sbill 			(*linesw[t].l_open)(dev, tp, addr);
25839Sbill 		if (u.u_error==0)
25939Sbill 			tp->t_line = t;
260174Sbill 		(void) spl0();
26139Sbill 		break;
26239Sbill 
26339Sbill 	/*
26439Sbill 	 * prevent more opens on channel
26539Sbill 	 */
26639Sbill 	case TIOCEXCL:
26739Sbill 		tp->t_state |= XCLUDE;
26839Sbill 		break;
26939Sbill 
27039Sbill 	case TIOCNXCL:
27139Sbill 		tp->t_state &= ~XCLUDE;
27239Sbill 		break;
27339Sbill 
27439Sbill 	/*
27539Sbill 	 * Set new parameters
27639Sbill 	 */
27739Sbill 	case TIOCSETP:
278191Sbill 	case TIOCSETN:
27939Sbill 		if (copyin(addr, (caddr_t)&iocb, sizeof(iocb))) {
28039Sbill 			u.u_error = EFAULT;
28139Sbill 			return(1);
28239Sbill 		}
283121Sbill 		(void) spl5();
284174Sbill 		if (tp->t_line == 0) {
285174Sbill 			if (com == TIOCSETP)
286174Sbill 				wflushtty(tp);
287174Sbill 			while (canon(tp)>=0)
288174Sbill 				;
289174Sbill 		} else if (tp->t_line == NTTYDISC) {
290174Sbill 			if (tp->t_flags&RAW || iocb.sg_flags&RAW ||
291174Sbill 			    com == TIOCSETP)
292174Sbill 				wflushtty(tp);
293174Sbill 			else if ((tp->t_flags&CBREAK) != (iocb.sg_flags&CBREAK)) {
294174Sbill 				if (iocb.sg_flags & CBREAK) {
295174Sbill 					catq(&tp->t_rawq, &tp->t_canq);
296174Sbill 					tq = tp->t_rawq;
297174Sbill 					tp->t_rawq = tp->t_canq;
298174Sbill 					tp->t_canq = tq;
299174Sbill 				} else {
300174Sbill 					tp->t_local |= LPENDIN;
301174Sbill 					if (tp->t_canq.c_cc)
302174Sbill 						panic("ioccom canq");
303174Sbill 					if (tp->t_chan)
304174Sbill 						(void) sdata(tp->t_chan);
305174Sbill 					else
306174Sbill 						wakeup((caddr_t)&tp->t_rawq);
307174Sbill 				}
308174Sbill 			}
309174Sbill 		}
31039Sbill 		if ((tp->t_state&SPEEDS)==0) {
311174Sbill 			tp->t_ispeed = iocb.sg_ispeed;
312174Sbill 			tp->t_ospeed = iocb.sg_ospeed;
31339Sbill 		}
314174Sbill 		tp->t_erase = iocb.sg_erase;
315174Sbill 		tp->t_kill = iocb.sg_kill;
316174Sbill 		tp->t_flags = iocb.sg_flags;
317121Sbill 		(void) spl0();
31839Sbill 		break;
31939Sbill 
32039Sbill 	/*
32139Sbill 	 * send current parameters to user
32239Sbill 	 */
32339Sbill 	case TIOCGETP:
324174Sbill 		iocb.sg_ispeed = tp->t_ispeed;
325174Sbill 		iocb.sg_ospeed = tp->t_ospeed;
326174Sbill 		iocb.sg_erase = tp->t_erase;
327174Sbill 		iocb.sg_kill = tp->t_kill;
328174Sbill 		iocb.sg_flags = tp->t_flags;
32939Sbill 		if (copyout((caddr_t)&iocb, addr, sizeof(iocb)))
33039Sbill 			u.u_error = EFAULT;
33139Sbill 		break;
33239Sbill 
33339Sbill 	/*
33439Sbill 	 * Hang up line on last close
33539Sbill 	 */
33639Sbill 
33739Sbill 	case TIOCHPCL:
33839Sbill 		tp->t_state |= HUPCLS;
33939Sbill 		break;
34039Sbill 
34139Sbill 	case TIOCFLUSH:
342872Sbill 		flushtty(tp, FREAD|FWRITE);
34339Sbill 		break;
34439Sbill 
34539Sbill 	/*
34639Sbill 	 * ioctl entries to line discipline
34739Sbill 	 */
34839Sbill 	case DIOCSETP:
34939Sbill 	case DIOCGETP:
350121Sbill 		if ((*linesw[tp->t_line].l_ioctl)(com, tp, addr))
351121Sbill 			u.u_error = ENOTTY;
35239Sbill 		break;
35339Sbill 
35439Sbill 	/*
35539Sbill 	 * set and fetch special characters
35639Sbill 	 */
35739Sbill 	case TIOCSETC:
358174Sbill 		if (copyin(addr, (caddr_t)&tun, sizeof(struct tchars)))
35939Sbill 			u.u_error = EFAULT;
36039Sbill 		break;
36139Sbill 
36239Sbill 	case TIOCGETC:
363174Sbill 		if (copyout((caddr_t)&tun, addr, sizeof(struct tchars)))
36439Sbill 			u.u_error = EFAULT;
36539Sbill 		break;
36639Sbill 
367174Sbill /* local ioctls */
368174Sbill 	case TIOCSLTC:
369174Sbill 		if (copyin(addr, (caddr_t)&tlun, sizeof (struct ltchars)))
370174Sbill 			u.u_error = EFAULT;
371174Sbill 		break;
372174Sbill 
373174Sbill 	case TIOCGLTC:
374174Sbill 		if (copyout((caddr_t)&tlun, addr, sizeof (struct ltchars)))
375174Sbill 			u.u_error = EFAULT;
376174Sbill 		break;
377174Sbill 
378174Sbill 	case FIONREAD: {
379340Sbill 		off_t nread;
380174Sbill 
381340Sbill 		switch (tp->t_line) {
382340Sbill 
383340Sbill 		case NETLDISC:
384340Sbill 			nread = tp->t_rec ? tp->t_inbuf : 0;
385340Sbill 			break;
386340Sbill 
387340Sbill 		case NTTYDISC:
388340Sbill 			nread = tp->t_canq.c_cc;
389340Sbill 			if (tp->t_flags & (RAW|CBREAK))
390340Sbill 				nread += tp->t_rawq.c_cc;
391340Sbill 			break;
392340Sbill 
393340Sbill 		case 0:
394340Sbill 			/* do something here ... */
395340Sbill 			;
396340Sbill 		}
397174Sbill 		if (copyout((caddr_t)&nread, addr, sizeof (off_t)))
398174Sbill 			u.u_error = EFAULT;
399174Sbill 		break;
400174Sbill 		}
401174Sbill 
402174Sbill 	/*
403174Sbill 	 * Should allow SPGRP and GPGRP only if tty open for reading.
404174Sbill 	 */
405174Sbill 	case TIOCSPGRP:
406728Sbill 		if (copyin(addr, (caddr_t)&tp->t_pgrp, sizeof (tp->t_pgrp)))
407728Sbill 			u.u_error = EFAULT;
408174Sbill 		break;
409174Sbill 
410174Sbill 	case TIOCGPGRP:
411174Sbill 		if (copyout((caddr_t)&tp->t_pgrp, addr, sizeof(tp->t_pgrp)))
412174Sbill 			u.u_error = EFAULT;
413174Sbill 		break;
414174Sbill 
415174Sbill 	/*
416174Sbill 	 * Modify local mode word.
417174Sbill 	 */
418174Sbill 	case TIOCLBIS:
419728Sbill 		if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local)))
420728Sbill 			u.u_error = EFAULT;
421728Sbill 		else
422728Sbill 			tp->t_local |= temp;
423174Sbill 		break;
424174Sbill 
425174Sbill 	case TIOCLBIC:
426728Sbill 		if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local)))
427728Sbill 			u.u_error = EFAULT;
428728Sbill 		else
429728Sbill 			tp->t_local &= ~temp;
430174Sbill 		break;
431174Sbill 
432174Sbill 	case TIOCLSET:
433728Sbill 		if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local)))
434728Sbill 			u.u_error = EFAULT;
435728Sbill 		else
436728Sbill 			tp->t_local = temp;
437174Sbill 		break;
438174Sbill 
439174Sbill 	case TIOCLGET:
440174Sbill 		if (copyout((caddr_t)&tp->t_local, addr, sizeof(tp->t_local)))
441174Sbill 			u.u_error = EFAULT;
442174Sbill 		break;
443174Sbill 
444213Sbill 	case TIOCOUTQ:
445213Sbill 		if (copyout((caddr_t)&tp->t_outq.c_cc, addr, sizeof(tp->t_outq.c_cc)))
446213Sbill 			u.u_error = EFAULT;
447213Sbill 		break;
448213Sbill 
449*887Sbill 	case TIOCSTI:
450*887Sbill 		c = fubyte(addr);
451*887Sbill 		if (u.u_uid && u.u_ttyp != tp || c < 0)
452*887Sbill 			u.u_error = EFAULT;
453*887Sbill 		else
454*887Sbill 			(*linesw[tp->t_line].l_rint)(c, tp);
455*887Sbill 		break;
456174Sbill /* end of locals */
457*887Sbill 
45839Sbill 	default:
45939Sbill 		return(0);
46039Sbill 	}
46139Sbill 	return(1);
46239Sbill }
46339Sbill 
46439Sbill /*
46539Sbill  * Wait for output to drain, then flush input waiting.
46639Sbill  */
46739Sbill wflushtty(tp)
46839Sbill register struct tty *tp;
46939Sbill {
47039Sbill 
471121Sbill 	(void) spl5();
47239Sbill 	while (tp->t_outq.c_cc && tp->t_state&CARR_ON) {
47339Sbill 		(*tp->t_oproc)(tp);
47439Sbill 		tp->t_state |= ASLEEP;
47539Sbill 		sleep((caddr_t)&tp->t_outq, TTOPRI);
47639Sbill 	}
477872Sbill 	flushtty(tp, FREAD|FWRITE);
478121Sbill 	(void) spl0();
47939Sbill }
48039Sbill 
48139Sbill /*
48239Sbill  * flush all TTY queues
48339Sbill  */
484872Sbill flushtty(tp, rw)
48539Sbill register struct tty *tp;
48639Sbill {
48739Sbill 	register s;
48839Sbill 
489340Sbill 	if (tp->t_line == NETLDISC)
490340Sbill 		return;
491121Sbill 	s = spl6();
492872Sbill 	if (rw & FREAD) {
493872Sbill 		while (getc(&tp->t_canq) >= 0)
494872Sbill 			;
495872Sbill 		wakeup((caddr_t)&tp->t_rawq);
496872Sbill 	}
497872Sbill 	if (rw & FWRITE) {
498872Sbill 		wakeup((caddr_t)&tp->t_outq);
499872Sbill 		tp->t_state &= ~TTSTOP;
500872Sbill 		(*cdevsw[major(tp->t_dev)].d_stop)(tp);
501872Sbill 		while (getc(&tp->t_outq) >= 0)
502872Sbill 			;
503872Sbill 	}
504872Sbill 	if (rw & FREAD) {
505872Sbill 		while (getc(&tp->t_rawq) >= 0)
506872Sbill 			;
507872Sbill 		tp->t_delct = 0;
508872Sbill 		tp->t_rocount = 0;		/* local */
509872Sbill 		tp->t_rocol = 0;
510872Sbill 		tp->t_lstate = 0;
511872Sbill 	}
51239Sbill 	splx(s);
51339Sbill }
51439Sbill 
51539Sbill 
51639Sbill 
51739Sbill /*
51839Sbill  * transfer raw input list to canonical list,
51939Sbill  * doing erase-kill processing and handling escapes.
52039Sbill  * It waits until a full line has been typed in cooked mode,
52139Sbill  * or until any character has been typed in raw mode.
52239Sbill  */
52339Sbill canon(tp)
52439Sbill register struct tty *tp;
52539Sbill {
52639Sbill 	register char *bp;
52739Sbill 	char *bp1;
52839Sbill 	register int c;
52939Sbill 	int mc;
53039Sbill 	int s;
53139Sbill 
53239Sbill 	if ((tp->t_flags&(RAW|CBREAK))==0 && tp->t_delct==0
53339Sbill 	    || (tp->t_flags&(RAW|CBREAK))!=0 && tp->t_rawq.c_cc==0) {
53439Sbill 		return(-1);
53539Sbill 	}
53639Sbill 	s = spl0();
53739Sbill loop:
53839Sbill 	bp = &canonb[2];
53939Sbill 	while ((c=getc(&tp->t_rawq)) >= 0) {
54039Sbill 		if ((tp->t_flags&(RAW|CBREAK))==0) {
54139Sbill 			if (c==0377) {
54239Sbill 				tp->t_delct--;
54339Sbill 				break;
54439Sbill 			}
54539Sbill 			if (bp[-1]!='\\') {
54639Sbill 				if (c==tp->t_erase) {
54739Sbill 					if (bp > &canonb[2])
54839Sbill 						bp--;
54939Sbill 					continue;
55039Sbill 				}
55139Sbill 				if (c==tp->t_kill)
55239Sbill 					goto loop;
55339Sbill 				if (c==tun.t_eofc)
55439Sbill 					continue;
55539Sbill 			} else {
55639Sbill 				mc = maptab[c];
55739Sbill 				if (c==tp->t_erase || c==tp->t_kill)
55839Sbill 					mc = c;
55939Sbill 				if (mc && (mc==c || (tp->t_flags&LCASE))) {
56039Sbill 					if (bp[-2] != '\\')
56139Sbill 						c = mc;
56239Sbill 					bp--;
56339Sbill 				}
56439Sbill 			}
56539Sbill 		}
56639Sbill 		*bp++ = c;
56739Sbill 		if (bp>=canonb+CANBSIZ)
56839Sbill 			break;
56939Sbill 	}
57039Sbill 	bp1 = &canonb[2];
571121Sbill 	(void) b_to_q(bp1, bp-bp1, &tp->t_canq);
57239Sbill 
57339Sbill 	if (tp->t_state&TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) {
57439Sbill 		if (putc(tun.t_startc, &tp->t_outq)==0) {
57539Sbill 			tp->t_state &= ~TBLOCK;
57639Sbill 			ttstart(tp);
57739Sbill 		}
57839Sbill 		tp->t_char = 0;
57939Sbill 	}
58039Sbill 
58139Sbill 	splx(s);
58239Sbill 	return(0);
58339Sbill }
58439Sbill 
58539Sbill 
58639Sbill /*
58739Sbill  * block transfer input handler.
58839Sbill  */
58939Sbill ttyrend(tp, pb, pe)
59039Sbill register struct tty *tp;
59139Sbill register char *pb, *pe;
59239Sbill {
59339Sbill 	int	tandem;
59439Sbill 
59539Sbill 	tandem = tp->t_flags&TANDEM;
59639Sbill 	if (tp->t_flags&RAW) {
597121Sbill 		(void) b_to_q(pb, pe-pb, &tp->t_rawq);
59839Sbill 		if (tp->t_chan)
599121Sbill 			(void) sdata(tp->t_chan); else
60039Sbill 			wakeup((caddr_t)&tp->t_rawq);
60139Sbill 	} else {
60239Sbill 		tp->t_flags &= ~TANDEM;
60339Sbill 		while (pb < pe)
60439Sbill 			ttyinput(*pb++, tp);
60539Sbill 		tp->t_flags |= tandem;
60639Sbill 	}
60739Sbill 	if (tandem)
60839Sbill 		ttyblock(tp);
60939Sbill }
61039Sbill 
61139Sbill /*
61239Sbill  * Place a character on raw TTY input queue, putting in delimiters
61339Sbill  * and waking up top half as needed.
61439Sbill  * Also echo if required.
61539Sbill  * The arguments are the character and the appropriate
61639Sbill  * tty structure.
61739Sbill  */
61839Sbill ttyinput(c, tp)
61939Sbill register c;
62039Sbill register struct tty *tp;
62139Sbill {
62239Sbill 	register int t_flags;
62339Sbill 	register struct chan *cp;
62439Sbill 
62539Sbill 	tk_nin += 1;
62639Sbill 	c &= 0377;
62739Sbill 	t_flags = tp->t_flags;
62839Sbill 	if (t_flags&TANDEM)
62939Sbill 		ttyblock(tp);
63039Sbill 	if ((t_flags&RAW)==0) {
63139Sbill 		c &= 0177;
63239Sbill 		if (tp->t_state&TTSTOP) {
63339Sbill 			if (c==tun.t_startc) {
63439Sbill 				tp->t_state &= ~TTSTOP;
63539Sbill 				ttstart(tp);
63639Sbill 				return;
63739Sbill 			}
63839Sbill 			if (c==tun.t_stopc)
63939Sbill 				return;
64039Sbill 			tp->t_state &= ~TTSTOP;
64139Sbill 			ttstart(tp);
64239Sbill 		} else {
64339Sbill 			if (c==tun.t_stopc) {
64439Sbill 				tp->t_state |= TTSTOP;
64539Sbill 				(*cdevsw[major(tp->t_dev)].d_stop)(tp);
64639Sbill 				return;
64739Sbill 			}
64839Sbill 			if (c==tun.t_startc)
64939Sbill 				return;
65039Sbill 		}
65139Sbill 		if (c==tun.t_quitc || c==tun.t_intrc) {
652872Sbill 			flushtty(tp, FREAD|FWRITE);
65339Sbill 			c = (c==tun.t_intrc) ? SIGINT:SIGQUIT;
65439Sbill 			if (tp->t_chan)
65539Sbill 				scontrol(tp->t_chan, M_SIG, c);
65639Sbill 			else
657174Sbill 				gsignal(tp->t_pgrp, c);
65839Sbill 			return;
65939Sbill 		}
66039Sbill 		if (c=='\r' && t_flags&CRMOD)
66139Sbill 			c = '\n';
66239Sbill 	}
66339Sbill 	if (tp->t_rawq.c_cc>TTYHOG) {
664872Sbill 		flushtty(tp, FREAD|FWRITE);
66539Sbill 		return;
66639Sbill 	}
66739Sbill 	if (t_flags&LCASE && c>='A' && c<='Z')
66839Sbill 		c += 'a'-'A';
669121Sbill 	(void) putc(c, &tp->t_rawq);
67039Sbill 	if (t_flags&(RAW|CBREAK)||(c=='\n'||c==tun.t_eofc||c==tun.t_brkc)) {
67139Sbill 		if ((t_flags&(RAW|CBREAK))==0 && putc(0377, &tp->t_rawq)==0)
67239Sbill 			tp->t_delct++;
67339Sbill 		if ((cp=tp->t_chan)!=NULL)
674121Sbill 			(void) sdata(cp); else
67539Sbill 			wakeup((caddr_t)&tp->t_rawq);
67639Sbill 	}
67739Sbill 	if (t_flags&ECHO) {
67839Sbill 		ttyoutput(c, tp);
67939Sbill 		if (c==tp->t_kill && (t_flags&(RAW|CBREAK))==0)
68039Sbill 			ttyoutput('\n', tp);
68139Sbill 		ttstart(tp);
68239Sbill 	}
68339Sbill }
68439Sbill 
68539Sbill 
68639Sbill /*
68739Sbill  * Send stop character on input overflow.
68839Sbill  */
68939Sbill ttyblock(tp)
69039Sbill register struct tty *tp;
69139Sbill {
69239Sbill 	register x;
69339Sbill 	x = q1.c_cc + q2.c_cc;
69439Sbill 	if (q1.c_cc > TTYHOG) {
695872Sbill 		flushtty(tp, FREAD|FWRITE);
69639Sbill 		tp->t_state &= ~TBLOCK;
69739Sbill 	}
69839Sbill 	if (x >= TTYHOG/2) {
69939Sbill 		if (putc(tun.t_stopc, &tp->t_outq)==0) {
70039Sbill 			tp->t_state |= TBLOCK;
70139Sbill 			tp->t_char++;
70239Sbill 			ttstart(tp);
70339Sbill 		}
70439Sbill 	}
70539Sbill }
70639Sbill 
70739Sbill /*
70839Sbill  * put character on TTY output queue, adding delays,
70939Sbill  * expanding tabs, and handling the CR/NL bit.
71039Sbill  * It is called both from the top half for output, and from
71139Sbill  * interrupt level for echoing.
71239Sbill  * The arguments are the character and the tty structure.
71339Sbill  */
71439Sbill ttyoutput(c, tp)
71539Sbill register c;
71639Sbill register struct tty *tp;
71739Sbill {
71839Sbill 	register char *colp;
71939Sbill 	register ctype;
72039Sbill 
72139Sbill 	/*
72239Sbill 	 * Ignore EOT in normal mode to avoid hanging up
72339Sbill 	 * certain terminals.
72439Sbill 	 * In raw mode dump the char unchanged.
72539Sbill 	 */
72639Sbill 	if ((tp->t_flags&RAW)==0) {
72739Sbill 		c &= 0177;
72839Sbill 		if ((tp->t_flags&CBREAK)==0 && c==CEOT)
72939Sbill 			return;
73039Sbill 	} else {
731121Sbill 		tk_nout++;
732121Sbill 		(void) putc(c, &tp->t_outq);
73339Sbill 		return;
73439Sbill 	}
73539Sbill 
73639Sbill 	/*
73739Sbill 	 * Turn tabs to spaces as required
73839Sbill 	 */
73939Sbill 	if (c=='\t' && (tp->t_flags&TBDELAY)==XTABS) {
740121Sbill 		c = 8 - (tp->t_col & 7);
741121Sbill 		(void) b_to_q("        ", c, &tp->t_outq);
742121Sbill 		tp->t_col += c;
743121Sbill 		tk_nout += c;
74439Sbill 		return;
74539Sbill 	}
746121Sbill 	tk_nout++;
74739Sbill 	/*
74839Sbill 	 * for upper-case-only terminals,
74939Sbill 	 * generate escapes.
75039Sbill 	 */
75139Sbill 	if (tp->t_flags&LCASE) {
75239Sbill 		colp = "({)}!|^~'`";
75339Sbill 		while(*colp++)
75439Sbill 			if(c == *colp++) {
75539Sbill 				ttyoutput('\\', tp);
75639Sbill 				c = colp[-2];
75739Sbill 				break;
75839Sbill 			}
75939Sbill 		if ('a'<=c && c<='z')
76039Sbill 			c += 'A' - 'a';
76139Sbill 	}
76239Sbill 	/*
76339Sbill 	 * turn <nl> to <cr><lf> if desired.
76439Sbill 	 */
76539Sbill 	if (c=='\n' && tp->t_flags&CRMOD)
76639Sbill 		ttyoutput('\r', tp);
767121Sbill 	(void) putc(c, &tp->t_outq);
76839Sbill 	/*
76939Sbill 	 * Calculate delays.
77039Sbill 	 * The numbers here represent clock ticks
77139Sbill 	 * and are not necessarily optimal for all terminals.
77239Sbill 	 * The delays are indicated by characters above 0200.
77339Sbill 	 * In raw mode there are no delays and the
77439Sbill 	 * transmission path is 8 bits wide.
77539Sbill 	 */
77639Sbill 	colp = &tp->t_col;
77739Sbill 	ctype = partab[c];
77839Sbill 	c = 0;
77939Sbill 	switch (ctype&077) {
78039Sbill 
78139Sbill 	/* ordinary */
78239Sbill 	case 0:
78339Sbill 		(*colp)++;
78439Sbill 
78539Sbill 	/* non-printing */
78639Sbill 	case 1:
78739Sbill 		break;
78839Sbill 
78939Sbill 	/* backspace */
79039Sbill 	case 2:
79139Sbill 		if (*colp)
79239Sbill 			(*colp)--;
79339Sbill 		break;
79439Sbill 
79539Sbill 	/* newline */
79639Sbill 	case 3:
79739Sbill 		ctype = (tp->t_flags >> 8) & 03;
79839Sbill 		if(ctype == 1) { /* tty 37 */
79939Sbill 			if (*colp)
80039Sbill 				c = max(((unsigned)*colp>>4) + 3, (unsigned)6);
80139Sbill 		} else
80239Sbill 		if(ctype == 2) { /* vt05 */
80339Sbill 			c = 6;
80439Sbill 		}
80539Sbill 		*colp = 0;
80639Sbill 		break;
80739Sbill 
80839Sbill 	/* tab */
80939Sbill 	case 4:
81039Sbill 		ctype = (tp->t_flags >> 10) & 03;
81139Sbill 		if(ctype == 1) { /* tty 37 */
81239Sbill 			c = 1 - (*colp | ~07);
81339Sbill 			if(c < 5)
81439Sbill 				c = 0;
81539Sbill 		}
81639Sbill 		*colp |= 07;
81739Sbill 		(*colp)++;
81839Sbill 		break;
81939Sbill 
82039Sbill 	/* vertical motion */
82139Sbill 	case 5:
82239Sbill 		if(tp->t_flags & VTDELAY) /* tty 37 */
82339Sbill 			c = 0177;
82439Sbill 		break;
82539Sbill 
82639Sbill 	/* carriage return */
82739Sbill 	case 6:
82839Sbill 		ctype = (tp->t_flags >> 12) & 03;
82939Sbill 		if(ctype == 1) { /* tn 300 */
83039Sbill 			c = 5;
83139Sbill 		} else if(ctype == 2) { /* ti 700 */
83239Sbill 			c = 10;
83339Sbill 		} else if(ctype == 3) { /* concept 100 */
83439Sbill 			int i;
835720Sbill 			if ((i = *colp) >= 0)
836720Sbill 				for (; i<9; i++)
837720Sbill 					(void) putc(0177, &tp->t_outq);
83839Sbill 		}
83939Sbill 		*colp = 0;
84039Sbill 	}
84139Sbill 	if(c)
842121Sbill 		(void) putc(c|0200, &tp->t_outq);
84339Sbill }
84439Sbill 
84539Sbill /*
84639Sbill  * Restart typewriter output following a delay
84739Sbill  * timeout.
84839Sbill  * The name of the routine is passed to the timeout
84939Sbill  * subroutine and it is called during a clock interrupt.
85039Sbill  */
85139Sbill ttrstrt(tp)
85239Sbill register struct tty *tp;
85339Sbill {
85439Sbill 
85539Sbill 	tp->t_state &= ~TIMEOUT;
85639Sbill 	ttstart(tp);
85739Sbill }
85839Sbill 
85939Sbill /*
86039Sbill  * Start output on the typewriter. It is used from the top half
86139Sbill  * after some characters have been put on the output queue,
86239Sbill  * from the interrupt routine to transmit the next
86339Sbill  * character, and after a timeout has finished.
86439Sbill  */
86539Sbill ttstart(tp)
86639Sbill register struct tty *tp;
86739Sbill {
86839Sbill 	register s;
86939Sbill 
87039Sbill 	s = spl5();
87139Sbill 	if((tp->t_state&(TIMEOUT|TTSTOP|BUSY)) == 0)
87239Sbill 		(*tp->t_oproc)(tp);
87339Sbill 	splx(s);
87439Sbill }
87539Sbill 
87639Sbill /*
87739Sbill  * Called from device's read routine after it has
87839Sbill  * calculated the tty-structure given as argument.
87939Sbill  */
88039Sbill ttread(tp)
88139Sbill register struct tty *tp;
88239Sbill {
88339Sbill register s;
88439Sbill 
88539Sbill 	if ((tp->t_state&CARR_ON)==0)
88639Sbill 		return(-1);
88739Sbill 	s = spl5();
88839Sbill 	if (tp->t_canq.c_cc==0)
88939Sbill 		while (canon(tp)<0)
89039Sbill 			if (tp->t_chan==NULL) {
89139Sbill 				sleep((caddr_t)&tp->t_rawq, TTIPRI);
89239Sbill 			} else {
89339Sbill 				splx(s);
89439Sbill 				return(0);
89539Sbill 			}
89639Sbill 	splx(s);
89739Sbill 	while (tp->t_canq.c_cc && passc(getc(&tp->t_canq))>=0)
89839Sbill 			;
89939Sbill 	return(tp->t_rawq.c_cc+tp->t_canq.c_cc);
90039Sbill }
90139Sbill 
90239Sbill /*
90339Sbill  * Called from the device's write routine after it has
90439Sbill  * calculated the tty-structure given as argument.
90539Sbill  */
90639Sbill caddr_t
90739Sbill ttwrite(tp)
90839Sbill register struct tty *tp;
90939Sbill {
91039Sbill 	/*
91139Sbill 	 * THE POSITIONING OF CP, CC, AND CE ARE CRITICAL
91239Sbill 	 * AND MUST NOT BE CHANGED WITHOUT PATCHING
91339Sbill 	 * THE 'ASM' INLINES BELOW.  WATCH OUT.
91439Sbill 	 */
91539Sbill 	register char *cp;
91639Sbill 	register int cc, ce;
91739Sbill 	register i;
91839Sbill 	char obuf[OBUFSIZ];
91939Sbill 
92039Sbill 	if ((tp->t_state&CARR_ON)==0)
92139Sbill 		return(NULL);
92239Sbill 	while (u.u_count) {
92339Sbill 		cc = MIN(u.u_count, OBUFSIZ);
92439Sbill 		cp = obuf;
92539Sbill 		iomove(cp, (unsigned)cc, B_WRITE);
92639Sbill 		if (u.u_error)
92739Sbill 			break;
928121Sbill 		(void) spl5();
92939Sbill 		while (tp->t_outq.c_cc > TTHIWAT) {
93039Sbill 			ttstart(tp);
93139Sbill 			tp->t_state |= ASLEEP;
93239Sbill 			if (tp->t_chan) {
93339Sbill 				u.u_base -= cc;
93439Sbill 				u.u_offset -= cc;
93539Sbill 				u.u_count += cc;
936121Sbill 				(void) spl0();
93739Sbill 				return((caddr_t)&tp->t_outq);
93839Sbill 			}
93939Sbill 			sleep((caddr_t)&tp->t_outq, TTOPRI);
94039Sbill 		}
941121Sbill 		(void) spl0();
94239Sbill 		if (tp->t_flags&LCASE) {
94339Sbill 			while (cc--)
94439Sbill 				ttyoutput(*cp++,tp);
94539Sbill 			continue;
94639Sbill 		}
94739Sbill 		while (cc) {
94839Sbill 			if (tp->t_flags&RAW)
94939Sbill 				ce=cc;
95039Sbill 			else {
95139Sbill #ifdef VAX
95239Sbill 				asm("	scanc	r9,(r10),_partab,$077");
95339Sbill 				asm("	subl3	r0,r9,r8");
95439Sbill #else
95539Sbill 				ce=0;
95639Sbill 				while(((partab[*(cp+ce)]&077)==0)&&(ce<cc))
95739Sbill 					ce++;
95839Sbill #endif
95939Sbill 				if (ce==0) {
96039Sbill 					ttyoutput(*cp++,tp);
96139Sbill 					cc--;
962121Sbill 					goto check;
96339Sbill 				}
96439Sbill 			}
96539Sbill 			i=b_to_q(cp,ce,&tp->t_outq);
96639Sbill 			ce-=i;
96739Sbill 			tk_nout+=ce;
96839Sbill 			tp->t_col+=ce;
96939Sbill 			cp+=ce;
97039Sbill 			cc-=ce;
971121Sbill check:
972121Sbill 			if (tp->t_outq.c_cc > TTHIWAT) {
973121Sbill 				(void) spl5();
97439Sbill 				while (tp->t_outq.c_cc > TTHIWAT) {
97539Sbill 					ttstart(tp);
97639Sbill 					tp->t_state |= ASLEEP;
97739Sbill 					sleep((caddr_t)&tp->t_outq, TTOPRI);
97839Sbill 				}
979121Sbill 				(void) spl0();
98039Sbill 			}
98139Sbill 		}
98239Sbill 	}
98339Sbill 	ttstart(tp);
98439Sbill 	return(NULL);
98539Sbill }
986