summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorgrange <grange@openbsd.org>2003-04-25 21:24:15 +0000
committergrange <grange@openbsd.org>2003-04-25 21:24:15 +0000
commit5355ba14089d06914326b12a58d772853a48e28b (patch)
tree7f39336c2d370fc8a5c06c0a4ffcef26accf97d4 /sys
parentstrings... ok tedu@, millert@ (diff)
downloadwireguard-openbsd-5355ba14089d06914326b12a58d772853a48e28b.tar.xz
wireguard-openbsd-5355ba14089d06914326b12a58d772853a48e28b.zip
lm(4) driver from NetBSD adapted for sysctl interface.
The lm driver provides support for the National Semiconductor LM series hardware monitors and register compatible chips. It supports LM78, LM78-J, LM79, Winbond W83697HF, W83627HF, W83781D and W83782D chips. Tested and ok'ed by millert@ and henning@.
Diffstat (limited to 'sys')
-rw-r--r--sys/conf/files6
-rw-r--r--sys/dev/ic/nslm7x.c850
-rw-r--r--sys/dev/ic/nslm7xvar.h140
-rw-r--r--sys/dev/isa/files.isa6
-rw-r--r--sys/dev/isa/lm_isa.c148
5 files changed, 1148 insertions, 2 deletions
diff --git a/sys/conf/files b/sys/conf/files
index 78bbe96330b..23f21ffbe0c 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -1,4 +1,4 @@
-# $OpenBSD: files,v 1.270 2003/03/29 00:51:38 mickey Exp $
+# $OpenBSD: files,v 1.271 2003/04/25 21:24:15 grange Exp $
# $NetBSD: files,v 1.87 1996/05/19 17:17:50 jonathan Exp $
# @(#)files.newconf 7.5 (Berkeley) 5/10/93
@@ -283,6 +283,10 @@ file dev/ic/iha.c iha
device trm: scsi
file dev/ic/trm.c trm
+# National Semiconductor LM7[89] and compatible hardware monitors
+device lm
+file dev/ic/nslm7x.c lm
+
# Attributes which machine-independent bus support can be attached to.
# These should be defined here, because some of these busses can have
# devices which provide these attributes, and we'd like to avoid hairy
diff --git a/sys/dev/ic/nslm7x.c b/sys/dev/ic/nslm7x.c
new file mode 100644
index 00000000000..4de9a93b329
--- /dev/null
+++ b/sys/dev/ic/nslm7x.c
@@ -0,0 +1,850 @@
+/* $OpenBSD: nslm7x.c,v 1.1 2003/04/25 21:24:15 grange Exp $ */
+/* $NetBSD: nslm7x.c,v 1.17 2002/11/15 14:55:41 ad Exp $ */
+
+/*-
+ * Copyright (c) 2000 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Bill Squier.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/kernel.h>
+#include <sys/queue.h>
+#include <sys/sensors.h>
+#include <sys/timeout.h>
+#include <machine/bus.h>
+
+#include <dev/ic/nslm7xvar.h>
+
+#if defined(LMDEBUG)
+#define DPRINTF(x) do { printf x; } while (0)
+#else
+#define DPRINTF(x)
+#endif
+
+struct cfdriver lm_cd = {
+ NULL, "lm", DV_DULL
+};
+
+void setup_fan(struct lm_softc *, int, int);
+void setup_temp(struct lm_softc *, int, int);
+void wb_setup_volt(struct lm_softc *);
+
+int lm_match(struct lm_softc *);
+int wb_match(struct lm_softc *);
+int def_match(struct lm_softc *);
+void lm_common_match(struct lm_softc *);
+int lm_generic_banksel(struct lm_softc *, int);
+
+void generic_stemp(struct lm_softc *, struct sensor *);
+void generic_svolt(struct lm_softc *, struct sensor *);
+void generic_fanrpm(struct lm_softc *, struct sensor *);
+
+void lm_refresh_sensor_data(struct lm_softc *);
+
+void wb_svolt(struct lm_softc *);
+void wb_stemp(struct lm_softc *, struct sensor *, int);
+void wb781_fanrpm(struct lm_softc *, struct sensor *);
+void wb_fanrpm(struct lm_softc *, struct sensor *);
+
+void wb781_refresh_sensor_data(struct lm_softc *);
+void wb782_refresh_sensor_data(struct lm_softc *);
+void wb697_refresh_sensor_data(struct lm_softc *);
+
+void lm_refresh(void *);
+
+#if 0
+int lm_gtredata(struct sysmon_envsys *, struct envsys_tre_data *);
+
+int generic_streinfo_fan(struct lm_softc *, struct envsys_basic_info *,
+ int, struct envsys_basic_info *);
+int lm_streinfo(struct sysmon_envsys *, struct envsys_basic_info *);
+int wb781_streinfo(struct sysmon_envsys *, struct envsys_basic_info *);
+int wb782_streinfo(struct sysmon_envsys *, struct envsys_basic_info *);
+#endif
+
+struct lm_chip {
+ int (*chip_match)(struct lm_softc *);
+};
+
+struct lm_chip lm_chips[] = {
+ { wb_match },
+ { lm_match },
+ { def_match } /* Must be last */
+};
+
+struct timeout lm_timeout;
+
+int
+lm_generic_banksel(struct lm_softc *lmsc, int bank)
+{
+ (*lmsc->lm_writereg)(lmsc, WB_BANKSEL, bank);
+ return (0);
+}
+
+/*
+ * bus independent probe
+ */
+int
+lm_probe(bus_space_tag_t iot, bus_space_handle_t ioh)
+{
+ u_int8_t cr;
+ int rv;
+
+ /* Check for some power-on defaults */
+ bus_space_write_1(iot, ioh, LMC_ADDR, LMD_CONFIG);
+
+ /* Perform LM78 reset */
+ bus_space_write_1(iot, ioh, LMC_DATA, 0x80);
+
+ /* XXX - Why do I have to reselect the register? */
+ bus_space_write_1(iot, ioh, LMC_ADDR, LMD_CONFIG);
+ cr = bus_space_read_1(iot, ioh, LMC_DATA);
+
+ /* XXX - spec says *only* 0x08! */
+ if ((cr == 0x08) || (cr == 0x01))
+ rv = 1;
+ else
+ rv = 0;
+
+ DPRINTF(("lm: rv = %d, cr = %x\n", rv, cr));
+
+ return (rv);
+}
+
+/*
+ * pre: lmsc contains valid busspace tag and handle
+ */
+void
+lm_attach(struct lm_softc *lmsc)
+{
+ u_int i;
+ extern int nsensors;
+ extern struct sensors_head sensors;
+
+ /* Install default bank selection routine, if none given. */
+ if (lmsc->lm_banksel == NULL)
+ lmsc->lm_banksel = lm_generic_banksel;
+
+ for (i = 0; i < sizeof(lm_chips) / sizeof(lm_chips[0]); i++)
+ if (lm_chips[i].chip_match(lmsc))
+ break;
+
+ /* Start the monitoring loop */
+ (*lmsc->lm_writereg)(lmsc, LMD_CONFIG, 0x01);
+
+ /* Initialize sensors */
+ for (i = 0; i < lmsc->numsensors; ++i) {
+ strlcpy(lmsc->sensors[i].device, lmsc->sc_dev.dv_xname,
+ sizeof(lmsc->sensors[i].device));
+ lmsc->sensors[i].num = nsensors++;
+ SLIST_INSERT_HEAD(&sensors, &lmsc->sensors[i], list);
+ }
+
+ /* Refresh sensors data every 1.5 seconds */
+ timeout_set(&lm_timeout, lm_refresh, lmsc);
+ timeout_add(&lm_timeout, (15 * hz) / 10);
+}
+
+int
+lm_match(struct lm_softc *sc)
+{
+ int i;
+
+ /* See if we have an LM78 or LM79 */
+ i = (*sc->lm_readreg)(sc, LMD_CHIPID) & LM_ID_MASK;
+ switch(i) {
+ case LM_ID_LM78:
+ printf(": LM78\n");
+ break;
+ case LM_ID_LM78J:
+ printf(": LM78J\n");
+ break;
+ case LM_ID_LM79:
+ printf(": LM79\n");
+ break;
+ case LM_ID_LM81:
+ printf(": LM81\n");
+ break;
+ default:
+ return 0;
+ }
+ lm_common_match(sc);
+ return 1;
+}
+
+int
+def_match(struct lm_softc *sc)
+{
+ int i;
+
+ i = (*sc->lm_readreg)(sc, LMD_CHIPID) & LM_ID_MASK;
+ printf(": Unknown chip (ID %d)\n", i);
+ lm_common_match(sc);
+ return 1;
+}
+
+void
+lm_common_match(struct lm_softc *sc)
+{
+ int i;
+ sc->numsensors = LM_NUM_SENSORS;
+ sc->refresh_sensor_data = lm_refresh_sensor_data;
+
+ for (i = 0; i < 7; ++i) {
+ sc->sensors[i].type = SENSOR_VOLTS_DC;
+ snprintf(sc->sensors[i].desc, sizeof(sc->sensors[i].desc),
+ "IN%d", i);
+ }
+
+ /* default correction factors for resistors on higher voltage inputs */
+ sc->sensors[0].rfact = sc->sensors[1].rfact =
+ sc->sensors[2].rfact = 10000;
+ sc->sensors[3].rfact = (int)(( 90.9 / 60.4) * 10000);
+ sc->sensors[4].rfact = (int)(( 38.0 / 10.0) * 10000);
+ sc->sensors[5].rfact = (int)((210.0 / 60.4) * 10000);
+ sc->sensors[6].rfact = (int)(( 90.9 / 60.4) * 10000);
+
+ sc->sensors[7].type = SENSOR_TEMP;
+ strlcpy(sc->sensors[7].desc, "Temp", sizeof(sc->sensors[7].desc));
+
+ setup_fan(sc, 8, 3);
+}
+
+int
+wb_match(struct lm_softc *sc)
+{
+ int i, j;
+
+ (*sc->lm_writereg)(sc, WB_BANKSEL, WB_BANKSEL_HBAC);
+ j = (*sc->lm_readreg)(sc, WB_VENDID) << 8;
+ (*sc->lm_writereg)(sc, WB_BANKSEL, 0);
+ j |= (*sc->lm_readreg)(sc, WB_VENDID);
+ DPRINTF(("winbond vend id 0x%x\n", j));
+ if (j != WB_VENDID_WINBOND)
+ return 0;
+ /* read device ID */
+ (*sc->lm_banksel)(sc, 0);
+ j = (*sc->lm_readreg)(sc, WB_BANK0_CHIPID);
+ DPRINTF(("winbond chip id 0x%x\n", j));
+ switch(j) {
+ case WB_CHIPID_83781:
+ case WB_CHIPID_83781_2:
+ printf(": W83781D\n");
+
+ for (i = 0; i < 7; ++i) {
+ sc->sensors[i].type = SENSOR_VOLTS_DC;
+ snprintf(sc->sensors[i].desc,
+ sizeof(sc->sensors[i].desc), "IN%d", i);
+ }
+
+ /* default correction factors for higher voltage inputs */
+ sc->sensors[0].rfact = sc->sensors[1].rfact =
+ sc->sensors[2].rfact = 10000;
+ sc->sensors[3].rfact = (int)(( 90.9 / 60.4) * 10000);
+ sc->sensors[4].rfact = (int)(( 38.0 / 10.0) * 10000);
+ sc->sensors[5].rfact = (int)((210.0 / 60.4) * 10000);
+ sc->sensors[6].rfact = (int)(( 90.9 / 60.4) * 10000);
+
+ setup_temp(sc, 7, 3);
+ setup_fan(sc, 10, 3);
+
+ sc->numsensors = WB83781_NUM_SENSORS;
+ sc->refresh_sensor_data = wb781_refresh_sensor_data;
+ return 1;
+ case WB_CHIPID_83697:
+ printf(": W83697HF\n");
+ wb_setup_volt(sc);
+ setup_temp(sc, 9, 2);
+ setup_fan(sc, 11, 3);
+ sc->numsensors = WB83697_NUM_SENSORS;
+ sc->refresh_sensor_data = wb697_refresh_sensor_data;
+ return 1;
+ case WB_CHIPID_83782:
+ printf(": W83782D\n");
+ break;
+ case WB_CHIPID_83627:
+ printf(": W83627HF\n");
+ break;
+ default:
+ printf(": unknow winbond chip ID 0x%x\n", j);
+ /* handle as a standart lm7x */
+ lm_common_match(sc);
+ return 1;
+ }
+ /* common code for the W83782D and W83627HF */
+ wb_setup_volt(sc);
+ setup_temp(sc, 9, 3);
+ setup_fan(sc, 12, 3);
+ sc->numsensors = WB_NUM_SENSORS;
+ sc->refresh_sensor_data = wb782_refresh_sensor_data;
+ return 1;
+}
+
+void
+wb_setup_volt(struct lm_softc *sc)
+{
+ sc->sensors[0].type = SENSOR_VOLTS_DC;
+ snprintf(sc->sensors[0].desc, sizeof(sc->sensors[0].desc), "VCORE_A");
+ sc->sensors[0].rfact = 10000;
+ sc->sensors[1].type = SENSOR_VOLTS_DC;
+ snprintf(sc->sensors[1].desc, sizeof(sc->sensors[1].desc), "VCORE_B");
+ sc->sensors[1].rfact = 10000;
+ sc->sensors[2].type = SENSOR_VOLTS_DC;
+ snprintf(sc->sensors[2].desc, sizeof(sc->sensors[2].desc), "+3.3V");
+ sc->sensors[2].rfact = 10000;
+ sc->sensors[3].type = SENSOR_VOLTS_DC;
+ snprintf(sc->sensors[3].desc, sizeof(sc->sensors[3].desc), "+5V");
+ sc->sensors[3].rfact = 16778;
+ sc->sensors[4].type = SENSOR_VOLTS_DC;
+ snprintf(sc->sensors[4].desc, sizeof(sc->sensors[4].desc), "+12V");
+ sc->sensors[4].rfact = 38000;
+ sc->sensors[5].type = SENSOR_VOLTS_DC;
+ snprintf(sc->sensors[5].desc, sizeof(sc->sensors[5].desc), "-12V");
+ sc->sensors[5].rfact = 10000;
+ sc->sensors[6].type = SENSOR_VOLTS_DC;
+ snprintf(sc->sensors[6].desc, sizeof(sc->sensors[6].desc), "-5V");
+ sc->sensors[6].rfact = 10000;
+ sc->sensors[7].type = SENSOR_VOLTS_DC;
+ snprintf(sc->sensors[7].desc, sizeof(sc->sensors[7].desc), "+5VSB");
+ sc->sensors[7].rfact = 15151;
+ sc->sensors[8].type = SENSOR_VOLTS_DC;
+ snprintf(sc->sensors[8].desc, sizeof(sc->sensors[8].desc), "VBAT");
+ sc->sensors[8].rfact = 10000;
+}
+
+void
+setup_temp(struct lm_softc *sc, int start, int n)
+{
+ int i;
+
+ for (i = 0; i < n; i++) {
+ sc->sensors[start + i].type = SENSOR_TEMP;
+ snprintf(sc->sensors[start + i].desc,
+ sizeof(sc->sensors[start + i].desc), "Temp%d", i + 1);
+ }
+}
+
+void
+setup_fan(struct lm_softc *sc, int start, int n)
+{
+ int i;
+
+ for (i = 0; i < n; ++i) {
+ sc->sensors[start + i].type = SENSOR_FANRPM;
+ snprintf(sc->sensors[start + i].desc,
+ sizeof(sc->sensors[start + i].desc), "Fan%d", i + 1);
+ }
+}
+
+#if 0
+int
+lm_gtredata(sme, tred)
+ struct sysmon_envsys *sme;
+ struct envsys_tre_data *tred;
+{
+ static const struct timeval onepointfive = { 1, 500000 };
+ struct timeval t;
+ struct lm_softc *sc = sme->sme_cookie;
+ int i, s;
+
+ /* read new values at most once every 1.5 seconds */
+ timeradd(&sc->lastread, &onepointfive, &t);
+ s = splclock();
+ i = timercmp(&mono_time, &t, >);
+ if (i) {
+ sc->lastread.tv_sec = mono_time.tv_sec;
+ sc->lastread.tv_usec = mono_time.tv_usec;
+ }
+ splx(s);
+
+ if (i)
+ sc->refresh_sensor_data(sc);
+
+ *tred = sc->sensors[tred->sensor];
+
+ return (0);
+}
+
+int
+generic_streinfo_fan(sc, info, n, binfo)
+ struct lm_softc *sc;
+ struct envsys_basic_info *info;
+ int n;
+ struct envsys_basic_info *binfo;
+{
+ u_int8_t sdata;
+ int divisor;
+
+ /* FAN1 and FAN2 can have divisors set, but not FAN3 */
+ if ((sc->sensors[binfo->sensor].type == SENSOR_FANRPM)
+ && (n < 2)) {
+ if (binfo->rpms == 0) {
+ binfo->validflags = 0;
+ return (0);
+ }
+
+ /* write back the nominal FAN speed */
+ info->rpms = binfo->rpms;
+
+ /* 153 is the nominal FAN speed value */
+ divisor = 1350000 / (binfo->rpms * 153);
+
+ /* ...but we need lg(divisor) */
+ if (divisor <= 1)
+ divisor = 0;
+ else if (divisor <= 2)
+ divisor = 1;
+ else if (divisor <= 4)
+ divisor = 2;
+ else
+ divisor = 3;
+
+ /*
+ * FAN1 div is in bits <5:4>, FAN2 div is
+ * in <7:6>
+ */
+ sdata = (*sc->lm_readreg)(sc, LMD_VIDFAN);
+ if ( n == 0 ) { /* FAN1 */
+ divisor <<= 4;
+ sdata = (sdata & 0xCF) | divisor;
+ } else { /* FAN2 */
+ divisor <<= 6;
+ sdata = (sdata & 0x3F) | divisor;
+ }
+
+ (*sc->lm_writereg)(sc, LMD_VIDFAN, sdata);
+ }
+ return (0);
+
+}
+
+int
+lm_streinfo(sme, binfo)
+ struct sysmon_envsys *sme;
+ struct envsys_basic_info *binfo;
+{
+ struct lm_softc *sc = sme->sme_cookie;
+
+ if (sc->sensors[binfo->sensor].type == SENSOR_VOLTS_DC)
+ sc->sensors[binfo->sensor].rfact = binfo->rfact;
+ else {
+ if (sc->sensors[binfo->sensor].type == SENSOR_FANRPM) {
+ generic_streinfo_fan(sc, &sc->sensors[binfo->sensor],
+ binfo->sensor - 8, binfo);
+ }
+ memcpy(sc->sensors[binfo->sensor].desc, binfo->desc,
+ sizeof(sc->sensors[binfo->sensor].desc));
+ sc->sensors[binfo->sensor].desc[
+ sizeof(sc->sensors[binfo->sensor].desc) - 1] = '\0';
+
+ binfo->validflags = ENVSYS_FVALID;
+ }
+ return (0);
+}
+
+int
+wb781_streinfo(sme, binfo)
+ struct sysmon_envsys *sme;
+ struct envsys_basic_info *binfo;
+{
+ struct lm_softc *sc = sme->sme_cookie;
+ int divisor;
+ u_int8_t sdata;
+ int i;
+
+ if (sc->sensors[binfo->sensor].type == SENSOR_VOLTS_DC)
+ sc->sensors[binfo->sensor].rfact = binfo->rfact;
+ else {
+ if (sc->sensors[binfo->sensor].type == SENSOR_FANRPM) {
+ if (binfo->rpms == 0) {
+ binfo->validflags = 0;
+ return (0);
+ }
+
+ /* write back the nominal FAN speed */
+ sc->sensors[binfo->sensor].rpms = binfo->rpms;
+
+ /* 153 is the nominal FAN speed value */
+ divisor = 1350000 / (binfo->rpms * 153);
+
+ /* ...but we need lg(divisor) */
+ for (i = 0; i < 7; i++) {
+ if (divisor <= (1 << i))
+ break;
+ }
+ divisor = i;
+
+ if (binfo->sensor == 10 || binfo->sensor == 11) {
+ /*
+ * FAN1 div is in bits <5:4>, FAN2 div
+ * is in <7:6>
+ */
+ sdata = (*sc->lm_readreg)(sc, LMD_VIDFAN);
+ if ( binfo->sensor == 10 ) { /* FAN1 */
+ sdata = (sdata & 0xCF) |
+ ((divisor & 0x3) << 4);
+ } else { /* FAN2 */
+ sdata = (sdata & 0x3F) |
+ ((divisor & 0x3) << 6);
+ }
+ (*sc->lm_writereg)(sc, LMD_VIDFAN, sdata);
+ } else {
+ /* FAN3 is in WB_PIN <7:6> */
+ sdata = (*sc->lm_readreg)(sc, WB_PIN);
+ sdata = (sdata & 0x3F) |
+ ((divisor & 0x3) << 6);
+ (*sc->lm_writereg)(sc, WB_PIN, sdata);
+ }
+ }
+ memcpy(sc->sensors[binfo->sensor].desc, binfo->desc,
+ sizeof(sc->sensors[binfo->sensor].desc));
+ sc->sensors[binfo->sensor].desc[
+ sizeof(sc->sensors[binfo->sensor].desc) - 1] = '\0';
+
+ binfo->validflags = ENVSYS_FVALID;
+ }
+ return (0);
+}
+
+int
+wb782_streinfo(sme, binfo)
+ struct sysmon_envsys *sme;
+ struct envsys_basic_info *binfo;
+{
+ struct lm_softc *sc = sme->sme_cookie;
+ int divisor;
+ u_int8_t sdata;
+ int i;
+
+ if (sc->sensors[binfo->sensor].type == SENSOR_VOLTS_DC)
+ sc->sensors[binfo->sensor].rfact = binfo->rfact;
+ else {
+ if (sc->sensors[binfo->sensor].type == SENSOR_FANRPM) {
+ if (binfo->rpms == 0) {
+ binfo->validflags = 0;
+ return (0);
+ }
+
+ /* write back the nominal FAN speed */
+ sc->sensors[binfo->sensor].rpms = binfo->rpms;
+
+ /* 153 is the nominal FAN speed value */
+ divisor = 1350000 / (binfo->rpms * 153);
+
+ /* ...but we need lg(divisor) */
+ for (i = 0; i < 7; i++) {
+ if (divisor <= (1 << i))
+ break;
+ }
+ divisor = i;
+
+ if (binfo->sensor == 12 || binfo->sensor == 13) {
+ /*
+ * FAN1 div is in bits <5:4>, FAN2 div
+ * is in <7:6>
+ */
+ sdata = (*sc->lm_readreg)(sc, LMD_VIDFAN);
+ if ( binfo->sensor == 12 ) { /* FAN1 */
+ sdata = (sdata & 0xCF) |
+ ((divisor & 0x3) << 4);
+ } else { /* FAN2 */
+ sdata = (sdata & 0x3F) |
+ ((divisor & 0x3) << 6);
+ }
+ (*sc->lm_writereg)(sc, LMD_VIDFAN, sdata);
+ } else {
+ /* FAN3 is in WB_PIN <7:6> */
+ sdata = (*sc->lm_readreg)(sc, WB_PIN);
+ sdata = (sdata & 0x3F) |
+ ((divisor & 0x3) << 6);
+ (*sc->lm_writereg)(sc, WB_PIN, sdata);
+ }
+ /* Bit 2 of divisor is in WB_BANK0_FANBAT */
+ (*sc->lm_banksel)(sc, 0);
+ sdata = (*sc->lm_readreg)(sc, WB_BANK0_FANBAT);
+ sdata &= ~(0x20 << (binfo->sensor - 12));
+ sdata |= (divisor & 0x4) << (binfo->sensor - 9);
+ (*sc->lm_writereg)(sc, WB_BANK0_FANBAT, sdata);
+ }
+
+ memcpy(sc->sensors[binfo->sensor].desc, binfo->desc,
+ sizeof(sc->sensors[binfo->sensor].desc));
+ sc->sensors[binfo->sensor].desc[
+ sizeof(sc->sensors[binfo->sensor].desc) - 1] = '\0';
+
+ binfo->validflags = ENVSYS_FVALID;
+ }
+ return (0);
+}
+#endif
+
+void
+generic_stemp(struct lm_softc *sc, struct sensor *sensor)
+{
+ int sdata = (*sc->lm_readreg)(sc, LMD_SENSORBASE + 7);
+
+ DPRINTF(("sdata[temp] 0x%x\n", sdata));
+ /* temp is given in deg. C, we convert to uK */
+ sensor->value = sdata * 1000000 + 273150000;
+}
+
+void
+generic_svolt(struct lm_softc *sc, struct sensor *sensors)
+{
+ int i, sdata;
+
+ for (i = 0; i < 7; i++) {
+ sdata = (*sc->lm_readreg)(sc, LMD_SENSORBASE + i);
+ DPRINTF(("sdata[volt%d] 0x%x\n", i, sdata));
+ /* voltage returned as (mV >> 4), we convert to uVDC */
+ sensors[i].value = (sdata << 4);
+ /* rfact is (factor * 10^4) */
+ sensors[i].value *= sensors[i].rfact;
+ /* division by 10 gets us back to uVDC */
+ sensors[i].value /= 10;
+
+ /* these two are negative voltages */
+ if ( (i == 5) || (i == 6) )
+ sensors[i].value *= -1;
+ }
+}
+
+void
+generic_fanrpm(struct lm_softc *sc, struct sensor *sensors)
+{
+ int i, sdata, divisor;
+
+ for (i = 0; i < 3; i++) {
+ sdata = (*sc->lm_readreg)(sc, LMD_SENSORBASE + 8 + i);
+ DPRINTF(("sdata[fan%d] 0x%x\n", i, sdata));
+ if (i == 2)
+ divisor = 2; /* Fixed divisor for FAN3 */
+ else if (i == 1) /* Bits 7 & 6 of VID/FAN */
+ divisor = ((*sc->lm_readreg)(sc,
+ LMD_VIDFAN) >> 6) & 0x3;
+ else
+ divisor = ((*sc->lm_readreg)(sc,
+ LMD_VIDFAN) >> 4) & 0x3;
+
+ if (sdata == 0xff || sdata == 0x00) {
+ sensors[i].value = 0;
+ } else {
+ sensors[i].value = 1350000 / (sdata << divisor);
+ }
+ }
+}
+
+/*
+ * pre: last read occurred >= 1.5 seconds ago
+ * post: sensors[] current data are the latest from the chip
+ */
+void
+lm_refresh_sensor_data(struct lm_softc *sc)
+{
+ /* Refresh our stored data for every sensor */
+ generic_stemp(sc, &sc->sensors[7]);
+ generic_svolt(sc, &sc->sensors[0]);
+ generic_fanrpm(sc, &sc->sensors[8]);
+}
+
+void
+wb_svolt(struct lm_softc *sc)
+{
+ int i, sdata;
+
+ for (i = 0; i < 9; ++i) {
+ if (i < 7) {
+ sdata = (*sc->lm_readreg)(sc, LMD_SENSORBASE + i);
+ } else {
+ /* from bank5 */
+ (*sc->lm_banksel)(sc, 5);
+ sdata = (*sc->lm_readreg)(sc, (i == 7) ?
+ WB_BANK5_5VSB : WB_BANK5_VBAT);
+ }
+ DPRINTF(("sdata[volt%d] 0x%x\n", i, sdata));
+ /* voltage returned as (mV >> 4), we convert to uV */
+ sdata = sdata << 4;
+ /* special case for negative voltages */
+ if (i == 5) {
+ /*
+ * -12Vdc, assume Winbond recommended values for
+ * resistors
+ */
+ sdata = ((sdata * 1000) - (3600 * 805)) / 195;
+ } else if (i == 6) {
+ /*
+ * -5Vdc, assume Winbond recommended values for
+ * resistors
+ */
+ sdata = ((sdata * 1000) - (3600 * 682)) / 318;
+ }
+ /* rfact is (factor * 10^4) */
+ sc->sensors[i].value = sdata * sc->sensors[i].rfact;
+ /* division by 10 gets us back to uVDC */
+ sc->sensors[i].value /= 10;
+ }
+}
+
+void
+wb_stemp(struct lm_softc *sc, struct sensor *sensors, int n)
+{
+ int sdata;
+
+ /* temperatures. Given in dC, we convert to uK */
+ sdata = (*sc->lm_readreg)(sc, LMD_SENSORBASE + 7);
+ DPRINTF(("sdata[temp0] 0x%x\n", sdata));
+ sensors[0].value = sdata * 1000000 + 273150000;
+ /* from bank1 */
+ if ((*sc->lm_banksel)(sc, 1)) {
+#if 0
+ sensors[1].validflags &= ~ENVSYS_FCURVALID;
+#endif
+ } else {
+ sdata = (*sc->lm_readreg)(sc, WB_BANK1_T2H) << 1;
+ sdata |= ((*sc->lm_readreg)(sc, WB_BANK1_T2L) & 0x80) >> 7;
+ DPRINTF(("sdata[temp1] 0x%x\n", sdata));
+ sensors[1].value = (sdata * 1000000) / 2 + 273150000;
+ }
+ if (n < 3)
+ return;
+ /* from bank2 */
+ if ((*sc->lm_banksel)(sc, 2)) {
+#if 0
+ sensors[2].validflags &= ~ENVSYS_FCURVALID;
+#endif
+ } else {
+ sdata = (*sc->lm_readreg)(sc, WB_BANK2_T3H) << 1;
+ sdata |= ((*sc->lm_readreg)(sc, WB_BANK2_T3L) & 0x80) >> 7;
+ DPRINTF(("sdata[temp2] 0x%x\n", sdata));
+ sensors[2].value = (sdata * 1000000) / 2 + 273150000;
+ }
+}
+
+void
+wb781_fanrpm(struct lm_softc *sc, struct sensor *sensors)
+{
+ int i, divisor, sdata;
+
+ (*sc->lm_banksel)(sc, 0);
+ for (i = 0; i < 3; i++) {
+ sdata = (*sc->lm_readreg)(sc, LMD_SENSORBASE + i + 8);
+ DPRINTF(("sdata[fan%d] 0x%x\n", i, sdata));
+ if (i == 0)
+ divisor = ((*sc->lm_readreg)(sc,
+ LMD_VIDFAN) >> 4) & 0x3;
+ else if (i == 1)
+ divisor = ((*sc->lm_readreg)(sc,
+ LMD_VIDFAN) >> 6) & 0x3;
+ else
+ divisor = ((*sc->lm_readreg)(sc, WB_PIN) >> 6) & 0x3;
+
+ DPRINTF(("sdata[%d] 0x%x div 0x%x\n", i, sdata, divisor));
+ if (sdata == 0xff || sdata == 0x00) {
+ sensors[i].value = 0;
+ } else {
+ sensors[i].value = 1350000 / (sdata << divisor);
+ }
+ }
+}
+
+void
+wb_fanrpm(struct lm_softc *sc, struct sensor *sensors)
+{
+ int i, divisor, sdata;
+
+ (*sc->lm_banksel)(sc, 0);
+ for (i = 0; i < 3; i++) {
+ sdata = (*sc->lm_readreg)(sc, LMD_SENSORBASE + i + 8);
+ DPRINTF(("sdata[fan%d] 0x%x\n", i, sdata));
+ if (i == 0)
+ divisor = ((*sc->lm_readreg)(sc,
+ LMD_VIDFAN) >> 4) & 0x3;
+ else if (i == 1)
+ divisor = ((*sc->lm_readreg)(sc,
+ LMD_VIDFAN) >> 6) & 0x3;
+ else
+ divisor = ((*sc->lm_readreg)(sc, WB_PIN) >> 6) & 0x3;
+ divisor |= ((*sc->lm_readreg)(sc,
+ WB_BANK0_FANBAT) >> (i + 3)) & 0x4;
+
+ DPRINTF(("sdata[%d] 0x%x div 0x%x\n", i, sdata, divisor));
+ if (sdata == 0xff || sdata == 0x00) {
+ sensors[i].value = 0;
+ } else {
+ sensors[i].value = 1350000 / (sdata << divisor);
+ }
+ }
+}
+
+void
+wb781_refresh_sensor_data(struct lm_softc *sc)
+{
+ /* Refresh our stored data for every sensor */
+ /* we need to reselect bank0 to access common registers */
+ (*sc->lm_banksel)(sc, 0);
+ generic_svolt(sc, &sc->sensors[0]);
+ (*sc->lm_banksel)(sc, 0);
+ wb_stemp(sc, &sc->sensors[7], 3);
+ (*sc->lm_banksel)(sc, 0);
+ wb781_fanrpm(sc, &sc->sensors[10]);
+}
+
+void
+wb782_refresh_sensor_data(struct lm_softc *sc)
+{
+ /* Refresh our stored data for every sensor */
+ wb_svolt(sc);
+ wb_stemp(sc, &sc->sensors[9], 3);
+ wb_fanrpm(sc, &sc->sensors[12]);
+}
+
+void
+wb697_refresh_sensor_data(struct lm_softc *sc)
+{
+ /* Refresh our stored data for every sensor */
+ wb_svolt(sc);
+ wb_stemp(sc, &sc->sensors[9], 2);
+ wb_fanrpm(sc, &sc->sensors[11]);
+}
+
+void
+lm_refresh(void *arg)
+{
+ struct lm_softc *sc = (struct lm_softc *)arg;
+
+ sc->refresh_sensor_data(sc);
+ timeout_add(&lm_timeout, (15 * hz) / 10);
+}
diff --git a/sys/dev/ic/nslm7xvar.h b/sys/dev/ic/nslm7xvar.h
new file mode 100644
index 00000000000..483993fc1e7
--- /dev/null
+++ b/sys/dev/ic/nslm7xvar.h
@@ -0,0 +1,140 @@
+/* $OpenBSD: nslm7xvar.h,v 1.1 2003/04/25 21:24:15 grange Exp $ */
+/* $NetBSD: nslm7xvar.h,v 1.10 2002/11/15 14:55:42 ad Exp $ */
+
+/*-
+ * Copyright (c) 2000 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Bill Squier.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _DEV_ISA_NSLM7XVAR_H_
+#define _DEV_ISA_NSLM7XVAR_H_
+
+/* ctl registers */
+
+#define LMC_ADDR 0x05
+#define LMC_DATA 0x06
+
+/* data registers */
+
+#define LMD_SENSORBASE 0x20 /* Sensors occupy 0x20 -- 0x2a */
+
+#define LMD_CONFIG 0x40 /* Configuration */
+#define LMD_ISR1 0x41 /* Interrupt Status 1 */
+#define LMD_ISR2 0x42 /* Interrupt Status 2 */
+#define LMD_SMI1 0x43 /* SMI Mask 1 */
+#define LMD_SMI2 0x44 /* SMI Mask 2 */
+#define LMD_NMI1 0x45 /* NMI Mask 1 */
+#define LMD_NMI2 0x46 /* NMI Mask 2 */
+#define LMD_VIDFAN 0x47 /* VID/Fan Divisor */
+#define LMD_SBUSADDR 0x48 /* Serial Bus Address */
+#define LMD_CHIPID 0x49 /* Chip Reset/ID */
+
+/* misc constants */
+
+#define LM_NUM_SENSORS 11
+#define LM_ID_LM78 0x00
+#define LM_ID_LM78J 0x40
+#define LM_ID_LM79 0xC0
+#define LM_ID_LM81 0x80
+#define LM_ID_MASK 0xFE
+
+/*
+ * additionnal registers for the Winbond chips:
+ * WB83781D: mostly lm7x compatible; extra temp sensors in bank1 & 2
+ * WB83782D & WB83627HF: voltage sensors needs different handling, more FAN
+ * dividers; mode voltage sensors, more temp sensors.
+ */
+#define WB_T23ADDR 0x4A /* temp sens 2/3 I2C addr */
+#define WB_PIN 0x4B /* pin & fan3 divider */
+#define WB_BANKSEL 0x4E /* banck select register */
+#define WB_BANKSEL_B0 0x00 /* select bank 0 */
+#define WB_BANKSEL_B1 0x01 /* select bank 1 */
+#define WB_BANKSEL_B2 0x02 /* select bank 2 */
+#define WB_BANKSEL_B3 0x03 /* select bank 3 */
+#define WB_BANKSEL_B4 0x04 /* select bank 4 */
+#define WB_BANKSEL_B5 0x05 /* select bank 5 */
+#define WB_BANKSEL_HBAC 0x80 /* hight byte access */
+
+#define WB_VENDID 0x4F /* vendor ID register */
+#define WB_VENDID_WINBOND 0x5CA3
+/* Bank0 regs */
+#define WB_BANK0_CHIPID 0x58
+#define WB_CHIPID_83781 0x10
+#define WB_CHIPID_83781_2 0x11
+#define WB_CHIPID_83782 0x30
+#define WB_CHIPID_83627 0x21
+#define WB_CHIPID_83697 0x60
+#define WB_BANK0_FANBAT 0x5D
+/* Bank1 regs */
+#define WB_BANK1_T2H 0x50
+#define WB_BANK1_T2L 0x51
+
+/* Bank2 regs */
+#define WB_BANK2_T3H 0x50
+#define WB_BANK2_T3L 0x51
+
+/* Bank4 regs 83782/83627 only */
+#define WB_BANK4_T1OFF 0x54
+#define WB_BANK4_T2OFF 0x55
+#define WB_BANK4_T3OFF 0x56
+
+/* Bank5 regs 83782/83627 only */
+#define WB_BANK5_5VSB 0x50
+#define WB_BANK5_VBAT 0x51
+
+#define WB83781_NUM_SENSORS 13
+#define WB83697_NUM_SENSORS 14
+#define WB_NUM_SENSORS 15
+
+struct lm_softc {
+ struct device sc_dev;
+
+ int lm_iobase;
+ bus_space_tag_t lm_iot;
+ bus_space_handle_t lm_ioh;
+
+ int sc_flags;
+ struct sensor sensors[WB_NUM_SENSORS];
+ u_int numsensors;
+ void (*refresh_sensor_data) (struct lm_softc *);
+
+ int (*lm_banksel)(struct lm_softc *, int);
+ u_int8_t (*lm_readreg)(struct lm_softc *, int);
+ void (*lm_writereg)(struct lm_softc *, int, int);
+};
+
+void lm_attach(struct lm_softc *);
+int lm_probe(bus_space_tag_t, bus_space_handle_t);
+
+#endif /* _DEV_ISA_NSLM7XVAR_H_ */
diff --git a/sys/dev/isa/files.isa b/sys/dev/isa/files.isa
index 88460e81030..f72f71bd10d 100644
--- a/sys/dev/isa/files.isa
+++ b/sys/dev/isa/files.isa
@@ -1,4 +1,4 @@
-# $OpenBSD: files.isa,v 1.82 2002/11/30 15:44:38 mickey Exp $
+# $OpenBSD: files.isa,v 1.83 2003/04/25 21:24:15 grange Exp $
# $NetBSD: files.isa,v 1.21 1996/05/16 03:45:55 mycroft Exp $
#
# Config file and device description for machine-independent ISA code.
@@ -384,6 +384,10 @@ file dev/isa/midi_pcppi.c midi_pcppi
attach lpt at isa with lpt_isa
file dev/isa/lpt_isa.c lpt_isa needs-flag
+# National Semiconductor LM7[89] and compatible hardware monitors
+attach lm at isa with lm_isa
+file dev/isa/lm_isa.c lm_isa
+
#
# PCMCIA PCIC (i82365SL and compatibles):
#
diff --git a/sys/dev/isa/lm_isa.c b/sys/dev/isa/lm_isa.c
new file mode 100644
index 00000000000..e9637a78a17
--- /dev/null
+++ b/sys/dev/isa/lm_isa.c
@@ -0,0 +1,148 @@
+/* $OpenBSD: lm_isa.c,v 1.1 2003/04/25 21:24:15 grange Exp $ */
+/* $NetBSD: lm_isa.c,v 1.9 2002/11/15 14:55:44 ad Exp $ */
+
+/*-
+ * Copyright (c) 2000 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Bill Squier.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/sensors.h>
+#include <machine/bus.h>
+
+#include <dev/isa/isareg.h>
+#include <dev/isa/isavar.h>
+
+#include <dev/ic/nslm7xvar.h>
+
+#if defined(LMDEBUG)
+#define DPRINTF(x) do { printf x; } while (0)
+#else
+#define DPRINTF(x)
+#endif
+
+int lm_isa_match(struct device *, void *, void *);
+void lm_isa_attach(struct device *, struct device *, void *);
+u_int8_t lm_isa_readreg(struct lm_softc *, int);
+void lm_isa_writereg(struct lm_softc *, int, int);
+
+struct cfattach lm_isa_ca = {
+ sizeof(struct lm_softc),
+ lm_isa_match,
+ lm_isa_attach
+};
+
+int
+lm_isa_match(struct device *parent, void *match, void *aux)
+{
+ bus_space_tag_t iot;
+ bus_space_handle_t ioh;
+ struct isa_attach_args *ia = aux;
+ int iobase;
+ int rv;
+
+ /* Must supply an address */
+ if (ia->ipa_nio < 1)
+ return (0);
+
+#ifdef __NetBSD__
+ if (ISA_DIRECT_CONFIG(ia))
+ return (0);
+
+ if (ia->ipa_io[0].ir_addr == ISACF_PORT_DEFAULT)
+ return (0);
+#endif
+
+ iot = ia->ia_iot;
+ iobase = ia->ipa_io[0].base;
+
+ if (bus_space_map(iot, iobase, 8, 0, &ioh))
+ return (0);
+
+
+ /* Bus independent probe */
+ rv = lm_probe(iot, ioh);
+
+ bus_space_unmap(iot, ioh, 8);
+
+ if (rv) {
+ ia->ipa_nio = 1;
+ ia->ipa_io[0].length = 8;
+
+ ia->ipa_nmem = 0;
+ ia->ipa_nirq = 0;
+ ia->ipa_ndrq = 0;
+ }
+
+ return (rv);
+}
+
+void
+lm_isa_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct lm_softc *lmsc = (void *)self;
+ int iobase;
+ bus_space_tag_t iot;
+ struct isa_attach_args *ia = aux;
+
+ iobase = ia->ipa_io[0].base;
+ iot = lmsc->lm_iot = ia->ia_iot;
+
+ if (bus_space_map(iot, iobase, 8, 0, &lmsc->lm_ioh)) {
+ printf(": can't map i/o space\n");
+ return;
+ }
+
+ /* Bus-independant attachment */
+ lmsc->lm_writereg = lm_isa_writereg;
+ lmsc->lm_readreg = lm_isa_readreg;
+
+ lm_attach(lmsc);
+}
+
+u_int8_t
+lm_isa_readreg(struct lm_softc *sc, int reg)
+{
+ bus_space_write_1(sc->lm_iot, sc->lm_ioh, LMC_ADDR, reg);
+ return (bus_space_read_1(sc->lm_iot, sc->lm_ioh, LMC_DATA));
+}
+
+void
+lm_isa_writereg(struct lm_softc *sc, int reg, int val)
+{
+ bus_space_write_1(sc->lm_iot, sc->lm_ioh, LMC_ADDR, reg);
+ bus_space_write_1(sc->lm_iot, sc->lm_ioh, LMC_DATA, val);
+}