Interdata_v6/usr/sys/cli.c
#
/*
* Current Loop Interface Driver
*
*/
#include "param.h"
#include "conf.h"
#include "proc.h"
#include "tty.h"
#include "user.h"
#define NCLI 1 /* number of terminals */
char cliaddr[NCLI] { /* cli addresses */
02
};
struct tty cli[NCLI]; /* common tty structure */
#define devmap(addr) &cli[addr-02] /* map phys addr => tty */
/* Current Loop Interface Command and Status Bits */
/* commands */
#define DISABLE 0200
#define ENABLE 0100
#define UNBLOCK 0040
#define BLOCK 0020
#define WRITE 0010
#define READ 0004
/* status */
#define OV 0200
#define BRK 0040
#define BSY 0010
#define EX 0004
#define DU 0001
#define WINIT WOPEN /* waiting to change mode read->write */
/*
* open routine:
* called each time a process opens a terminal as a character file
*
* - if the terminal was previously inactive, set up the initial status
* and arm interrupts
*/
cliopen(dev,flag)
{
register struct tty *tp;
int clistart();
if (dev.d_minor >= NCLI) { /* minor device number too large ? */
u.u_error = ENXIO; /* yes, return error */
return;
}
tp = &cli[dev.d_minor]; /* get tty struct for terminal */
tp->t_dev = dev; /* set device number in tty struct */
if ((tp->t_state & ISOPEN) == 0) {
tp->t_state = ISOPEN | CARR_ON | SSTART;
if (tp->t_flags == 0)
tp->t_flags = XTABS | LCASE | CRMOD | ECHO;
tp->t_erase = CERASE;
tp->t_kill = CKILL;
tp->t_addr = &clistart; /* special output start routine */
cliparam(tp); /* enable read and set parms */
trace(0x1000,"cliopen rd:",rd(cliaddr[dev.d_minor]));
}
if (u.u_procp->p_ttyp == 0) /* give a process to the tty */
u.u_procp->p_ttyp = tp;
}
/*
* close routine:
* - called only when last process using terminal releases it
*/
cliclose (dev)
{
register struct tty *tp;
tp = &cli[dev.d_minor]; /* find tty struct for terminal */
wflushtty(tp); /* flush queues */
tp->t_state = 0; /* clear status */
oc(cliaddr[dev.d_minor], DISABLE | READ | BLOCK); /* disable read */
}
/*
* read, write, stty, gtty routines:
* - call standard tty routines
*/
cliread(dev)
{
ttread(&cli[dev.d_minor]);
}
cliwrite(dev)
{
ttwrite(&cli[dev.d_minor]);
}
clisgtty(dev, v)
{
register struct tty *tp;
tp = &cli[dev.d_minor];
ttystty(tp, v);
if ( (v==0) && !(tp->t_state & BUSY)) /* if read and if ECHO, set hardware echo */
cliparam(tp);
}
/*
* set device parameters
* enable read; if ECHO, enable hardware echo.
*
*/
cliparam(tp)
struct tty *tp;
{
/***
oc(cliaddr[tp->t_dev.d_minor], ENABLE | READ | ((tp->t_flag & ECHO) ?
UNBLOCK : BLOCK));
***/ oc(cliaddr[tp->t_dev.d_minor], ENABLE | READ | BLOCK);
return;
}
/*
*
* When the interface changes from read to write, an interrupt
* is generated. This is where we enable the transmit side.
* If busy is set , then a write is in progress and there is
* nothing to do.
*
*/
clistart(atp)
struct tty *atp;
{
register struct tty *tp;
tp = atp;
if ( !(tp->t_state & BUSY)) {
tp->t_state =| (WINIT | BUSY); /* set winit flag */
oc(cliaddr[tp->t_dev.d_minor], ENABLE | WRITE | BLOCK ); /* enable write */
}
}
/*
* second level output start routine
*
* This routine is called from cliint on write interrupt
* to send a character.
*
*/
clistrto(atp)
struct tty *atp;
{
int ttrstrt();
register struct tty *tp;
register c;
tp = atp;
/* get character to output */
c = getc(&tp->t_outq);
if (c < 0) /* no more chars on outq, start reading */
{
cliparam(tp); /* enable read */
return;
}
if (c > 0177) {
/* timeout delay */
tp->t_state =| TIMEOUT;
timeout(&ttrstrt, tp, c&0177);
} else {
/* write character to device */
tp->t_state =| BUSY;
wd(cliaddr[tp->t_dev.d_minor], c);
trace(0x1000, "wrt", ss(cliaddr[tp->t_dev.d_minor]));
}
}
/* interrupt handler
*/
cliint(addr,stat)
int addr;
int stat;
{
register struct tty *tp;
register c;
tp = devmap(addr);
if ( !(tp->t_state & ISOPEN)) /* return if device not open */
return;
if (tp->t_state & BUSY) /* if write enable or write complete */
{
if (stat & BRK) /* if BRK key hit */
{
trace(0x1000,"brk :",0);
c = CINTR; /* set character to del */
tp->t_state =& ~(BUSY | WINIT); /* reset flags */
cliparam(tp); /* reset to read mode */
ttyinput(c, tp);
}
else
if (tp->t_state & WINIT)
{
/* if WINIT, interrupt was write enable */
trace(0x1000, "WINIT", stat);
tp->t_state =& ~(BUSY | WINIT);
clistrto(tp);
}
else
{
/* else interrupt was write complete */
trace(0x1000, "wint", stat);
tp->t_state =& ~BUSY;
clistrto(tp);
if (tp->t_outq.c_cc <= TTLOWAT && (tp->t_state&ASLEEP))
{
tp->t_state =& ~ASLEEP;
wakeup(&tp->t_outq);
}
}
}
else /* read complete interrupt */
{
trace(0x1000, "rint", stat);
c = rd(addr) & 0177;
trace(0x1000, "c = ", c);
ttyinput(c, tp);
}
trace(0x1000,"int exit ss:",ss(addr));
trace(0x1000,"t_state",tp->t_state);
trace(0x1000,"addr",addr);
}