V9/sys/dev.old/im.oc

#include "im.h"

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

struct imdevice {
	short	wcr;		/* Unibus word count reg */
	u_short	bar;		/* Unibus address register */
	u_short	csr;		/* Unibus status/command reg */
	u_short	idr;		/* Input Data Register */
};
#define	eir	csr		/* Error and Information Register */
#define	odr	idr		/* Output Data Register */

/*
 * Unibus status/command register bits
 */

#define GO		0000001		/* starts dma       (W) */
#define H_STROBE	0000002		/* host strobe    (R/W) */
#define H_INTER		0000004		/* host interrupt (R/W) */
#define H_RESET		0000010		/* host reset     (R/W) */
#define X16		0000020		/* extended buss address bit 16 (R/W) */
#define X17		0000040		/* extended buss address bit 17 (R/W) */
#define IENABLE		0000100		/* interrupt enable (R/W) */
#define READY		0000200		/* dev req's int. at end of dma (R) */
#define NOT_USED	0000400
#define S_STROBE	0001000		/* scanner strobe (R) */
#define S_INTER		0002000		/* scanner interrupt (R) */
#define S_RESET		0004000		/* scanner power off (R) */
#define	MAINT		0010000		/* maintenance mode (R/W) */
#define ATTNT		0020000		/* attention, interface interrupt (R) */
#define NEX		0040000		/* non existent memory error */
#define	ERROR		0100000		/* dr11w interface error  */

/*
 * Function codes
 */
#define	WR_IMAGE	(1<<1)
#define	WR_CMD		(4<<1)
#define	WR_RLE		(5<<1)	
#define RD_CMD		(7<<1)
#define RD_IMAGE	(3<<1)
#define	FUNCMASK	(7<<1)
#define	TOGGLE		(8<<1)	/* toggle between X and WR_CMD, WR_CMD first */

/*
 * IOCTL
 */
#define	IMRESET	(('i'<<8)|1)

#define BUSY 01
#define DMAPRI (PZERO-1)
#define WAITPRI (PZERO+1)

int	improbe(), imattach(), imintr();
struct	uba_device *imdinfo[NIM];
u_short	imstd[] = { 0772470, 0000000, 0 };
struct	uba_driver imdriver = {
	improbe, 0, imattach, 0, imstd, "im", imdinfo, 0, 0
};

struct imsoftc {
	char	open;
	short	uid;
	short	state;
	int	ubinfo;
	int	count;
	struct	buf *bp;
	int	bufp;
	int	icnt;
} imsoftc[NIM];

int	imstrategy();
u_int	imminphys();
struct	buf rimbuf[NIM];

#define UNIT(dev) (minor(dev))

improbe(reg)
	caddr_t reg;
{
	register int br, imec;		/* value-result */
	register struct imdevice *imaddr = (struct imdevice *) reg;

#ifdef lint
	br = 0; imec = br; br = imec;
	imintr(0);
#endif
/*	imaddr->csr = H_STROBE|H_INTER|H_RESET|IENABLE;
	DELAY(10000);
	imaddr->csr = 0;
	/* KLUDGE */
	br=0x15;
	imec=0174;
	return (sizeof (struct imdevice));
}

/*ARGSUSED*/
imattach(ui)
	struct uba_device *ui;
{

}

imopen(dev)
	dev_t dev;
{
	register struct imsoftc *imp;
	register struct uba_device *ui;

	if (UNIT(dev) >= NIM || (imp = &imsoftc[minor(dev)])->open ||
	    (ui = imdinfo[UNIT(dev)]) == 0 || ui->ui_alive == 0)
		u.u_error = EBUSY;
	else {
		imp->open = 1;
		imp->icnt = 0;
		imp->state = 0;
		imp->uid = u.u_uid;
	}
}

imclose(dev)
	dev_t dev;
{

	imsoftc[minor(dev)].open = 0;
	imsoftc[minor(dev)].state = 0;
}

imread(dev, uio)
	dev_t dev;
	struct uio *uio;
{
	register int unit = UNIT(dev);

	if (unit >= NIM)
		return (ENXIO);
	return (physio(imstrategy, &rimbuf[unit], dev, B_READ, imminphys, uio));
}

imwrite(dev, uio)
	dev_t dev;
	struct uio *uio;
{
	register int unit = UNIT(dev);

	if (unit >= NIM)
		return (ENXIO);
	return (physio(imstrategy, &rimbuf[unit], dev, B_WRITE, imminphys, uio));
}

u_int
imminphys(bp)
	register struct buf *bp;
{

	if (bp->b_bcount > 65536)	/* may be able to do twice as much */
		bp->b_bcount = 65536;
}

imstrategy(bp)
	register struct buf *bp;
{
	register struct imsoftc *imp = &imsoftc[UNIT(bp->b_dev)];
	register struct uba_device *ui;

	if (UNIT(bp->b_dev) >= NIM || (ui = imdinfo[UNIT(bp->b_dev)]) == 0
				|| ui->ui_alive == 0)
		goto bad;
	(void) spl5();
	while (imp->state & BUSY)
		sleep((caddr_t)imp, DMAPRI+1);
	imp->state |= BUSY;
	imp->bp = bp;
	if(bp->b_bcount<=0 || (bp->b_bcount&1) || 
	    ((int)bp->b_un.b_addr&1)){
		u.u_error = EINVAL;
		goto bad;
	}
	imp->ubinfo = ubasetup(ui->ui_ubanum, bp, UBA_NEEDBDP);
	imp->bufp = imp->ubinfo & 0x3ffff;
	imp->count = -(bp->b_bcount>>1);	/* it's a word count */
	imstart(ui);
	if(tsleep((caddr_t)imp, DMAPRI+1, 15) != TS_OK){
		register struct imdevice *imaddr = (struct imdevice *) ui->ui_addr;
		bp->b_flags |= B_ERROR;
		/* stop the dma */
		imslam(imaddr);
		imaddr->wcr=0xFFFF;	/* gently; -1 first... */
		imaddr->wcr=0x0000;	/* then zero */
		/* reset device */
		imslam(imaddr);
		/* fake an interrupt to clear software status */
		imintr(UNIT(bp->b_dev));
	}
	imp->count = 0;
	imp->bufp = 0;
	(void) spl0();
	ubarelse(ui->ui_ubanum, &imp->ubinfo);
	imp->bp = 0;
	iodone(bp);
	wakeup((caddr_t)imp);
	return;
   bad:
	imp->state &= ~BUSY;
	bp->b_flags |= B_ERROR;
	iodone(bp);
	return;
}

imslam(imaddr)
	register struct imdevice *imaddr;
{
	register i;
	imaddr->csr=MAINT;
	for(i=0; i<10; i++)
		;
	imaddr->csr=0;
	for(i=0; i<10; i++)
		;
}

imstart(ui)
	register struct uba_device *ui;
{
	register int csr;
	register struct imdevice *imaddr = (struct imdevice *) ui->ui_addr;
	register struct imsoftc *imp = &imsoftc[UNIT(ui->ui_unit)];

	csr = IENABLE|((imp->bufp>>12)&060) | H_INTER;
	imaddr->wcr = imp->count;
	imaddr->bar = imp->bufp;
	imaddr->csr = csr;	/* No GO bit; let function codes settle */
	imaddr->csr = csr|GO;
}

/*ARGSUSED*/
imioctl(dev, cmd, data)
	dev_t dev;
	int cmd;
	register caddr_t data;
{
	register struct uba_device *ui = imdinfo[UNIT(dev)];
	register struct imsoftc *imp = &imsoftc[UNIT(dev)];
	int i;

	switch (cmd) {
	case IMRESET:
		if(i = imreset(dev))
			return(i);
		break;
	default:
		return (ENOTTY);
	}
	return u.u_error;
}

/*ARGSUSED*/
imintr(dev)
	dev_t dev;
{
	register struct imdevice *imaddr =
			(struct imdevice *) imdinfo[UNIT(dev)]->ui_addr;
	register struct imsoftc *imp = &imsoftc[UNIT(dev)];
	register csr;

	imp->icnt++;
	if (imp->state&BUSY) {
		csr = imaddr->csr;
		if(csr & ERROR){
			imaddr->eir |= ERROR;
			printf("im: CSR %x EIR %x\n", csr, imaddr->eir);
		}
		imaddr->csr = csr&~FUNCMASK;
		imp->state &= ~BUSY;
		wakeup((caddr_t)imp);
	}
}

imreset(dev)
	dev_t dev;
{
	register int i;
	register struct uba_device *ui;
	register struct imsoftc *imp = imsoftc;
	register struct imdevice *imaddr =
			(struct imdevice *) imdinfo[UNIT(dev)]->ui_addr;
	int csr;

	printf("reset im%d", dev);
	if(!(imaddr->csr&S_RESET))	/* no power ? */
		return(ENODEV);
	if(imp->state&BUSY)
		return(EBUSY);
	csr = H_INTER|H_STROBE|H_RESET;
	imaddr->csr = csr;
	return(0);
}