BBN-V6/dmr/dc.c

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

#
/*
 *  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;
	}
}