V9/sys/dev.old/ju.c

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

/* Jupiter driver -- both 8 bit programmed i/o and 16 bit dma i/o */

#include "ju.h"
#include "../h/param.h"
#include "../h/dir.h"
#include "../h/user.h"
#include "../h/buf.h"
#include "../h/pte.h"
#include "../h/ubavar.h"
#include "../h/ubareg.h"
#include "../h/systm.h"

#define JUPRI PZERO+10
#define JULOWAT 50

struct judevice {
	unsigned short	jucsr,	/* interface card csr */
		jutc,	/* transfer count */
		juba,	/* bus address */
		juxba,	/* extended bus address */
		judcsr,	/* device csr */
		judcw,	/* device command word */
		judsw,	/* device status word */
		juvec;	/* interrupt vector */
};

#define JBUFSIZ	512
#define JUSIZ (2*JBUFSIZ)

#define JNTRIES 2000
#define MAXSAME 60
struct ju {
	unsigned char jucbuf[JUSIZ];	/* one buffer */
	unsigned char *jur, *juw;	/* two chasing pointers */
	int jucc;		/* char count to dismbiguate */
	unsigned short flag;		/* the case of jur == juw */
	unsigned int writes, lastwrite;
	unsigned short samewrite;
	int waitcount;
} jutab[NJU];

int jutimeout;
int waitpoke, timerpoke;
/* FLAG BITS */
#define OPEN	010
#define DIWAIT	020
#define DEBUG	040
#define ASLP	0100
#define ESLP	0200
#define DMA	0400
#define TIWAIT	01000

/*	I/O LOCATIONS	*/
#define	DA	0777320
#define	CSR	DA+0
#define TC	DA+02
#define BA	DA+04
#define XBA	DA+06
#define DCSR	DA+010
#define DCW	DA+012
#define DSW	DA+014
#define VEC	DA+016
/*
	DA	device base address
	CSR	csr for interface card
	TC	transfer count
	BA	bus address
	XBA	extended bus address
	DCSR	csr for device
	DCW	command word to device
	DSW	status word from device
	VEC	interrupt vector
*/

/*	BIT DEFINITIONS:	*/

/*	interface csr register	*/
#define C_GO	1
#define C_DFD	2
#define C_BY	020
#define C_DIR	040
#define C_TIE	0100
#define C_DON	0200
#define C_FIFO	01400
#define C_WDF	02000
#define C_PGE	010000
#define C_VE	020000
#define C_MTO	040000
#define C_ERR	0100000
/*
	C_GO	dma go bit
	C_DFD	data flag done
	C_BY	byte mode
	C_DIR	xfer direction (1 for read from device)
	C_TIE	enable transfer complete interrupt
	C_DON	transfer done
	C_FIFO	fifo level
	C_WDF	waiting for data flag
	C_PGE	program error
	C_VE	vector error
	C_MTO	memory timeout
	C_ERR	any error
*/

/*	device csr register	*/
#define D_RST	1
#define	D_SNS	2
#define D_DIE	0100
#define D_DIR	0200
/*
	D_RST	reset terminal
	D_SNS	sense line
	D_DIE	enable devive interrupt
	D_DIR	device interrupt request
*/

/*	device command word	*/
#define DC_SI	01000
#define DC_RST	0400
/*
	DC_SI	suppress interrupt from terminal
	DC_RST	reset terminal
*/
/*	device status word	*/
#define DS_BSY	0100000
#define DS_PBR	040000
#define DS_KSR	020000
/*
	DS_BSY	device busy
	DS_PBR	parallel byte ready
	DS_KSR	keystroke ready
*/

int juattach(), juprobe(), judgo(), judintr(), jutintr();
int justrategy(), justart();

struct uba_ctlr *jucinfo[NJU];
struct uba_ctlr juctlr[NJU];	/* juattach() sets jucinfo to point to this */
struct uba_device *judinfo[NJU];
u_short justd[] = { 0 };
struct uba_driver judriver =
	{ juprobe, 0, juattach, judgo, justd, "ju", judinfo ,"ju", jucinfo };

#define ui_open ui_type
struct buf jubuf[NJU];
struct buf judtab[NJU];
juprobe(reg)
caddr_t reg;
{
	register int br, cvec;
	register struct judevice *juaddr = (struct judevice *)reg;

	juaddr->juvec = 0500;	/* set interrupt vector xxx ? */
/*
	juaddr->judcsr &= ~D_DIR;	|* clear interrupt request bit *|
	juaddr->judcsr |= D_DIE;	|* enable interrupt, the one that *|
					|* happens when terminal is ready *|
	juaddr->judcsr |= D_DIR;	|*cause an interrupt *|
	DELAY(10000);
*/
	br = 0x14;			/* BR Level 14 = UNIBUS 4 */
	cvec = 0500;
	return(1);
}

juattach(ui)	/* initialization on system boot */
register struct uba_device *ui;
{
	register struct uba_ctlr *um;
	register int unit;

	unit = ui->ui_unit;

	um = &juctlr[unit];
	jucinfo[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;
}

static int jerror,
	entries,direntries,breturns,oreturns,
	impossible, jutotali, jubytes;
static int jwrites, jwaits, jwritepokes, jfullpokes, jreads;
juopen(dev, flag)
dev_t dev;
{
	register int s;
	register unit, d;
	int jutimer();
	register struct ju *ju;
	register struct uba_device *ui;

	d = minor(dev);
	unit = d&07;
	ju = &jutab[unit];
	ui = judinfo[unit];
	if(unit >= NJU || ui->ui_alive == 0 || (ju->flag & OPEN)) {
		u.u_error = ENXIO;
		return;	
	}
	jerror=waitpoke=timerpoke=0;
	entries=direntries=breturns=oreturns=0;
	jwrites=jwaits=jwritepokes=jfullpokes=jreads=0;
	jubytes=jutotali=impossible=0;
	ju->flag = OPEN;
	ju->juw = ju->jur = ju->jucbuf;
	ju->jucc = 0;

	ui->ui_open++;
	while(((struct judevice *)ui->ui_addr)->judsw&DS_BSY)
		sleep((caddr_t)&lbolt,JUPRI);
	if(jutimeout == 0) {	/* i.e. there is not a timer already going */
		jutimeout++;
		timeout(jutimer, (caddr_t)0, 60);
	}

}

jutimer()
{
register struct ju *ju;
register unit, flag, ps;
register struct judevice *juaddr;

	for (unit=flag=0; unit < NJU; unit++) {
		ju = &jutab[unit];
		if (ju->flag&OPEN==0) {
			continue;
		}
		juaddr = (struct judevice *)(judinfo[unit]->ui_addr);
		flag++;	/* unit is active */
		ps = spl4();
		if (ju->flag & TIWAIT) {
			if (ju->writes == ju->lastwrite) {
				if (++(ju->samewrite) > MAXSAME) {
				if(ju->flag & DEBUG)printf("timer TIWAIT\n");
					juaddr->jucsr &= ~C_GO;
					jutintr(unit);
				}
			} else
				ju->lastwrite = ju->writes;
		}
		if (ju->flag&DIWAIT) {
			/* judintr thinks it has work to do, */
			/* is waiting for a device interrupt */
			if ((juaddr->judsw & DS_BSY) == 0) {
				/* device is not busy! */
				timerpoke++;
				judintr(unit);
			}
		}
		splx(ps);
	}
	if(flag) {	/* keep timer going */
		timeout(jutimer, (caddr_t)0, 60);
	} else {	/* no active devices, shut down timer */
		jutimeout = 0;
	}
}
#define DEBUGON	(('J'<<8)|1)
#define DEBUGOFF (('J'<<8)|2)
#define DMAON	(('J'<<8)|3)
#define DMAOFF	(('J'<<8)|4)
#define READREGS (('J'<<8)|6)

struct juregs {
	unsigned short	jucsr,
			judcsr,
			judsw;
};

juioctl(dev, cmd, addr)
register dev_t	dev;
register struct juregs	*addr;
register cmd;
{
	int unit;
	struct ju *ju;
	struct judevice *juaddr;

	unit = minor(dev)&07;
	ju = &jutab[unit];
	juaddr = (struct judevice *)judinfo[unit]->ui_addr;

	switch(cmd){
		case DMAON:
			if(ju->jucc > 0)juwait(ju,0); /* flush pg buffer */
			ju->flag |= DMA;
			if(ju->flag & DEBUG)printf("ju: DMAON\n");
			break;
		case DMAOFF:
			ju->flag &= ~DMA;
			break;
		case READREGS:
			addr->jucsr = juaddr->jucsr;
			addr->judcsr = juaddr->judcsr;
			addr->judsw = juaddr->judsw;
			break;
		case DEBUGON:
			ju->flag |= DEBUG;
			printf("ju: DEBUGON\n");
			break;
		case DEBUGOFF:
			ju->flag &= ~DEBUG;
			break;
		default:
			u.u_error = EFAULT;
	}
}
juclose(dev)
register dev_t dev;
{
	register unit;
	register struct ju *ju;

	unit = minor(dev)&07;
	ju = &jutab[unit];

	ju->flag &= ~OPEN;	/* to shut off timer */
	juwait(ju,0);
	((struct judevice *)judinfo[unit]->ui_addr)->jucsr = 0;
	((struct judevice *)judinfo[unit]->ui_addr)->judcsr = 0;

	judinfo[unit]->ui_open = 0;
	if(ju->flag&DEBUG) {
	printf("juclose: errors %d waitpokes %d timerpokes %d\n",
		jerror,waitpoke,timerpoke);
	printf("	judintr: %d entries, of which %d had D_DIR set\n",
			entries, direntries);
	printf("		%d returns on busy, %d out bottom\n",
			breturns, oreturns);
	printf("%d writes, %d reads, %d writepokes, %d fullpokes, %d waits\n",
		jwrites,jreads,jwritepokes,jfullpokes,jwaits);
	if(jubytes)
	printf("totali %d on %d bytes sent, %d average\n",jutotali,jubytes,
		jutotali/jubytes);
	}
	ju->flag = 0;
}

juwait(ju, count)
register struct ju *ju;
register count;
{
	register int s, times;
	register r;

	jwaits++;
	times = 60;
	ju->waitcount = count;
	while(ju->jucc > count){
		ju->flag |= ASLP;
		r = tsleep((caddr_t)ju, JUPRI, 1);
		if(r == TS_TIME) {	/* timed out */
			if ((ju->flag&DIWAIT) == 0) {
				/* oddly enough judintr doesn't think it has */
				/* any work to do */
				s = spl4();
				waitpoke++;
				judintr(ju-jutab);
				splx(s);
			}
			times--;
			if(times==0) {
				printf("jupiter timeout, buffer flushed\n");
				goto flush;
			}
		}
		if (r==TS_SIG) {
		flush:
			ju->jur = ju->juw = ju->jucbuf;
			ju->jucc = 0;
		}
	}
}

unsigned short jcheck(addr,bitmask,value)
register unsigned short *addr;
register unsigned int bitmask, value;
{
	register int times;
	unsigned short data;

	times = 0;
	while (((data = *addr) & bitmask) != value)
		if (times++ >= JNTRIES) {
			times = 0;
			if (tsleep((caddr_t)addr, JUPRI, 1) == TS_SIG)
				return 0;
		}

	return data;
}

juread(dev)
{
	register struct judevice *addr;
	register struct ju *ju;
	register int unit, count;
	register unsigned char *bptr;

	unit = dev & 07;
	ju = &jutab[unit];
	addr = (struct judevice *)judinfo[unit]->ui_addr;
	jreads++;

	if (ju->jucc)
		juwait(ju, 0);
	if(ju->flag&DMA) {
		if(ju->flag&DEBUG)
			printf("attempting dma read to ju\n");
		ju->flag |= TIWAIT;
		physio(justrategy,&jubuf[unit],dev,B_READ,minphys);
		return;
	}
	count = u.u_count;
	bptr = ju->jucbuf;

	addr->judcsr &= ~D_DIR;
	if(ju->flag&DEBUG)printf("DSW address %o\n",&(addr->judsw));
	while (count--) {
		*bptr++ = (unsigned char)(jcheck(&(addr->judsw),DS_PBR, DS_PBR)
						&0xFF) ;
		if(ju->flag&DEBUG)printf("DSW is %x\n",(unsigned int)addr->judsw);
		jcheck(&(addr->judsw), DS_PBR, 0);
			/* send PBA command */
		jcheck(&(addr->judsw), DS_BSY, 0);
		addr->judcw = 033;
		if(ju->flag & DEBUG)printf("end of read loop, data %x\n",
					(int)(*(bptr-1)));
	}

	iomove(ju->jucbuf, u.u_count, B_READ);
}

juwrite(dev)
{
	register struct ju *ju;
	register unsigned char *p;
	register c, cc;
	register s;
	register unsigned char *jur;
	register int unit;

	unit = minor(dev) & 07;
	ju = &jutab[unit];
	ju->writes++;
	jwrites++;

	if(ju->flag&DMA) {
		if(ju->flag&DEBUG)
			printf("attempting dma write to ju\n");
		ju->flag |= TIWAIT;
		physio(justrategy,&jubuf[unit],dev,B_WRITE,minphys);
	}
	else {
	while(u.u_count) {
		jur = ju->jur;
		if(jur > ju->juw)
			cc = jur - ju->juw;
		else if (jur == ju->juw && ju->jucc != 0)
			cc = 0;	/* buffer full */
		else		/* from juw to end of buffer */
			cc = ju->jucbuf + JUSIZ - ju->juw;
		if(u.u_count < cc)
			cc = u.u_count;
		if(cc == 0) {	/* the buffer must be full */
			s = spl4(); /* correct priority?xxx */
			if ((ju->flag&DIWAIT) == 0) {
				jfullpokes++;
				judintr(unit);
			}
			splx(s);
			juwait(ju,JULOWAT);
		}
		else {	/* queue up some characters */
			iomove(ju->juw, cc, B_WRITE);
			if((ju->juw += cc) >= ju->jucbuf + JUSIZ)
				ju->juw = ju->jucbuf;
			s = spl4();
			ju->jucc += cc;
			if (( ju->flag&DIWAIT) == 0) {
				jwritepokes++;
				judintr(unit);
			}
			splx(s);
		}
	}
	}
}

/* Since justrategy is currently called only by juwrite
	via physio, there will be only one transaction in each
	DMA-U's queue at a given time. So we tack the given buffer
	header pointer on at the end of the queue, and call justart
*/
justrategy(bp)
register struct buf *bp;
{
	register struct uba_device *ui;
	register struct uba_ctlr *um;
	register struct buf *dp;
	register judvma;
	dev_t unit;
	int ps;

	ps = spl4();
	unit = minor(bp->b_dev);
	ui = judinfo[unit];
	um = ui->ui_mi;		/* ctlr pointer */
	dp = &judtab[unit];
	dp->b_actf = bp;
	dp->b_actl = bp;
	bp->av_forw = NULL;
	um->um_tab.b_actf = dp;
	um->um_tab.b_actl = dp;
	um->um_cmd = C_TIE | C_GO;
	if (bp->b_flags & B_READ)
		um->um_cmd |= C_DIR;

	justart(um);
	splx(ps);
}

justart(um)
register struct uba_ctlr *um;
{
	register struct buf *bp, *dp;
	register struct judevice *juaddr;

	dp = um->um_tab.b_actf;
	bp = dp->b_actf;
	um->um_tab.b_active++;
	juaddr = (struct judevice *)um->um_addr;
	jcheck(&(juaddr->judsw), DS_BSY, 0);
	juaddr->jutc = -bp->b_bcount / sizeof(short);
	juaddr->judcsr = juaddr->jucsr = 0;
	(void) ubago(judinfo[minor(bp->b_dev)]);
}

judgo(um)
register struct uba_ctlr *um;
{
	register struct judevice *juaddr = (struct judevice *)um->um_addr;

	juaddr->juba = um->um_ubinfo;
	juaddr->juxba = (um->um_ubinfo>>16) & 3;
	juaddr->jucsr = um->um_cmd;
}
jutintr(dev)
register dev_t	dev;
{
	register struct buf *bp, *dp;
	register struct judevice *juaddr;
	register struct uba_ctlr *um;
	register unit;
	register struct ju *ju;

	unit = minor(dev) & 07;
	um = jucinfo[unit];

	ju = &jutab[unit];
	ju->flag &= ~TIWAIT;
	ju->samewrite = 0;
	juaddr = (struct judevice *)um->um_addr;
	juaddr->jucsr = 0;
	if(um->um_tab.b_active == 0)
			return;

	dp = um->um_tab.b_actf;
	bp = dp->b_actf;

	/* should check for errors? */

	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 = (-juaddr->jutc * sizeof(short));
	ubadone(um);
	iodone(bp);
}

static int jcount;
judintr(dev)
register dev_t	dev;
{
	register struct ju *ju;
	register struct judevice *addr;
	register c, cc, unit;

	unit = minor(dev) & 07;
	ju = &jutab[unit];
	ju->flag &= ~DIWAIT;
	addr = (struct judevice *)judinfo[unit]->ui_addr;

	entries++; if(addr->judcsr&D_DIR)direntries++;

	if (addr->jucsr&C_ERR) {
		printf("error: ju %d %x\n",dev,(int)addr->jucsr);
		addr->jucsr &= ~C_ERR;
		ju->flag &= ~DIWAIT;
		ju->flag |= ESLP;
		jerror++;
		return;
	}

	cc = 0;
	while (ju->jucc > 0) {
		addr->judcsr &= ~D_DIR;	/* clear interrupt request bit */
		for(jcount=0;jcount<JNTRIES;jcount++)
			if( (addr->judsw&DS_BSY) == 0 )goto putout;
			/* busy too long -- sleep */
			addr->judcsr |= D_DIE;
			ju->flag |= DIWAIT;
			if(ju->flag&ASLP && ju->jucc <= ju->waitcount){
				ju->flag &= ~ASLP;
				wakeup((caddr_t)ju);
			}
			breturns++;
			return;
	putout:		/* not busy: output a byte */
		addr->judcw = *(ju->jur)++;
		if (ju->jur == ju->jucbuf + JUSIZ)
			ju->jur = ju->jucbuf;
		ju->jucc--;
		cc++;
		jutotali += jcount;
		jubytes++;
	}


	out:	if(cc && ju->flag&ASLP && ju->jucc <= ju->waitcount) {
			ju->flag &= ~ASLP;
			wakeup ((caddr_t)ju);
		}
		oreturns++;
}