To: wesommer@mit.eduF
Cc: nathanw@mit.edu
From: Nathan J. Williams <nathanw@mit.edu>
Subject: LM78 round 2
--------


	Here's a new round of diffs 




Index: lm78.c
===================================================================
RCS file: lm78.c
diff -N lm78.c
*** /dev/null	Tue Mar  9 18:11:11 1999
--- lm78.c	Tue Mar  9 20:20:16 1999
***************
*** 0 ****
--- 1,340 ----
+ 
+ #define LM78_DEBUG
+ 
+ #include <sys/param.h>
+ #include <sys/systm.h>
+ #include <sys/device.h>
+ #include <sys/ioctl.h>
+ #include <sys/conf.h>
+ 
+ #include <machine/cpu.h>
+ #include <machine/bus.h>
+ 
+ #include <dev/isa/isavar.h>
+ 
+ #include <dev/isa/lm78reg.h>
+ #include <dev/isa/lm78var.h>
+ #include <dev/isa/lm78io.h>
+ 
+ int lm78_probe __P((struct device *, struct cfdata *, void *));
+ void lm78_attach __P((struct device *, struct device *, void *));
+ 
+ int lm78_read __P((struct lm78_softc *, int offset));
+ void lm78_write __P((struct lm78_softc *, int offset, int value));
+ int lm78_ready __P((struct lm78_softc *));
+ 
+ void lm78_load_status __P((struct lm78_softc *));
+ 
+ #ifdef LM78_DEBUG
+ void lm78_dump __P((struct lm78_softc *));
+ #endif
+ 
+ struct cfattach lm_ca = {
+ 	sizeof(struct lm78_softc), lm78_probe, lm78_attach
+ };
+ 
+ extern struct cfdriver lm_cd;
+ 
+ cdev_decl(lm);
+ 
+ extern volatile struct timeval mono_time;
+ 
+ #ifdef LM78_DEBUG
+ #define DPRINTF(x) printf x
+ #else
+ #define DPRINTF
+ #endif
+ 
+ int
+ lm78_probe(parent, match, aux)
+ 	struct device *parent;
+ 	struct cfdata *match;
+ 	void *aux;
+ {
+ 	struct isa_attach_args *ia = aux;
+ 	struct lm78_softc probesc, *sc= &probesc;
+ 
+ 	bus_space_tag_t iot;
+ 	bus_space_handle_t ioh;
+ 
+ 	int i, found;
+ 
+ 	iot = ia->ia_iot;
+ 	sc->sc_iot = iot;
+ 
+ 	/* We can't figure out the IO base, so wildcarding fails. */
+ 	if (ia->ia_iobase == IOBASEUNK)
+ 		return (0);
+ 
+ 	/* 
+      * The range of the LM78 overlaps with the range of the DMA
+ 	 * page mapping registers.
+ 	 * It "just so happens" that the ports interleave, and we don't 
+ 	 * need the ports at the bottom of the LM78's range, so we 
+ 	 * just allocate the two that we need. 
+ 	 */
+  
+ 	if (bus_space_map(iot, ia->ia_iobase + LM78_BASE_OFF, LM78_IOSIZE_OFF,
+ 			0, &ioh))
+ 		return (0);
+ 
+ 	sc->sc_ioh = ioh;
+ 	ia->ia_iosize = LM78_IOSIZE;
+ 	ia->ia_msize = 0;
+ 
+ 	/*
+ 	 * Here is the actual probe: Check that the value of the 
+ 	 * Serial Bus Address register has the reset value. 
+ 	 */
+ 	i = lm78_read(sc, LM78_SERIALADDR);
+ 	found = (i == LM78_SERIALADDR_DEFAULT);
+ 	
+ 	bus_space_unmap(iot, ioh, LM78_IOSIZE_OFF);
+ 
+ 	return found;
+ }
+ 	
+ void lm78_attach(parent, self, aux)
+ 	 struct device *parent, *self;
+ 	 void *aux;
+ {
+ 	struct lm78_softc *sc = (void *)self;
+ 	struct isa_attach_args *ia = aux;
+ 
+ 	printf("\n");
+ 
+ 	sc->sc_iot = ia->ia_iot;
+ 
+ 	if (bus_space_map(sc->sc_iot, ia->ia_iobase + LM78_BASE_OFF, 
+ 			LM78_IOSIZE_OFF, 0, &sc->sc_ioh)) {
+ 		DPRINTF(("lm78_attach: Couldn't map I/O region at %x, size %x\n",
+ 			ia->ia_iobase + LM78_BASE_OFF, LM78_IOSIZE_OFF));
+ 		return;
+ 	}
+ #ifdef LM78_DEBUG
+ 	lm78_dump(sc);
+ #endif
+ 
+ 	/* Reset chip */
+ 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, 
+ 		LM78_RESETID, LM78_RESETID_RESET);
+ 
+ 	sc->last_read.tv_sec = 0;
+ 	sc->last_read.tv_usec = 0;
+ 	
+ }
+ 
+ #ifdef LM78_DEBUG
+ void
+ lm78_dump(sc)
+ 	struct lm78_softc *sc;
+ {
+ 	int i, j;
+ 	  
+ 	for (i = 0; i < 0x80; i++) {
+ 		if (i % 16 == 0)
+ 		  printf("\nLM78 space from %02x: ", i);
+ 		j = lm78_read(sc, i);
+ 		if (j == -1)
+ 		  printf("-- ");
+ 		else
+ 		  printf("%02x ", j);
+ 	  }
+  printf("\n");
+ }
+ #endif
+ 
+ int
+ lmopen(dev, flags, fmt, p)
+ 	dev_t dev;
+ 	int flags, fmt;
+ 	struct proc *p;
+ {
+ 	int unit = minor(dev);
+ 	struct lm78_softc *sc;
+ 
+ 	if (unit >= lm_cd.cd_ndevs ||
+ 		(sc = lm_cd.cd_devs[unit]) == NULL)
+ 			return (ENXIO);
+ 
+ 	/* XXX Do we actually need to do anything here? */
+ 
+ 	return (0);	
+ }
+ 
+ int
+ lmclose(dev, flags, fmt, p)
+ 	dev_t dev;
+ 	int flags, fmt;
+ 	struct proc *p;
+ {
+ 	/* XXX Again, do we need to do anything? */
+ 	return (0);
+ }
+ 
+ int
+ lmread(dev, uio, flags)
+ 	dev_t dev;
+ 	struct uio *uio;
+ 	int flags;
+ {
+ 	/* What do we want to return, anyway? */
+ 	return (ENODEV);
+ }
+ 
+ int
+ lmwrite(dev, uio, flags)
+ 	dev_t dev;
+ 	struct uio *uio;
+ 	int flags;
+ {
+ 	return (ENODEV);
+ }
+ 
+ int
+ lmioctl(dev, cmd, data, flags, p)
+ 	dev_t dev;
+ 	u_long cmd;
+ 	caddr_t data;
+ 	int flags;
+ 	struct proc *p;
+ {
+ 	struct timeval now;
+ 	int unit = minor(dev);
+ 	struct lm78_softc *sc = lm_cd.cd_devs[unit];
+ 	int tmp;
+ 
+ 	switch (cmd) {
+ 	case LM78GET:
+ 	  /* For proper operation, the full set of ADC values can not 
+        * be read more often than every 1.5 seconds. If less time has
+        * passed, return the old data. 
+ 	   */
+ 		now = mono_time;
+ 		if ((now.tv_sec - sc->last_read.tv_sec) > 1 ||
+ 			((now.tv_sec - sc->last_read.tv_sec == 1) && 
+ 			 (now.tv_usec + (1000000 - sc->last_read.tv_usec) > 500000)))
+ 			lm78_load_status(sc);
+ 		memcpy(data, &sc->status, sizeof(sc->status));
+ 		break;
+ 
+ 	case LM78CLEARCHAS:
+ 		tmp = lm78_read(sc, LM78_NMI2);
+ 		lm78_write(sc, LM78_NMI2, tmp | LM78_NMI2_CHASCLEAR);
+ 		break;
+ 		
+ 		
+ 		  
+ 	default:
+ 		return (ENOTTY);	  
+ 	}
+ 
+ 	return (0);
+ }
+ 
+ void
+ lm78_load_status(sc)
+ 	struct lm78_softc *sc;
+ {
+ 	int fancnt, divvid, isr;
+   /*
+    * Grab the time before we start reading, to ensure acceptable delays
+    * between successive reads.
+    */
+ 	sc->last_read = mono_time;
+ 
+ 	sc->status.analog[0] = 16 * lm78_read(sc, LM78_VALUE_IN0);
+ 	sc->status.analog[1] = 16 * lm78_read(sc, LM78_VALUE_IN1);
+ 	sc->status.analog[2] = 16 * lm78_read(sc, LM78_VALUE_IN2);
+ 	sc->status.analog[3] = 16 * lm78_read(sc, LM78_VALUE_IN3);
+ 	sc->status.analog[4] = 16 * lm78_read(sc, LM78_VALUE_IN4);
+ 	sc->status.analog[5] = 16 * lm78_read(sc, LM78_VALUE_IN5);
+ 	sc->status.analog[6] = 16 * lm78_read(sc, LM78_VALUE_IN6);
+ 
+ 	sc->status.temp = lm78_read(sc, LM78_VALUE_TEMP);
+ 
+ 	divvid = lm78_read(sc, LM78_VIDFAN);
+ 	
+ 	sc->status.din = divvid & 15;
+ 	divvid >>= 4;
+ 
+ 	fancnt = lm78_read(sc, LM78_VALUE_FAN1);
+ 	if (fancnt <= 0)
+ 		sc->status.fanspeed[0] = -1;
+ 	else
+ 		sc->status.fanspeed[0] = LM78_RPM(fancnt, divvid >> 2);
+ 
+ 	fancnt = lm78_read(sc, LM78_VALUE_FAN2);
+ 	if (fancnt <= 0)
+ 		sc->status.fanspeed[1] = -1;
+ 	else
+ 		sc->status.fanspeed[1] = LM78_RPM(fancnt, divvid & 3);
+ 
+ 	fancnt = lm78_read(sc, LM78_VALUE_FAN3);
+ 	if (fancnt <= 0)
+ 		sc->status.fanspeed[2] = -1;
+ 	else
+ 		sc->status.fanspeed[2] = LM78_RPM(fancnt, 2);
+ 
+ 	/* XXX this clears pending interrupts */
+ 	isr = lm78_read(sc, LM78_ISR2);
+ 	if (isr & LM78_MASK2_CHAS)
+ 		sc->status.intrusion = 1;
+ 	else
+ 		sc->status.intrusion = 0;
+ }
+ 
+ int
+ lm78_read(sc, offset)
+ 	struct lm78_softc *sc;
+ 	int offset;
+ {
+ 
+ 	bus_space_tag_t iot = sc->sc_iot;
+ 	bus_space_handle_t ioh = sc->sc_ioh;
+ 	int i;
+ 
+ 	for (i = LM78_TIMEOUT; i > 0; --i) {
+ 		if (lm78_ready(sc)) {
+ 			bus_space_write_1(iot, ioh, LM78_ADDR_OFF, offset);
+ 			i = bus_space_read_1(iot, ioh, LM78_DATA_OFF);
+ 			return i;
+ 		} else
+ 			delay(10);
+ 	}
+ 
+ 	DPRINTF(("lm78_read: timed out\n"));
+ 	return (-1);
+ }
+ 
+ void
+ lm78_write(sc, offset, value)
+ 	struct lm78_softc *sc;
+ 	int offset, value;
+ {
+ 
+ 	bus_space_tag_t iot = sc->sc_iot;
+ 	bus_space_handle_t ioh = sc->sc_ioh;
+ 	int i;
+ 
+ 	for (i = LM78_TIMEOUT; i > 0; --i) {
+ 		if (lm78_ready(sc)) {
+ 			bus_space_write_1(iot, ioh, LM78_ADDR_OFF, offset);
+ 			bus_space_write_1(iot, ioh, LM78_DATA_OFF, value);
+ 		} else
+ 			delay(10);
+ 	}
+ 
+ 	DPRINTF(("lm78_write: timed out\n"));
+ }
+ 
+ int
+ lm78_ready(sc)
+ 	 struct lm78_softc *sc;
+ {
+ 	return ((bus_space_read_1(sc->sc_iot, sc->sc_ioh, LM78_ADDR_OFF) & 
+ 			 LM78_ADDR_BUSY) == 0);
+ }
+ 
+ 
Index: lm78reg.h
===================================================================
RCS file: lm78reg.h
diff -N lm78reg.h
*** /dev/null	Tue Mar  9 18:11:11 1999
--- lm78reg.h	Tue Mar  9 20:20:16 1999
***************
*** 0 ****
--- 1,177 ----
+ 
+ 
+ /* 
+  * All data from National Semiconducter's data sheet.
+  * http://www.national.com/ds/LM/LM78.pdf
+  */
+ 
+ 
+ #define LM78_IOSIZE	8
+ 
+ /* Registers in the IO space */
+ #define LM78_POST1	0x00
+ #define LM78_POST2	0x04
+ #define LM78_ADDR	0x05
+ #define   LM78_ADDR_BUSY	(1<<7)
+ #define LM78_DATA	0x06
+ 
+ /* 
+  * Because of the evil overlap with the DMA mapping registers, we're going
+  * to need offsets relative to where we start mapping this device, not the
+  * actual bottom of its I/O space.
+  */
+ 
+ #define LM78_BASE_OFF 	LM78_ADDR
+ #define LM78_IOSIZE_OFF	2
+ #define LM78_ADDR_OFF (LM78_ADDR - LM78_BASE_OFF)
+ #define LM78_DATA_OFF (LM78_DATA - LM78_BASE_OFF)
+ 
+ 
+ /* Registers in the LM78's internal address space */
+ 
+ /*
+  * Accessing certain regions of the internal address space will 
+  * automatically increment the value of the LM78_ADDR register, allowing
+  * regions to be written a little more easily. Those regions are noted 
+  * in the list below.
+  * The autoincrementing stops when it reaches the end of the 
+  * range, rather than wrapping around.
+  */
+  
+ /* POST data written to 0x80 and 0x84 during boot */
+ #define LM78_POSTBASE	0x00	/* Auto-incrementing */
+ #define LM78_POSTSIZE	0x20
+ 
+ /* Storage for the values sampled from the system */
+ #define LM78_VALUEBASE	0x20
+ #define LM78_VALUESIZE	0x20
+ 
+ /* 
+  * The data sheet says that reading these causes the ADC to restart 
+  * conversion, so no one value should be read more often than 
+  * every 120ms.
+  */
+ 
+ /* 8-bit ADC */
+ 
+ /* Scale: 16mV. Total range is 0-4.08V */
+ #define LM78_VALUE_IN0		0x20
+ #define LM78_VALUE_IN1		0x21
+ #define LM78_VALUE_IN2		0x22
+ #define LM78_VALUE_IN3		0x23
+ #define LM78_VALUE_IN4		0x24
+ #define LM78_VALUE_IN5		0x25	/* Inverted */
+ #define LM78_VALUE_IN6		0x26	/* Inverted */
+ 
+ /*
+  * This value is two's-compliment in one degree C steps, so the 
+  * expressable range is -128 deg C to 127 deg C (-198 deg F to 
+  * 260 deg F for the old-fashioned). 
+  */
+ #define LM78_VALUE_TEMP 	0x27
+ 
+ /*
+  * Count from a 22.5kHz oscillator, reset twice per fan revolution.
+  * The relation between the count and fan RPM is:
+  * RPM = 1.35e6 / (count * divisor) 
+  * where divisor can be set to 1,2,4, or 8 for fan 1 and 2, and 
+  * fan3 always has a divisor value of 2.
+  */
+ #define LM78_RPM(count, div) (1350000L/((count)*(div)))
+ #define LM78_VALUE_FAN1		0x28
+ #define LM78_VALUE_FAN2		0x29
+ #define LM78_VALUE_FAN3		0x2a
+ 
+ /* If one of the seven analog inputs goes outside the [low,high] range
+  * specified here, an interrupt will be triggered (conditional on the 
+  * SMI/NMI/IRQ masks, of course).
+  * The high interrupt may be disabled by setting the threshold to 0xff 
+  */
+ #define LM78_VALUE_IN0_HIGH	0x2b
+ #define LM78_VALUE_IN0_LOW	0x2c
+ #define LM78_VALUE_IN1_HIGH	0x2d
+ #define LM78_VALUE_IN1_LOW	0x2e
+ #define LM78_VALUE_IN2_HIGH	0x2f
+ #define LM78_VALUE_IN2_LOW	0x30
+ #define LM78_VALUE_IN3_HIGH	0x31
+ #define LM78_VALUE_IN3_LOW	0x32
+ #define LM78_VALUE_IN4_HIGH	0x33
+ #define LM78_VALUE_IN4_LOW	0x34
+ #define LM78_VALUE_IN5_HIGH	0x35
+ #define LM78_VALUE_IN5_LOW	0x36
+ #define LM78_VALUE_IN6_HIGH	0x37
+ #define LM78_VALUE_IN6_LOW	0x38
+ 
+ /* 
+  * Normally, a temperature interrupt will be generated when the 
+  * temperature goes above HIGH, and then again when it goes below HYST. 
+  * If HYST is set to 127, the interrupt will be set whenever the temperature
+  * is greater than HIGH.
+  */
+ #define LM78_VALUE_TEMP_HIGH	0x39
+ #define LM78_VALUE_TEMP_HYST	0x3a /* Temperature hysteresis threshold */
+ 
+ /*
+  * If the counter exceeds this value (that is, if the fan is spinning
+  * too slowly), an interrupt will be generated. 
+  * The interrupt may be disabled by setting the limit to 0xff.
+  */
+ #define LM78_VALUE_FAN1_LIMIT	0x3b
+ #define LM78_VALUE_FAN2_LIMIT	0x3c
+ #define LM78_VALUE_FAN3_LIMIT	0x3d
+ 
+ 
+ #define LM78_CONF	0x40
+ #define   LM78_CONF_ENABLE	(1<<0)	/* Enable monitoring loop */
+ #define   LM78_SMI_ENABLE	(1<<1)
+ #define   LM78_NMIIRQ_ENABLE	(1<<2)
+ #define   LM78_INT_CLEAR	(1<<3)	/* Disables SMI and NMI/IRQ */
+ #define   LM78_RESET		(1<<4)
+ #define   LM78_NMIIRQ_SELECT	(1<<5)  /* 0 for irq, 1 for NMI */
+ #define   LM78_PSWITCH_BYPASS	(1<<6)
+ #define   LN78_INITIALIZE	(1<<7)	/* Set register values to defaults */
+ 
+ /* Interrupt status */ 
+ /* Reading the ISR clears the interrupt */
+ #define LM78_ISR1	0x41	/* Auto-increments to ISR2 */
+ #define LM78_ISR2	0x42
+ /* SMI mask */
+ #define LM78_SMI1	0x43	/* Auto-increments to SMI2 */
+ #define LM78_SMI2	0x44
+ #define   LM78_SMI2_RESET_ENABLE	(1<<7)
+ /* NMI/IRQ mask */
+ #define LM78_NMI1	0x45	/* Auto-increments to NMI2 */
+ #define LM78_NMI2	0x46
+ #define   LM78_NMI2_CHASCLEAR	(1<<7)	/* Valid in NMI2 only */
+ 
+ /* The status/mask registers use the following bits: */
+ #define LM78_MASK1_IN0	(1<<0)
+ #define LM78_MASK1_IN1	(1<<1)
+ #define LM78_MASK1_IN2	(1<<2)
+ #define LM78_MASK1_IN3	(1<<3)
+ #define LM78_MASK1_TEMP	(1<<4)
+ #define LM78_MASK1_BTI	(1<<5)
+ #define LM78_MASK1_FAN1 (1<<6)
+ #define LM78_MASK1_FAN2 (1<<7)
+ 
+ #define LM78_MASK2_IN4	(1<<0)
+ #define LM78_MASK2_IN5	(1<<1)
+ #define LM78_MASK2_IN6	(1<<2)
+ #define LM78_MASK2_FAN3 (1<<3)
+ #define LM78_MASK2_CHAS (1<<4)	/* Chassis intrusion */
+ #define LN78_MASK2_OFLW (1<<5)	/* POST RAM overflow */
+ #define LN78_MASK2_SMI	(1<<6)
+ 
+ #define LM78_VIDFAN	0x47 	/* Fan 1 and 2 divisors and VID readings */
+ #define   LM78_VIDFAN_VIDMASK	0x0f
+ #define   LM78_VIDFAN_FAN1MASK	0x30 
+ #define   LM78_VIDFAN_FAN2MASK	0xc0 
+ #define LM78_SERIALADDR	0x48 	/* Serial bus address */
+ #define   LM78_SERIALADDR_DEFAULT	0x2d 	/* Used for probing */
+ #define LM78_RESETID	0x49
+ #define   LM78_RESETID_RESET	(1<<5) 	/* Write this bit to reset the chip */
+ #define   LM78_DEVID		(1<<6) 	/* 1 for the LM78-J, 0 for older */
+ 
+ /* Same value RAM, but this range autoincrements */
+ #define LM78_VALUE2BASE	0x60 
+ #define LM78_VALUE2SIZE 0x20 
Index: lm78var.h
===================================================================
RCS file: lm78var.h
diff -N lm78var.h
*** /dev/null	Tue Mar  9 18:11:11 1999
--- lm78var.h	Tue Mar  9 20:20:16 1999
***************
*** 0 ****
--- 1,22 ----
+ 
+ struct lm78_data {
+ 	int analog[7];		/* mV */
+ 	int temp;		/* deg C */
+  	int fanspeed[3];	/* RPM */
+ 	int din;		/* four bits of digital input */
+ 	int intrusion;		/* Has their been a chassis intrusion? */
+ };
+ 
+ struct lm78_softc {
+ 	struct device sc_dev;
+ 
+ 	bus_space_tag_t sc_iot;
+ 	bus_space_handle_t sc_ioh;
+ 
+ 	struct timeval last_read;
+ 	struct lm78_data status;
+ };
+ 
+ 
+ /* Length of time we'll retry a read or write. */
+ #define LM78_TIMEOUT	5000 	/* 5ms */
Index: lm78io.h
===================================================================
RCS file: lm78io.h
diff -N lm78io.h
*** /dev/null	Tue Mar  9 18:11:11 1999
--- lm78io.h	Tue Mar  9 20:20:16 1999
***************
*** 0 ****
--- 1,9 ----
+ 
+ 
+ /* 
+  * ioctl definitions for LM78 interface.
+  */
+ 
+ 
+ #define LM78GET		_IOR('l', 1, struct lm78_data)	/* Grab status */
+ #define LM78CLEARCHAS	_IO('l', 2)	/* Reset "Chassis intrusion" */
Index: files.isa
===================================================================
RCS file: /cvsroot/src/sys/dev/isa/files.isa,v
retrieving revision 1.81
diff -c -r1.81 files.isa
*** files.isa	1998/12/16 11:33:50	1.81
--- files.isa	1999/03/10 04:20:17
***************
*** 324,329 ****
--- 323,333 ----
  device	aria: audio, mulaw, auconv
  attach	aria at isa
  file	dev/isa/aria.c			aria needs-flag
+ 
+ # LM78 system monitoring widget
+ device	lm
+ attach	lm at isa
+ file	dev/isa/lm78.c			lm
  
  #
  # PlanetConnect satellite receiver driver.
Index: isadma.c
===================================================================
RCS file: /cvsroot/src/sys/dev/isa/isadma.c,v
retrieving revision 1.41
diff -c -r1.41 isadma.c
*** isadma.c	1999/02/22 02:33:48	1.41
--- isadma.c	1999/03/10 04:20:18
***************
*** 152,157 ****
--- 152,158 ----
  	bus_dma_tag_t dmat;
  	struct device *dev;
  {
+ 	int i;
  
  	ids->ids_dev = dev;
  
***************
*** 181,189 ****
  		if (bus_space_map(ids->ids_bst, IO_DMA2, DMA2_IOSIZE, 0,
  		    &ids->ids_dma2h))
  			panic("_isa_dmainit: unable to map DMA controller #2");
! 		if (bus_space_map(ids->ids_bst, IO_DMAPG, 0xf, 0,
! 		    &ids->ids_dmapgh))
! 			panic("_isa_dmainit: unable to map DMA page registers");
  
  		/*
  		 * All 8 DMA channels start out "masked".
--- 182,195 ----
  		if (bus_space_map(ids->ids_bst, IO_DMA2, DMA2_IOSIZE, 0,
  		    &ids->ids_dma2h))
  			panic("_isa_dmainit: unable to map DMA controller #2");
! 		for (i = 0; i < 4; i++)
! 			if (bus_space_map(ids->ids_bst, IO_DMAPG + dmapageport[0][i], 
! 				0x1, 0, &ids->ids_dmapgh[0][i]))
! 				panic("_isa_dmainit: unable to map DMA page registers");
! 		for (i = 0; i < 4; i++)
! 			if (bus_space_map(ids->ids_bst, IO_DMAPG + dmapageport[1][i], 
! 				0x1, 0, &ids->ids_dmapgh[1][i]))
! 				panic("_isa_dmainit: unable to map DMA page registers");
  
  		/*
  		 * All 8 DMA channels start out "masked".
***************
*** 385,392 ****
  
  		/* send start address */
  		waport = DMA1_CHN(ochan);
! 		bus_space_write_1(ids->ids_bst, ids->ids_dmapgh,
! 		    dmapageport[0][ochan], (dmaaddr >> 16) & 0xff);
  		bus_space_write_1(ids->ids_bst, ids->ids_dma1h, waport,
  		    dmaaddr & 0xff);
  		bus_space_write_1(ids->ids_bst, ids->ids_dma1h, waport,
--- 391,398 ----
  
  		/* send start address */
  		waport = DMA1_CHN(ochan);
! 		bus_space_write_1(ids->ids_bst, ids->ids_dmapgh[0][ochan], 0,
! 		    (dmaaddr >> 16) & 0xff);
  		bus_space_write_1(ids->ids_bst, ids->ids_dma1h, waport,
  		    dmaaddr & 0xff);
  		bus_space_write_1(ids->ids_bst, ids->ids_dma1h, waport,
***************
*** 404,411 ****
  
  		/* send start address */
  		waport = DMA2_CHN(ochan);
! 		bus_space_write_1(ids->ids_bst, ids->ids_dmapgh,
! 		    dmapageport[1][ochan], (dmaaddr >> 16) & 0xff);
  		dmaaddr >>= 1;
  		bus_space_write_1(ids->ids_bst, ids->ids_dma2h, waport,
  		    dmaaddr & 0xff);
--- 410,417 ----
  
  		/* send start address */
  		waport = DMA2_CHN(ochan);
! 		bus_space_write_1(ids->ids_bst, ids->ids_dmapgh[1][ochan], 0,
! 		    (dmaaddr >> 16) & 0xff);
  		dmaaddr >>= 1;
  		bus_space_write_1(ids->ids_bst, ids->ids_dma2h, waport,
  		    dmaaddr & 0xff);
Index: isadmavar.h
===================================================================
RCS file: /cvsroot/src/sys/dev/isa/isadmavar.h,v
retrieving revision 1.15
diff -c -r1.15 isadmavar.h
*** isadmavar.h	1999/02/22 02:32:43	1.15
--- isadmavar.h	1999/03/10 04:20:18
***************
*** 59,65 ****
  	bus_space_tag_t ids_bst;	/* bus space tag for DMA controller */
  	bus_space_handle_t ids_dma1h;	/* handle for DMA controller #1 */
  	bus_space_handle_t ids_dma2h;	/* handle for DMA controller #2 */
! 	bus_space_handle_t ids_dmapgh;	/* handle for DMA page registers */
  	bus_dma_tag_t ids_dmat;		/* DMA tag for DMA controller */
  	bus_dmamap_t ids_dmamaps[8];	/* DMA maps for each channel */
  	bus_size_t ids_dmalength[8];	/* size of DMA transfer per channel */
--- 59,65 ----
  	bus_space_tag_t ids_bst;	/* bus space tag for DMA controller */
  	bus_space_handle_t ids_dma1h;	/* handle for DMA controller #1 */
  	bus_space_handle_t ids_dma2h;	/* handle for DMA controller #2 */
! 	bus_space_handle_t ids_dmapgh[2][4];	/* handles for DMA page registers */
  	bus_dma_tag_t ids_dmat;		/* DMA tag for DMA controller */
  	bus_dmamap_t ids_dmamaps[8];	/* DMA maps for each channel */
  	bus_size_t ids_dmalength[8];	/* size of DMA transfer per channel */
