LSX/sys/kl.c
#
/*
* 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();
}