V9/sys/dev.old/om.c

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

/* ******************************************************************** */
/*									*/
/*			METHEUS Corporation				*/
/*									*/
/*		UNIX - DMA Interface Driver Source Code			*/
/*									*/
/*	This program and the subroutines implemented thereby are	*/
/*	proprietary information of Metheus Corporation and may not	*/
/*	be reproduced, or disclosed or released to, or used by any	*/
/*	other person without the express written consent of Metheus	*/
/*	Corporation.							*/
/*									*/
/*	(c) 1983 Metheus Corporation					*/
/*	All rights reserved						*/
/*									*/
/*	UNIX DR-11W DMA Interface Software by Ed Mills			*/
/*									*/
/*	Version: UNIX DMA Interface Driver low-level (OM) routines	*/
/*	Release: 1.0							*/
/*	Date: May 15, 1983						*/
/*									*/
/*									*/
/*									*/
/*	FUNCTIONAL DESCRIPTION:						*/
/*									*/
/*		OPEN:							*/
/*			omopen initializes the device and allows	*/
/*			IO to commence. Only one user may have the	*/
/*			device open at any given time.			*/
/*			omopen sets the read mode to no stall and	*/
/*			and the timeout period to 1 second. (see below)	*/
/*			omopen sets the write mode to no stall and	*/
/*			and the timeout period to 1 minute. (see below)	*/
/*									*/
/*		CLOSE:							*/
/*			omclose disallows further IO and makes the	*/
/*			device available for another user to open.	*/
/*									*/
/*		READ:							*/
/*			omread has two modes, stall and no stall.	*/
/*			In stall mode omread behaves as a standard	*/
/*			read. It stalls until the requested amount	*/
/*			of data has been read and then returns.		*/
/*			In no stall mode omread waits for the timeout	*/
/*			period (set via ioctl) to expire. If the	*/
/*			requested data is available before the end of	*/
/*			the timeout period, it is returned. If not,	*/
/*			then as much data as was available is returned.	*/
/*			In either case, the user level read returns the	*/
/*			actual number read.				*/
/*			Since the OMEGA 440 can only transmit words,	*/
/*			the count requested from omread must be even	*/
/*			or an IO error will be generated.		*/
/*									*/
/*		WRITE:							*/
/*			omwrite transmits the requested number of bytes	*/
/*			to the device. Like READ, WRITE has two modes,	*/
/*			stall and no stall which behave similarly to	*/
/*			omread's.					*/
/*			Since the OMEGA 440 can only transmit words,	*/
/*			the count sent to omwrite must be even or an	*/
/*			IO error will be generated.			*/
/*									*/
/*		IOCTL:							*/
/*			omioctl has 14 commands, OM_SETRSTALL,		*/
/*			OM_SETNORSTALL, OM_GETRSTALL,, OM_SETRTIMEOUT,	*/
/*			OM_GETRTIMEOUT, OM_SETWSTALL, OM_SETNOWSTALL,	*/
/*			OM_GETWSTALL, OM_SETWTIMEOUT, OM_GETWTIMEOUT,	*/
/*			OM_WRITEREADY, OM_READREADY, OM_BUSY,		*/
/*			and OM_RESET.					*/
/*									*/
/*		    OM_SETRSTALL:					*/
/*			Set omread to stall mode.			*/
/*									*/
/*		    OM_SETNORSTALL:					*/
/*			Set omread to no stall mode.			*/
/*									*/
/*		    OM_GETRSTALL:					*/
/*			Returns true if in read stall mode.		*/
/*									*/
/*		    OM_SETRTIMEOUT:					*/
/*			Sets the read stall mode timeout period in	*/
/*			tenths of a second.				*/
/*									*/
/*		    OM_GETRTIMEOUT:					*/
/*			Returns the read stall mode timeout period in	*/
/*			tenths of a second.				*/
/*									*/
/*		    OM_SETWSTALL:					*/
/*			Set omwrite to stall mode.			*/
/*									*/
/*		    OM_SETNOWSTALL:					*/
/*			Set omwrite to no stall mode.			*/
/*									*/
/*		    OM_GETWSTALL:					*/
/*			Returns true if in write stall mode.		*/
/*									*/
/*		    OM_SETWTIMEOUT:					*/
/*			Sets the write stall mode timeout period in	*/
/*			tenths of a second.				*/
/*									*/
/*		    OM_GETWTIMEOUT:					*/
/*			Returns the write stall mode timeout period in	*/
/*			tenths of a second.				*/
/*									*/
/*		    OM_WRITEREADY:					*/
/*			Returns a value of 1 if the device can accept	*/
/*			data, 0 otherwise. Internally this is the	*/
/*			DR11-W STAT A bit.				*/
/*									*/
/*		    OM_READREADY:					*/
/*			Returns a value of 1 if the device has data	*/
/*			to be read, 0 otherwise. Internally this is	*/
/*			the DR11-W STAT B bit.				*/
/*									*/
/*		    OM_BUSY:						*/
/*			Returns a value of 1 if the device is busy,	*/
/*			0 otherwise. Internally this is the DR11-W	*/
/*			STAT C bit.					*/
/*									*/
/*		    OM_RESET:						*/
/*			Resets the OMEGA to its power on condition	*/
/*			by asserting the CSR MAINTENANCE bit.		*/
/*									*/
/*									*/
/*	CAVEATS:							*/
/*									*/
/*		This driver is designed to allow multiple devices,	*/
/*			although it has only been tested with one.	*/
/*		This driver should also function with the DR11-B,	*/
/*			although this hasn't been tested either.	*/
/*									*/
/*	USER NOTES:							*/
/*									*/
/*		All IO is done with an even number of bytes. Hence,	*/
/*		when writing, a zero byte should be appended on the	*/
/*		end of odd length byte arrays. This must only be done	*/
/*		between commands, never within one. When reading, the	*/
/*		user must gaurentee that there is an even number number	*/
/*		of bytes to be read. i.e. send the read pixel command	*/
/*		twice.							*/
/*									*/
/*		Data pending to be read can prevent write operations.	*/
/*		Hopefully, one always knows when there is data to be	*/
/*		read. If not, one can read 2 bytes at a time until the	*/
/*		READREADY ioctl clears. CLEARINPUT_OM() in om-dmacros.h	*/
/*		does this.						*/
/*									*/
/*		If the OMEGA ever does hang, typing ^C's on the		*/
/*		terminal and THEN cycling the OMEGA's power seems	*/
/*		to fix things.						*/
/*									*/
/*									*/
/*	INSTALLATION:							*/
/*									*/
/*	The standard DR11-W parameters are,				*/
/*									*/
/*		Base address		0772410				*/
/*		CSR address		0772414				*/
/*		Interrupt vector	0124				*/
/*		Interrupt priority	5				*/
/*									*/
/*	The following line should be in the system configuration file.	*/
/* 
device		om0	at uba? csr 0172414		vector omintr
/*									*/
/*	The configure routine should reflect the new device.		*/
/*	(/usr/beaver/usr/sys/dev/conf.c on vlsi-vax.)			*/
/*									*/
/*	For vlsi-vax the following was added,

#include "om.h"
#if NOM > 0
int	omopen(),omclose(),omread(),omwrite(),omioctl();
#else
#define	omopen	nodev
#define	omclose	nodev
#define	omread	nodev
#define	omwrite	nodev
#define	omioctl	nodev
#endif

struct cdevsw	cdevsw[] =
{
	omopen,		omclose,	omread,		omwrite,
	omioctl,	nulldev,	nodev,		0,
	0,	
};
									*/
/* ******************************************************************** */
/*									*/
/*	Finally, om.h should be put in the configuration directory	*/
/*	to define NOM.							*/
/*									*/
/* ******************************************************************** */

#include "om.h"
#if NOM > 0

#include "../h/param.h"
#include "../h/dir.h"
#include "../h/user.h"
#include "../h/buf.h"
#include "../h/systm.h"
#include "../h/ubavar.h"
#include "../h/om-consts.h"

#define	OMPRI	(PZERO)

struct	omdevice {
	unsigned short	WC;	 /* 2410 Word count. */
	unsigned short	BAR;	 /* 2412 Bus address register. */
	unsigned short	CSR_EIR; /* 2414 Control and status register -
					 Error and information register. */
				 /* We never use the EIR. We should always
				    write CSR bit 15 as a zero. */
	unsigned short	IDR_ODR; /* 2416 Input data register -
					 Output data register. */
	};

/* DR11-W CSR register bits. */
#define	OM_ERROR	0100000
#define	OM_NEXMEM	0040000
#define	OM_ATTN		0020000
#define	OM_MAINT	0010000
#define	OM_STATA	0004000
#define	OM_STATB	0002000
#define	OM_STATC	0001000
#define	OM_CYCLE	0000400
#define	OM_READY	0000200
#define	OM_IENABLE	0000100
#define	OM_XBA		0000060
#define	OM_FUNCTION3	0000010
#define	OM_FUNCTION2	0000004
#define	OM_FUNCTION1	0000002
#define	OM_GO		0000001

/* Amounts to shift by to get the status bits from the CSR. */
#define	OM_STATA_SHIFT	11
#define	OM_STATB_SHIFT	10
#define	OM_STATC_SHIFT	9

/* DR11-W EIR register bits. OM_ERROR, OM_NEXMEM, and OM_ATTN also apply. */
#define	OM_MCREQ	0010000
#define	OM_ACLO		0004000
#define	OM_PARERR	0002000
#define	OM_BURSTDL	0001000
#define OM_NCBURST	0000400
#define	OM_EIRREG	0000001

/* The following are specific to the OMEGA 440 as interfaced to the DR11-W. */
#define	OM_READ		OM_FUNCTION1	/* Read from OMEGA. */
#define	OM_WRITE	0		/* Write to OMEGA. */
#define	OM_WAKEUP	OM_FUNCTION3	/* Have OMEGA assert ATTN line which
					   will cause an error, stop any pending
					   DMA, and cause an interrupt if
					   enabled. */
#define	OM_WRITE_SHIFT	OM_STATA_SHIFT	/* Ready to write bit. */
#define	OM_READ_SHIFT	OM_STATB_SHIFT	/* Ready to read bit. */
#define	OM_BUSY_SHIFT	OM_STATC_SHIFT	/* Busy bit. */

struct om_softc {
	short	sc_state;	/* Current state of the device. */
	short	sc_operation;	/* Current operation (read or write). */
	unsigned int
		sc_rtimoticks,	/* Number of ticks before timing out
				   on a no stall read. */
		sc_wtimoticks,	/* Number of ticks before timing out
				   on a no stall write. */
		sc_currenttimo;	/* The number of the current timeout call
				   to omrwtimo. */
	int	sc_ubinfo;	/* UNIBUS information. */
	int	sc_ubadd;	/* physical unibus address for cursor	*/
unsigned char	sc_curbuf[512];	/* buffer for cursor dma commands	*/
} om_softc[NOM];


/* sc_state bits */
#define	OMSC_OPEN	(1 << 0)	/* The device is open. */
#define	OMSC_BUSY	(1 << 1)	/* The device is busy. */
#define	OMSC_NORSTALL	(1 << 2)	/* The device is set to use
					   no stall mode for reads. */
#define	OMSC_NOWSTALL	(1 << 3)	/* The device is set to use
					   no stall mode for writes. */
#define	OMSC_TIMEDOUT	(1 << 4)	/* The device timed out on a
					   stall mode read or write. */

struct	uba_device *omdinfo[NOM];

#define	OMUNIT(dev)	(minor(dev))

struct	buf rombuf[NOM];

int	omprobe(), omattach(), omstrategy(), omrwtimo();
unsigned minomph();

u_short	omstd[] = { 0772410, 0772430, 0 };
struct	uba_driver omdriver = {
	omprobe,	/* Address of probe routine to cause an interrupt. */
	0,		/* ? */
	omattach,	/* Address of attach routine to set IO address. */
	0,		/* ? */
	omstd,		/* Address of the device (omdevice) on the UNIBUS. */
	"om",		/* Name of the device. */
	omdinfo,	/* UBA device information for the device. */
	0, 0
	};


/* OMPROBE */
/* Omprobe generates an interrupt when called by asserting the OMEGA attention
   line with interrupts enabled. */

omprobe(reg)
	caddr_t reg;
{
	register int br, cvec;		/* value-result */
	register struct omdevice *omaddr = (struct omdevice *)(reg-04);

#ifdef lint
	br = 0; cvec = br; br = cvec;
#endif
	/* Stop any DMA and force an interrupt. */
	omaddr->CSR_EIR = (OM_ATTN | OM_WAKEUP | OM_IENABLE);
	DELAY(100);
	omaddr->CSR_EIR = OM_IENABLE;
	/* kludge */
	br = 0x15;
	switch ((int)omaddr & 070)
	{
	case 010:
		cvec = 0124;
		break;
	case 030:
		cvec = 0134;
		break;
	}
	return (sizeof (struct omdevice));
}


/* OMATTACH */
/* Attach to and initialize the device. */

omattach(ui)	struct uba_device *ui;
{
 register struct omdevice *omaddr;
 register struct om_softc *omsp;

	/* Move the address back from the CSR to the begining of the device. */
	ui->ui_addr -= 04;
	ui->ui_physaddr -= 04;
	omaddr = (struct omdevice *)ui->ui_addr;

	/* Initialize the DR11-W by setting then clearing MAINT in the CSR
	   with CYCLE and GO  clear. */
	omaddr->CSR_EIR = 0;
	omaddr->CSR_EIR = OM_MAINT;
	DELAY(100);
	omaddr->CSR_EIR = 0;

	omaddr->CSR_EIR = OM_IENABLE;	/* Enable interrupts. */

	/* Set the current timeout to zero. */
	/* What I want here is for OMUNIT(ui->ui_unit) to give the minor
	   device number of each device as we attach to it. I think that's
	   what it does. When there is only one device, I know that's what
	   it does. I check range just to make sure things never get out
	   of hand. Since all we need from sc_currenttimo is that it be
	   distinct each time we increment it, we don't really care where
	   it starts. */
	omsp = &om_softc[OMUNIT(ui->ui_unit)];
	if ((OMUNIT(ui->ui_unit) >= 0) && (OMUNIT(ui->ui_unit) < NOM))
		omsp->sc_currenttimo = 0;

	/* allocate a physical unibus dma buffer for cursor tracking */
	if(omsp->sc_ubadd == 0)
	  { omsp->sc_ubadd = uballoc(0,	 /* which unibus adapter */
				(caddr_t)omsp->sc_curbuf,
				sizeof(omsp->sc_curbuf), 0);
	    if(omsp->sc_ubadd == 0)
		panic("UB AD 0 in omattach"); 
	  }
}

/* OMOPEN */
/* Open the device. */

omopen(dev)
	dev_t dev;
{
	register struct om_softc *sc;
	register struct uba_device *ui;
	register struct omdevice *omaddr;

	if ((OMUNIT(dev) >= NOM) ||	/* No such device. */
	    ((ui = omdinfo[OMUNIT(dev)]) == 0)) { /* Device not there. */
		u.u_error = ENXIO;
		return;
		}

	if ((ui->ui_alive) == 0) { /* Dead. */
		u.u_error = EIO;
		return;
		}

	if (((sc = &om_softc[OMUNIT(dev)])->sc_state)&OMSC_OPEN) {
		u.u_error = EBUSY;	/* Already open. */
		return;
		}

	/* Set only the open bit in the state. */
	(sc->sc_state) = OMSC_OPEN;

	/* Set the read no stall timeout to 1 second. */
	(sc->sc_rtimoticks) = hz;

	/* Set the write no stall timeout to 1 minute. */
	(sc->sc_wtimoticks) = hz*60;

	/* Start the self-kicker. */
	omtimo(dev);

	/* Stop any DMA without causing an interrupt. (No OM_IENABLE bit.) */
	omaddr = (struct omdevice *)ui->ui_addr;
	omaddr->CSR_EIR = (OM_WAKEUP | OM_ATTN);
	DELAY(100);

/* ************************************************************************ */
/*
/*	The following commented piece of code will cause the OMEGA to do a
/*	hardware reset each time it is opened. This gaurentees the device to
/*	be in a known state, but doesn't allow a program to manipulate an
/*	image produced by a previous program since it clears the screen.
/*
/* ************************************************************************ */
/*
/*	/* Initialize the DR11-W by setting then clearing MAINT in the CSR
/*	   with CYCLE and GO  clear. */
/*	omaddr->CSR_EIR = 0;
/*	omaddr->CSR_EIR = OM_MAINT;
/*	DELAY(100);
/*	omaddr->CSR_EIR = 0;
/*
/*	/* Wait for the omega to become ready. */
/*	while((omaddr->CSR_EIR)&OM_STATC)
/*		sleep((caddr_t)sc, OMPRI);
/*
/* ************************************************************************ */

	/* Enable interrupts. */
	omaddr->CSR_EIR = OM_IENABLE;


	/* Make sure the device is really there and OK. */
/* forget this! */
/*	if (((omaddr->CSR_EIR) >> OM_BUSY_SHIFT) & 1) {
/*		u.u_error = EIO;
/*		sc->sc_state = 0;
/*		return;
/*		}
*/
}


/* OMCLOSE */
/* Close the device. */

omclose(dev)
	dev_t dev;
{
	register struct om_softc *sc = &om_softc[OMUNIT(dev)];

	/* Set the state blank. */
	sc->sc_state = 0;
}


/* OMREAD */
/* Reads characters from the device. If in stall mode, the read will be the
   standard read which will not return until the requested number of characters
   have been read. If in no stall mode, then the read will return after an
   interval set in omioctl and report how many characters it read.
   The count must be even since the DMA is by words. */

omread(dev)
	dev_t dev;
{
	register struct om_softc *sc = &om_softc[OMUNIT(dev)];
	register struct omdevice *omaddr =
	    (struct omdevice *)omdinfo[OMUNIT(dev)]->ui_addr;
	register int spl;

	/* Make sure that the count is even. */
	if (u.u_count & 1) {
		u.u_error = EINVAL;
		return;
		}

	/* Set the DR11-W to read. */
	sc->sc_operation = OM_READ;

	/* The following is to make up for something physio should really do
	   for us. If bp->b_resid has been left non-zero by the last call,
	   (ie an error), and the present call has a count of zero then the
	   old residual will be returned as the count. To correct this, we just
	   set the residual to zero before we start. */
	rombuf[OMUNIT(dev)].b_resid = 0;

	/* Are we in no stall or stall mode? */
	if ((sc->sc_state) & OMSC_NORSTALL) {

		/* We're in no stall mode. */

		/* Start the timer running. */
		/* Don't let anything stop us once the timer's running. */
		spl = spl6();
		timeout(omrwtimo, (caddr_t)
				( ((sc->sc_currenttimo)<<8) | OMUNIT(dev) ),
							(sc->sc_rtimoticks));

		/* Perform the read. */
		physio(omstrategy, &rombuf[OMUNIT(dev)], dev, B_READ, minomph);
		if (u.u_error) (void) splx(spl);

		/* Update the current timeout number. */
		(sc->sc_currenttimo)++;

		/* Did we timeout? */
		if ((sc->sc_state) & OMSC_TIMEDOUT) {

			/* Clear the timeout. */
			(sc->sc_state) &= (~OMSC_TIMEDOUT);

			/* Patch up the error. */

			/* We made the error ourself, ignore it. */
			u.u_error = 0;
			}
		}

	    else {

		/* We're in stall mode. */

		/* Perform the read. */
		physio(omstrategy, &rombuf[OMUNIT(dev)], dev, B_READ, minomph);
		}
}


/* OMWRITE */
/* omwrite writes the passed data to the device using DMA.
   The count must be even since the DMA is by words. */
/* Timeouts are handled as in omread. */

omwrite(dev)
	dev_t dev;
{
	register struct om_softc *sc = &om_softc[OMUNIT(dev)];
	register int spl;

	/* Make sure that the count is even. */
	if (u.u_count & 1) {
		u.u_error = EINVAL;
		return;
		}

	/* This call is to write around a system bug--on a B_WRITE call to
	   physio, the system checks to see if the user has read access to the
	   requested block.  Then it locks necessary pages in virtual memory.
	   It checks for write access in the course of this, and, if the user
	   does not have it, panics ("vslock").  So, if the user sends, say, an
	   address in his code (0 is an example), the system crashes.  So I
	   start by checking for write access. */
	if (useracc(u.u_base,u.u_count,B_WRITE) == NULL) {
		u.u_error = EFAULT;
		return;
		}

	/* Set the DR11-W to write. */
	sc->sc_operation = OM_WRITE;

	/* The following is to make up for something physio should really do
	   for us. If bp->b_resid has been left non-zero by the last call,
	   (ie an error), and the present call has a count of zero then the
	   old residual will be returned as the count. To correct this, we just
	   set the residual to zero before we start. */
	rombuf[OMUNIT(dev)].b_resid = 0;

	/* Are we in no stall or stall mode? */
	if ((sc->sc_state) & OMSC_NOWSTALL) {

		/* We're in no stall mode. */

		/* Start the timer running. */
		/* Don't let anything stop us once the timer's running. */
		spl = spl6();
		timeout(omrwtimo, (caddr_t)
				( ((sc->sc_currenttimo)<<8) | OMUNIT(dev) ),
							(sc->sc_wtimoticks));

		/* Perform the write. */
		physio(omstrategy, &rombuf[OMUNIT(dev)], dev,
							B_WRITE, minomph);
		if (u.u_error) (void) splx(spl);

		/* Update the current timeout number. */
		(sc->sc_currenttimo)++;

		/* Did we timeout? */
		if ((sc->sc_state) & OMSC_TIMEDOUT) {

			/* Clear the timeout. */
			(sc->sc_state) &= (~OMSC_TIMEDOUT);

			/* Patch up the error. */

			/* We made the error ourself, ignore it. */
			u.u_error = 0;
			}
		}

	    else {

		/* We're in stall mode. */

		/* Perform the write. */
		physio(omstrategy, &rombuf[OMUNIT(dev)], dev,
							B_WRITE, minomph);
		}
}


/* OMIOCTL */
/* IO control function. */

omioctl(dev, cmd, addr, flag)
	dev_t dev;
	int cmd;
	register caddr_t addr;
	int flag;

{
	register struct om_softc *sc = &om_softc[OMUNIT(dev)];
	register struct omdevice *omaddr =
	    (struct omdevice *)omdinfo[OMUNIT(dev)]->ui_addr;
	int temp;

	switch(cmd) {

	case OM_SETRSTALL:

		/* Set read stall mode. */
		(sc->sc_state) &= (~OMSC_NORSTALL);
		break;

	case OM_SETNORSTALL:

		/* Set read stall mode. */
		(sc->sc_state) |= OMSC_NORSTALL;
		break;

	case OM_GETRSTALL:

		/* Returns true if in read stall mode. */
		temp = (!((sc->sc_state)&OMSC_NORSTALL));
		if (copyout((caddr_t)&temp, addr, sizeof(temp))) {
			u.u_error = EFAULT;
			}
		break;

	case OM_SETRTIMEOUT:

		/* Set the number of ticks before a no stall read times out.
		   The argument is given in tenths of a second. */
		if (copyin(addr, (caddr_t)&temp, sizeof(temp))) {
			u.u_error = EFAULT;
			break;
			}
		if (temp < 1) {
			u.u_error = EINVAL;
			temp = 1;
			}
		(sc->sc_rtimoticks) = (temp * hz )/10;
		break;

	case OM_GETRTIMEOUT:

		/* Returns the number of tenths of seconds before
		   a no stall read times out. */
		/* The argument is given in tenths of a second. */
		temp = ((sc->sc_rtimoticks)*10)/hz;
		if (copyout((caddr_t)&temp, addr, sizeof(temp))) {
			u.u_error = EFAULT;
			}
		break;

	case OM_SETWSTALL:

		/* Set write stall mode. */
		(sc->sc_state) &= (~OMSC_NOWSTALL);
		break;

	case OM_SETNOWSTALL:

		/* Set write stall mode. */
		(sc->sc_state) |= OMSC_NOWSTALL;
		break;

	case OM_GETWSTALL:

		/* Returns true if in write stall mode. */
		temp = (!((sc->sc_state)&OMSC_NOWSTALL));
		if (copyout((caddr_t)&temp, addr, sizeof(temp))) {
			u.u_error = EFAULT;
			}
		break;

	case OM_SETWTIMEOUT:

		/* Set the number of ticks before a no stall write times out.
		   The argument is given in tenths of a second. */
		if (copyin(addr, (caddr_t)&temp, sizeof(temp))) {
			u.u_error = EFAULT;
			break;
			}
		if (temp < 1) {
			u.u_error = EINVAL;
			temp = 1;
			}
		(sc->sc_wtimoticks) = (temp * hz )/10;
		break;

	case OM_GETWTIMEOUT:

		/* Returns the number of tenths of seconds before
		   a no stall write times out. */
		/* The argument is given in tenths of a second. */
		temp = ((sc->sc_wtimoticks)*10)/hz;
		if (copyout((caddr_t)&temp, addr, sizeof(temp))) {
			u.u_error = EFAULT;
			}
		break;

	case OM_WRITEREADY:

		/* Returns a value of 1 if the device can accept
		   data, 0 otherwise. Internally this is the
		   DR11-W STAT A bit. */
		temp = (((omaddr->CSR_EIR) >> OM_WRITE_SHIFT) & 1);
		if (copyout((caddr_t)&temp, addr, sizeof(temp))) {
			u.u_error = EFAULT;
			}
		break;

	case OM_READREADY:

		/* Returns a value of 1 if the device has data
		   to be read, 0 otherwise. Internally this is
		   the DR11-W STAT B bit. */
		temp = (((omaddr->CSR_EIR) >> OM_READ_SHIFT) & 1);
		if (copyout((caddr_t)&temp, addr, sizeof(temp))) {
			u.u_error = EFAULT;
			}
		break;

	case OM_BUSY:

		/* Returns a value of 1 if the device is busy,
		   0 otherwise. Internally this is the DR11-W
		   STAT C bit. */
		temp = (((omaddr->CSR_EIR) >> OM_BUSY_SHIFT) & 1);
		if (copyout((caddr_t)&temp, addr, sizeof(temp))) {
			u.u_error = EFAULT;
			}
		break;

	case OM_RESET:

		/* Resets the OMEGA to its power on condition
		   by asserting the CSR MAINTENANCE bit. */

		/* Initialize the DR11-W by setting then clearing MAINT
		   in the CSR with CYCLE and GO clear. */
		omaddr->CSR_EIR = 0;
		omaddr->CSR_EIR = OM_MAINT;
		DELAY(100);
		omaddr->CSR_EIR = 0;

		/* Wait for the omega to become ready. */
/* forget this! */
/*		while((omaddr->CSR_EIR)&OM_STATC)
/*			tsleep((caddr_t)sc, OMPRI, 30);
*/
		break;

	default:

		/* Flag the error. */
		u.u_error = EINVAL;
		break;

	}

	return;
}


/* OMSTRATEGY */
/* Routine to determine the DMA strategy for physio. */

omstrategy(bp)
	register struct buf *bp;
{
	register int e;
	register int spl;
	register struct om_softc *sc = &om_softc[OMUNIT(bp->b_dev)];
	register struct uba_device *ui = omdinfo[OMUNIT(bp->b_dev)];
	register struct omdevice *omaddr = (struct omdevice *)ui->ui_addr;

	spl = spl6();
	while (sc->sc_state & OMSC_BUSY)
		tsleep((caddr_t)sc, OMPRI, 30);
	sc->sc_state |= OMSC_BUSY;
	sc->sc_ubinfo = ubasetup(ui->ui_ubanum, bp, UBA_NEEDBDP);
	omstart(bp->b_dev, bp->b_bcount);
	e = omwait(bp->b_dev);
	(bp->b_resid) = u.u_count - (bp->b_bcount) +
						(((-(omaddr->WC))&0xFFFF)<<1);
	(void) splx(spl);
	ubarelse(ui->ui_ubanum, &sc->sc_ubinfo);
	sc->sc_state &= ~OMSC_BUSY;
	iodone(bp);
	if (e)
		/* Cause physio to terminate and
		   geterror to give an EIO error. */
		(bp->b_flags) |= B_ERROR;
	wakeup((caddr_t)sc);
}


/* MINOMPH */
/* Set the maximum physical transfer size. */

unsigned
minomph(bp)
	struct buf *bp;
{

	if (bp->b_bcount > OM_BLOCKSIZE)
		bp->b_bcount = OM_BLOCKSIZE;
}


/* OMSTART */
/* Start a DMA IO transfer. */

omstart(dev, count)
	dev_t dev;
	long count;
{
	register int spl;
	register struct om_softc *sc = &om_softc[OMUNIT(dev)];
	register struct omdevice *omaddr =
	    (struct omdevice *)omdinfo[OMUNIT(dev)]->ui_addr;
	int i;

	spl = spl7();	/* don't interrupt me with a cursor */
	for (i = 100; (omaddr->CSR_EIR & OM_READY == 0) && i; --i)
		;	/* wait in case cursor dma active */
	if (i == 0)
	{
		(void) splx(spl);
		printf("omstart: device busy\n");
		u.u_error = EIO;
		return;
	}

	/* Set the DMA buffer address. */
	(omaddr->BAR) = (sc->sc_ubinfo);

	/* Set the word count to the 2's complement
	   of the count in words. */
	(omaddr->WC) = (-(count>>1));

	/* Start the transfer with interrupts enabled. */
	(omaddr->CSR_EIR) = (OM_IENABLE | (sc->sc_operation) |
	     ((sc->sc_ubinfo >> 12) & OM_XBA));
	(omaddr->CSR_EIR) = (OM_IENABLE | (sc->sc_operation) |
	     ((sc->sc_ubinfo >> 12) & OM_XBA)| OM_GO);

	(void) splx(spl);
	return;
}


/* OMRWTIMO */
/* Routine to deal with no stall read/write timeouts. If the read/write
   completed by itself, we just return. If not, we mark a timeout and
   cause a DMA error and interrupt. */

omrwtimo(timeoutinfo)
	register unsigned int timeoutinfo;
	/* The low 8 bits of timeoutinfo are the minor device number.
	   The remaining higher bits are the current timeout number. */
{
	register int minordev = OMUNIT(timeoutinfo);
	register struct om_softc *sc = &om_softc[minordev];
	register struct omdevice *omaddr =
		(struct omdevice *)omdinfo[minordev]->ui_addr;

	/* If this is not the timeout that omread/omwrite is waiting for
	   then we should just go away. */
	if ((timeoutinfo&(~0377)) != ((sc->sc_currenttimo)<<8)) return;

	/* Mark that the device timed out. */
	(sc->sc_state) |= OMSC_TIMEDOUT;

	/* Send an OM_WAKEUP signal to halt any pending DMA and generate
	   an interrupt so that omwait will see the error and tell everyone
	   the transfer is done. */
	omaddr->CSR_EIR = (OM_ATTN | OM_WAKEUP | OM_IENABLE);
}


/* OMWAIT */
/* Wait for the DR11-W to come ready.
   Return a non-zero value if there is an error. */

omwait(dev)
	dev_t dev;
{
	register struct omdevice *omaddr =
	    (struct omdevice *)omdinfo[OMUNIT(dev)]->ui_addr;
	register struct om_softc *sc = &om_softc[OMUNIT(dev)];
	register int e;

	while (!((e = (omaddr->CSR_EIR)) & OM_READY)) {
		tsleep((caddr_t)sc, OMPRI, 30);
		}

	/* Reset any error conditions. */
	(omaddr->CSR_EIR) = OM_IENABLE;

	return (e & OM_ERROR);
}


/* OMINTR */
/* Wakup any process waiting for an interrupt. */

omintr(dev)
	dev_t dev;
{
	register struct om_softc *sc = &om_softc[OMUNIT(dev)];

	wakeup((caddr_t)sc);
}


/* OMTIMO */
/* Kick the driver every second. */

omtimo(dev)
	dev_t dev;
{
	register struct om_softc *sc = &om_softc[OMUNIT(dev)];

	if (sc->sc_state&OMSC_OPEN)
		timeout(omtimo, (caddr_t)dev, hz);
	omintr(dev);
}

omcur(dev, x, y)	/* position cursor - called from bpd driver */
dev_t dev;
{
        register struct uba_device *ui = omdinfo[minor(dev)];
        register struct omdevice *omp = (struct omdevice *)(ui->ui_addr);
        register struct om_softc *oms = &om_softc[minor(dev)];
        register i, j;
	int spl;

	spl = spl6();
        if( (oms->sc_state & OMSC_OPEN == 0) ||
	    (oms->sc_state & OMSC_BUSY)      ||
	    (omp->CSR_EIR & OM_READY == 0) )
		return;
        x *= 1280; x /= 1024;	/* scale x coordinate	*/
	y = 1024 - y;		/* negate y coordinate	*/
	/* setup cursor command */
	oms->sc_curbuf[0] = 0x52;		/* movp1 opcode	*/
	oms->sc_curbuf[1] = x & 0xFF;
	oms->sc_curbuf[2] = (x >> 8) & 0x07;
	oms->sc_curbuf[3] = y & 0xFF;
	oms->sc_curbuf[4] = (y >> 8) & 0x07;
	oms->sc_curbuf[5] = 0x71;		/* display cursor opcode */

	omp->BAR = oms->sc_ubadd;		/* setup dma	*/
	omp->WC = -3;	
	omp->CSR_EIR = OM_WRITE|(OM_XBA & (oms->sc_ubadd >> 12));
	omp->CSR_EIR = OM_WRITE|OM_GO|(OM_XBA & (oms->sc_ubadd >> 12));
	splx(spl);
}