BBN-V6/dmr/gnn.c

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

#
/*
 *      Genisco display driver
 *
 *      Bruce Borden				 4-Sep-77
 *		VTUNIX Modifications
 */

#include "../h/param.h"
#include "../h/conf.h"
#include "../h/buf.h"
#include "../h/user.h"
#include "../h/old_tty.h"
#include "../h/proc.h"

/* #define GNTTTY  1               /* define for v-terminal driver */
#define GNRAND  1               /* define for Rand Genisco */
/* #define GNHIRES   1             /* define for high-resolution config */
/* #define GNNOSC  1               /* define for NOSC Genisco */
/* #define RANDEBUG 1              /* horrible kludge for debugging */

struct {
	int gnopen;             /* open count */
	char *gnbp;             /* buffer pointer */
	char *gnbuf;		/* buffer data area */
	char *gnenbuf;          /* room for one more defn */
	char gnpc;              /* program counter of pgp (saved during dump) */
	char gnstate;           /* see states below */
} gn;


/* gnstate flags */

#define BUSY    01              /* Buffer busy flag */
#define WAITING 02              /* Someone waiting for the buffer */
#define GNTIO   04              /* io in progress from term device */

/* external page device registers */
struct {
	int noop;
	int strt;
	int clr;
	int iopls;
	int doc;
	int dob;
	int doa;
	int nio;
};

#define GEN     0167730         /* 0167750 for HI-RES B/W */

#ifdef GNNOSC
#ifdef GNHIRES
#define GEN     0167750
#endif
#endif

#define GNPRI   1               /* sleep priority - pretty high */


gnopen(dev)
{
	gn.gnopen++;
	if(gn.gnbp == 0) {
		gn.gnbp = getblk(NODEV);
		gn.gnbuf = gn.gnbp->b_addr;
		gn.gnenbuf = &gn.gnbuf[512-26]; /* 24 chars needed for defn */
	}                                       /* so have 2 for slop */
}

gnclose(dev)
{

	if(--gn.gnopen == 0) {
		gn.gnstate = 0;
		if(gn.gnbp != 0) {
#ifdef BUFMOD
			brelse(gn.gnbp,&bfreelist);
#endif
#ifndef BUFMOD
			brelse(gn.gnbp);
#endif BUFMOD
			gn.gnbp = 0;
		}
	}
}

/* Returns at Priority Level 5 with Genisco BUFFER not busy     */
/*      but with state flagged buffer BUSY                      */
gnwait()
{
	spl5();
	while (gn.gnstate&BUSY) {
		gn.gnstate =| WAITING;
		sleep(gn.gnbp,GNPRI);   /* wait on the buffer */
	}
	gn.gnstate =& ~WAITING;
	gn.gnstate =| BUSY;
	/* spl0(); */
}

gnint()
{
	GEN->nio = 0;	/* ack the interrupt, i hope */
	GEN->clr++;
#ifdef GNTTTY
	if (gn.gnstate&GNTIO) {
		gn.gnstate =& ~(GNTIO|BUSY);
		gntstart();
	} else
#endif
	wakeup(&gn);
}

gnread(dev)
{
	register c, tc, n;

	switch(dev.d_minor) {
case 0:		/* dump pgp memory */
		c = u.u_count;
		if(u.u_offset[1] + u.u_count >= 512) {
			if(u.u_offset[1] >= 512)
				return;		/* eof */
			c = 512-u.u_offset[1];
		}
		gnwait();       /* Returns at level 5 */
		gn.gnpc = GEN->dob.hibyte & 0377;     /* save the pgp pc */
		GEN->noop++;
		GEN->doa = (gn.gnbuf>>1)&077777; /* address */
		GEN->noop++;
		GEN->dob = -256;        /* word count */
		GEN->clr++;             /* set direction */
		GEN->doc = 0;		/* address */
		GEN->clr++;             /* start it */
		sleep(&gn, GNPRI);      /* wait for completion */
		if (GEN->dob != 0)
			u.u_error = EIO;
		GEN->doc = gn.gnpc;     /* restore the pgp pc */
		GEN->noop++;
		spl0();
		iomove(gn.gnbp, u.u_offset[1], c, B_READ);
		break;

case 1:		/* read from pgp */
		gnwait();
		while(u.u_count) {
			tc = c = min(u.u_count,512);
			if (c&01) tc++;
			GEN->doa = (gn.gnbuf>>1)&077777;
			GEN->clr++;
			GEN->dob = -(tc>>1);
			GEN->strt++;    /* start the pgp */
			sleep(&gn, GNPRI);      /* wait for completion */
			/* resid count */
			if (n = GEN->dob.lobyte)
				c = tc + (n|0177400) << 1;

			iomove(gn.gnbp, 0, c, B_READ);
			if (n) break;
		}
	}
	spl0();
	gn.gnstate =& ~BUSY;            /* Buffer no longer busy */
#ifdef GNTTTY
	gntstart();                     /* start term i/o if needed */
#endif
	if((gn.gnstate&(WAITING|BUSY)) == WAITING)
		wakeup(gn.gnbp);        /* wake them up */
}

gnwrite(dev)
{
	register tc, c, n;

	switch(dev.d_minor) {
case 0:		/* load */
		c = u.u_count;
		if(c <= 0 || u.u_offset[1] >= 512)
			return;
		if(u.u_offset[1] + c > 512)
			c = 512 - u.u_offset[1];
		n = u.u_offset[1];
		gnwait();
		iomove(gn.gnbp,u.u_offset[1],c,B_WRITE);

		/* Handle odd boundaries and counts */
		if (n&01)
		{       c++;
			gn.gnbuf[--n] = '\0';
		}
		if ((n+c)&01)
			gn.gnbuf[n + c++] = '\0';

		GEN->doa = ((gn.gnbuf+n)>>1)&077777;
		GEN->iopls++;
		GEN->dob = -(c>>1);
		GEN->noop++;
		GEN->doc = n>>1;
		GEN->clr++;              /* start it */
		sleep(&gn, GNPRI);      /* wait for completion */
		if (GEN->dob != 0)
			u.u_error = EIO;
		break;

case 1:		/* write */
		gnwait();
		while(u.u_count) {
			tc = c = min(u.u_count,512);
			iomove(gn.gnbp,0,c,B_WRITE);
			if (c&01) /* If count is odd, pad with null */
				gn.gnbuf[tc++] = '\0';
			GEN->doa = (gn.gnbuf>>1)&077777;
			GEN->iopls++;   /* set write */
			GEN->dob = -(tc>>1);
			GEN->strt = 0;
			sleep(&gn, GNPRI);      /* wait for completion */

			n = GEN->dob.lobyte;
		/*      printf ("n = %d ucount = %d\n",n,u.u_count); */

			if (n)
			{       u.u_count =- (((n|0177400)<<1) + (c&01));
				break;
			}
		}
	}
	spl0();
	gn.gnstate =& ~BUSY;            /* Buffer no longer busy */
#ifdef GNTTTY
	gntstart();                     /* start term i/o if needed */
#endif
					/* if anyone wants the buf */
	if((gn.gnstate&(WAITING|BUSY)) == WAITING)
		wakeup(gn.gnbp);        /* wake them up */
}

gnsgty(dev,v)
int *v;
{

	if(v) {		/* gtty */
		v[0] = 0;
		v[1] = GEN->doc;
		GEN->noop++;
		v[2] = GEN->dob.hibyte & 0377;
		GEN->noop++;
		return;
	}
	switch(u.u_arg[0]) {

case 0100001:	/* start */
		if(u.u_arg[2].hibyte)
			GEN->nio++;     /* bad addr - no set */
		else
			GEN->doc = u.u_arg[2];
		GEN->strt++;
		return;

case 0100002:	/* stop or single step */
		GEN->nio = 0;
		GEN->iopls++;
		return;

	}
	u.u_error = EINVAL;	/* bad argument */
}

#ifdef  GNTTTY                  /* Genisco Virtual Terminal Interface */


/************ Declarations for terminal devices *************/

#define	NGNWINS 16	/* # of windows pgp can handle      */

#ifdef GNHIRES
#define GNCWIDTH 12     /* Width of Genisco characters      */
#define GNCHEIGHT 24    /* Height of Genisco characters     */
#endif
#ifndef GNHIRES
#define GNCWIDTH 6      /* Width of Genisco characters      */
#define GNCHEIGHT 12    /* Height of Genisco characters     */
#endif

#define GNFLAG    0200  /* Flag char for Genisco escapes    */
#define GNSETWIN  0176  /* Genisco set window command is    */
                        /*  GNFLAG followed by GNSETWIN     */
#define HISPEED   14    /* use OPTIONA as speed             */
#define GNTLINES  42
#define GNTCOLS   85
#define GNQUANTA  50	/* Num chars output per window	    */

#ifdef GNNOSC           /* NOSC defns   *********************/
#define NGNCRT  3       /* Number of Genisco CRTs on sys    */
int gnplanes[NGNCRT] {   07,  070,  0700 } ;
#endif                                          /************/

#ifdef RANDEBUG         /* debug defns  *********************/
#define NGNCRT  3       /* Number of Genisco CRTs on sys    */
int gnplanes[NGNCRT] {   01,  02,  04 } ;
#endif                                          /************/

#ifdef GNRAND           /* RAND defns   *********************/
#define NGNCRT  1       /* Number of Genisco CRTs on sys    */
#ifdef GNHIRES
int gnplanes[NGNCRT] {  017 } ;
#endif
#ifndef GNHIRES
int gnplanes[NGNCRT] {  007 } ;
#endif
#endif                                          /************/

struct	tty gnt11[NGNCRT];
char	gntmap[NGNWINS];

extern struct vterm vt_structures[];

/************ End declarations for terminal devices *********/

gntopen(dev, flag)
{
	register struct tty *tp;
	register struct vterm *vt;
	extern gntstart(), gntwmap();

	if(dev.d_minor >= NGNCRT) {
		u.u_error = ENXIO;
		return;
	}
	tp = &gnt11[dev.d_minor];
	if((tp->t_state&ISOPEN) == 0) {
		tp->t_state = ISOPEN|CARR_ON|SSTART;
		tp->t_flags = CRMOD;
		tp->t_addr  = gntstart;
		tp->t_dev   = dev;
		tp->t_speed = HISPEED | (HISPEED<<8);
		gnopen(-1);             /* Get a sys buffer if needed */
		if(vt_open(tp))         /* turn into a vt */
			return;
		vt = tp->t_vterm;
		if(gntwmap(vt)) {
			u.u_error = ENOSPC;
			return;
		}
		vt->v_curw.w_lrhc.integ = vt->v_maxw.w_lrhc.integ =
			((GNTLINES-1)<<8)|(GNTCOLS-1);
		vt->v_flags =| LEVEL8; /* 8-Bit Data Path flag */
		vt->v_flags =& ~VTLOCK; /* Not KBD locked! */
		vt->v_caddr = gntwmap;
	}
}


gntclose(dev)
{
	register struct tty *tp;

	tp = &gnt11[dev.d_minor];
	tp->t_state = 0;
	gnwait();               /* wait for buf not busy */
	  gn.gnstate =& ~BUSY;  /* don't really want the buf at all */
	  spl0();
	vt_ttclose(tp);
	gnclose(-1);            /* just don't want this to give up */
				/*   active buffer */
}


gntwrite(dev)
{
	ttwrite(gnt11[dev.d_minor].t_vterm);
}

gntread(dev)
{
	ttread(gnt11[dev.d_minor].t_vterm);
}

gntsgtty(dev, v)
{
	register struct tty *tp;

	tp = &gnt11[dev.d_minor];
	if(vt_ttsgtty(tp->t_vterm, v) == 0)
		tp->t_flags =& ~(NLDELAY|TBDELAY|CRDELAY|VTDELAY);
}


gntstart()
{
	register struct tty *tp;
	register struct vterm *vt;
	register char *cp;
    /***int sps; ***/
	int windef[5], cnt, quant;
	static struct tty *curtty;
	char *cw;

	if(gn.gnstate&BUSY) return;
    /***sps = PS->integ;
	spl5();         ***/
	cp = gn.gnbuf;
	if((tp = curtty) == 0)
		if((tp = gntgwork()) == 0)
			goto out;       /* No Work for the nonce */
		else
			goto setwin;    /* This must be new window */

	do {

		if(tp->t_state&KBDSYNC) { /* Currently, this has no meaning */
			tp->t_state =& ~KBDSYNC;
			if(tp->t_kbd) {
				tp->t_screen = tp->t_kbd;
				if(tp->t_screen->v_outq.c_cc)
					goto setwin;
			}
		}

		if((vt = tp->t_screen) == 0 || vt->v_state&VT_CLOSED)
			goto next;              /* This screen unusable */

		if(vt->v_flags & VIRGIN)        /* window redefined! */
			goto setwin;

		quant = GNQUANTA;	/* smoothing factor */
		while(quant-- && (cnt = getc(&vt->v_outq)) >= 0) {
			if(cnt == 0 || cnt == GNFLAG) {
				*cp++ = GNFLAG;
				*cp++ = ~cnt;
			} else
				*cp++ = cnt;
			if(cp >= &gn.gnbuf[510]) /* leave room for 2 chars */
				goto send;
		}
		if(vt->v_state&VT_OSLEEP && vt->v_outq.c_cc <= TTLOWAT) {
			vt->v_state =& ~VT_OSLEEP;
			wakeup(&vt->v_outq);    /* wake oput blocked procs */
		}
   next:
		if(cp >= gn.gnenbuf || !(gnt_nxo(tp) || (tp = gntgwork())))
			break;                  /* No more to do */
   setwin:
		vt = tp->t_screen;
		*cp++ = GNFLAG;                 /* Select this window */
		if((*cp++ = vt->v_mapw) == 0)
			panic("Missing Mapped Genisco Window");
		if(vt->v_flags&VIRGIN) {        /* First time ?? */
			cw = &vt->v_curw;       /* Current Window def */
			windef[0] = cw->w_ulhc.cr_row * GNCHEIGHT;
			windef[1] = (cw->w_lrhc.cr_row + 1)
				    * GNCHEIGHT + windef[0];
			windef[2] = cw->w_ulhc.cr_col * GNCWIDTH;
			windef[3] = (cw->w_lrhc.cr_col + 1)
				    * GNCWIDTH + windef[2];
			windef[4] = gnplanes[tp->t_dev.d_minor];

			*cp++ = GNFLAG; *cp++ = GNSETWIN;
			for(cw = windef; cw < &windef[5];)
/* This line:
 *				if(*cw == 0 || *cw == GNFLAG) {
 * had sign extension problems... the following line only works
 * if GNFLAG == 0200!!
 */
				if((*cw & 0177) == 0) {
					*cp++ = GNFLAG;
					*cp++ = ~*cw++;
				} else
					*cp++ = *cw++;

			vt->v_flags =& ~VIRGIN; /* No Longer Virgin */
		}

		curtty = tp;

	} while(cp < gn.gnenbuf);               /* Glutton... eat till full */

 send:  if(cnt = cp - gn.gnbuf) {

		if(cnt&01) {
			*cp++ = 0;
			cnt++;
		}

#ifdef DEBUG
		VT_DB3 {
			printf("GNN:Writing %d:", cnt);
			for(cp=gn.gnbuf; cp<&gn.gnbuf[cnt];cp++) {
				if(((cp-gn.gnbuf)%10) == 0) printf("\n");
				printf(" %o", *cp&0377);
			}
			printf("\n");
		}
#endif

		GEN->doa = (gn.gnbuf>>1)&077777;
		GEN->iopls++;                   /* set write */
		GEN->dob = -(cnt>>1);
		GEN->strt = 0;
		gn.gnstate =| BUSY|GNTIO;  /* flag buf busy & term i/o  */
					   /*  in progress              */
	} else if(gn.gnstate & WAITING)    /* If no term i/o, start any */
		wakeup(gn.gnbp);           /* direct i/o if desired     */

  out:  ;
   /*   PS->integ = sps;  */
}


gntgwork()
{
	register struct tty *tp;
	register struct vterm *vt;

/*      Redundant code below...  mob:12/19/77 */
/*      for(tp = gnt11; tp < &gnt11[NGNCRT]; tp++)
		if((tp->t_state&ISOPEN) && vt_nxo(tp))
			return(tp);
*/
	for(tp = gnt11; tp < &gnt11[NGNCRT]; tp++)
		if((tp->t_state&ISOPEN) && gnt_nxo(tp))
			return(tp);
	return(0);
}


gntgvt(dev)
{
	int minor;

	if((minor = dev.d_minor) >= NGNCRT)
		return(0);
	return(gnt11[minor].t_vterm);
}

gnt_nxo(atp)
struct tty *atp;
{
	register struct tty *tp;
	register struct vterm *vt;

	tp = atp;
	if(vt = vt_nxo(tp))
		return(vt);
	if((vt = tp->t_screen)->v_outq.c_cc)
		return(vt);
	return(0);
}

gntwmap(avt)
struct vterm *avt;
{
	register struct vterm *vt;
	register int i;

	if((vt = avt) == 0)
		panic("Zero VT");
	if(i = vt->v_mapw) {
		gntmap[i - 1] = 0;
		vt->v_mapw = 0;
		return(0);
	} else {
		for(i = 0; i < NGNWINS; i++)
			if(gntmap[i] == 0) {
				gntmap[i] = (vt - vt_structures) + 1;
				vt->v_mapw = i + 1;
				return(0);
			}
		return(1);
	}
}