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


/* device registers */
#define	IREG	0xfffa80
#define	OREG	0xfffa88

struct	vii_reg {
		unsigned short	reg_csr;	/* Control/Status register */
		unsigned short	reg_wc;		/* Word count register */
		unsigned short	reg_addrl;	/* Bus address register (low) */
		unsigned short	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_init()
{
 	register	struct vii_reg	*dreg;

	dreg = (struct vii_reg *)IREG;
	dreg->reg_csr = RES | HEN;
	while (!(dreg->reg_csr & RDY))
		;
	dreg->reg_csr = EN | HEN;
	dreg = (struct vii_reg *)OREG;
	dreg->reg_csr = RES | HEN;
}

/* Read the next packet.  Return the length of the packet.
 * Return 0 if there is no packet ready.
 */
vii_read(buf, len)
register	char	*buf;
register	int	len;
{
	register	struct vii_reg	*dreg;

	dreg = (struct vii_reg *)IREG;
	if (!(dreg->reg_csr & RDY))
		return 0;
	dreg->reg_addrl = (unsigned short)buf;
	dreg->reg_addrh = (unsigned short)((unsigned long)buf >> 16);
	dreg->reg_wc = -((len + 1) >> 1);
	dreg->reg_csr = DMA | HEN;
	while (!(dreg->reg_csr & RDY))
		;
	dreg->reg_csr = EN | HEN;
	len += dreg->reg_csr << 1;	/* this is really subtracting */
	bswap(buf, len);
	return len;
}

/* Write a packet to the net. */
vii_write(buf, len)
register	char	*buf;
register	int	len;
{
	register struct vii_reg	*dreg;
	register int	csr;

	bswap(buf, len);
	dreg = (struct vii_reg *)OREG;
again:	dreg->reg_addrl = (unsigned short)buf;
	dreg->reg_addrh = (unsigned short)((unsigned int)buf >> 16);
	dreg->reg_wc = -((len + 1) >> 1);
	dreg->reg_csr = DMA | CPB | EN;
	while (!((csr = dreg->reg_csr) & RDY))
		;
	if (csr & OERR) {
		puts("retransmitting pkt\n");
		goto again;
	}
	bswap(buf, len);
}

/*
dump(p)
	char *p; {
	int i,j;

	for(i = 1; i < 17; i++) {
		printf("%02x ", *p++&0xff);
		if(i%16 == 0) printf("\n");
	}

	printf("\n");
	}
 */
