BBN-V6/dmr/dc.c
#
/*
* Written by John Lowry, 1975
*/
/*
* DC-11 driver
*/
#include "../h/param.h"
#include "../h/user.h"
#include "../h/old_tty.h"
#include "../h/proc.h"
#include "../h/conf.h"
#include "../h/buf.h"
/* base address */
#define DCADDR 0174000
#define NDC11 1 /* was 14 */
#define DCPRI 5
/* Control bits */
#define CDLEAD 01
#define CARRIER 04
#define SPEED1 030 /* was 010 */
#define STOP1 0400
#define READY 0200
#define RQSEND 01
#define PARITY 040
#define ERROR 0100000
#define CTRANS 040000
#define RINGIND 020000
#define CTSEND 02
#define RCVFLG 02 /* same was WOPEN, which is not needed here */
struct dcregs {
int dcrcsr;
int dcrbuf;
int dctcsr;
int dctbuf;
};
#define PS 0177776
int ps;
struct
{ char *dc_buf;
char *dc_bufp;
int dc_sent;
int dc_grabbed;
} dcb[4]; /* to be assigned system buffers */
struct
{ int dc_state;
int dc_flags;
int cur_buf; /* which of dcb[*] has the last character */
int dc_uid;
char dc_poke;
char dc_wakeup;
int dc_nxmit;
} hdc11;
struct tty dc11[NDC11];
int dcrstab[] {
0, /* 0 baud */
0, /* 50 baud */
0, /* 75 baud */
0, /* 110 baud */
01101, /* 134.5 baud: 7b/ch, speed 0 */
0111, /* 150 baud: 8b/ch, speed 1 */
0, /* 200 baud */
0121, /* 300 baud: 8b/ch, speed 2 */
0, /* 600 baud */
0131, /* 1200 baud */
0, /* 1800 baud */
0, /* 2400 baud */
0, /* 4800 baud */
0, /* 9600 baud */
0, /* X0 */
0, /* X1 */
};
int dctstab[] {
0, /* 0 baud */
0, /* 50 baud */
0, /* 75 baud */
0, /* 110 baud */
0501, /* 134.5 baud: stop 1 */
0511, /* 150 baud */
0, /* 200 baud */
0521, /* 300 baud */
0, /* 600 baud */
0130, /* 1200 baud:no RQSEND */
0, /* 1800 baud */
0, /* 2400 baud */
0, /* 4800 baud */
0, /* 9600 baud */
0, /* X0 */
0, /* X1 */
};
dcopen(dev, flag)
{
register struct tty *rtp;
register *addr;
extern dcstart();
int i;
if (dev.d_minor > NDC11) /* not >= since we got one and are */
{ u.u_error = ENXIO; /* using it two ways */
return;
}
if (dev.d_minor == 1) /* half duplex */
{
if ((hdc11.dc_state &ISOPEN ) || (rtp->t_state&ISOPEN))
{ u.u_error = EBUSY; /* must check both tables!!! */
return;
}
hdc11.dc_state = ISOPEN;
hdc11.dc_flags = EVENP;
hdc11.dc_uid = u.u_uid;
DCADDR -> dcrcsr = IENABLE|CDLEAD|SPEED1;
DCADDR -> dctcsr = IENABLE|SPEED1|RQSEND;
hdc11.cur_buf = 0;
hdc11.dc_poke = 0;
hdc11.dc_nxmit = 0;
for (i=0; i<4; i++)
dcb[i].dc_grabbed = 0;
}
else /* full duplex */
{
rtp = &dc11[dev.d_minor];
rtp->t_addr = addr = DCADDR + dev.d_minor*8;
rtp->t_state =| WOPEN;
addr->dcrcsr =| IENABLE|CDLEAD;
if (((rtp->t_state&ISOPEN) == 0) && /* check both here, too */
((hdc11.dc_state &ISOPEN) == 0)) {
rtp->t_erase = CERASE;
rtp->t_kill = CKILL;
addr->dcrcsr = IENABLE|CDLEAD|SPEED1;
addr->dctcsr = IENABLE|SPEED1|STOP1|RQSEND;
rtp->t_state = ISOPEN | WOPEN;
rtp->t_flags = ODDP|EVENP|ECHO;
}
if (addr->dcrcsr & CARRIER)
rtp->t_state =| CARR_ON;
while ((rtp->t_state & CARR_ON) == 0)
sleep(&rtp->t_rawq, TTIPRI);
ttyopen(dev, rtp);
}
}
dcclose(dev)
{ register int i;
register struct tty *tp;
if (dev.d_minor == 1) /* half duplex */
{
hdc11.dc_state = 0;
DCADDR -> dcrcsr = 0;
DCADDR -> dcrcsr = CDLEAD;
for (i=0; i<4; i++)
if (dcb[i].dc_grabbed) {
#ifdef BUFMOD
brelse(dcb[i].dc_buf,&bfreelist);
#endif
#ifndef BUFMOD
brelse(dcb[i].dc_buf);
#endif BUFMOD
dcb[i].dc_buf = 0;
}
}
else /* full duplex */
{
(tp = &dc11[dev.d_minor])->t_state = 0;
if (tp->t_flags&HUPCL)
tp->t_addr->dcrcsr =& ~CDLEAD;
wflushtty(tp);
}
}
dcwrite(dev) /* Write grabs the system buffers for read */
{ register int i; /* It is done here because it's too late */
register char *bp; /* to do it if you're in read already. */
/* Write uses only one buffer for itself */
/* since it's very unlikely a user will */
/* send more than 50 chars--much less 512 */
/* (Above refers to half duplex operation) */
if (dev.d_minor == 1) /* half duplex */
{
if (u.u_count==0)
return;
for (i=0; i<4; i++)
if (dcb[i].dc_grabbed==0)
{ dcb[i].dc_buf = getblk(NODEV);
dcb[i].dc_bufp = dcb[i].dc_buf -> b_addr;
dcb[i].dc_sent = 0;
dcb[i].dc_grabbed = 1;
}
while (hdc11.dc_nxmit)
{ hdc11.dc_wakeup++;
sleep (&hdc11.dc_wakeup, DCPRI);
}
dcb[0].dc_bufp = bp = dcb[0].dc_buf->b_addr;
hdc11.dc_nxmit = u.u_count > 512 ? 512 : u.u_count;
iomove(dcb[0].dc_buf, 0, hdc11.dc_nxmit, B_WRITE);
dcstart();
}
else /* full duplex */
ttwrite(&dc11[dev.d_minor]);
}
dcxint(dev)
{
register struct tty *tp;
if (dev.d_minor == 1) /* half duplex */
{
if (hdc11.dc_state & RCVFLG) /* last dcstart was for an eot */
{ DCADDR -> dctcsr =& ~RQSEND;
hdc11.cur_buf = 0;
dcb[0].dc_bufp = dcb[0].dc_buf -> b_addr;
}
else
dcstart();
}
else /* full duplex */
{
ttstart(tp = &dc11[dev.d_minor]);
if (tp->t_outq.c_cc == 0 || tp->t_outq.c_cc == TTLOWAT)
wakeup(&tp->t_outq);
}
}
dcstart ()
{ register int c;
extern char partab[];
if ((DCADDR->dctcsr&READY) == 0 ||
(hdc11.dc_state&(RCVFLG & ISOPEN) != ISOPEN)) return;
if ((DCADDR->dctcsr & CTSEND) == 0)
{ timeout (&dcstart, 0, 12);
return;
}
if (--hdc11.dc_nxmit >= 0)
{ ps = PS -> integ;
spl5();
c = (*dcb[0].dc_bufp++);
DCADDR -> dctbuf = c =| (partab[c]&0200);
if ((c & 0177) == 004)
hdc11.dc_state =| RCVFLG;
PS->integ = ps;
}
else
{ hdc11.dc_nxmit = 0;
if (hdc11.dc_wakeup)
{ hdc11.dc_wakeup = 0;
wakeup (&hdc11.dc_wakeup);
}
}
}
dcrint(dev)
{
register struct tty *tp;
register int c; /* rint reads until it gets an <eot> or */
register int csr; /* until it runs out of buffer space. */
/* It tells read it's through by the */
/* wakeup on dc11.dc_poke.(It won't run */
/* out of space if you grab 4 buffers.) */
/* (Above refer to half duplex operation)*/
if (dev.d_minor == 1) /* half duplex */
{
c = DCADDR -> dcrbuf;
csr = DCADDR -> dcrcsr;
if ((csr & ERROR) == 0) /* not ctrans, overrun, or ring */
{ csr =& PARITY;
if (csr&&(hdc11.dc_flags&ODDP) ||
!csr&&(hdc11.dc_flags&EVENP))
{ if (dcb[hdc11.cur_buf].dc_bufp <
dcb[hdc11.cur_buf].dc_buf->b_addr + 512)
{ *dcb[hdc11.cur_buf].dc_bufp++ = (c & 0177);
}
else if (hdc11.cur_buf < 3)
{ dcb[hdc11.cur_buf++].dc_sent = 1;
*dcb[hdc11.cur_buf].dc_bufp++ = (c & 0177);
++hdc11.dc_poke;
wakeup (&hdc11.dc_poke);
}
else c = 004;
if ((c & 0177) == 004) /* turn the line around */
{ DCADDR -> dctcsr =| RQSEND;
hdc11.dc_state =& ~RCVFLG;
dcb[hdc11.cur_buf].dc_sent = 1;
++hdc11.dc_poke;
wakeup (&hdc11.dc_poke);
}
}
}
}
else /* full duplex */
{
tp = &dc11[dev.d_minor];
c = tp->t_addr->dcrbuf;
/*
* If carrier is off, and an open is not in progress,
* knock down the CD lead to hang up the local dataset
* and signal a hangup.
*/
if (((csr = tp->t_addr->dcrcsr) & CARRIER) == 0) {
if ((tp->t_state&WOPEN) == 0) {
tp->t_addr->dcrcsr =& ~CDLEAD;
if (tp->t_state & CARR_ON)
signal(tp, SIGHUP);
flushtty(tp);
}
tp->t_state =& ~CARR_ON;
return;
}
if (csr&ERROR || (tp->t_state&ISOPEN)==0) {
if (tp->t_state&WOPEN && csr&CARRIER)
tp->t_state =| CARR_ON;
wakeup(tp);
return;
}
csr =& PARITY;
if (csr&&(tp->t_flags&ODDP) || !csr&&(tp->t_flags&EVENP))
ttyinput(c, tp);
}
}
dcread(dev) /* read wakes up each time a system buffer becomes full */
{ register char *bp, **epp;
int count;
register int i;
if (dev.d_minor == 1) /* half duplex */
{
while (hdc11.dc_poke == 0)
sleep (&hdc11.dc_poke, DCPRI);
for (i=0; i <= hdc11.cur_buf;i++)
if (dcb[i].dc_sent==1)
{ count = ((i==hdc11.cur_buf) ?
dcb[i].dc_bufp - (dcb[i].dc_buf->b_addr) :512);
iomove (dcb[i].dc_buf, 0, count, B_READ);
++dcb[i].dc_sent;
}
hdc11.dc_poke = 0;
if (!(hdc11.dc_state & RCVFLG)) /* xmit state; clean up */
for (i=0; i<4; i++) { /* and release buffers */
#ifdef BUFMOD
brelse(dcb[i].dc_buf,&bfreelist);
#endif
#ifndef BUFMOD
brelse(dcb[i].dc_buf); /* until the next write */
#endif BUFMOD
dcb[i].dc_buf = 0; /* call grabs 'em again */
hdc11.cur_buf = 0;
dcb[i].dc_sent = 0;
dcb[i].dc_grabbed = 0;
}
}
else /* full duplex */
ttread(&dc11[dev.d_minor]);
}
dcsgtty(dev, av)
int *av;
{
register struct tty *tp;
register r;
if (dev.d_minor == 1) /* half duplex */
{ /* modes for nytib cemented in */
}
else /* full duplex */
{
tp = &dc11[dev.d_minor];
if (ttystty(tp, av))
return;
if (r = dcrstab[tp->t_speeds.lobyte&017])
tp->t_addr->dcrcsr = r;
else
tp->t_addr->dcrcsr =& ~CDLEAD;
if (r = dctstab[tp->t_speeds.hibyte&017])
tp->t_addr->dctcsr = r;
}
}