LSX/sys/kl.c

Compare this file to the similar file:
Show the results in this format:

#
/*
 *	Copyright 1975 Bell Telephone Laboratories Inc
 */

/*
 *   KL/DL-11 driver
 */
#include "param.h"
#include "user.h"
#include "systm.h"
#include "inode.h"
#include "file.h"
#include "reg.h"
#include "tty.h"
#include "proc.h"

/* base address */
#define	KLADDR	0177560	/* console */
#define	NKL11	1
#define DSRDY	02
#define	RDRENB	01

struct	tty kl11[NKL11];

struct klregs {
	int klrcsr;
	int klrbuf;
	int kltcsr;
	int kltbuf;
}

klopen()
{
	register struct tty *tp;
	tp = &kl11[0];
	if((tp->t_modes & TOPEN) == 0) {
		tp->t_modes =| TOPEN;
		tp->t_flags = ECHO|CRMOD|LCASE;
	}
	KLADDR->klrcsr =| IENABLE|DSRDY|RDRENB;
	KLADDR->kltcsr =| IENABLE;
}

klclose()
{

	wflushtty();
}

klxint()
{
	register struct tty *tp;

	tp = kl11;
	ttstart();
	if (tp->t_outq.c_cc == 0 || tp->t_outq.c_cc == TTLOWAT)
		wakeup(&tp->t_outq);
}

klrint()
{
	register int c;

	c = KLADDR->klrbuf;
	KLADDR->klrcsr =| RDRENB;
	if ((c&0177)==0)
		KLADDR->kltbuf = c;	/* hardware botch */
	ttyinput(c);
}

klsgtty(f)
{
	register struct tty *tp;
	register int *a;

	tp = &kl11[0];
	a = u.u_arg[0];
	a =+ 2;
	wflushtty(tp);
	if(f)
		tp->t_flags = fuword(a);
	else
		suword(a,tp->t_flags);
}

/*
 * general TTY subroutines
 */

/*
 * Input mapping table-- if an entry is non-zero, when the
 * corresponding character is typed preceded by "\" the escape
 * sequence is replaced by the table value.  Mostly used for
 * upper-case only terminals.
 */
char	maptab[]
{
	000,000,000,000,004,000,000,000,
	000,000,000,000,000,000,000,000,
	000,000,000,000,000,000,000,000,
	000,000,000,000,000,000,000,000,
	000,'|',000,'#',000,000,000,'`',
	'{','}',000,000,000,000,000,000,
	000,000,000,000,000,000,000,000,
	000,000,000,000,000,000,000,000,
	'@',000,000,000,000,000,000,000,
	000,000,000,000,000,000,000,000,
	000,000,000,000,000,000,000,000,
	000,000,000,000,000,000,'~',000,
	000,'A','B','C','D','E','F','G',
	'H','I','J','K','L','M','N','O',
	'P','Q','R','S','T','U','V','W',
	'X','Y','Z',000,000,000,000,000,
};

/*
 * The actual structure of a clist block manipulated by
 * getc and putc (mch.s)
 */
struct cblock {
	struct cblock *c_next;
	char info[6];
};

/* The character lists-- space for 6*NCLIST characters */
struct cblock cfree[NCLIST];
/* List head for unused character blocks. */
struct cblock *cfreelist;


/*
 * Wait for output to drain, then flush input waiting.
 */
wflushtty()
{
	register struct tty *tp;

	tp = kl11;
	spl7();
	while (tp->t_outq.c_cc) {
		sleep(&tp->t_outq, TTOPRI);
	}
	flushtty();
	spl0();
}

/*
 * Initialize clist by freeing all character blocks, then count
 * number of character devices. (Once-only routine)
 */
cinit()
{
	register int ccp;
	register struct cblock *cp;

	ccp = cfree;
	for (cp=(ccp+07)&~07; cp <= &cfree[NCLIST-1]; cp++) {
		cp->c_next = cfreelist;
		cfreelist = cp;
	}
}

/*
 * flush all TTY queues
 */
flushtty()
{
	register struct tty *tp;
	register int sps;

	tp = kl11;
	while (getc(&tp->t_canq) >= 0);
	while (getc(&tp->t_outq) >= 0);
	wakeup(&tp->t_rawq);
	wakeup(&tp->t_outq);
	sps = spl7();
	while (getc(&tp->t_rawq) >= 0);
	tp->t_delct = 0;
	rstps(sps);
}

/*
 * transfer raw input list to canonical list,
 * doing erase-kill processing and handling escapes.
 * It waits until a full line has been typed in cooked mode,
 * or until any character has been typed in raw mode.
 */
canon()
{
	register char *bp;
	char *bp1;
	register struct tty *tp;
	register int c;

	tp = kl11;
	spl7();
	while (tp->t_delct==0) {
		sleep(&tp->t_rawq, TTIPRI);
	}
	spl0();
loop:
	bp = &canonb[2];
	while ((c=getc(&tp->t_rawq)) >= 0) {
		if (c==0377) {
			tp->t_delct--;
			break;
		}
		if (bp[-1]!='\\') {
			if(c == CERASE) {
				if (bp > &canonb[2])
					bp--;
				continue;
			}
			if(c == CKILL)
				goto loop;
			if (c==CEOT)
				continue;
		} else {
			if(maptab[c] && (maptab[c] == c ||(tp->t_flags&LCASE))) {
				if(bp[-2] != '\\')
					c = maptab[c];
				bp--;
			}
		}
		*bp++ = c;
		if (bp>=canonb+CANBSIZ)
			break;
	}
	bp1 = bp;
	bp = &canonb[2];
	c = &tp->t_canq;
	while (bp<bp1)
		putc(*bp++, c);
	return(1);
}

/*
 * Place a character on raw TTY input queue, putting in delimiters
 * and waking up top half as needed.
 * Also echo if required.
 * The arguments are the character and the appropriate
 * tty structure.
 */
ttyinput(ac)
{
	register int c;
	register struct tty *tp;
	register flags;

	tp = kl11;
	c = ac;
	flags = tp->t_flags;
	c =& 0177;
	if(flags & CRMOD) if(c == '\r')
		c = '\n';
	if (c==CQUIT || c==CINTR) {
		signal(c==CINTR? SIGINT:SIGQIT);
		flushtty();
		return;
	}
	if (tp->t_rawq.c_cc>=TTYHOG) {
		flushtty();
		return;
	}
	if(flags & LCASE)
		if(c>='A' && c<='Z')
			c =+ 'a'-'A';
	putc(c, &tp->t_rawq);
	if (c=='\n' || c==004) {
		wakeup(&tp->t_rawq);
		if (putc(0377, &tp->t_rawq)==0)
			tp->t_delct++;
	}
	if(flags & ECHO) {
		ttyoutput(c);
		ttstart();
	}
}

/*
 * put character on TTY output queue, adding delays,
 * expanding tabs, and handling the CR/NL bit.
 * It is called both from the top half for output, and from
 * interrupt level for echoing.
 * The arguments are the character and the tty structure.
 */
ttyoutput(ac)
{
	register int c;
	register struct tty *rtp;
	register char *colp;

	rtp = kl11;
	c = ac&0177;
	/*
	 * Turn tabs to spaces as required
	 */
	if (c=='\t') {
		do
			ttyoutput(' ');
		while (rtp->t_col&07);
		return;
	}
	/*
	 * for upper-case-only terminals,
	 * generate escapes.
	 */
	colp = "({)}!|^~'`";
	if(rtp->t_flags & LCASE) {
		while(*colp++)
			if(c == *colp++) {
				ttyoutput('\\');
				c = colp[-2];
				break;
			}
		if ('a'<=c && c<='z')
			c =+ 'A' - 'a';
	}

	/*
	 * turn <nl> to <cr><lf> if desired.
	 */
	if(rtp->t_flags & CRMOD)
		if (c=='\n')
			ttyoutput('\r');
	if (putc(c, &rtp->t_outq))
		return;

	colp = &rtp->t_col;
	switch (c) {

	/* ordinary */
	default:
		(*colp)++;
		break;

	/* backspace */
	case 010:
		if (*colp)
			(*colp)--;
		break;

	/* newline */
	case '\n':
		*colp = 0;
		break;


	/* carriage return */
	case '\r':
		ttyoutput(0177);
		ttyoutput(0177);
		ttyoutput(0177);
		ttyoutput(0177);
		*colp = 0;
	}
}

/*
 * Start output on the typewriter. It is used from the top half
 * after some characters have been put on the output queue,
 * from the interrupt routine to transmit the next
 * character, and after a timeout has finished.
 * If the SSTART bit is off for the tty the work is done here,
 * using the protocol of the single-line interfaces (KL, DL, DC);
 * otherwise the address word of the tty structure is
 * taken to be the name of the device-dependent startup routine.
 */
ttstart()
{
	register int c;
	register struct tty *tp;

	tp = kl11;
	if ((KLADDR->kltcsr&DONE)==0)
		return;
	if ((c=getc(&tp->t_outq)) >= 0) {
		KLADDR->kltbuf = c;
	}
}

/*
 * Called from device's read routine after it has
 * calculated the tty-structure given as argument.
 * The pc is backed up for the duration of this call.
 * In case of a caught interrupt, an RTI will re-execute.
 */
ttread()
{
	register struct tty *tp;

	tp = kl11;
	if (tp->t_canq.c_cc || canon(tp))
		while (tp->t_canq.c_cc && passc(getc(&tp->t_canq))>=0);
}

/*
 * Called from the device's write routine after it has
 * calculated the tty-structure given as argument.
 */
ttwrite()
{
	register struct tty *tp;
	register int c;

	tp = kl11;
	while ((c=cpass())>=0) {
		spl7();
		while (tp->t_outq.c_cc > TTHIWAT) {
			ttstart();
			sleep(&tp->t_outq, TTOPRI);
		}
		spl0();
		ttyoutput(c);
	}
	ttstart();
}