SysIII/usr/src/uts/vax/io/dmc.c

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

#include "sys/param.h"
#include "sys/buf.h"
#include "sys/dir.h"
#include "sys/user.h"
#include "sys/tty.h"
#include "sys/uba.h"

struct device *dmc_addr[];
struct device {
union {
	char	b[8];
	short	w[4];
} un;
};

#define	bsel0	un.b[0]
#define	bsel1	un.b[1]
#define	bsel2	un.b[2]
#define	bsel3	un.b[3]
#define	bsel4	un.b[4]
#define	bsel5	un.b[5]
#define	bsel6	un.b[6]
#define	bsel7	un.b[7]
#define	sel0	un.w[0]
#define	sel2	un.w[1]
#define	sel4	un.w[2]
#define	sel6	un.w[3]

int	dmc_cnt;

#define RWMAX	7
#define	MAXBUF	8192

/* Defines for bsel0 and bsel2. */
#define	BACCI	0
#define	CNTLI	1
#define	BASEI	3
#define	INX	0		/* transmit block */
#define	INR	4		/* read  block */
#define	RQI	040		/* port request bit */
#define	IEI	0100		/* enable input interrupts */
#define	RDYI	0200		/* port ready */

#define	BACCO	0
#define	CNTLO	1
#define	OUX	0		/* transmit block */
#define	OUR	4		/* read  block */
#define	IEO	0100		/* enable output interrupts */
#define	RDYO	0200		/* port available */

#define	MCLR	0100		/* DMC11 Master Clear */

/* Defines for CNTLI mode (set into sel6). */
#define	HDPLX	02000		/* half duplex DDCMP operation */
#define	SEC	04000		/* half duplex secondary station */
#define	MAINT	0400		/* enter maintenance mode */

/* Defines for BACCI/O and BASEI mode (set into sel6). */
#define	DMXMEM	0140000		/* xmem bit position */
#define	CCOUNT	037777		/* character count mask */
#define	RESUME	02000		/* resume (BASEI only) */

/* Defines for CNTLO (set in sel6). */
#define FATAL	01620

struct dmc {
	int	b_flags;
	struct buf *b_forw;
	struct buf *b_back;
	struct buf *av_forw;
	struct clist dm_que;
	char	dm_rwq[2];
	short	dm_ioc[16];
	struct buf dm_rbuf[2];
	int	dm_map[2];
	short	dm_base[128];
};

#define	DMCOPEN	2

#define NDMC 2
struct	dmc dmc11[NDMC];

dmcopen(dev)
{
	register struct dmc *dmp;

	if (dev >= dmc_cnt || dev >= NDMC) {
		u.u_error = ENXIO;
		return;
	}
	dmp = &dmc11[dev];
	if((dmp->b_flags&DMCOPEN) == 0) {
		dmp->b_flags = DMCOPEN;
		dmcinit(dev);
		dmp->dm_map[0] = ubmalloc(MAXBUF, 0);
		dmp->dm_map[1] = ubmalloc(MAXBUF, 0);
	}
}

dmcclose(dev)
{
	register struct dmc *dmp;

	dmp = &dmc11[dev];
	dmcclr(dev);
	ubmfree(dmp->dm_map[0]);
	ubmfree(dmp->dm_map[1]);
	dmp->b_flags &= ~DMCOPEN;
}

dmcinit(dev)
{
	register struct dmc *dmp;
	paddr_t	base;

	dmp = &dmc11[dev];
	dmcclr(dev);
	dmc_addr[dev]->bsel2 |= IEO;
	base = ubmdata(dmp->dm_base);
	dmcload(dmp, BASEI, loword(base), hiword(base)<<14);
	dmcload(dmp, CNTLI, 0, 0);
}

dmcclr(dev)
{
	int sps;
	register struct dmc *dmp;
	register struct buf *bp;

	sps = spl5();
	dmc_addr[dev]->bsel1 = MCLR;
	splx(sps);

	dmp = &dmc11[dev];
	dmp->dm_rwq[0] = dmp->dm_rwq[1] = 0;

	/* Mark all buffers bad. */
	while(bp = dmp->av_forw) {
		bp->b_flags |= B_ERROR;
		dmp->av_forw = bp->av_forw;
		iodone(bp);
	}
}

dmcstrategy(bp)
register struct buf *bp;
{
	register struct dmc *dmp;
	register struct buf *abp;
	int sps;

	if (bp->b_bcount > MAXBUF) {
		bp->b_flags |= B_ERROR;
		iodone(bp);
		return;
	}
	dmp = &dmc11[minor(bp->b_dev)];
	abp = (struct buf *)dmp;
	bp->av_forw = NULL;
	sps = spl5();
	while (abp->av_forw)
		abp = abp->av_forw;
	abp->av_forw = bp;
	dmcstart(dmp, bp->b_flags&B_READ);
	splx(sps);
}

dmcstart(dmp, flag)
register struct dmc *dmp;
{
	register struct buf *bp;
	paddr_t addr;

	bp = (struct buf *)dmp;
	while (bp = bp->av_forw) {
		if ((bp->b_flags&(B_STALE|B_READ))!=flag)
			continue;
		if (dmp->dm_rwq[flag] >= RWMAX) {
			return;
		}
		dmp->dm_rwq[flag]++;
		bp->b_flags |= B_STALE;
		addr = ubmaddr(bp, dmp->dm_map[flag]);
		dmcload(dmp, flag<<2, loword(addr), 
			(bp->b_bcount&CCOUNT)|((hiword(addr)&03)<<14));
		return;
	}
}

dmcload(dmp, type, w0, w1)
register struct dmc *dmp;
{
	register struct device *kp;
	register dev;
	int	sps;

	dev = dmp-dmc11;
	kp = dmc_addr[dev];
	sps = spl5();
	kp->bsel0 |= RQI;
	putc(lobyte(w0), &dmp->dm_que);
	putc(hibyte(w0), &dmp->dm_que);
	putc(lobyte(w1), &dmp->dm_que);
	putc(hibyte(w1), &dmp->dm_que);
	putc(type, &dmp->dm_que);
	dmcrint(dev);
	splx(sps);
}

dmcrint(dev)
{
	register struct dmc *dmp;
	register struct device *kp;

	kp = dmc_addr[dev];
	kp->bsel0 &= ~IEI;
	dmp = &dmc11[dev];
	while (kp->bsel0&RDYI) {
		kp->bsel4 = getc(&dmp->dm_que);
		kp->bsel5 = getc(&dmp->dm_que);
		kp->bsel6 = getc(&dmp->dm_que);
		kp->bsel7 = getc(&dmp->dm_que);
		kp->bsel0 = getc(&dmp->dm_que)|RDYI;
		while (kp->bsel0&RDYI);
		if (dmp->dm_que.c_cc==0)
			return;
		kp->bsel0 = RQI;
	}
	if (dmp->dm_que.c_cc)
		kp->bsel0 |= IEI;
}

dmcxint(dev)
{
	register struct device *dp;
	register struct dmc *dmp;
	register struct buf *bp, *abp;
	short	*ip;
	int	count, flag;

	dp = dmc_addr[dev];
	count = dp->sel6;
	flag = dp->bsel2&7;
	dp->bsel2 &= ~RDYO;

	dmp = &dmc11[dev];
	switch(flag) {

	case OUX:
	case OUR:
		bp = (struct buf *)dmp;
		flag >>= 2;

		/*
		 * Look through the active Q for the buffer
		 * the DMC11 says is finished. Assume the DMC11
		 * returns the buffers in FIFO order.
		 */
		while(abp = bp,bp = bp->av_forw) {
			if ((bp->b_flags&B_READ)!=flag)
				continue;
			dmp->dm_rwq[flag]--;
			dmp->dm_ioc[flag]++;
			bp->b_resid = bp->b_bcount - count&CCOUNT;
			abp->av_forw = bp->av_forw;
			iodone(bp);
			dmcstart(dmp, flag);
			return;
		}
		printf("DMC%d lost block\n", dev);
		return;

	case CNTLO:
		if (count&FATAL)
			dmcinit(dev);
		ip = &dmp->dm_ioc[2];
		while(count) {
			if (count&01)
				(*ip)++;
			ip++;
			count >>= 1;
		}
	}
}

dmcread(dev)
{
	physio(dmcstrategy,&dmc11[dev].dm_rbuf[B_READ],dev,B_READ);
}

dmcwrite(dev)
{
	physio(dmcstrategy,&dmc11[dev].dm_rbuf[B_WRITE],dev,B_WRITE);
}