/* Copyright 1984 by the Massachusetts Institute of Technology */

/* Device driver for the vii ring network interface.  Written for the
 * 68000 q-bus processor made by Periphere Computer Systeme.
 */

#include	<types.h>
#include	"../../sys/include/sys.h"


/* device registers */
struct	vii_reg {
		unss	reg_csr;	/* Control/Status register */
		unss	reg_wc;		/* Word count register */
		unss	reg_addrl;	/* Bus address register (low) */
		unss	reg_addrh;	/* Bus address register (high) */
};


/* bit definitions for the csr */
#define	EN	0x1	/* enable */
#define	DMA	0x2	/* dma enable */
#define	HEN	0x4	/* host enable (input csr) */
#define CPB	0x4	/* clear packet buffer (output csr) */
#define	STEN	0x8	/* self test enable */
#define	DLOOP	0x10	/* digital loopback (input) */
#define	IR	0x10	/* initialize ring (output) */
#define	RES	0x20	/* reset */
#define	IEN	0x40	/* interrupt enable */
#define	RDY	0x80	/* ready */

#define	IDP	0x100	/* input data present (input) */
#define	REF	0x100	/* refused (output) */
#define	NXM	0x200	/* nxm */
#define	OVR	0x400	/* overrun */
#define	ODD	0x800	/* input odd byte count */
#define	PE	0x1000	/* parity error (input) */
#define	TMO	0x1000	/* timeout (output) */
#define	RNOK	0x2000	/* ring not ok */
#define	BDF	0x4000	/* bad format */
#define	NIR	0x8000	/* not in ring */

/* Errors */
#define	HRDERR	(NXM | NIR)		/* errors which should never occur */
#define	IERR	(IDP | OVR | PE | BDF)	/* random input errors */
#define	OERR	(REF | OVR | TMO | BDF)	/* random output errors */

/* vii device initialization routine.
 */

vii_up(devp)
reg	dct	*devp;
{
	reg	struct vii_reg	*dreg;

	printf("vii_up:\n");
	dreg = (struct vii_reg *)devp->d_csr;
	dreg->reg_csr = RES | RES | HEN;	/* HEN is CPB on output */
	devp->d_flg = D_INI;
}

/* hack to get at high 16 bits of a pointer */
struct	ltow {
	unss	high;
	unss	low;
};

/* input transfer initialization routine */
viiin(devp)
reg	dct	*devp;
{
	reg	unsl	addr;
	reg	struct vii_reg	*dreg;

	dreg = (struct vii_reg *)devp->d_csr;
	dreg->reg_addrl = (unss)devp->d_addr;
	dreg->reg_addrh = (unss)((word)devp->d_addr >> 16);
	dreg->reg_wc = -((devp->d_breq + 1) >> 1);
	dreg->reg_csr = DMA | HEN | IEN | EN;
}

/* output transfer initialization routine */
viiot(devp)
reg	dct	*devp;
{
	reg struct vii_reg	*dreg;
	reg unss	csr;

	dreg = (struct vii_reg *)devp->d_csr;
	dreg->reg_addrl = (unss)devp->d_addr;
	dreg->reg_addrh = (unss)((word)devp->d_addr >> 16);
	dreg->reg_wc = -((devp->d_breq + 1) >> 1);
	csr = dreg->reg_csr;
	dreg->reg_csr = ((csr & RNOK) ?
			DMA | IEN | CPB | EN | IR :
			DMA | IEN | CPB | EN );
}

/* input interrupt routine */
viiii(devp)
reg	dct	*devp;
{
	reg struct vii_reg	*dreg;
	reg iorb	*iob;
	reg unss	csr;

	dreg = (struct vii_reg *)devp->d_csr;
	iob = devp->d_qhd;
	csr = dreg->reg_csr;
	if (csr & HRDERR) bughalt("VII: input hard error");
	if (csr & IERR) iob->i_stat |= I_ERR;	/* should return more
						 * useful information */
	iob->i_stat |= I_DONE;
	iob->i_bxfr = devp->d_breq + (dreg->reg_wc << 1);
	if (csr & ODD) iob->i_bxfr--;
	iocmr(devp);
}

/* output interrupt routine */
viioi(devp)
reg	dct	*devp;
{
	reg struct vii_reg	*dreg;
	reg iorb	*iob;
	reg unss	csr;

	dreg = (struct vii_reg *)devp->d_csr;
	iob = devp->d_qhd;
	csr = dreg->reg_csr;
	if (csr & HRDERR) bughalt("VII: output hard error");
	if (csr & OERR) iob->i_stat |= I_ERR;	/* should return more
						 * useful information */
		/* if the error was a timeout then the packet should
		 * be retransmitted now without a new DMA. Oh well. */
	iob->i_stat |= I_DONE;
	iob->i_bxfr = devp->d_breq;
	iocmr(devp);
}
