# This is a shell archive. Save it in a file, remove anything before # this line, and then unpack it by entering "sh file". Note, it may # create directories; files and directories will be owned by you and # have default permissions. # # This archive contains: # # share/man/man4/lm7x.4 # sys/dev/ic/lm7x.c # sys/dev/ic/lm7xreg.h # sys/dev/ic/lm7xvar.h # sys/dev/isa/lm7x_isa.c # sys/sys/lm7xio.h # usr.sbin/lmhw/ # usr.sbin/lmhw/Makefile # usr.sbin/lmhw/lmhw.8 # usr.sbin/lmhw/lmhw.c # usr.sbin/lmhw/pathnames.h # LM7X.changed # LM7X.diffs # LM7X.files # echo x - share/man/man4/lm7x.4 sed 's/^X//' >share/man/man4/lm7x.4 << 'END-of-share/man/man4/lm7x.4' X.\"#ident "@(#)LM7X:$Name$:$Id$" X.\" X.\" Copyright (c) 1988,1999 Greg A. Woods X.\" X.\" Redistribution of this software in both source and binary forms, with X.\" or without modification, is permitted provided that all of the X.\" following conditions are met: X.\" X.\" 1. Redistributions of source code, either alone or as part of a X.\" collective work, must retain this entire copyright notice, and the X.\" following disclaimer, without alteration, in each file that X.\" contains part of this software. X.\" X.\" 2. Redistributions of this software in binary form, either alone or X.\" as part of a collective work, must reproduce this entire copyright X.\" notice, the following disclaimer, without alteration, in either X.\" the documentation, and/or header files, and/or other materials X.\" provided as part of the distribution. X.\" X.\" 3. The following acknowledgement must appear in printed documentation X.\" accompanying a physical distribution of a collective work X.\" including this software, and must appear in a text file X.\" accompanying an electronic distribution of a collective work X.\" including this software: X.\" X.\" This product includes software developed by Greg A. Woods. X.\" X.\" 4. The name of the author may NOT be used to endorse or promote X.\" products derived from this software without specific prior written X.\" permission. The use of the author's name strictly to meet the X.\" requirements of the previous terms is not to be considered X.\" promotion or endorsement under this term. X.\" X.\" 5. Altered versions (derivative works) must be plainly marked as X.\" such, and must not be misrepresented as being the original X.\" software. This copyright notice, and the following disclaimer, X.\" must not be removed from any derivative work and must not be X.\" changed in any way. X.\" X.\" All other rights are reserved. X.\" X.\" DISCLAIMER: X.\" X.\" THIS SOFTWARE IS PROVIDED BY GREG A. WOODS ``AS IS'' AND ANY EXPRESS X.\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED X.\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE X.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY X.\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL X.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE X.\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS X.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER X.\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR X.\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN X.\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. X.\" X.Dd July 13, 1998 X.Dt LM7X 4 i386 X.Os NetBSD 1.4 X.Sh NAME X.Nm lm7x X.Nd LM78/LM79 hardware monitor interface X.Sh SYNOPSIS X.Cd device lm7x0 at isa? port "IO_LM78" X.Fd #include X.Sh DESCRIPTION XThe X.Nm lm7x Xdriver provides support for the National Semiconductor X.Em LM78 Xor X.Em LM79 Xhardware monitor ASICs found on modern X.Nm i386 Xmotherboards such as the Asus P2L97, various Intel and FIC motherboards, Xetc. Currently only an ISA bus interface interface is provided. X.Pp XThis driver only implements an X.Fn ioctl Xinterface. X.Pp XSee the header file for a list of supported ioctls and for a description Xof the data structures. X.Sh FILES X.Bl -tag -width /dev/lm7x00 -compact X.It Pa /dev/lm7x0 X.El X.Sh SEE ALSO X.Xr isa 4 , X.Xr lmhw 8 X.Sh HISTORY XThe X.Nm Xcommand first appeared in X.Nx 1.4 . X.Sh AUTHOR X.An "Greg A. Woods" Aq woods@planix.com X.Sh BUGS XThis is a low-level driver that should only be used to probe the device Xand feed information to something like X.Xr sysctl 2 Xand/or X.Xr kernfs 5 . END-of-share/man/man4/lm7x.4 echo x - sys/dev/ic/lm7x.c sed 's/^X//' >sys/dev/ic/lm7x.c << 'END-of-sys/dev/ic/lm7x.c' X#ident "@(#)LM7X:$Name$:$Id$" X X/* X * lm7x: LM78/LM79 hardware monitor chip driver X */ X X/* X * Copyright (c) 1999 Greg A. Woods X * X * Redistribution of this software in both source and binary forms, with X * or without modification, is permitted provided that all of the X * following conditions are met: X * X * 1. Redistributions of source code, either alone or as part of a X * collective work, must retain this entire copyright notice, and the X * following disclaimer, without alteration, in each file that X * contains part of this software. X * X * 2. Redistributions of this software in binary form, either alone or X * as part of a collective work, must reproduce this entire copyright X * notice, the following disclaimer, without alteration, in either X * the documentation, and/or header files, and/or other materials X * provided as part of the distribution. X * X * 3. The following acknowledgement must appear in printed documentation X * accompanying a physical distribution of a collective work X * including this software, and must appear in an ASCII file X * accompanying an electronic distribution of a collective work X * including this software: X * X * This product includes software developed by Greg A. Woods. X * X * 4. The name of the author may NOT be used to endorse or promote X * products derived from this software without specific prior written X * permission. The use of the author's name strictly to meet the X * requirements of the previous terms is not to be considered X * promotion or endorsement under this term. X * X * 5. Altered versions (derivative works) must be plainly marked as X * such, and must not be misrepresented as being the original X * software. This copyright notice, and the following disclaimer, X * must not be removed from any derivative work and must not be X * changed in any way. X * X * All other rights are reserved. X * X * DISCLAIMER: X * X * THIS SOFTWARE IS PROVIDED BY GREG A. WOODS ``AS IS'' AND ANY EXPRESS X * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED X * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE X * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY X * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL X * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE X * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS X * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER X * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR X * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN X * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. X */ X X#include X#include X#include X#include X#include X#include X#include X#include X#include X#include X#include X#include X#include X X#include /* ioctl() cmd & data structures */ X X#include X#include X#include X X#include /* LM78/LM79 generic constants */ X#include /* LM78/LM79 generic software context */ X Xextern struct cfdriver lm7x_cd; /* driver state, inc. cd_devs[unit] == softc's */ X Xcdev_decl(lm7x_); /* XXX only actually have open/close/ioctl */ X X/* X * prototypes for helper routines X */ Xstatic void lm7x_selreg __P((bus_space_tag_t, bus_space_handle_t, unsigned)); Xstatic u_int8_t lm7x_get __P((bus_space_tag_t, bus_space_handle_t, unsigned)); Xstatic void lm7x_set __P((bus_space_tag_t, bus_space_handle_t, unsigned, unsigned)); Xstatic int lm7x_get_fan_divisor __P((unsigned, int)); Xstatic int lm7x_rpm_to_count __P((int, int)); Xstatic int lm7x_count_to_rpm __P((int, int)); Xstatic void lm7x_print_data __P((struct lm7x_softc *)); X#if 0 /* def LM7X_DEBUG */ Xstatic void lm7x_print_reg __P((struct lm7x_softc *, char *)); X#endif X X/* X * generic probe routine X */ Xint Xlm7x_probe(iot, ioh) X bus_space_tag_t iot; X bus_space_handle_t ioh; X{ X u_int8_t rvalue; X X /* X * XXX this could be dangerous. X * We must initialize the chip before we probe. X * NOTE: luckily this does not reset the value of LM78_INTREG_SIOADDR. X */ X lm7x_set(iot, ioh, LM78_INTREG_CONFIG, LM7X_CONF_INITIALIZE); X DELAY(10000); /* XXX 10ms enough???? */ X X /* simple sanity check to see if there's really an LM78 there */ X rvalue = lm7x_get(iot, ioh, LM78_INTREG_CONFIG); X#ifdef LM7X_DEBUG X printf("lm7x_probe: internal config register (@0x40) = %#x\n", rvalue); X#endif X X return (rvalue == LM7X_CONF_DEFAULT) ? 1 : 0; X} X X/* X * generic attach routine X */ Xvoid Xlm7x_attach(sc, iot, ioh) X struct lm7x_softc *sc; X bus_space_tag_t iot; X bus_space_handle_t ioh; X{ X u_int8_t c; X X c = lm7x_get(iot, ioh, LM78_INTREG_CHIP); X if (c & LM79_CHIP_DEVID) { X sc->sc_type = LM7X_LM79; X printf(": LM79.\n"); X } else { X if (c & LM78_CHIP_DEVID) { X sc->sc_type = LM7X_LM78J; X printf(": LM78-J.\n"); X } else { X sc->sc_type = LM7X_LM78; X printf(": LM78.\n"); X } X } X X /* Mask off all interrupts by default. */ X lm7x_set(iot, ioh, LM78_INTREG_SMI1_MASK, LM78_SMI1_ALL_OFF); X lm7x_set(iot, ioh, LM78_INTREG_SMI2_MASK, LM78_SMI2_ALL_OFF | LM78_SMI2_RESET_ENAB); X lm7x_set(iot, ioh, LM78_INTREG_NMI1_MASK, LM78_NMI1_ALL_OFF); X lm7x_set(iot, ioh, LM78_INTREG_NMI2_MASK, LM78_NMI2_ALL_OFF); X /* X * Start the LM78 monitoring and configure IRQ handling. X * X * set 0: START X * set 2: NMI/IRQ# Enable X * clear 3: INT_Clear X * set 5: NMI/IRQ# Select X * X * Note that it is unlikely the interrupt lines will be connected to X * the main system interrupt controller. X * X * XXX This device will likely have to be polled. X */ X c = lm7x_get(iot, ioh, LM78_INTREG_CONFIG); /* XXX should just ignore startup value? */ X c |= LM7X_CONF_START; /* Start monitoring */ X c &= ~LM7X_CONF_SMI_ENAB; /* Disable SMI */ X c |= LM7X_CONF_NMIIRQ_ENAB; /* Enable NMI/IRQ interrupt reporting */ X c |= LM7X_CONF_NMIIRQ_SEL; /* Select NMI interrupt reporting */ X c &= ~LM7X_CONF_INTR_CLR; /* Allow interrupts & monitoring */ X lm7x_set(iot, ioh, LM78_INTREG_CONFIG, c); X DELAY(1500000); /* await one monitoring loop iteration */ X sc->sc_running = 1; /* we're up and running.... */ X X sc->sc_mult.lm7x_mult_in0 = LM7X_DEFAULT_MULT_IN0; X sc->sc_mult.lm7x_mult_in1 = LM7X_DEFAULT_MULT_IN1; X sc->sc_mult.lm7x_mult_in2 = LM7X_DEFAULT_MULT_IN2; X sc->sc_mult.lm7x_mult_in3 = LM7X_DEFAULT_MULT_IN3; X sc->sc_mult.lm7x_mult_in4 = LM7X_DEFAULT_MULT_IN4; X sc->sc_mult.lm7x_mult_in5 = LM7X_DEFAULT_MULT_IN5; X sc->sc_mult.lm7x_mult_in6 = LM7X_DEFAULT_MULT_IN6; X X c = lm7x_get(iot, ioh, LM78_INTREG_INT2); X if (c & LM78_INT2_CHASSIS) X printf("%s: Chassis intrusion flag detected!\n", sc->sc_dev.dv_xname); X /* XXX should we clear the chassis intrusion now it's been reported? */ X X#ifdef LM7X_DEBUG /* XXX Should we always report all initial values? */ X lm7x_print_data(sc); X#endif X X return; X} X X X/* X * lm7x cdevsw interface routines X */ X Xint Xlm7x_open(dev, flags, fmt, p) X dev_t dev; X int flags; X int fmt; X struct proc *p; X{ X struct lm7x_softc *sc; X int unit = minor(dev); X X if (unit >= lm7x_cd.cd_ndevs) { X printf("lm7x%d: cannot open for pid %d, impossible unit (>= %d [NLM7X]).\n", X unit, (int) p->p_pid, lm7x_cd.cd_ndevs); X return (ENXIO); X } X sc = lm7x_cd.cd_devs[unit]; X if (!sc) { X#ifdef DIAGNOSTIC X printf("lm7x%d: cannot open for pid %d, IO port not configured.\n", X unit, (int) p->p_pid); X#endif X return (ENXIO); X } X X if (sc->sc_state != LM7X_SC_NONE) { X printf("lm7x%d: pid = %d, still open by pid %d [sc_state = %x]\n", X unit, (int) p->p_pid, sc->sc_state, (int) sc->sc_pid); X return(EBUSY); X } else X sc->sc_state |= LM7X_SC_INIT; X X /* XXX if not sc_running, should we start it up now, or report an error? */ X X sc->sc_state = LM7X_SC_OPEN; X sc->sc_pid = p->p_pid; X X#ifdef LM7X_DEBUG X printf("lm7x%d: pid = %d, successfully opened.\n", unit, (int) p->p_pid); X#endif X return(0); X} X Xint Xlm7x_close(dev, flags, fmt, p) X dev_t dev; X int flags; X int fmt; X struct proc *p; X{ X struct lm7x_softc *sc; X int unit = minor(dev); X X if (unit >= lm7x_cd.cd_ndevs) { X printf("lm7x%d: cannot close for pid %d, impossible unit (>= %d [NLM7X]).\n", X unit, (int) p->p_pid, lm7x_cd.cd_ndevs); X return (ENXIO); X } X sc = lm7x_cd.cd_devs[unit]; X if (!sc) { X#ifdef DIAGNOSTIC X printf("lm7x%d: cannot close for pid %d, IO port not configured.\n", X unit, (int) p->p_pid); X#endif X return (ENXIO); X } X X if (! sc->sc_state & LM7X_SC_OPEN) { /* impossible? */ X#ifdef DIAGNOSTIC X printf("lm7x%d: close requested by pid %d, device not open!\n", X unit, (int) p->p_pid); X#endif X return (EBADF); X } X X sc->sc_state &= ~LM7X_SC_OPEN; X X#ifdef LM7X_DEBUG X if (sc->sc_pid != p->p_pid) X printf("lm7x%d: opened by pid = %d, closed by pid = %d.\n", unit, (int) sc->sc_pid, (int) p->p_pid); X#endif X /* XXX do any cleanup */ X X sc->sc_state = LM7X_SC_NONE; X sc->sc_pid = 0; /* XXX or -1? */ X X#ifdef LM7X_DEBUG X printf("lm7x%d: pid = %d, successfully closed.\n", unit, (int) p->p_pid); X#endif X return(0); X} X Xint Xlm7x_ioctl(dev, cmd, data, flags, p) X dev_t dev; X u_long cmd; X caddr_t data; X int flags; X struct proc *p; X{ X int error = 0; X int unit = minor(dev); X struct lm7x_softc *sc; X bus_space_tag_t iot; X bus_space_handle_t ioh; X u_int8_t c; X X#ifdef LM7X_DEBUG X printf("lm7x%d: pid = %d, ioctl(%s, '%c'[%d], len=%d)\n", X unit, (int) p->p_pid, X ((cmd & IOC_DIRMASK) == IOC_VOID) ? "IOC_VOID" : X ((cmd & IOC_DIRMASK) == IOC_OUT) ? "IOC_OUT" : X ((cmd & IOC_DIRMASK) == IOC_IN) ? "IOC_IN" : X ((cmd & IOC_DIRMASK) == IOC_INOUT) ? "IOC_INOUT" : "IOC_unknown", X (char) IOCGROUP(cmd), (int) (cmd & 0xff), (int) IOCPARM_LEN(cmd)); X printf("lm7x%d: data = %p, flags=%#x\n", unit, (void *) data, flags); X#endif X if (IOCGROUP(cmd) != LM7X_IOC_GROUP) { X#ifdef DIAGNOSTIC X printf("lm7x%d: cannot ioctl for pid %d, IO port not configured.\n", X unit, (int) p->p_pid); X#endif X return (ENOTTY); X } X X if (unit >= lm7x_cd.cd_ndevs) { X printf("lm7x%d: cannot ioctl for pid %d, impossible unit (>= %d [NLM7X]).\n", X unit, (int) p->p_pid, lm7x_cd.cd_ndevs); X return (ENXIO); X } X if (!(sc = lm7x_cd.cd_devs[unit])) { X#ifdef DIAGNOSTIC X printf("lm7x%d: cannot ioctl for pid %d, IO port not configured.\n", X unit, (int) p->p_pid); X#endif X return (ENXIO); X } X if (! sc->sc_state & LM7X_SC_OPEN) { /* impossible? */ X#ifdef DIAGNOSTIC X printf("lm7x%d: ioctl requested by pid %d, device not open!\n", X unit, (int) p->p_pid); X#endif X return (EBADF); X } X iot = sc->sc_iot; X ioh = sc->sc_ioh; X X switch (cmd) { X case LM7X_ENANMI: /* Select NMI interrupt reporting */ X c = lm7x_get(iot, ioh, LM78_INTREG_CONFIG); X c |= LM7X_CONF_NMIIRQ_SEL; X lm7x_set(iot, ioh, LM78_INTREG_CONFIG, c); X break; X case LM7X_DISNMI: /* Select IRQ interrupt reporting */ X c = lm7x_get(iot, ioh, LM78_INTREG_CONFIG); X c &= ~LM7X_CONF_NMIIRQ_SEL; X lm7x_set(iot, ioh, LM78_INTREG_CONFIG, c); X break; X case LM7X_ENAINT: /* Enable NMI/IRQ interrupt reporting */ X c = lm7x_get(iot, ioh, LM78_INTREG_CONFIG); X c |= LM7X_CONF_NMIIRQ_ENAB; X lm7x_set(iot, ioh, LM78_INTREG_CONFIG, c); X break; X case LM7X_DISINT: /* Disable NMI/IRQ interrupt reporting */ X c = lm7x_get(iot, ioh, LM78_INTREG_CONFIG); X c &= ~LM7X_CONF_NMIIRQ_ENAB; X lm7x_set(iot, ioh, LM78_INTREG_CONFIG, c); X break; X case LM7X_ENASMI: /* Enable SMI */ X c = lm7x_get(iot, ioh, LM78_INTREG_CONFIG); X c |= LM7X_CONF_SMI_ENAB; X lm7x_set(iot, ioh, LM78_INTREG_CONFIG, c); X break; X case LM7X_DISSMI: /* Disable SMI */ X c = lm7x_get(iot, ioh, LM78_INTREG_CONFIG); X c &= ~LM7X_CONF_SMI_ENAB; X lm7x_set(iot, ioh, LM78_INTREG_CONFIG, c); X break; X case LM7X_PWRBYPASS: /* drive 0 on Power Switch Bypass pin */ X c = lm7x_get(iot, ioh, LM78_INTREG_CONFIG); X c |= LM7X_CONF_POWER_BYPASS; X lm7x_set(iot, ioh, LM78_INTREG_CONFIG, c); X break; X case LM7X_CLRPWRBYPASS: /* drive 1 on Power Switch Bypass pin */ X c = lm7x_get(iot, ioh, LM78_INTREG_CONFIG); X c &= ~LM7X_CONF_POWER_BYPASS; X lm7x_set(iot, ioh, LM78_INTREG_CONFIG, c); X break; X case LM7X_CLRCHASS: X c = lm7x_get(iot, ioh, LM78_INTREG_NMI2_MASK); X c |= LM78_NMI2_CHASSIS_CLR; X lm7x_set(iot, ioh, LM78_INTREG_NMI2_MASK, c); X break; X case LM7X_GETSTATUS: { X lm7x_status_t *cur = (lm7x_status_t *) data; X int fan1_divisor; X int fan2_divisor; X int fan3_divisor; X X#ifdef DIAGNOSTIC X if (IOCPARM_LEN(cmd) != sizeof(*cur)) { X printf("lm7x%d: pid = %d, invalid LM7X_GETSTATUS request length (k%u != u%u).\n", X unit, (int) p->p_pid, sizeof(*cur), (int) IOCPARM_LEN(cmd)); X } X#endif X cur->lm7x_vid = lm7x_get(iot, ioh, LM78_INTREG_VID_FAN); X fan1_divisor = lm7x_get_fan_divisor(cur->lm7x_vid, 1); X fan2_divisor = lm7x_get_fan_divisor(cur->lm7x_vid, 2); X fan3_divisor = lm7x_get_fan_divisor(cur->lm7x_vid, 3); X cur->lm7x_vid &= LM78_VID_MASK; /* chop off divisor bits */ X if (sc->sc_type == LM7X_LM79) { X cur->lm7x_vid |= (lm7x_get(iot, ioh, LM78_INTREG_CHIP) & LM79_CHIP_VID4) ? (1<<4) : 0; X } X cur->lm7x_in0 = lm7x_get(iot, ioh, LM78_INTREG_DATA_IN0) * sc->sc_mult.lm7x_mult_in0; X cur->lm7x_in1 = lm7x_get(iot, ioh, LM78_INTREG_DATA_IN1) * sc->sc_mult.lm7x_mult_in1; X cur->lm7x_in2 = lm7x_get(iot, ioh, LM78_INTREG_DATA_IN2) * sc->sc_mult.lm7x_mult_in2; X cur->lm7x_in3 = lm7x_get(iot, ioh, LM78_INTREG_DATA_IN3) * sc->sc_mult.lm7x_mult_in3; X cur->lm7x_in4 = lm7x_get(iot, ioh, LM78_INTREG_DATA_IN4) * sc->sc_mult.lm7x_mult_in4; X cur->lm7x_in5 = -lm7x_get(iot, ioh, LM78_INTREG_DATA_IN5) * sc->sc_mult.lm7x_mult_in5; X cur->lm7x_in6 = -lm7x_get(iot, ioh, LM78_INTREG_DATA_IN6) * sc->sc_mult.lm7x_mult_in6; X cur->lm7x_temp = lm7x_get(iot, ioh, LM78_INTREG_DATA_TEMP); X cur->lm7x_fan1 = lm7x_count_to_rpm(lm7x_get(iot, ioh, LM78_INTREG_DATA_FAN1), fan1_divisor); X cur->lm7x_fan2 = lm7x_count_to_rpm(lm7x_get(iot, ioh, LM78_INTREG_DATA_FAN2), fan2_divisor); X cur->lm7x_fan3 = lm7x_count_to_rpm(lm7x_get(iot, ioh, LM78_INTREG_DATA_FAN3), fan3_divisor); X cur->lm7x_config = lm7x_get(iot, ioh, LM78_INTREG_CONFIG); X cur->lm7x_intstat = lm7x_get(iot, ioh, LM78_INTREG_INT2) << 8; X cur->lm7x_intstat |= lm7x_get(iot, ioh, LM78_INTREG_INT1); X cur->lm7x_smimask = lm7x_get(iot, ioh, LM78_INTREG_SMI2_MASK) << 8; X cur->lm7x_smimask |= lm7x_get(iot, ioh, LM78_INTREG_SMI1_MASK); X cur->lm7x_nmimask = lm7x_get(iot, ioh, LM78_INTREG_NMI2_MASK) << 8; X cur->lm7x_nmimask |= lm7x_get(iot, ioh, LM78_INTREG_NMI1_MASK); X X break; X } X case LM7X_GETLIMITS: { X lm7x_limits_t *cur = (lm7x_limits_t *) data; X u_int8_t value; X int fan1_divisor; X int fan2_divisor; X int fan3_divisor; X X#ifdef DIAGNOSTIC X if (IOCPARM_LEN(cmd) != sizeof(*cur)) { X printf("lm7x%d: pid = %d, invalid LM7X_GETLIMITS request length (k%u != u%u).\n", X unit, (int) p->p_pid, sizeof(*cur), (int) IOCPARM_LEN(cmd)); X } X#endif X value = lm7x_get(iot, ioh, LM78_INTREG_VID_FAN); X fan1_divisor = lm7x_get_fan_divisor(value, 1); X fan2_divisor = lm7x_get_fan_divisor(value, 2); X fan3_divisor = lm7x_get_fan_divisor(value, 3); X cur->lm7x_in0lo = lm7x_get(iot, ioh, LM78_INTREG_LIM_IN0_LO) * sc->sc_mult.lm7x_mult_in0; X cur->lm7x_in0hi = lm7x_get(iot, ioh, LM78_INTREG_LIM_IN0_HI) * sc->sc_mult.lm7x_mult_in0; X cur->lm7x_in1lo = lm7x_get(iot, ioh, LM78_INTREG_LIM_IN1_LO) * sc->sc_mult.lm7x_mult_in1; X cur->lm7x_in1hi = lm7x_get(iot, ioh, LM78_INTREG_LIM_IN1_HI) * sc->sc_mult.lm7x_mult_in1; X cur->lm7x_in2lo = lm7x_get(iot, ioh, LM78_INTREG_LIM_IN2_LO) * sc->sc_mult.lm7x_mult_in2; X cur->lm7x_in2hi = lm7x_get(iot, ioh, LM78_INTREG_LIM_IN2_HI) * sc->sc_mult.lm7x_mult_in2; X cur->lm7x_in3lo = lm7x_get(iot, ioh, LM78_INTREG_LIM_IN3_LO) * sc->sc_mult.lm7x_mult_in3; X cur->lm7x_in3hi = lm7x_get(iot, ioh, LM78_INTREG_LIM_IN3_HI) * sc->sc_mult.lm7x_mult_in3; X cur->lm7x_in4lo = lm7x_get(iot, ioh, LM78_INTREG_LIM_IN4_LO) * sc->sc_mult.lm7x_mult_in4; X cur->lm7x_in4hi = lm7x_get(iot, ioh, LM78_INTREG_LIM_IN4_HI) * sc->sc_mult.lm7x_mult_in4; X cur->lm7x_in5lo = -lm7x_get(iot, ioh, LM78_INTREG_LIM_IN5_LO) * sc->sc_mult.lm7x_mult_in5; X cur->lm7x_in5hi = -lm7x_get(iot, ioh, LM78_INTREG_LIM_IN5_HI) * sc->sc_mult.lm7x_mult_in5; X cur->lm7x_in6lo = -lm7x_get(iot, ioh, LM78_INTREG_LIM_IN6_LO) * sc->sc_mult.lm7x_mult_in6; X cur->lm7x_in6hi = -lm7x_get(iot, ioh, LM78_INTREG_LIM_IN6_HI) * sc->sc_mult.lm7x_mult_in6; X cur->lm7x_temphyst = lm7x_get(iot, ioh, LM78_INTREG_LIM_TEMPHYST); X cur->lm7x_overtemp = lm7x_get(iot, ioh, LM78_INTREG_LIM_OVERTEMP); X cur->lm7x_fan1lo = lm7x_count_to_rpm(lm7x_get(iot, ioh, LM78_INTREG_LIM_FAN1_LO), fan1_divisor); X cur->lm7x_fan2lo = lm7x_count_to_rpm(lm7x_get(iot, ioh, LM78_INTREG_LIM_FAN2_LO), fan2_divisor); X cur->lm7x_fan3lo = lm7x_count_to_rpm(lm7x_get(iot, ioh, LM78_INTREG_LIM_FAN3_LO), fan3_divisor); X X break; X } X case LM7X_SETLIMITS: { X lm7x_limits_t *cur = (lm7x_limits_t *) data; X u_int8_t value; X int fan1_divisor; X int fan2_divisor; X int fan3_divisor; X X#ifdef DIAGNOSTIC X if (IOCPARM_LEN(cmd) != sizeof(*cur)) { X printf("lm7x%d: pid = %d, invalid LM7X_SETLIMITS request length (k%u != u%u).\n", X unit, (int) p->p_pid, sizeof(*cur), (int) IOCPARM_LEN(cmd)); X } X#endif X value = lm7x_get(iot, ioh, LM78_INTREG_VID_FAN); X fan1_divisor = lm7x_get_fan_divisor(value, 1); X fan2_divisor = lm7x_get_fan_divisor(value, 2); X fan3_divisor = lm7x_get_fan_divisor(value, 3); X lm7x_set(iot, ioh, LM78_INTREG_LIM_IN0_LO, cur->lm7x_in0lo / sc->sc_mult.lm7x_mult_in0); X lm7x_set(iot, ioh, LM78_INTREG_LIM_IN0_HI, cur->lm7x_in0hi / sc->sc_mult.lm7x_mult_in0); X lm7x_set(iot, ioh, LM78_INTREG_LIM_IN1_LO, cur->lm7x_in1lo / sc->sc_mult.lm7x_mult_in0); X lm7x_set(iot, ioh, LM78_INTREG_LIM_IN1_HI, cur->lm7x_in1hi / sc->sc_mult.lm7x_mult_in0); X lm7x_set(iot, ioh, LM78_INTREG_LIM_IN2_LO, cur->lm7x_in2lo / sc->sc_mult.lm7x_mult_in0); X lm7x_set(iot, ioh, LM78_INTREG_LIM_IN2_HI, cur->lm7x_in2hi / sc->sc_mult.lm7x_mult_in0); X lm7x_set(iot, ioh, LM78_INTREG_LIM_IN3_LO, cur->lm7x_in3lo / sc->sc_mult.lm7x_mult_in0); X lm7x_set(iot, ioh, LM78_INTREG_LIM_IN3_HI, cur->lm7x_in3hi / sc->sc_mult.lm7x_mult_in0); X lm7x_set(iot, ioh, LM78_INTREG_LIM_IN4_LO, cur->lm7x_in4lo / sc->sc_mult.lm7x_mult_in0); X lm7x_set(iot, ioh, LM78_INTREG_LIM_IN4_HI, cur->lm7x_in4hi / sc->sc_mult.lm7x_mult_in0); X lm7x_set(iot, ioh, LM78_INTREG_LIM_IN5_LO, -cur->lm7x_in5lo / sc->sc_mult.lm7x_mult_in0); X lm7x_set(iot, ioh, LM78_INTREG_LIM_IN5_HI, -cur->lm7x_in5hi / sc->sc_mult.lm7x_mult_in0); X lm7x_set(iot, ioh, LM78_INTREG_LIM_IN6_LO, -cur->lm7x_in6lo / sc->sc_mult.lm7x_mult_in0); X lm7x_set(iot, ioh, LM78_INTREG_LIM_IN6_HI, -cur->lm7x_in6hi / sc->sc_mult.lm7x_mult_in0); X lm7x_set(iot, ioh, LM78_INTREG_LIM_TEMPHYST, cur->lm7x_temphyst); X lm7x_set(iot, ioh, LM78_INTREG_LIM_OVERTEMP, cur->lm7x_overtemp); X lm7x_set(iot, ioh, LM78_INTREG_LIM_FAN1_LO, lm7x_rpm_to_count(cur->lm7x_fan1lo, fan1_divisor)); X lm7x_set(iot, ioh, LM78_INTREG_LIM_FAN2_LO, lm7x_rpm_to_count(cur->lm7x_fan2lo, fan2_divisor)); X lm7x_set(iot, ioh, LM78_INTREG_LIM_FAN3_LO, lm7x_rpm_to_count(cur->lm7x_fan3lo, fan3_divisor)); X X break; X } X#if 0 /* not yet implemented */ X case LM7X_GETPOST: X break; X case LM7X_PUTPOST: X break; X#endif X case LM7X_GETMULT: X#ifdef DIAGNOSTIC X if (IOCPARM_LEN(cmd) != sizeof(sc->sc_mult)) { X printf("lm7x%d: pid = %d, invalid LM7X_GETMULT request length (k%u != u%u).\n", X unit, (int) p->p_pid, sizeof(sc->sc_mult), (int) IOCPARM_LEN(cmd)); X } X#endif X memcpy(data, (void *) &sc->sc_mult, sizeof(sc->sc_mult)); X break; X case LM7X_SETMULT: X#ifdef DIAGNOSTIC X if (IOCPARM_LEN(cmd) != sizeof(sc->sc_mult)) { X printf("lm7x%d: pid = %d, invalid LM7X_SETMULT request length (k%u != u%u).\n", X unit, (int) p->p_pid, sizeof(sc->sc_mult), (int) IOCPARM_LEN(cmd)); X } X#endif X memcpy((void *) &sc->sc_mult, data, sizeof(sc->sc_mult)); X break; X case LM7X_PRINT: X lm7x_print_data(sc); X break; X default: X#ifdef DIAGNOSTIC X printf("lm7x%d: unknown ioctl requested by pid %d.\n", X unit, (int) p->p_pid); X#endif X error = ENODEV; X } X X#ifdef LM7X_DEBUG X printf("lm7x%d: pid = %d, ioctl(%s, '%c'[%u], len=%d) returning %d.\n", X unit, (int) p->p_pid, X ((cmd & IOC_DIRMASK) == IOC_VOID) ? "IOC_VOID" : X ((cmd & IOC_DIRMASK) == IOC_OUT) ? "IOC_OUT" : X ((cmd & IOC_DIRMASK) == IOC_IN) ? "IOC_IN" : X ((cmd & IOC_DIRMASK) == IOC_INOUT) ? "IOC_INOUT" : "IOC_unknown", X (char) IOCGROUP(cmd), (int) (cmd & 0xff), (int) IOCPARM_LEN(cmd), X error); X#endif X X return(error); X} X X/* X * lm7x helper routines X */ X Xstatic void /* XXX could/should be a macro or inline */ Xlm7x_selreg(iot, ioh, regno) X bus_space_tag_t iot; X bus_space_handle_t ioh; X unsigned regno; X{ X bus_space_write_1(iot, ioh, LM78_ADDR_PORT_OFFSET, regno); X return; X} X Xstatic u_int8_t /* XXX could/should be a macro or inline */ Xlm7x_get(iot, ioh, regno) X bus_space_tag_t iot; X bus_space_handle_t ioh; X unsigned regno; X{ X lm7x_selreg(iot, ioh, regno); X return bus_space_read_1(iot, ioh, LM78_DATA_PORT_OFFSET); X} X Xstatic void /* XXX could/should be a macro or inline */ Xlm7x_set(iot, ioh, regno, value) X bus_space_tag_t iot; X bus_space_handle_t ioh; X unsigned regno; X unsigned value; X{ X lm7x_selreg(iot, ioh, regno); X bus_space_write_1(iot, ioh, LM78_DATA_PORT_OFFSET, value); X return; X} X X/* X * NOTE: the fan counter/divisor setup is kinda weird.... X * X * Fan tachometer inputs gate an internal 22.5 kHz clock to the 8-bit counter X * for one period of the fan signal. Fans normally provide two pulses per X * revolution(*). The formula is thus: X * X * 1.35 x 10^6 X * count = ------------- X * RPM x divisor X * X * NOTE: typical practice is to consider 70% or less of normal RPM to be a fan X * failure. X * X * (*) the Intel Pentium-II Developer manual actually specifies two pulse-per X * revolution tachometer output for the CPU heatsink fan. Hopefully system X * vendors will follow suite for power supply and chassis fans. X * X * XXX it may make sense to have the 1350000 constant be programmable should X * similar chips come available that have different internal counter clocks. X * X * XXX either that or just do the math in user-land.... X */ X X/* X * returns the fan divisor factor X * X * VID/Fan <5:4> for Fan #1 X * VID/Fan <7:6> for Fan #2 X * X * binary 00 = divide by 1 X * binary 01 = divide by 2 X * binary 10 = divide by 4 X * binary 11 = divide by 8 X */ Xstatic int Xlm7x_get_fan_divisor(vid_value, fan) X unsigned vid_value; /* 8-bit value from VID/Fan (0x47) */ X int fan; /* fan 1, 2, or 3 */ X{ X int dv; X X if (fan < 1 || fan > 3) X return -1; X X if (fan == 3) /* fan #3 divisor is not programmable */ X return 2; X X /* X * right shift the value into bits 1 & 0 and mask off all other bits X * shift the bit pair left by one to give power of 2. X */ X dv = (1 << ((vid_value >> (fan == 1 ? 4 : 6)) & 0x3)); X X#if 0 /* XXX if << doesn't fill with 1's, then we need this: */ X switch (dv) { X case 0: X return 1; X case 6: X return 8; X } X#endif X X return dv; X} X X/* X * returns fan RPMs given count and divisor X */ Xstatic int Xlm7x_count_to_rpm(ct, divisor) X int ct; /* fan sensor count */ X int divisor; /* fan divisor */ X{ X if (ct == 255) X return 0; /* Stopped/disconn. fans read zero */ X if (ct == 0) X ct = 1; /* Let us not divide by zero... */ X return 1350000 / (ct * divisor); X} X X/* X * returns fan count when given fan RPM and divisor X */ Xstatic int Xlm7x_rpm_to_count(rpm, divisor) X int rpm; /* fan RPM */ X int divisor; /* fan speed divisor */ X{ X int v; X X if (rpm == 0) X return 255; /* Let us not divide by zero... */ X v = 1350000 / (rpm * divisor); X if (v > 255) X v = 255; /* must be an 8-bit value */ X return v; X} X X/* X * Interpret data as appropriate for ASUS P2L97 (and other?) motherboard(s) X * X * Note that the voltage probe multipliers are as recommended by National X * Semiconductor's application note, and they seem to apply to the ASUS P2L97 X * motherboard as well..... X * X * See also LM7X_GETSTATUS ioctl().... X */ Xstatic void Xlm7x_print_data(sc) X struct lm7x_softc *sc; X{ X bus_space_tag_t iot = sc->sc_iot; X bus_space_handle_t ioh = sc->sc_ioh; X char *devnm = sc->sc_dev.dv_xname; X u_int8_t value; X int fan1_divisor; X int fan2_divisor; X int fan3_divisor; X int millivolts; X X value = lm7x_get(iot, ioh, LM78_INTREG_INT2); X printf("%s: Chassis intrusion = %d.\n", devnm, value & LM78_INT2_CHASSIS); X value = lm7x_get(iot, ioh, LM78_INTREG_VID_FAN); X fan1_divisor = lm7x_get_fan_divisor(value, 1); X fan2_divisor = lm7x_get_fan_divisor(value, 2); X fan3_divisor = lm7x_get_fan_divisor(value, 3); X value &= LM78_VID_MASK; /* chop off divisor bits */ X if (sc->sc_type == LM7X_LM79) { X value |= (lm7x_get(iot, ioh, LM78_INTREG_CHIP) & LM79_CHIP_VID4) ? (1<<4) : 0; X } X printf("%s: VID = %#x.\n", devnm, value); X value = lm7x_get(iot, ioh, LM78_INTREG_DATA_FAN1); X printf("%s: FAN#1 @ %d RPM\n", devnm, lm7x_count_to_rpm(value, fan1_divisor)); X value = lm7x_get(iot, ioh, LM78_INTREG_DATA_FAN2); X printf("%s: FAN#2 @ %d RPM\n", devnm, lm7x_count_to_rpm(value, fan2_divisor)); X value = lm7x_get(iot, ioh, LM78_INTREG_DATA_FAN3); X printf("%s: FAN#3 @ %d RPM\n", devnm, lm7x_count_to_rpm(value, fan3_divisor)); X millivolts = lm7x_get(iot, ioh, LM78_INTREG_DATA_IN0) * sc->sc_mult.lm7x_mult_in0; X printf("%s: Voltage probe #0 (CPU Core) @ %d.%d volts\n", X devnm, millivolts / 1000, (millivolts % 1000) / 100); X millivolts = lm7x_get(iot, ioh, LM78_INTREG_DATA_IN1) * sc->sc_mult.lm7x_mult_in1; X printf("%s: Voltage probe #1 (???) @ %d.%d volts\n", X devnm, millivolts / 1000, (millivolts % 1000) / 100); X millivolts = lm7x_get(iot, ioh, LM78_INTREG_DATA_IN2) * sc->sc_mult.lm7x_mult_in2; X printf("%s: Voltage probe #2 (+3.3v) @ %d.%d volts\n", X devnm, millivolts / 1000, (millivolts % 1000) / 100); X millivolts = lm7x_get(iot, ioh, LM78_INTREG_DATA_IN3) * sc->sc_mult.lm7x_mult_in3; X printf("%s: Voltage probe #3 (+5v) @ %d.%d volts\n", X devnm, millivolts / 1000, (millivolts % 1000) / 100); X millivolts = lm7x_get(iot, ioh, LM78_INTREG_DATA_IN4) * sc->sc_mult.lm7x_mult_in4; X printf("%s: Voltage probe #4 (+12v) @ %d.%d volts\n", X devnm, millivolts / 1000, (millivolts % 1000) / 100); X millivolts = lm7x_get(iot, ioh, LM78_INTREG_DATA_IN5) * sc->sc_mult.lm7x_mult_in5; X printf("%s: Voltage probe #5 (-12v) @ -%d.%d volts\n", X devnm, millivolts / 1000, (millivolts % 1000) / 100); X millivolts = lm7x_get(iot, ioh, LM78_INTREG_DATA_IN6) * sc->sc_mult.lm7x_mult_in6; X printf("%s: Voltage probe #6 (-5v) @ -%d.%d volts\n", X devnm, millivolts / 1000, (millivolts % 1000) / 100); X value = lm7x_get(iot, ioh, LM78_INTREG_DATA_TEMP); /* XXX signed 2's compliment, LSB=1 deg. C */ X printf("%s: Chip Temp @ %d°C, %d°F\n", devnm, value, ((int) value * 9 / 5) + 32); X X return; X} X X#if 0 /* def LM7X_DEBUG */ X X/* X * Useful to see all the interesting registers X * X * XXX not currently used.... X */ Xstatic void Xlm7x_print_reg(sc, info) X struct lm7x_softc *sc; X char *info; /* string to include in printf() */ X{ X bus_space_tag_t iot = sc->sc_iot; X bus_space_handle_t ioh = sc->sc_ioh; X char *devnm = sc->sc_dev.dv_xname; X u_int8_t regno; X u_int8_t value; X X /* XXX many magic assumptions.... */ X for (regno = LM78_INTREG_CONFIG; regno <= LM78_INTREG_CHIP; regno++) { X value = lm7x_get(iot, ioh, regno); X printf("%s: %s register %#x = %#x.\n", devnm, info, regno, (unsigned) value); X } X X return; X} X X#endif /* 0 */ /* LM7X_DEBUG */ END-of-sys/dev/ic/lm7x.c echo x - sys/dev/ic/lm7xreg.h sed 's/^X//' >sys/dev/ic/lm7xreg.h << 'END-of-sys/dev/ic/lm7xreg.h' X#ident "@(#)LM7X:$Name$:$Id$" X X/* X * lm7x: LM78/LM79 hardware monitor chip registers. X */ X X/* X * Copyright (c) 1998,1999 Greg A. Woods X * X * Redistribution of this software in both source and binary forms, with X * or without modification, is permitted provided that all of the X * following conditions are met: X * X * 1. Redistributions of source code, either alone or as part of a X * collective work, must retain this entire copyright notice, and the X * following disclaimer, without alteration, in each file that X * contains part of this software. X * X * 2. Redistributions of this software in binary form, either alone or X * as part of a collective work, must reproduce this entire copyright X * notice, the following disclaimer, without alteration, in either X * the documentation, and/or header files, and/or other materials X * provided as part of the distribution. X * X * 3. The following acknowledgement must appear in printed documentation X * accompanying a physical distribution of a collective work X * including this software, and must appear in a text file X * accompanying an electronic distribution of a collective work X * including this software: X * X * This product includes software developed by Greg A. Woods. X * X * 4. The name of the author may NOT be used to endorse or promote X * products derived from this software without specific prior written X * permission. The use of the author's name strictly to meet the X * requirements of the previous terms is not to be considered X * promotion or endorsement under this term. X * X * 5. Altered versions (derivative works) must be plainly marked as X * such, and must not be misrepresented as being the original X * software. This copyright notice, and the following disclaimer, X * must not be removed from any derivative work and must not be X * changed in any way. X * X * All other rights are reserved. X * X * DISCLAIMER: X * X * THIS SOFTWARE IS PROVIDED BY GREG A. WOODS ``AS IS'' AND ANY EXPRESS X * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED X * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE X * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY X * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL X * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE X * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS X * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER X * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR X * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN X * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. X */ X X/* NOTE: all registers are 8-bits */ X X#define LM78_NUM_PORTS 8 X X#define LM78_ADDR_POST_OFFSET 0x0 /* port offset P.O.S.T. from ISA */ X#define LM78_ADDR_RES1_OFFSET 0x1 /* reserved */ X#define LM78_ADDR_RES2_OFFSET 0x2 /* reserved */ X#define LM78_ADDR_RES3_OFFSET 0x3 /* reserved */ X#define LM78_ADDR_POST2_OFFSET 0x4 /* 2nd port offset P.O.S.T. from ISA */ X#define LM78_ADDR_PORT_OFFSET 0x5 /* port offset to address register */ X#define LM78_DATA_PORT_OFFSET 0x6 /* port offset to data register */ X#define LM78_ADDR_RES4_OFFSET 0x7 X X/* X * POST RAM at internal registers 0x00-0x1F X * (address auto-increments on read and write) X */ X#define LM78_INTREG_POST_BASE 0x00 X X/* X * Value RAM at internal registers 0x20-0x3F X */ X#define LM78_INTREG_VALUE_BASE 0x20 X X/* X * Data Registers X */ X#define LM78_INTREG_DATA_IN0 0x20 /* units of 16 millivolts */ X#define LM78_INTREG_DATA_IN1 0x21 X#define LM78_INTREG_DATA_IN2 0x22 X#define LM78_INTREG_DATA_IN3 0x23 X#define LM78_INTREG_DATA_IN4 0x24 X#define LM78_INTREG_DATA_IN5 0x25 /* represents negative volts */ X#define LM78_INTREG_DATA_IN6 0x26 /* represents negative volts */ X#define LM78_INTREG_DATA_TEMP 0x27 /* signed 2's compliment, LSB=1 degree C */ X#define LM78_INTREG_DATA_FAN1 0x28 /* "counts" per pulse */ X#define LM78_INTREG_DATA_FAN2 0x29 X#define LM78_INTREG_DATA_FAN3 0x2A X X/* X * Limit Registers X */ X#define LM78_INTREG_LIM_IN0_HI 0x2B /* units of 16 millivolts */ X#define LM78_INTREG_LIM_IN0_LO 0x2C X#define LM78_INTREG_LIM_IN1_HI 0x2D X#define LM78_INTREG_LIM_IN1_LO 0x2E X#define LM78_INTREG_LIM_IN2_HI 0x2F X#define LM78_INTREG_LIM_IN2_LO 0x30 X#define LM78_INTREG_LIM_IN3_HI 0x31 X#define LM78_INTREG_LIM_IN3_LO 0x32 X#define LM78_INTREG_LIM_IN4_HI 0x33 X#define LM78_INTREG_LIM_IN4_LO 0x34 X#define LM78_INTREG_LIM_IN5_HI 0x35 /* represents negative volts */ X#define LM78_INTREG_LIM_IN5_LO 0x36 /* represents negative volts */ X#define LM78_INTREG_LIM_IN6_HI 0x37 /* represents negative volts */ X#define LM78_INTREG_LIM_IN6_LO 0x37 /* represents negative volts */ X#define LM78_INTREG_LIM_OVERTEMP 0x39 /* signed 2's compliment, LSB=1 degree C */ X#define LM78_INTREG_LIM_TEMPHYST 0x3A X#define LM78_INTREG_LIM_FAN1_LO 0x3B /* "counts" per pulse */ X#define LM78_INTREG_LIM_FAN2_LO 0x3C X#define LM78_INTREG_LIM_FAN3_LO 0x3D X#define LM78_INTREG_RESERVED_1 0x3E X#define LM78_INTREG_RESERVED_2 0x3F X X/* X * Control Register X */ X#define LM78_INTREG_CONFIG 0x40 X X/* X * Bit masks for LM78_INTREG_CONFIG settings are in X */ X X/* X * Interrupt status registers X */ X#define LM78_INTREG_INT1 0x41 /* (address auto-increments after read and write) */ X#define LM78_INTREG_INT2 0x42 X X/* X * Interrupt mask registers (for SMI) X */ X#define LM78_INTREG_SMI1_MASK 0x43 /* (address auto-increments after read and write) */ X#define LM78_INTREG_SMI2_MASK 0x44 X X/* X * Interrupt mask registers (for NMI/IRQ) X */ X#define LM78_INTREG_NMI1_MASK 0x45 /* (address auto-increments after read and write) */ X#define LM78_INTREG_NMI2_MASK 0x46 X X/* X * Bit masks for individual interrupt status and mask registers: X */ X#define LM78_INT1_IN0 0x01 X#define LM78_INT1_IN1 0x02 X#define LM78_INT1_IN2 0x04 X#define LM78_INT1_IN3 0x08 X#define LM78_INT1_TEMP 0x10 X#define LM78_INT1_BTI 0x20 /* board temp interrupt input */ X#define LM78_INT1_FAN1 0x40 X#define LM78_INT1_FAN2 0x80 X X#define LM78_INT2_IN4 0x01 X#define LM78_INT2_IN5 0x02 X#define LM78_INT2_IN6 0x04 X#define LM78_INT2_FAN3 0x08 X#define LM78_INT2_CHASSIS 0x10 X#define LM78_INT2_FIFO 0x20 /* P.O.S.T. RAM FIFO overflow */ X#define LM78_INT2_SMI_IN 0x40 /* SMI input has gone low */ X#define LM78_INT2_RESERVED 0x80 X X#define LM78_SMI1_IN0 0x01 X#define LM78_SMI1_IN1 0x02 X#define LM78_SMI1_IN2 0x04 X#define LM78_SMI1_IN3 0x08 X#define LM78_SMI1_TEMP 0x10 X#define LM78_SMI1_BTI 0x20 X#define LM78_SMI1_FAN1 0x40 X#define LM78_SMI1_FAN2 0x80 X X#define LM78_SMI1_ALL_OFF 0xff X X#define LM78_SMI2_IN4 0x01 X#define LM78_SMI2_IN5 0x02 X#define LM78_SMI2_IN6 0x04 X#define LM78_SMI2_FAN3 0x08 X#define LM78_SMI2_CHASSIS 0x10 X#define LM78_SMI2_FIFO 0x20 X#define LM78_SMI2_SMI_IN 0x40 X X#define LM78_SMI2_ALL_OFF 0x7f X/* X * a one enables the RESET# bit in the configuration register X */ X#define LM78_SMI2_RESET_ENAB 0x80 X X#define LM78_NMI1_IN0 0x01 X#define LM78_NMI1_IN1 0x02 X#define LM78_NMI1_IN2 0x04 X#define LM78_NMI1_IN3 0x08 X#define LM78_NMI1_TEMP 0x10 X#define LM78_NMI1_BTI 0x20 X#define LM78_NMI1_FAN1 0x40 X#define LM78_NMI1_FAN2 0x80 X X#define LM78_NMI1_ALL_OFF 0xff X X#define LM78_NMI2_IN4 0x01 X#define LM78_NMI2_IN5 0x02 X#define LM78_NMI2_IN6 0x04 X#define LM78_NMI2_FAN3 0x08 X#define LM78_NMI2_CHASSIS 0x10 X#define LM78_NMI2_FIFO 0x20 X#define LM78_NMI2_SMI_IN 0x40 X X#define LM78_NMI2_ALL_OFF 0x7f X/* X * Writing a one output a minimum 20ms active low pulse on the chassis X * intrusion pin. The bit self clears after the pulse has been sent. X */ X#define LM78_NMI2_CHASSIS_CLR 0x80 /* read only? */ X X/* X * VID and FAN divisor register X */ X#define LM78_INTREG_VID_FAN 0x47 X X/* X * Bit masks for VID_FAN register X */ X#define LM78_VID_MASK 0x0f /* 0-3: VID0-VID3 */ X#define LM78_FAN1_DIV_MASK 0x30 /* 4-5: FAN 1 divisor */ X#define LM78_FAN2_DIV_MASK 0xc0 /* 6-7: FAN 2 divisor */ X X/* Note that the FAN 3 divisor is always considered to be "2". */ X/* X * Note also that the Intel Pentium-II Developer manual specifies two pulse-per X * revolution tachometer output for the CPU heatsink fan. X */ X X/* X * I2C serial bus address register X */ X#define LM78_INTREG_SIOADDR 0x48 X X#define LM78_SIOADDR_INIT 0x2D /* initial power on value */ X X/* X * Chip Reset / ID register (LM79 also has VID4 input in bit 0) X */ X#define LM78_INTREG_CHIP 0x49 X X/* X * Bit masks for LM78_INTREG_CHIP settings: X */ X#define LM79_CHIP_VID4 0x01 /* 0: current state of VID4 */ X#define LM78_CHIP_RESET 0x20 /* 5: 1 = reset all registers to power-on defaults */ X#define LM78_CHIP_DEVID 0x40 /* 6: 0 = LM78, 1 = LM78-J */ X#define LM79_CHIP_DEVID 0x80 /* 7: 0 = LM78/LM78-J, 1 = LM79 */ X X/* X * Value RAM at 0x60-0x7F (address auto-increments after read and write) X */ X#define LM78_INTREG_VALUE_BASE_AUTO 0x60 END-of-sys/dev/ic/lm7xreg.h echo x - sys/dev/ic/lm7xvar.h sed 's/^X//' >sys/dev/ic/lm7xvar.h << 'END-of-sys/dev/ic/lm7xvar.h' X#ident "@(#)LM7X:$Name$:$Id$" X X/* X * lm7x: LM78/LM79 hardware monitor bus-independent software context X */ X X/* X * Copyright (c) 1999 Greg A. Woods X * X * Redistribution of this software in both source and binary forms, with X * or without modification, is permitted provided that all of the X * following conditions are met: X * X * 1. Redistributions of source code, either alone or as part of a X * collective work, must retain this entire copyright notice, and the X * following disclaimer, without alteration, in each file that X * contains part of this software. X * X * 2. Redistributions of this software in binary form, either alone or X * as part of a collective work, must reproduce this entire copyright X * notice, the following disclaimer, without alteration, in either X * the documentation, and/or header files, and/or other materials X * provided as part of the distribution. X * X * 3. The following acknowledgement must appear in printed documentation X * accompanying a physical distribution of a collective work X * including this software, and must appear in a text file X * accompanying an electronic distribution of a collective work X * including this software: X * X * This product includes software developed by Greg A. Woods. X * X * 4. The name of the author may NOT be used to endorse or promote X * products derived from this software without specific prior written X * permission. The use of the author's name strictly to meet the X * requirements of the previous terms is not to be considered X * promotion or endorsement under this term. X * X * 5. Altered versions (derivative works) must be plainly marked as X * such, and must not be misrepresented as being the original X * software. This copyright notice, and the following disclaimer, X * must not be removed from any derivative work and must not be X * changed in any way. X * X * All other rights are reserved. X * X * DISCLAIMER: X * X * THIS SOFTWARE IS PROVIDED BY GREG A. WOODS ``AS IS'' AND ANY EXPRESS X * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED X * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE X * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY X * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL X * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE X * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS X * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER X * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR X * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN X * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. X */ X X/* X * array of driver software context structures X */ Xstruct lm7x_softc { X struct device sc_dev; /* device glue */ X bus_space_tag_t sc_iot; /* space tag */ X bus_space_handle_t sc_ioh; /* space handle */ X int sc_type; /* LM78/LM79/etc. (XXX bitfield?) */ X short sc_running; /* has been started up */ X short sc_state; /* OPENed, etc. (XXX bitfield?) */ X pid_t sc_pid; /* pid which OPENed */ X lm7x_mult_t sc_mult; /* voltage multipliers */ X}; X X/* X * for sc_type: X */ X#define LM7X_LM78 0x01 X#define LM7X_LM78J 0x02 X#define LM7X_LM79 0x04 X X/* X * bits for sc_state X */ X#define LM7X_SC_NONE 0x00 /* device is unused */ X#define LM7X_SC_OPEN 0x01 /* device is open */ X#define LM7X_SC_INIT 0x02 /* waiting to initialize for open */ X X/* X * prototypes for generic routines. X */ Xextern int lm7x_probe __P((bus_space_tag_t, bus_space_handle_t)); Xextern void lm7x_attach __P((struct lm7x_softc *, bus_space_tag_t, bus_space_handle_t)); END-of-sys/dev/ic/lm7xvar.h echo x - sys/dev/isa/lm7x_isa.c sed 's/^X//' >sys/dev/isa/lm7x_isa.c << 'END-of-sys/dev/isa/lm7x_isa.c' X#ident "@(#)LM7X:$Name$:$Id$" X X/* X * lm7x: ISA attachment for LM78/LM79 hardware monitor chip driver X */ X X/* X * Copyright (c) 1998,1999 Greg A. Woods X * X * Redistribution of this software in both source and binary forms, with X * or without modification, is permitted provided that all of the X * following conditions are met: X * X * 1. Redistributions of source code, either alone or as part of a X * collective work, must retain this entire copyright notice, and the X * following disclaimer, without alteration, in each file that X * contains part of this software. X * X * 2. Redistributions of this software in binary form, either alone or X * as part of a collective work, must reproduce this entire copyright X * notice, the following disclaimer, without alteration, in either X * the documentation, and/or header files, and/or other materials X * provided as part of the distribution. X * X * 3. The following acknowledgement must appear in printed documentation X * accompanying a physical distribution of a collective work X * including this software, and must appear in a text file X * accompanying an electronic distribution of a collective work X * including this software: X * X * This product includes software developed by Greg A. Woods. X * X * 4. The name of the author may NOT be used to endorse or promote X * products derived from this software without specific prior written X * permission. The use of the author's name strictly to meet the X * requirements of the previous terms is not to be considered X * promotion or endorsement under this term. X * X * 5. Altered versions (derivative works) must be plainly marked as X * such, and must not be misrepresented as being the original X * software. This copyright notice, and the following disclaimer, X * must not be removed from any derivative work and must not be X * changed in any way. X * X * All other rights are reserved. X * X * DISCLAIMER: X * X * THIS SOFTWARE IS PROVIDED BY GREG A. WOODS ``AS IS'' AND ANY EXPRESS X * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED X * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE X * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY X * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL X * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE X * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS X * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER X * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR X * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN X * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. X */ X X/* X * This driver currently only probes the chip (and if LM7X_DEBUG is set it will X * also display an interpretation of the probe values at boot (attach) time). X * X * It is unlikely that the IRQ#/NMI lines from the chip are connected to the X * system interrupt controller (at least not on the ASUS P2L97), so any use of X * the watchdog monitors will require polling the chip at no more than 1.5 X * second intervals. X */ X X#include "lm7x_isa.h" /* gen by config(8) to specify NLM7X */ X X#if NLM7X_ISA > 0 X X#if defined(DEBUG) && !defined(LM7X_DEBUG) X# define LM7X_DEBUG 1 X#endif X X#include X#include X#include X#include X#include X#include X#include X#include X#include X#include X#include X#include X#include X X#include /* ioctl() cmd & data structures */ X X#include X#include X#include X X#include X#include X#include X X#include /* LM78/LM79 generic constants */ X#include /* LM78/LM79 generic software context */ X Xstatic int lm7x_probe_isa __P((struct device *, struct cfdata *, void *)); Xstatic void lm7x_attach_isa __P((struct device *, struct device *, void *)); X X/* X * driver attachment: used in ioconf.c cfdata array X */ Xstruct cfattach lm7x_isa_ca = { X sizeof(struct lm7x_softc), lm7x_probe_isa, lm7x_attach_isa X}; X X/* X * Probe routine. Return 1 if device exists. X */ Xstatic int Xlm7x_probe_isa(parent, match, aux) X struct device *parent; X struct cfdata *match; X void *aux; X{ X struct isa_attach_args *ia = aux; X bus_space_tag_t iot = ia->ia_iot; X bus_space_handle_t ioh; X int result = 0; X X if (bus_space_map(iot, ia->ia_iobase, LM78_NUM_PORTS, 0, &ioh)) X return (0); X X if (ia->ia_iobase == ISACF_PORT_DEFAULT) { /* "port?" used in configuration */ X ia->ia_iobase = IO_LM7X; /* try the default.... */ X#ifdef LM7X_DEBUG X printf("lm7x%d: iobase not specified, setting to default of %#x.\n", match->cf_unit, ia->ia_iobase); X#endif X } X result = lm7x_probe(iot, ioh); X X ia->ia_iosize = LM78_NUM_PORTS; X ia->ia_msize = 0; X X bus_space_unmap(iot, ioh, LM78_NUM_PORTS); X X#ifdef LM7X_DEBUG X printf("lm7x%d: probe at iobase=%#x, %s.\n", X match->cf_unit, ia->ia_iobase, result ? "OK" : "LM78 not found"); X#endif X X return (result); X} X X/* X * Attach routine - announce which it is, and wire into system X */ Xstatic void Xlm7x_attach_isa(parent, self, aux) X struct device *parent; X struct device *self; X void *aux; X{ X struct lm7x_softc *sc = (struct lm7x_softc *) self; X struct isa_attach_args *ia = aux; X bus_space_tag_t iot = ia->ia_iot; X bus_space_handle_t ioh; X X /* Map the card. */ X if (bus_space_map(iot, ia->ia_iobase, ia->ia_iosize, 0, &ioh)) { X printf("%s: can't map i/o space\n", sc->sc_dev.dv_xname); X return; X } X X sc->sc_iot = iot; X sc->sc_ioh = ioh; X#if 0 /* XXX do we need to shlep this around? */ X sc->sc_ic = ia->ia_ic; X#endif X sc->sc_running = 0; X sc->sc_type = 0; X sc->sc_pid = 0; /* XXX or -1? */ X X lm7x_attach(sc, iot, ioh); X X return; X} X X#endif /* NLM7X > 0 */ END-of-sys/dev/isa/lm7x_isa.c echo x - sys/sys/lm7xio.h sed 's/^X//' >sys/sys/lm7xio.h << 'END-of-sys/sys/lm7xio.h' X#ident "@(#)LM7X:$Name$:$Id$" X X/* X * lm7x: LM78/LM79 hardware monitor ioctl() interface [see lm7x(4)]. X */ X X/* X * Copyright (c) 1998,1999 Greg A. Woods X * X * Redistribution of this software in both source and binary forms, with X * or without modification, is permitted provided that all of the X * following conditions are met: X * X * 1. Redistributions of source code, either alone or as part of a X * collective work, must retain this entire copyright notice, and the X * following disclaimer, without alteration, in each file that X * contains part of this software. X * X * 2. Redistributions of this software in binary form, either alone or X * as part of a collective work, must reproduce this entire copyright X * notice, the following disclaimer, without alteration, in either X * the documentation, and/or header files, and/or other materials X * provided as part of the distribution. X * X * 3. The following acknowledgement must appear in printed documentation X * accompanying a physical distribution of a collective work X * including this software, and must appear in a text file X * accompanying an electronic distribution of a collective work X * including this software: X * X * This product includes software developed by Greg A. Woods. X * X * 4. The name of the author may NOT be used to endorse or promote X * products derived from this software without specific prior written X * permission. The use of the author's name strictly to meet the X * requirements of the previous terms is not to be considered X * promotion or endorsement under this term. X * X * 5. Altered versions (derivative works) must be plainly marked as X * such, and must not be misrepresented as being the original X * software. This copyright notice, and the following disclaimer, X * must not be removed from any derivative work and must not be X * changed in any way. X * X * All other rights are reserved. X * X * DISCLAIMER: X * X * THIS SOFTWARE IS PROVIDED BY GREG A. WOODS ``AS IS'' AND ANY EXPRESS X * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED X * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE X * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY X * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL X * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE X * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS X * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER X * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR X * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN X * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. X */ X X#include X X#define LM7X_CYCLE_TIME 2 /* # of seconds for chip monitor cycle */ X X/* X * Bit masks for simulated 16bit interrupt status and mask registers: X * (reg_2 << 8) | reg_1 X */ X#define LM7X_INT_IN0 0x0001 X#define LM7X_INT_IN1 0x0002 X#define LM7X_INT_IN2 0x0004 X#define LM7X_INT_IN3 0x0008 X#define LM7X_INT_TEMP 0x0010 X#define LM7X_INT_BTI 0x0020 X#define LM7X_INT_FAN1 0x0040 X#define LM7X_INT_FAN2 0x0080 X#define LM7X_INT_IN4 0x0100 X#define LM7X_INT_IN5 0x0200 X#define LM7X_INT_IN6 0x0400 X#define LM7X_INT_FAN3 0x0800 X#define LM7X_INT_CHASSIS 0x1000 X#define LM7X_INT_FIFO 0x2000 X#define LM7X_INT_SMI_IN 0x4000 X#define LM7X_INT_RESERVED 0x8000 X X#define LM7X_INT_MASK_ALL_OFF 0x7fff /* only for SMI/NMI masks */ X X#define LM7X_SMI_RESET_ENAB 0x8000 /* only for SMI Mask */ X#define LM7X_NMI_CHASSI_CLR 0x8000 /* only for NMI Mask */ X X/* X * Bit masks for configuration register: X */ X#define LM7X_CONF_START 0x01 /* 0: enable monitoring loop */ X#define LM7X_CONF_SMI_ENAB 0x02 /* 1: enable SMI# (Sys Mgmt Interrupt) */ X#define LM7X_CONF_NMIIRQ_ENAB 0x04 /* 2: enable NMI or IRQ */ X#define LM7X_CONF_INTR_CLR 0x08 /* 3: 1 = disable SMI&NMI/IRQ, stop monitor */ X#define LM7X_CONF_RESET 0x10 /* 4: output 20ms active low RESET# (see LM7X_SMI2_RESET_ENAB) */ X#define LM7X_CONF_NMIIRQ_SEL 0x20 /* 5: 0 = IRQ#, 1 = NMI */ X#define LM7X_CONF_POWER_BYPASS 0x40 /* 6: 1 = active low on power switch bypass pin */ X#define LM7X_CONF_INITIALIZE 0x80 /* 7: configuration initialization (self clears) */ X X#define LM7X_CONF_DEFAULT LM7X_CONF_INTR_CLR /* power on default value */ X Xtypedef struct lm7x_status { X int lm7x_in0; /* millivolts */ X int lm7x_in1; X int lm7x_in2; X int lm7x_in3; X int lm7x_in4; X int lm7x_in5; /* will always be negative */ X int lm7x_in6; /* will always be negative */ X int lm7x_temp; /* degrees Celsius */ X int lm7x_fan1; /* RPMs */ X int lm7x_fan2; X int lm7x_fan3; X u_int8_t lm7x_config; /* configuration register */ X u_int16_t lm7x_intstat; /* interrupt status registers */ X u_int16_t lm7x_smimask; /* MSB ignored on set */ X u_int16_t lm7x_nmimask; /* MSB ignored on set */ X u_int8_t lm7x_vid; /* VID pins from CPU */ X u_int8_t lm7x_saddr; /* SMB address */ X} lm7x_status_t; X X/* X * Conversion table from Voltage Identification (VID) to Vcc(core) values (in X * Volts) for Pentium II at 233, 266, 300 and 333 MHz: X * (from the Intel Pentium-II Data Sheet Order # 243335-003) X * X * 0x00 2.05 X * 0x01 2.00 X * 0x02 1.95 X * 0x03 1.90 X * 0x04 1.85 X * 0x05 1.80 X * (0x6 - 0xf reserved) X * 0x10 3.5 X * 0x11 3.4 X * 0x12 3.3 X * 0x13 3.3 X * 0x14 3.1 X * 0x15 3.0 X * 0x16 2.9 X * 0x17 2.8 X * 0x18 2.7 X * 0x19 2.6 X * 0x1a 2.5 X * 0x1b 2.4 X * 0x1c 2.3 X * 0x1d 2.2 X * 0x1e 2.1 X * 0x1f No Core X */ X X/* X * setting "hi" limit to INT_MAX disables over-limit interrupts X * "hi" limits are tested with '>' and "lo" are tested with '<=' X */ Xtypedef struct lm7x_limits { X int lm7x_in0lo; /* millivolts */ X int lm7x_in0hi; X int lm7x_in1lo; X int lm7x_in1hi; X int lm7x_in2lo; X int lm7x_in2hi; X int lm7x_in3lo; X int lm7x_in3hi; X int lm7x_in4lo; X int lm7x_in4hi; X int lm7x_in5lo; /* must be negative */ X int lm7x_in5hi; /* must be negative */ X int lm7x_in6lo; /* must be negative */ X int lm7x_in6hi; /* must be negative */ X int lm7x_temphyst; /* degrees Celsius */ X int lm7x_overtemp; /* degrees Celsius */ X int lm7x_fan1lo; /* RPMs */ X int lm7x_fan2lo; X int lm7x_fan3lo; X} lm7x_limits_t; X X/* X * Default voltage probe multipliers from NS LM78/LM79 application note. The X * result of multiplying with the register value is millivolts. The voltage X * probes feed 8-bit AtoD converters with a 16 millivolt per unit. The normal X * range of a probe is 0V to 4.08V. The 5V and 12V sources are attenuated to X * approximately 3V, and these multipliers are used to compensate the ADC value X * for display purposes. X */ X#define LM7X_DEFAULT_MULT_IN0 16 /* usually CPU Core volts */ X#define LM7X_DEFAULT_MULT_IN1 16 /* ???? */ X#define LM7X_DEFAULT_MULT_IN2 16 /* + 3.3vdc */ X#define LM7X_DEFAULT_MULT_IN3 27 /* + 5.0vdc ~ 16 * 1.68 */ X#define LM7X_DEFAULT_MULT_IN4 64 /* +12.0vdc 16 * 4 */ X#define LM7X_DEFAULT_MULT_IN5 64 /* -12.0vdc 16 * 4 */ X#define LM7X_DEFAULT_MULT_IN6 26 /* - 5.0vdc ~ 16 * 1.67 */ X Xtypedef struct lm7x_mult { X int lm7x_mult_in0; /* multiplier for millivolts */ X int lm7x_mult_in1; X int lm7x_mult_in2; X int lm7x_mult_in3; X int lm7x_mult_in4; X int lm7x_mult_in5; X int lm7x_mult_in6; X} lm7x_mult_t; X X#define LM7X_POSTBUFSIZ 32 /* P.O.S.T. buffer */ X X/* X * LM7X ioctl() commands X */ X#define LM7X_IOC_GROUP 'l' X X#define LM7X_ENANMI _IO(LM7X_IOC_GROUP, 1) /* enable interrupt via NMI (default) */ X#define LM7X_DISNMI _IO(LM7X_IOC_GROUP, 2) /* enable interrupt via IRQ */ X#define LM7X_ENAINT _IO(LM7X_IOC_GROUP, 3) /* enable NMI/IRQ interrupts (default) */ X#define LM7X_DISINT _IO(LM7X_IOC_GROUP, 4) /* disable NMI/IRQ interrupts */ X#define LM7X_ENASMI _IO(LM7X_IOC_GROUP, 5) /* enable SMI interrupts */ X#define LM7X_DISSMI _IO(LM7X_IOC_GROUP, 6) /* disable SMI interrupts (default) */ X#define LM7X_PWRBYPASS _IO(LM7X_IOC_GROUP, 7) /* drive 0 on pwr sw bypass */ X#define LM7X_CLRPWRBYPASS _IO(LM7X_IOC_GROUP, 8) /* drive 1 on pwr sw bypass (default) */ X#define LM7X_CLRCHASS _IO(LM7X_IOC_GROUP, 9) /* clear chassis intrusion flag */ X#define LM7X_GETSTATUS _IOR(LM7X_IOC_GROUP, 10, struct lm7x_status) X#define LM7X_GETLIMITS _IOR(LM7X_IOC_GROUP, 11, struct lm7x_limits) X#define LM7X_SETLIMITS _IOW(LM7X_IOC_GROUP, 12, struct lm7x_limits) X#define LM7X_GETPOST _IOR(LM7X_IOC_GROUP, 13, char[LM7X_POSTBUFSIZ]) X#define LM7X_PUTPOST _IOW(LM7X_IOC_GROUP, 14, char[LM7X_POSTBUFSIZ]) X#define LM7X_GETMULT _IOR(LM7X_IOC_GROUP, 15, struct lm7x_mult) X#define LM7X_SETMULT _IOW(LM7X_IOC_GROUP, 16, struct lm7x_mult) X#define LM7X_PRINT _IO(LM7X_IOC_GROUP, 17) /* trigger kernel status printfs */ END-of-sys/sys/lm7xio.h echo c - usr.sbin/lmhw/ mkdir -p usr.sbin/lmhw/ > /dev/null 2>&1 echo x - usr.sbin/lmhw/Makefile sed 's/^X//' >usr.sbin/lmhw/Makefile << 'END-of-usr.sbin/lmhw/Makefile' XPROG= lmhw XSRCS= lmhw.c X XMAN= lmhw.8 X X.include END-of-usr.sbin/lmhw/Makefile echo x - usr.sbin/lmhw/lmhw.8 sed 's/^X//' >usr.sbin/lmhw/lmhw.8 << 'END-of-usr.sbin/lmhw/lmhw.8' X.\"#ident "@(#)LMHW:$Name: $:$Id: lmhw.8,v 1.1 1998/07/07 21:17:05 woods Exp $" X.\" X.\" Copyright (c) 1998,1999 Greg A. Woods X.\" X.\" Redistribution of this software in both source and binary forms, with X.\" or without modification, is permitted provided that all of the X.\" following conditions are met: X.\" X.\" 1. Redistributions of source code, either alone or as part of a X.\" collective work, must retain this entire copyright notice, and the X.\" following disclaimer, without alteration, in each file that X.\" contains part of this software. X.\" X.\" 2. Redistributions of this software in binary form, either alone or X.\" as part of a collective work, must reproduce this entire copyright X.\" notice, the following disclaimer, without alteration, in either X.\" the documentation, and/or header files, and/or other materials X.\" provided as part of the distribution. X.\" X.\" 3. The following acknowledgement must appear in printed documentation X.\" accompanying a physical distribution of a collective work X.\" including this software, and must appear in a text file X.\" accompanying an electronic distribution of a collective work X.\" including this software: X.\" X.\" This product includes software developed by Greg A. Woods. X.\" X.\" 4. The name of the author may NOT be used to endorse or promote X.\" products derived from this software without specific prior written X.\" permission. The use of the author's name strictly to meet the X.\" requirements of the previous terms is not to be considered X.\" promotion or endorsement under this term. X.\" X.\" 5. Altered versions (derivative works) must be plainly marked as X.\" such, and must not be misrepresented as being the original X.\" software. This copyright notice, and the following disclaimer, X.\" must not be removed from any derivative work and must not be X.\" changed in any way. X.\" X.\" All other rights are reserved. X.\" X.\" DISCLAIMER: X.\" X.\" THIS SOFTWARE IS PROVIDED BY GREG A. WOODS ``AS IS'' AND ANY EXPRESS X.\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED X.\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE X.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY X.\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL X.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE X.\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS X.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER X.\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR X.\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN X.\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. X.\" X.Dd July 7, 1998 X.Dt LMHW 8 X.Os X.Sh NAME X.Nm lmhw X.Nd set/display hardware monitor values X.Sh SYNOPSIS X.Nm X.Op Fl f Ar device X.Op Fl dv X.Oo X.Fl h | X.Fl l | X.Fl s | X.Fl p X.Oc X.Sh DESCRIPTION XThe X.Nm Xcommand is used to set and display hardware monitor device values. X.Ss Argument List Processing X.Bl -tag -width Ds X.It Fl f dev XUse the specified device file instead of the default. X.It Fl d XBecome a daemon process and monitor for alarm interrupts. X.It Fl l XPrint the current values of all the limit registers. X.It Fl s XPrint the current probe values. X.It Fl p XCause the kernel to print the current probe values. X.El X.Sh FILES X.Bl -tag -width /dev/lm7x0 -compact X.It Pa /dev/lm7x0 XThe default hardware monitor device. X.\" .Sh RETURN VALUES X.\" .Sh ENVIRONMENT X.\" .Sh FILES X.\" .Sh EXAMPLES X.\" .Sh DIAGNOSTICS X.\" .Sh ERRORS X.\" .Sh SEE ALSO X.\" .Sh STANDARDS X.Sh HISTORY XThe X.Nm Xcommand first appeared in X.Nx 1.4 . X.Sh AUTHOR X.An "Greg A. Woods" Aq woods@planix.com X.Sh BUGS XShould be subsumed into X.Xr sysctl 8 Xand/or X.Xr kernfs 5 . END-of-usr.sbin/lmhw/lmhw.8 echo x - usr.sbin/lmhw/lmhw.c sed 's/^X//' >usr.sbin/lmhw/lmhw.c << 'END-of-usr.sbin/lmhw/lmhw.c' X#ident "@(#)LMHW:$Name: $:$Id: lmhw.c,v 1.1 1998/07/07 21:17:06 woods Exp $" X X/* X * lmhw: low-level interface to LM78/LM79 hardware monitor driver X */ X X/* X * Copyright (c) 1999 Greg A. Woods X * X * Redistribution of this software in both source and binary forms, with X * or without modification, is permitted provided that all of the X * following conditions are met: X * X * 1. Redistributions of source code, either alone or as part of a X * collective work, must retain this entire copyright notice, and the X * following disclaimer, without alteration, in each file that X * contains part of this software. X * X * 2. Redistributions of this software in binary form, either alone or X * as part of a collective work, must reproduce this entire copyright X * notice, the following disclaimer, without alteration, in either X * the documentation, and/or header files, and/or other materials X * provided as part of the distribution. X * X * 3. The following acknowledgement must appear in printed documentation X * accompanying a physical distribution of a collective work X * including this software, and must appear in a text file X * accompanying an electronic distribution of a collective work X * including this software: X * X * This product includes software developed by Greg A. Woods. X * X * 4. The name of the author may NOT be used to endorse or promote X * products derived from this software without specific prior written X * permission. The use of the author's name strictly to meet the X * requirements of the previous terms is not to be considered X * promotion or endorsement under this term. X * X * 5. Altered versions (derivative works) must be plainly marked as X * such, and must not be misrepresented as being the original X * software. This copyright notice, and the following disclaimer, X * must not be removed from any derivative work and must not be X * changed in any way. X * X * All other rights are reserved. X * X * DISCLAIMER: X * X * THIS SOFTWARE IS PROVIDED BY GREG A. WOODS ``AS IS'' AND ANY EXPRESS X * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED X * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE X * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY X * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL X * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE X * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS X * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER X * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR X * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN X * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. X */ X X#include X#include X X#include X#include X#include X#include X#include X#include X#include X X#include X#include X X#include X#include "pathnames.h" X X#define GETOPT_OPTS "f:hlspdv" X#define LMHW_USAGE "[-d] [-h|-l|-s|-p] [-v] [-f dev]" X#define LMHW_HELP "\ X -d run in daemon mode\n\ X -f dev specify device filename\n\ X -l print the limits information\n\ X -p cause kernel to print the status\n\ X -s print the status information\n\ X -v be verbose (run in foreground)\n\ X" X Xchar *argv0 = "lmhw"; /* for error messages */ Xint verbose = 0; /* be chatty, run in foreground */ Xint do_daemon = 0; /* run as a daemon */ X Xstatic void lmhw_print_limits __P((char *)); Xstatic void lmhw_print_status __P((char *)); Xstatic void lmhw_kprint __P((char *)); Xstatic void usage __P((void)); Xstatic void help __P((void)); X Xextern int opterr; /* for getopt() */ Xextern int optind; /* for getopt() */ Xextern char *optarg; /* for getopt() */ X Xextern int main __P((int, char *[])); X Xint Xmain(argc, argv) X int argc; X char *argv[]; X{ X int c; X int lmhwfd = -1; X char *devname = _PATH_DEVLMHW; X char *logprefix; X X argv0 = (argv0 = strrchr(argv[0], '/')) ? argv0 + 1 : argv[0]; X X while ((c = getopt(argc, argv, GETOPT_OPTS)) != -1) { X switch (c) { X case 'd': X do_daemon = 1; X break; X case 'f': X devname = optarg; X if (devname[0] != '/') { X static char namebuf[BUFSIZ]; X X snprintf(namebuf, sizeof(namebuf) - 1, "%s%s", _PATH_DEV, devname); X namebuf[BUFSIZ - 1] = '\0'; X devname = namebuf; X } X break; X case 'l': X lmhw_print_limits(devname); X exit(0); X /* NOTREACHED */ X case 's': X lmhw_print_status(devname); X exit(0); X /* NOTREACHED */ X case 'p': X lmhw_kprint(devname); X exit(0); X /* NOTREACHED */ X case 'v': X verbose = 1; X break; X case 'h': X help(); X /* NOTREACHED */ X case '?': X usage(); X /* NOTREACHED */ X default: X fprintf(stderr, "%s: impossible result '%c' from getopt(%s).\n", X argv0, c, GETOPT_OPTS); X exit(1); X /* NOTREACHED */ X } X } X X /* default fall-through case is daemon mode */ X if (daemon(0, verbose) == -1) { X syslog(LOG_ERR, "daemon(): %m"); X exit(1); X /* NOTREACHED */ X } X logprefix = (logprefix = strrchr(devname, '/')) ? logprefix + 1 : devname; X /* XXX should we let syslogd.conf decide if we go to the console? */ X openlog(logprefix, LOG_CONS, LOG_DAEMON); X syslog(LOG_INFO, "starting hardware monitoring"); X while (do_daemon) { X static lm7x_status_t lmhwst; X static lm7x_limits_t lmhwlim; X X /* X * open the device, X * get the current status, X * check for interrupts X * syslog info about any interrupts, X * close the device to unlock it. X */ X if ((lmhwfd = open(devname, O_RDONLY, 0)) == -1) { X syslog(LOG_ERR, "%m"); X exit(1); X /* NOTREACHED */ X } X if (ioctl(lmhwfd, LM7X_GETSTATUS, (void *) &lmhwst) == -1) { X syslog(LOG_ALERT, "%m"); X exit(1); X /* NOTREACHED */ X } X if (! lmhwst.lm7x_config & LM7X_CONF_START || ! lmhwst.lm7x_config & LM7X_CONF_INTR_CLR) { X syslog(LOG_ALERT, "monitor chip apparently not running!"); X /* XXX should we start it instead of waiting for a human? */ X /* XXX or maybe we should just keep syslog'ing and waiting? */ X exit(1); X /* NOTREACHED */ X } X if (ioctl(lmhwfd, LM7X_GETLIMITS, (void *) &lmhwlim) == -1) { X syslog(LOG_ALERT, "%m"); X exit(1); X /* NOTREACHED */ X } X if ((lmhwfd = close(lmhwfd)) == -1) { X syslog(LOG_ERR, "%m"); X exit(1); X /* NOTREACHED */ X } X /* decode interrupt bits and log event */ X /* XXX should the syslog level be configurable? */ X if (lmhwst.lm7x_intstat & LM7X_INT_IN0) { X syslog(LOG_ALERT, "voltage probe 0 exceeded limit: %.3f (hi=%.3f, lo=%.3f)", X lmhwst.lm7x_in0 / 1000.0f, lmhwlim.lm7x_in0hi / 1000.0f, lmhwlim.lm7x_in0lo / 1000.0f); X } else if (lmhwst.lm7x_intstat & LM7X_INT_IN1) { X syslog(LOG_ALERT, "voltage probe 1 exceeded limit: %.3f (hi=%.3f, lo=%.3f)", X lmhwst.lm7x_in1 / 1000.0f, lmhwlim.lm7x_in1hi / 1000.0f, lmhwlim.lm7x_in1lo / 1000.0f); X } else if (lmhwst.lm7x_intstat & LM7X_INT_IN2) { X syslog(LOG_ALERT, "voltage probe 2 exceeded limit: %.3f (hi=%.3f, lo=%.3f)", X lmhwst.lm7x_in2 / 1000.0f, lmhwlim.lm7x_in2hi / 1000.0f, lmhwlim.lm7x_in2lo / 1000.0f); X } else if (lmhwst.lm7x_intstat & LM7X_INT_IN3) { X syslog(LOG_ALERT, "voltage probe 3 exceeded limit: %.3f (hi=%.3f, lo=%.3f)", X lmhwst.lm7x_in3 / 1000.0f, lmhwlim.lm7x_in3hi / 1000.0f, lmhwlim.lm7x_in3lo / 1000.0f); X } else if (lmhwst.lm7x_intstat & LM7X_INT_TEMP) { X syslog(LOG_ALERT, "Temperature probe 3 exceeded limit: %d(C) (hi=%d, hyst=%d)", X lmhwst.lm7x_temp, lmhwlim.lm7x_overtemp, lmhwlim.lm7x_temphyst); X } else if (lmhwst.lm7x_intstat & LM7X_INT_BTI) { X syslog(LOG_ALERT, "Board Temperature Interrupt (BTI) detected."); X } else if (lmhwst.lm7x_intstat & LM7X_INT_FAN1) { X syslog(LOG_ALERT, "Fan #1 below limit: %d RPM (low=%d)", X lmhwst.lm7x_fan1, lmhwlim.lm7x_fan1lo); X } else if (lmhwst.lm7x_intstat & LM7X_INT_FAN2) { X syslog(LOG_ALERT, "Fan #2 below limit: %d RPM (low=%d)", X lmhwst.lm7x_fan2, lmhwlim.lm7x_fan2lo); X } else if (lmhwst.lm7x_intstat & LM7X_INT_IN4) { X syslog(LOG_ALERT, "voltage probe 4 exceeded limit: %.3f (hi=%.3f, lo=%.3f)", X lmhwst.lm7x_in4 / 1000.0f, lmhwlim.lm7x_in4hi / 1000.0f, lmhwlim.lm7x_in4lo / 1000.0f); X } else if (lmhwst.lm7x_intstat & LM7X_INT_IN5) { X syslog(LOG_ALERT, "voltage probe 5 exceeded limit: %.3f (hi=%.3f, lo=%.3f)", X lmhwst.lm7x_in5 / 1000.0f, lmhwlim.lm7x_in5hi / 1000.0f, lmhwlim.lm7x_in5lo / 1000.0f); X } else if (lmhwst.lm7x_intstat & LM7X_INT_IN6) { X syslog(LOG_ALERT, "voltage probe 6 exceeded limit: %.3f (hi=%.3f, lo=%.3f)", X lmhwst.lm7x_in6 / 1000.0f, lmhwlim.lm7x_in6hi / 1000.0f, lmhwlim.lm7x_in6lo / 1000.0f); X } else if (lmhwst.lm7x_intstat & LM7X_INT_FAN3) { X syslog(LOG_ALERT, "Fan #3 below limit: %d RPM (low=%d)", X lmhwst.lm7x_fan3, lmhwlim.lm7x_fan3lo); X } else if (lmhwst.lm7x_intstat & LM7X_INT_CHASSIS) { X syslog(LOG_ALERT, "Chassis Intrusion (BTI) detected."); X } else if (lmhwst.lm7x_intstat & LM7X_INT_FIFO) { X syslog(LOG_ALERT, "FIFO overflow detected."); X } else if (lmhwst.lm7x_intstat & LM7X_INT_SMI_IN) { X syslog(LOG_ALERT, "System Management Interrupt (SMI) input detected."); X } else if (lmhwst.lm7x_intstat & LM7X_INT_RESERVED) { X syslog(LOG_ERR, "Impossible interrupt detected (reserved)."); X } X sleep(LM7X_CYCLE_TIME); X } X X exit(0); X /* NOTREACHED */ X} X Xstatic void Xlmhw_print_status(devname) X char *devname; X{ X static lm7x_status_t lmhwst; X int lmhwfd; X X if ((lmhwfd = open(devname, O_RDONLY, 0)) == -1) { X fprintf(stderr, "%s: open(%s): %s\n", argv0, devname, strerror(errno)); X exit(1); X /* NOTREACHED */ X } X if (ioctl(lmhwfd, LM7X_GETSTATUS, (void *) &lmhwst) == -1) { X fprintf(stderr, "%s: ioctl(%s, LM7X_GETSTATUS): %s\n", argv0, devname, strerror(errno)); X exit(1); X /* NOTREACHED */ X } X if ((lmhwfd = close(lmhwfd)) == -1) { X fprintf(stderr, "%s: close(%s): %s\n", argv0, devname, strerror(errno)); X exit(1); X /* NOTREACHED */ X } X printf("lm7x_in0 = %#.3f volts\n", lmhwst.lm7x_in0 / 1000.0f); X printf("lm7x_in1 = %#.3f volts\n", lmhwst.lm7x_in1 / 1000.0f); X printf("lm7x_in2 = %#.3f volts\n", lmhwst.lm7x_in2 / 1000.0f); X printf("lm7x_in3 = %#.3f volts\n", lmhwst.lm7x_in3 / 1000.0f); X printf("lm7x_in4 = %#.3f volts\n", lmhwst.lm7x_in4 / 1000.0f); X printf("lm7x_in5 = %#.3f volts\n", lmhwst.lm7x_in5 / 1000.0f); X printf("lm7x_in6 = %#.3f volts\n", lmhwst.lm7x_in6 / 1000.0f); X printf("lm7x_temp = %d degrees C\n", lmhwst.lm7x_temp); X printf("lm7x_fan1 = %d RPM\n", lmhwst.lm7x_fan1); X printf("lm7x_fan2 = %d RPM\n", lmhwst.lm7x_fan2); X printf("lm7x_fan3 = %d RPM\n", lmhwst.lm7x_fan3); X printf("lm7x_config = %0#4o \n", lmhwst.lm7x_config); X printf("lm7x_intstat = %0#7o\n", lmhwst.lm7x_intstat); X printf("lm7x_smimask = %0#7o\n", lmhwst.lm7x_smimask); X printf("lm7x_nmimask = %0#7o\n", lmhwst.lm7x_nmimask); X printf("lm7x_vid = %#04o\n", lmhwst.lm7x_vid); X printf("lm7x_saddr = %#04x\n", lmhwst.lm7x_saddr); X X return; X} X Xstatic void Xlmhw_print_limits(devname) X char *devname; X{ X static lm7x_limits_t lmhwlim; X int lmhwfd; X X if ((lmhwfd = open(devname, O_RDONLY, 0)) == -1) { X fprintf(stderr, "%s: open(%s): %s\n", argv0, devname, strerror(errno)); X exit(1); X /* NOTREACHED */ X } X if (ioctl(lmhwfd, LM7X_GETLIMITS, (void *) &lmhwlim) == -1) { X fprintf(stderr, "%s: ioctl(%s, LM7X_GETLIMITS): %s\n", argv0, devname, strerror(errno)); X exit(1); X /* NOTREACHED */ X } X if ((lmhwfd = close(lmhwfd)) == -1) { X fprintf(stderr, "%s: close(%s): %s\n", argv0, devname, strerror(errno)); X exit(1); X /* NOTREACHED */ X } X printf("lm7x_in0lo = %.3f volts\n", lmhwlim.lm7x_in0lo / 1000.0f); X printf("lm7x_in0hi = %.3f volts\n", lmhwlim.lm7x_in0hi / 1000.0f); X printf("lm7x_in1lo = %.3f volts\n", lmhwlim.lm7x_in1lo / 1000.0f); X printf("lm7x_in1hi = %.3f volts\n", lmhwlim.lm7x_in1hi / 1000.0f); X printf("lm7x_in2lo = %.3f volts\n", lmhwlim.lm7x_in2lo / 1000.0f); X printf("lm7x_in2hi = %.3f volts\n", lmhwlim.lm7x_in2hi / 1000.0f); X printf("lm7x_in3lo = %.3f volts\n", lmhwlim.lm7x_in3lo / 1000.0f); X printf("lm7x_in3hi = %.3f volts\n", lmhwlim.lm7x_in3hi / 1000.0f); X printf("lm7x_in4lo = %.3f volts\n", lmhwlim.lm7x_in4lo / 1000.0f); X printf("lm7x_in4hi = %.3f volts\n", lmhwlim.lm7x_in4hi / 1000.0f); X printf("lm7x_in5lo = %.3f volts\n", lmhwlim.lm7x_in5lo / 1000.0f); X printf("lm7x_in5hi = %.3f volts\n", lmhwlim.lm7x_in5hi / 1000.0f); X printf("lm7x_in6lo = %.3f volts\n", lmhwlim.lm7x_in6lo / 1000.0f); X printf("lm7x_in6hi = %.3f volts\n", lmhwlim.lm7x_in6hi / 1000.0f); X printf("lm7x_temphyst = %d degrees C\n", lmhwlim.lm7x_temphyst); X printf("lm7x_overtemp = %d degrees C\n", lmhwlim.lm7x_overtemp); X printf("lm7x_fan1lo = %d RPM\n", lmhwlim.lm7x_fan1lo); X printf("lm7x_fan2lo = %d RPM\n", lmhwlim.lm7x_fan2lo); X printf("lm7x_fan3lo = %d RPM\n", lmhwlim.lm7x_fan3lo); X X return; X} X Xstatic void Xlmhw_kprint(devname) X char *devname; X{ X int lmhwfd; X X if ((lmhwfd = open(devname, O_RDONLY, 0)) == -1) { X fprintf(stderr, "%s: open(%s): %s\n", argv0, devname, strerror(errno)); X exit(1); X /* NOTREACHED */ X } X if (ioctl(lmhwfd, LM7X_PRINT, (void *) NULL) == -1) { X fprintf(stderr, "%s: ioctl(%s, LM7X_PRINT): %s\n", argv0, devname, strerror(errno)); X exit(1); X /* NOTREACHED */ X } X if ((lmhwfd = close(lmhwfd)) == -1) { X fprintf(stderr, "%s: close(%s): %s\n", argv0, devname, strerror(errno)); X exit(1); X /* NOTREACHED */ X } X X return; X} X Xstatic void Xusage() X{ X fprintf(stderr, "Usage: %s %s\n", argv0, LMHW_USAGE); X exit(2); X /* NOTREACHED */ X} X Xstatic void Xhelp() X{ X printf("Usage: %s %s\n%s", argv0, LMHW_USAGE, LMHW_HELP); X exit(0); X /* NOTREACHED */ X} END-of-usr.sbin/lmhw/lmhw.c echo x - usr.sbin/lmhw/pathnames.h sed 's/^X//' >usr.sbin/lmhw/pathnames.h << 'END-of-usr.sbin/lmhw/pathnames.h' X#ident "@(#)LM7X:$Name$:$Id$" X X/* X * lmhw: low-level interface to LM78/LM79 hardware monitor driver X * X * this file is in the public domain X */ X X#define _PATH_DEVLMHW "/dev/lm7x0" END-of-usr.sbin/lmhw/pathnames.h echo x - LM7X.changed sed 's/^X//' >LM7X.changed << 'END-of-LM7X.changed' Xetc/etc.i386/MAKEDEV Xshare/man/man4/isa.4 Xsys/arch/i386/conf/GENERIC Xsys/arch/i386/i386/conf.c Xsys/conf/files Xsys/dev/ic/Makefile Xsys/dev/isa/files.isa Xsys/dev/isa/isareg.h Xsys/sys/Makefile END-of-LM7X.changed echo x - LM7X.diffs sed 's/^X//' >LM7X.diffs << 'END-of-LM7X.diffs' XIndex: etc/etc.i386/MAKEDEV X=================================================================== XRCS file: /cvs/NetBSD/src/etc/etc.i386/MAKEDEV,v Xretrieving revision 1.1.1.4 Xdiff -c -r1.1.1.4 MAKEDEV X*** etc/etc.i386/MAKEDEV 1998/11/16 19:24:28 1.1.1.4 X--- etc/etc.i386/MAKEDEV 1999/02/12 02:05:22 X*************** X*** 89,94 **** X--- 89,95 ---- X # apm power management device X # tun* network tunnel driver X # joy* joystick device X+ # lm7x* Hardware monitor X # satlink* PlanetConnect satellite receiver driver X # scsibus* SCSI busses X # ss* SCSI scanner X*************** X*** 110,120 **** X X all) X sh $0 std fd wt0 fd0 fd1 wd0 wd1 wd2 wd3 sd0 sd1 sd2 sd3 sd4 X! sh $0 tty0 tty1 pty0 pty1 raid0 raid1 raid2 raid3 X sh $0 st0 st1 ch0 cd0 cd1 mcd0 vnd0 vnd1 lpa0 lpa1 lpa2 X sh $0 lpt0 lpt1 lpt2 ttyv0 bpf0 bpf1 bpf2 bpf3 tun0 tun1 ipl X sh $0 ccd0 ccd1 ccd2 ccd3 md0 ss0 ch0 uk0 uk1 random X! sh $0 speaker lkm mms0 lms0 pms0 audio joy0 joy1 apm local satlink0 X sh $0 ttyv0 ttyv1 ttyv2 ttyv3 ttyv4 ttyv5 ttyv6 ttyv7 ttyv8 X sh $0 usbs X sh $0 music rmidi0 rmidi1 rmidi2 rmidi3 rmidi4 rmidi5 rmidi6 rmidi7 X--- 111,121 ---- X X all) X sh $0 std fd wt0 fd0 fd1 wd0 wd1 wd2 wd3 sd0 sd1 sd2 sd3 sd4 X! sh $0 tty0 tty1 pty0 pty1 pty2 pty3 raid0 raid1 raid2 raid3 X sh $0 st0 st1 ch0 cd0 cd1 mcd0 vnd0 vnd1 lpa0 lpa1 lpa2 X sh $0 lpt0 lpt1 lpt2 ttyv0 bpf0 bpf1 bpf2 bpf3 tun0 tun1 ipl X sh $0 ccd0 ccd1 ccd2 ccd3 md0 ss0 ch0 uk0 uk1 random X! sh $0 speaker lkm mms0 lms0 pms0 audio joy0 joy1 apm lm7x0 local satlink0 X sh $0 ttyv0 ttyv1 ttyv2 ttyv3 ttyv4 ttyv5 ttyv6 ttyv7 ttyv8 X sh $0 usbs X sh $0 music rmidi0 rmidi1 rmidi2 rmidi3 rmidi4 rmidi5 rmidi6 rmidi7 X*************** X*** 505,510 **** X--- 506,518 ---- X rm -f satlink$unit X mknod satlink$unit c 45 $unit X chmod 444 satlink$unit X+ ;; X+ X+ lm7x*) X+ unit=${i#lm7x}; X+ rm -f lm7x$unit X+ mknod lm7x$unit c 60 $unit X+ chmod 444 lm7x$unit X ;; X X random) XIndex: share/man/man4/isa.4 X=================================================================== XRCS file: /cvs/NetBSD/src/share/man/man4/isa.4,v Xretrieving revision 1.1.1.3 Xdiff -c -r1.1.1.3 isa.4 X*** share/man/man4/isa.4 1998/07/26 19:06:50 1.1.1.3 X--- share/man/man4/isa.4 1999/09/25 04:15:44 X*************** X*** 192,197 **** X--- 192,202 ---- X Windows Sound System-compatible sound cards based on the AD1848 and X compatible chips. X .El X+ .Ss Miscellaneous Devices X+ .Bl -tag -width misc -offset indent X+ .It lm7x X+ LM78/LM79 hardware monitor interface X+ .El X .Pp X Note that some X .Tn ISA XIndex: sys/arch/i386/conf/GENERIC X=================================================================== XRCS file: /cvs/NetBSD/src/sys/arch/i386/conf/GENERIC,v Xretrieving revision 1.1.1.10 Xdiff -c -r1.1.1.10 GENERIC X*** sys/arch/i386/conf/GENERIC 1998/11/16 21:03:09 1.1.1.10 X--- sys/arch/i386/conf/GENERIC 1999/04/06 17:27:47 X*************** X*** 61,80 **** X X # Diagnostic/debugging support options X options DIAGNOSTIC # cheap kernel consistency checks X! #options DEBUG # expensive debugging checks/support X #options KMEMSTATS # kernel memory statistics (vmstat -m) X options DDB # in-kernel debugger X #options DDB_HISTORY_SIZE=100 # enable history editing in DDB X #options KGDB # remote debugger X #options "KGDB_DEVNAME=\"com\"",KGDBADDR=0x3f8,KGDBRATE=9600 X! #makeoptions DEBUG="-g" # compile full symbol table X X # Compatibility options X options COMPAT_NOMID # compatibility with 386BSD, BSDI, NetBSD 0.8, X! options COMPAT_09 # NetBSD 0.9, X! options COMPAT_10 # NetBSD 1.0, X! options COMPAT_11 # NetBSD 1.1, X! options COMPAT_12 # NetBSD 1.2, X options COMPAT_13 # NetBSD 1.3, X options COMPAT_43 # and 4.3BSD X options COMPAT_386BSD_MBRPART # recognize old partition ID X--- 61,80 ---- X X # Diagnostic/debugging support options X options DIAGNOSTIC # cheap kernel consistency checks X! options DEBUG # expensive debugging checks/support X #options KMEMSTATS # kernel memory statistics (vmstat -m) X options DDB # in-kernel debugger X #options DDB_HISTORY_SIZE=100 # enable history editing in DDB X #options KGDB # remote debugger X #options "KGDB_DEVNAME=\"com\"",KGDBADDR=0x3f8,KGDBRATE=9600 X! #makeoptions DEBUG="-g" # compile full symbol table (and add -DDEBUG) X X # Compatibility options X options COMPAT_NOMID # compatibility with 386BSD, BSDI, NetBSD 0.8, X! #options COMPAT_09 # NetBSD 0.9, X! #options COMPAT_10 # NetBSD 1.0, X! #options COMPAT_11 # NetBSD 1.1, X! #options COMPAT_12 # NetBSD 1.2, X options COMPAT_13 # NetBSD 1.3, X options COMPAT_43 # and 4.3BSD X options COMPAT_386BSD_MBRPART # recognize old partition ID X*************** X*** 95,101 **** X file-system NFS # Network File System client X file-system CD9660 # ISO 9660 + Rock Ridge file system X file-system MSDOSFS # MS-DOS file system X! file-system FDESC # /dev/fd X file-system KERNFS # /kern X file-system NULLFS # loopback file system X file-system PORTAL # portal filesystem (still experimental) X--- 95,101 ---- X file-system NFS # Network File System client X file-system CD9660 # ISO 9660 + Rock Ridge file system X file-system MSDOSFS # MS-DOS file system X! file-system FDESC # /dev/fd (see fd(4) instead) X file-system KERNFS # /kern X file-system NULLFS # loopback file system X file-system PORTAL # portal filesystem (still experimental) X*************** X*** 115,131 **** X #options GATEWAY # packet forwarding X options INET # IP + ICMP + TCP + UDP X #options MROUTING # IP multicast routing X! options NS # XNS X #options NSIP # XNS tunneling over IP X! options ISO,TPIP # OSI X! options EON # OSI tunneling over IP X! options CCITT,LLC,HDLC # X.25 X! options NETATALK # AppleTalk networking protocols X #options PPP_BSDCOMP # BSD-Compress compression support for PPP X #options PPP_DEFLATE # Deflate compression support for PPP X #options PPP_FILTER # Active filter support for PPP (requires bpf) X! #options PFIL_HOOKS # pfil(9) packet filter hooks X! #options IPFILTER_LOG # ipmon(8) log support X X # Compatibility with 4.2BSD implementation of TCP/IP. Not recommended. X #options TCP_COMPAT_42 X--- 115,131 ---- X #options GATEWAY # packet forwarding X options INET # IP + ICMP + TCP + UDP X #options MROUTING # IP multicast routing X! #options NS # XNS X #options NSIP # XNS tunneling over IP X! #options ISO,TPIP # OSI X! #options EON # OSI tunneling over IP X! #options CCITT,LLC,HDLC # X.25 X! #options NETATALK # AppleTalk networking protocols X #options PPP_BSDCOMP # BSD-Compress compression support for PPP X #options PPP_DEFLATE # Deflate compression support for PPP X #options PPP_FILTER # Active filter support for PPP (requires bpf) X! options PFIL_HOOKS # pfil(9) packet filter hooks X! options IPFILTER_LOG # ipmon(8) log support (requires ipfilter) X X # Compatibility with 4.2BSD implementation of TCP/IP. Not recommended. X #options TCP_COMPAT_42 X*************** X*** 467,473 **** X X # ISA Plug-and-Play audio devices X ess* at isapnp? # ESS Tech ES1887, ES1888, ES888 audio X! guspnp* at isapnp? # Gravis Ultra Sound PnP audio X sb* at isapnp? # SoundBlaster-compatible audio X wss* at isapnp? # Windows Sound System X ym* at isapnp? # Yamaha OPL3-SA3 audio X--- 467,473 ---- X X # ISA Plug-and-Play audio devices X ess* at isapnp? # ESS Tech ES1887, ES1888, ES888 audio X! guspnp* at isapnp? # Gravis Ultra Sound PnP audio X sb* at isapnp? # SoundBlaster-compatible audio X wss* at isapnp? # Windows Sound System X ym* at isapnp? # Yamaha OPL3-SA3 audio X*************** X*** 536,541 **** X--- 536,544 ---- X # Planetconnect Satellite receiver driver. X #satlink0 at isa? port 0x300 drq 1 X X+ # Hardware monitor X+ lm7x0 at isa? port 0x290 # lm78/lm79 hardware monitor X+ options LM7X_DEBUG X X # Pull in optional local configuration X include "arch/i386/conf/GENERIC.local" X*************** X*** 550,556 **** X X # network pseudo-devices X pseudo-device bpfilter 8 # Berkeley packet filter X! pseudo-device ipfilter # IP filter (firewall) and NAT X pseudo-device loop # network loopback X pseudo-device ppp 2 # Point-to-Point Protocol X pseudo-device sl 2 # Serial Line IP X--- 553,559 ---- X X # network pseudo-devices X pseudo-device bpfilter 8 # Berkeley packet filter X! pseudo-device ipfilter # IP filter and NAT [see IPFILTER_LOG] X pseudo-device loop # network loopback X pseudo-device ppp 2 # Point-to-Point Protocol X pseudo-device sl 2 # Serial Line IP XIndex: sys/arch/i386/i386/conf.c X=================================================================== XRCS file: /cvs/NetBSD/src/sys/arch/i386/i386/conf.c,v Xretrieving revision 1.1.1.5 Xdiff -c -r1.1.1.5 conf.c X*** sys/arch/i386/i386/conf.c 1998/11/16 21:03:25 1.1.1.5 X--- sys/arch/i386/i386/conf.c 1998/12/06 20:29:48 X*************** X*** 137,149 **** X (dev_type_stop((*))) enodev, 0, dev_init(c,n,poll), \ X (dev_type_mmap((*))) enodev } X X! /* open, close, ioctl */ X #define cdev_usb_init(c,n) { \ X dev_init(c,n,open), dev_init(c,n,close), (dev_type_read((*))) enodev, \ X (dev_type_write((*))) enodev, dev_init(c,n,ioctl), \ X (dev_type_stop((*))) enodev, 0, dev_init(c,n,poll), \ X (dev_type_mmap((*))) enodev } X X cdev_decl(cn); X cdev_decl(ctty); X #define mmread mmrw X--- 137,156 ---- X (dev_type_stop((*))) enodev, 0, dev_init(c,n,poll), \ X (dev_type_mmap((*))) enodev } X X! /* open, close, ioctl, poll */ X #define cdev_usb_init(c,n) { \ X dev_init(c,n,open), dev_init(c,n,close), (dev_type_read((*))) enodev, \ X (dev_type_write((*))) enodev, dev_init(c,n,ioctl), \ X (dev_type_stop((*))) enodev, 0, dev_init(c,n,poll), \ X (dev_type_mmap((*))) enodev } X X+ /* open, close, ioctl */ X+ #define cdev_lm7x_init(c,n) { \ X+ dev_init(c,n,open), dev_init(c,n,close), (dev_type_read((*))) enodev, \ X+ (dev_type_write((*))) enodev, dev_init(c,n,ioctl), \ X+ (dev_type_stop((*))) enodev, 0, (dev_type_poll((*))) enodev, \ X+ (dev_type_mmap((*))) enodev } X+ X cdev_decl(cn); X cdev_decl(ctty); X #define mmread mmrw X*************** X*** 284,289 **** X--- 291,299 ---- X cdev_decl(i4btel); X #endif X X+ #include "lm7x_isa.h" X+ cdev_decl(lm7x_); X+ X struct cdevsw cdevsw[] = X { X cdev_cn_init(1,cn), /* 0: virtual console */ X*************** X*** 365,370 **** X--- 375,381 ---- X cdev_vc_nb_init(NVCODA,vc_nb_), /* 60: coda file system psdev */ X cdev_scsibus_init(NSCSIBUS,scsibus), /* 61: SCSI bus */ X cdev_disk_init(NRAID,raid), /* 62: RAIDframe disk driver */ X+ cdev_lm7x_init(NLM7X_ISA,lm7x_), /* 63: lm78/lm79 hw monitor */ X }; X int nchrdev = sizeof(cdevsw) / sizeof(cdevsw[0]); X XIndex: sys/conf/files X=================================================================== XRCS file: /cvs/NetBSD/src/sys/conf/files,v Xretrieving revision 1.1.1.9 Xdiff -c -r1.1.1.9 files X*** sys/conf/files 1998/11/16 21:23:08 1.1.1.9 X--- sys/conf/files 1998/12/06 20:09:30 X*************** X*** 311,316 **** X--- 311,320 ---- X define rtl80x9 X file dev/ic/rtl80x9.c rtl80x9 X X+ # National Semiconductor LM78/LM79 driver back-end X+ define lm7x X+ file dev/ic/lm7x.c lm7x needs-flag X+ X # XXX THE FOLLOWING BLOCK SHOULD BE UNCOMMENTED, BUT CANNOT X # XXX BECAUSE NOT ALL PORTS USE THE MI wdc DRIVER YET. X # XIndex: sys/dev/ic/Makefile X=================================================================== XRCS file: /cvs/NetBSD/src/sys/dev/ic/Makefile,v Xretrieving revision 1.1.1.2 Xdiff -c -r1.1.1.2 Makefile X*** sys/dev/ic/Makefile 1998/11/16 21:25:17 1.1.1.2 X--- sys/dev/ic/Makefile 1998/11/27 00:59:00 X*************** X*** 11,17 **** X i8237reg.h i8253reg.h i82586reg.h i82586var.h i82595reg.h \ X ics2101reg.h ims332reg.h intersil7170.h interwavereg.h \ X interwavevar.h ispmbox.h ispreg.h ispvar.h lemacreg.h lemacvar.h \ X! lptreg.h lptvar.h mb86960reg.h mb86960var.h mc146818reg.h \ X mc6845reg.h midwayreg.h midwayvar.h ncr5380reg.h ncr5380var.h \ X ncr53c9xreg.h ncr53c9xvar.h ne2000reg.h ne2000var.h nec765reg.h \ X ns16450reg.h ns16550reg.h opl3sa3.h pcdisplay.h pcdisplayvar.h \ X--- 11,17 ---- X i8237reg.h i8253reg.h i82586reg.h i82586var.h i82595reg.h \ X ics2101reg.h ims332reg.h intersil7170.h interwavereg.h \ X interwavevar.h ispmbox.h ispreg.h ispvar.h lemacreg.h lemacvar.h \ X! lm7xio.h lptreg.h lptvar.h mb86960reg.h mb86960var.h mc146818reg.h \ X mc6845reg.h midwayreg.h midwayvar.h ncr5380reg.h ncr5380var.h \ X ncr53c9xreg.h ncr53c9xvar.h ne2000reg.h ne2000var.h nec765reg.h \ X ns16450reg.h ns16550reg.h opl3sa3.h pcdisplay.h pcdisplayvar.h \ XIndex: sys/dev/isa/files.isa X=================================================================== XRCS file: /cvs/NetBSD/src/sys/dev/isa/files.isa,v Xretrieving revision 1.1.1.7 Xdiff -c -r1.1.1.7 files.isa X*** sys/dev/isa/files.isa 1998/11/16 21:25:37 1.1.1.7 X--- sys/dev/isa/files.isa 1998/12/11 05:50:43 X*************** X*** 356,363 **** X--- 356,369 ---- X device spkr X attach spkr at pcppi X file dev/isa/spkr.c spkr needs-flag X+ X attach midi at pcppi with midi_pcppi: midisyn X file dev/isa/midi_pcppi.c midi_pcppi X+ X+ # LM78/79 hardware monitor X+ device lm7x X+ attach lm7x at isa with lm7x_isa X+ file dev/isa/lm7x_isa.c lm7x_isa needs-flag X X # X # ISA Plug 'n Play autoconfiguration glue. XIndex: sys/dev/isa/isareg.h X=================================================================== XRCS file: /cvs/NetBSD/src/sys/dev/isa/isareg.h,v Xretrieving revision 1.1.1.2 Xdiff -c -r1.1.1.2 isareg.h X*** sys/dev/isa/isareg.h 1998/03/24 01:26:12 1.1.1.2 X--- sys/dev/isa/isareg.h 1998/12/06 21:53:46 X*************** X*** 84,90 **** X X #define IO_LPT2 0x278 /* Parallel Port #2 */ X X! /* 0x280 - 0x2E7 Open */ X X #define IO_COM4 0x2e8 /* COM4 i/o address */ X X--- 84,94 ---- X X #define IO_LPT2 0x278 /* Parallel Port #2 */ X X! /* 0x280 - 0x28F Open */ X! X! #define IO_LM7X 0x290 /* Nat. Semi. LM78 or LM79 */ X! X! /* 0x298 - 0x2E7 Open */ X X #define IO_COM4 0x2e8 /* COM4 i/o address */ X XIndex: sys/sys/Makefile X=================================================================== XRCS file: /cvs/NetBSD/src/sys/sys/Makefile,v Xretrieving revision 1.1.1.2 Xdiff -c -r1.1.1.2 Makefile X*** sys/sys/Makefile 1998/11/16 21:35:58 1.1.1.2 X--- sys/sys/Makefile 1999/02/12 02:07:55 X*************** X*** 8,14 **** X dkstat.h dmap.h domain.h errno.h exec.h exec_aout.h exec_ecoff.h \ X exec_elf.h exec_script.h extent.h fcntl.h fdio.h featuretest.h file.h \ X filedesc.h filio.h gmon.h inttypes.h ioccom.h ioctl.h ioctl_compat.h \ X! ipc.h kcore.h kernel.h kgdb.h ktrace.h lkm.h localedef.h lock.h \ X lockf.h malloc.h map.h mbuf.h md5.h midiio.h mman.h mount.h msg.h \ X msgbuf.h mtio.h namei.h param.h poll.h pool.h proc.h protosw.h \ X ptrace.h queue.h reboot.h resource.h resourcevar.h rnd.h scanio.h \ X--- 8,14 ---- X dkstat.h dmap.h domain.h errno.h exec.h exec_aout.h exec_ecoff.h \ X exec_elf.h exec_script.h extent.h fcntl.h fdio.h featuretest.h file.h \ X filedesc.h filio.h gmon.h inttypes.h ioccom.h ioctl.h ioctl_compat.h \ X! ipc.h kcore.h kernel.h kgdb.h ktrace.h lkm.h lm7x.h localedef.h lock.h \ X lockf.h malloc.h map.h mbuf.h md5.h midiio.h mman.h mount.h msg.h \ X msgbuf.h mtio.h namei.h param.h poll.h pool.h proc.h protosw.h \ X ptrace.h queue.h reboot.h resource.h resourcevar.h rnd.h scanio.h \ END-of-LM7X.diffs echo x - LM7X.files sed 's/^X//' >LM7X.files << 'END-of-LM7X.files' Xshare/man/man4/lm7x.4 Xsys/dev/ic/lm7x.c Xsys/dev/ic/lm7xreg.h Xsys/dev/ic/lm7xvar.h Xsys/dev/isa/lm7x_isa.c Xsys/sys/lm7xio.h Xusr.sbin/lmhw/ Xusr.sbin/lmhw/Makefile Xusr.sbin/lmhw/lmhw.8 Xusr.sbin/lmhw/lmhw.c Xusr.sbin/lmhw/pathnames.h XLM7X.changed XLM7X.diffs XLM7X.files END-of-LM7X.files exit .