V9/sys/dev.old/eikonix.oc

/*	dr.c	4.10	82/05/18	*/

#include "ekx.h"
/*
 * UNIBUS DR11-B driver for various graphical systems,.
 * TS
 */

#include "../h/param.h"
#include "../h/systm.h"
#include "../h/cpu.h"
#include "../h/nexus.h"
#include "../h/dk.h"
#include "../h/buf.h"
#include "../h/conf.h"
#include "../h/dir.h"
#include "../h/user.h"
#include "../h/map.h"
#include "../h/pte.h"
#include "../h/mtpr.h"
#include "../h/vm.h"
#include "../h/ubavar.h"
#include "../h/ubareg.h"
#include "../h/cmap.h"

#include "../h/ekcmd.h"

struct ekdevice{
	u_short ekgc;
	u_short ekdc;
	u_short ekgs;
	u_short ekds;
	short ekwc;
	u_short ekba;
	u_short ekcs;
	u_short ekdata;
};
struct ekctl {
	u_short mode;
	u_short dma_device;
	u_short device;
	u_short state;
} ek[NEKX];
#define	EK_GO	01
#define EK_FCTN		016
#define EK_12BIT	0
#define EK_12BITST	04
#define EK_8BIT		02
#define EK_8BITST	06
#define EK_DARK		0
#define EK_GAIN		02
#define EK_HTST		010
#define EK_GTST		012
#define EK_X1617	060
#define	EK_IE	0100
#define EK_READY	0200
#define EK_DIR	0400
#define EK_ODEV		01000
#define EK_OVER		02000
#define EK_ATTN	020000
#define	EK_NEX	040000
#define	EK_ERROR	0100000

int	ekxprobe(),ekxattach(),ekxdgo(),ekxintr();
int	ekstrategy(),ekstart();
struct	uba_ctlr *ekxminfo[NEKX];
struct	uba_device *ekxdinfo[NEKX];
struct	uba_ctlr ekctlr[NEKX];	/* ekxminfo points to this */
u_short ekxstd[]	= { 0163700, 0};	
struct	uba_driver ekxdriver =
	{ ekxprobe,0,ekxattach,ekxdgo,ekxstd,"ekx",ekxdinfo,"ekx",ekxminfo };

#define ui_open	ui_type
struct	buf	ekbuf[NEKX];
struct	buf	ekutab[NEKX];
int ct1, ct2, ct3, ct4, ct5, ct6, ct7, ct8, ct9, ct10, ct11;
short sekgs, sekds,  sekcs;
unsigned short sekwc;

/*ARGSUSED*/
ekxprobe(reg)
caddr_t reg;
{
	register int br,cvec;

#ifdef LINT
	br = 0; cvec = br; br = cvec;
#endif

/* There seems to be no way to make this vile animal
   interrupt, so we cheat...				*/

	br = 0x15;
	cvec = 0270;
}

ekxattach(ui)
register struct uba_device *ui;
{
	register struct uba_ctlr *um;
	register int unit;

	unit = ui->ui_unit;

	um = &ekctlr[unit];
	ekxminfo[unit] = um;
	ui->ui_ctlr = unit;
	ui->ui_mi = um;
	um->um_driver = ui->ui_driver;
	um->um_ctlr = unit;
	um->um_ubanum = ui->ui_ubanum;
	um->um_alive = 1;
	um->um_intr = ui->ui_intr;
	um->um_addr = ui->ui_addr;
	um->um_hd = ui->ui_hd;
}

ekxopen(dev)
dev_t dev;
{
	register int unit;

	ct1 = ct2 = ct3 = ct4 = ct5 = 0;
	ct6 = ct7 = ct8 = ct9 = 0;
	ct10 = ct11 = 0;
	unit = minor(dev);
	if((unit >= NEKX) || (ekxdinfo[unit]->ui_open)) {
		u.u_error = ENXIO;
		return;
	}
	ekxdinfo[unit]->ui_open++;
}

ekxclose(dev)
dev_t dev;
{
	register int unit;

	ekxdinfo[minor(dev)]->ui_open = 0;
}

ekxread(dev)
dev_t dev;
{
	register int unit = minor(dev);

	ct1++;
	physio(ekstrategy,&ekbuf[unit],dev,B_READ,minphys);
	ct2++;
}

ekxwrite(dev)
dev_t dev;
{
	register int unit = minor(dev);

	physio(ekstrategy,&ekbuf[unit],dev,B_WRITE,minphys);
}

/*
 * Due to the fact the ekstrategy routine is called only by ekxread
 * and ekxwrite via physio, there will only be one transaction in each
 * DR11-B's queue at any time.  Therefore, one can just tack the given
 * buffer header pointer on at the end of the queue, and call ekstart.
 */
ekstrategy(bp)
register struct buf *bp;
{
	register struct uba_device *ui;
	register struct uba_ctlr *um;
	register struct buf *dp;
	register int s;
	struct ekdevice *draddr;
	dev_t unit;

	ct3++;
	unit = minor(bp->b_dev);	/* chose a DR11-B */
	ui = ekxdinfo[unit];
	um = ui->ui_mi;		/* get ctlr ptr */
	dp = &ekutab[unit];
	s = spl5();
	dp->b_actf = bp;
	dp->b_actl = bp;
	bp->av_forw = NULL;
	um->um_tab.b_actf = dp;
	um->um_tab.b_actl = dp;

	ekstart(um);
	splx(s);
	switch(tsleep((caddr_t)bp, PRIBIO+1, 20)) {
	case TS_OK:
		break;
	case TS_SIG:	/* not supposed to happen*/
	case TS_TIME:
		draddr = (struct ekdevice *)um->um_addr;
		sekgs = draddr->ekgs;
		sekds = draddr->ekds;
		sekwc = draddr->ekwc;
		sekcs = draddr->ekcs;
		printf("gs %o ds %o wc %o cs %o\n",sekgs, sekds, sekwc, sekcs);
		printf("ct1 %o ct2 %o ct3 %o ct4 %o ct5 %o ct6 %o\n",ct1,ct2,ct3,ct4,ct5,ct6);
		printf("ct7 %o ct8 %o ct9 %o ct10 %o ct11 %o\n",ct7,ct8,ct9,ct10,ct11);
		bp->b_flags |= B_DONE | B_ERROR;
		s = spl6();
		ekxintr(unit);
		splx(s);
	}
}

ekstart(um)
register struct uba_ctlr *um;
{
	register struct buf *bp,*dp;
	register struct ekdevice *draddr;
	register struct ekctl *ekp;
	int cmd;

	dp = um->um_tab.b_actf;
	bp = dp->b_actf;
	ekp = &ek[minor(bp->b_dev)];

	um->um_tab.b_active++;
	draddr = (struct ekdevice *)um->um_addr;
	draddr->ekwc = -bp->b_bcount / sizeof (short);
	if(bp->b_flags & B_READ)
		cmd = EK_IE|EK_DIR|ekp->mode;	
	else
		cmd = EK_IE|ekp->dma_device;
	um->um_cmd = cmd|EK_GO;
	ct4++;
	draddr->ekcs = cmd;
	ct5++;
	DELAY(10);
	if( ubago(ekxdinfo[minor(bp->b_dev)])== 0)
		printf("ubago returned 0\n");
}

ekxioctl(dev, cmd, arg)
dev_t dev;
int cmd;
register caddr_t arg;
{
	register struct ekctl *ekp = &ek[minor(dev)];
	register struct uba_device *ui = ekxdinfo[minor(dev)];
	register struct ekdevice *draddr = (struct ekdevice *)ui->ui_addr;
	u_short realcmd;

	if( (cmd != EKGS) && (cmd != EKDMA)){
		if(copyin(arg, (caddr_t)&realcmd, sizeof(realcmd))){
			u.u_error = EFAULT;
			return;
		}
	}
	switch(cmd){
	case EKGC:
		draddr->ekgc = realcmd;
		return;
	case EKDC:
		draddr->ekdc = realcmd;
		return;
	case EKGS:
		realcmd = draddr->ekgs;
		break;
	case EKDS:
		draddr->ekdc = EKDC_READ|realcmd;
		realcmd = draddr->ekds;
		break;
	case EKMOD:
		ek->mode = realcmd & EK_FCTN;
		return;
	case EKDEV:
		ek->dma_device = realcmd & EK_FCTN;
		return;
	default:
		u.u_error = ENXIO;
		return;
	}
	if(copyout((caddr_t)&realcmd, arg, sizeof(realcmd)))
		u.u_error = EFAULT;
}
ekreset() {}
ekxdgo(um)
struct uba_ctlr *um;
{
	register struct ekdevice *draddr = (struct ekdevice *)um->um_addr;

	ct6++;
	draddr->ekba = um->um_ubinfo;
	draddr->ekcs = um->um_cmd|((um->um_ubinfo>>12)&EK_X1617);
	ct7++;
}
ekxintr(dr11)
register dr11;
{
	register struct buf *bp,*dp;
	register struct ekdevice *draddr;
	register struct uba_ctlr *um;
	register int stat;

	ct8++;
	um = ekxminfo[dr11];

	if(um->um_tab.b_active == 0)
		return;

	if(ekxdinfo[dr11]->ui_open == 0)
		return;
	dp = um->um_tab.b_actf;
	bp = dp->b_actf;
	draddr = (struct ekdevice *)um->um_addr;
	stat = draddr->ekcs;

	if(stat & EK_ODEV){
		ct11++;
	}

			/*should check stat&EK_OVER for retry*/
	if((stat&EK_ERROR) && draddr->ekwc && (draddr->ekba == 0)) {
		draddr->ekcs = um->um_cmd|(((um->um_ubinfo>>12)+1)&EK_X1617);
		ct10++;
	}

	um->um_tab.b_active = 0;
	um->um_tab.b_errcnt = 0;
	um->um_tab.b_actf = dp->b_forw;
	dp->b_errcnt = 0;
	dp->b_active = 0;
	bp->b_resid = (-draddr->ekwc * sizeof(short));
	ubadone(um);
	iodone(bp);
	ct9++;
}