Import it(4) and lm(4), supporting most popular Super I/O Hardware Monitors.

Submitted by:	Constantine A. Murenin <cnst@FreeBSD.org>
Sponsored by:	Google Summer of Code 2007 (GSoC2007/cnst-sensors)
Mentored by:	syrinx
Tested by:	many
OKed by:	kensmith
Obtained from:	OpenBSD (parts)
This commit is contained in:
Alexander Leidinger 2007-10-14 10:55:50 +00:00
parent 99f6b270e3
commit 989500bf1a
16 changed files with 2048 additions and 0 deletions

View File

@ -131,6 +131,7 @@ MAN= aac.4 \
iscsi_initiator.4 \
isp.4 \
ispfw.4 \
${_it.4} \
iwi.4 \
ixgb.4 \
joy.4 \
@ -143,6 +144,7 @@ MAN= aac.4 \
le.4 \
led.4 \
lge.4 \
lm.4 \
lmc.4 \
lo.4 \
lp.4 \
@ -547,6 +549,7 @@ _ichwd.4= ichwd.4
_if_nfe.4= if_nfe.4
_if_nve.4= if_nve.4
_if_nxge.4= if_nxge.4
_it.4= it.4
_ipmi.4= ipmi.4
_nfsmb.4= nfsmb.4
_nfe.4= nfe.4

104
share/man/man4/it.4 Normal file
View File

@ -0,0 +1,104 @@
.\" $FreeBSD$
.\" $OpenBSD: it.4,v 1.8 2006/09/08 15:09:14 jmc Exp $
.\"
.\" Copyright (c) 2003 Julien Bordet <zejames@greygats.org>
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
.Dd 13 September 2007
.Dt IT 4
.Os
.Sh NAME
.Nm it
.Nd ITE IT8705F/12F/16F and SiS SiS950 Super I/O Hardware Monitor
.Sh SYNOPSIS
.Cd "device isa"
.Cd "device it"
.Pp
In
.Pa /boot/device.hints :
.Cd hint.it.0.at="isa"
.Cd hint.it.0.port="0x290"
.Cd hint.it.1.at="isa"
.Cd hint.it.1.port="0xc00"
.Cd hint.it.2.at="isa"
.Cd hint.it.2.port="0xd00"
.Sh DESCRIPTION
The
.Nm
driver provides support for the
.Tn IT8705F , IT8712F , IT8716F
and
.Tn SiS950
hardware monitors.
The values are exposed through the
.Va HW_SENSORS
.Xr sysctl 3
interface.
.Pp
Most supported devices possess 15 sensors:
.Bl -column "Sensor" "Units" "Typical" -offset indent
.It Sy "Sensor" Ta Sy "Units" Ta Sy "Typical Use"
.It Li "Fan0" Ta "RPM" Ta "CPU Fan"
.It Li "Fan1" Ta "RPM" Ta "Fan"
.It Li "Fan2" Ta "RPM" Ta "Fan"
.It Li "IN0" Ta "uV DC" Ta "Core voltage"
.It Li "IN1" Ta "uV DC" Ta "Core voltage"
.It Li "IN2" Ta "uV DC" Ta "+3.3V"
.It Li "IN3" Ta "uV DC" Ta "+5V"
.It Li "IN4" Ta "uV DC" Ta "+12V"
.It Li "IN5" Ta "uV DC" Ta "Unknown"
.It Li "IN6" Ta "uV DC" Ta "-12V"
.It Li "IN7" Ta "uV DC" Ta "-5V"
.It Li "IN8" Ta "uV DC" Ta "VBAT"
.It Li "Temp" Ta "uK" Ta "Motherboard Temperature"
.It Li "Temp" Ta "uK" Ta "Motherboard Temperature"
.It Li "Temp" Ta "uK" Ta "CPU Temperature"
.El
.Pp
For some devices, sensors' names and numbers will be different.
.Sh SEE ALSO
.Xr systat 1 ,
.Xr sysctl 3 ,
.Xr sensorsd 8 ,
.Xr sysctl 8
.Sh HISTORY
The
.Nm
driver first appeared in
.Ox 3.4 .
.Fx
support was added in
.Fx 7.XXX .
.Sh AUTHORS
.An -nosplit
The
.Nm
driver was written by
.An Julien Bordet Aq zejames@greyhats.org .
It was ported to
.Fx
by
.An Constantine A. Murenin Aq cnst@FreeBSD.org
as a part of a Google Summer of Code 2007 project.
.Sh BUGS
Interrupt support is unimplemented.

138
share/man/man4/lm.4 Normal file
View File

@ -0,0 +1,138 @@
.\" $FreeBSD$
.\" $OpenBSD: lm.4,v 1.16 2007/05/26 22:38:55 cnst Exp $
.\" $NetBSD: lm.4,v 1.11 2001/09/22 01:22:49 wiz Exp $
.\"
.\" Copyright (c) 2000 The NetBSD Foundation, Inc.
.\" All rights reserved.
.\"
.\" This code is derived from software contributed to The NetBSD Foundation
.\" by Bill Squier.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\" 3. All advertising materials mentioning features or use of this software
.\" must display the following acknowledgement:
.\" This product includes software developed by the NetBSD
.\" Foundation, Inc. and its contributors.
.\" 4. Neither the name of The NetBSD Foundation nor the names of its
.\" contributors may be used to endorse or promote products derived
.\" from this software without specific prior written permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
.Dd 19 August 2007
.Dt LM 4
.Os
.Sh NAME
.Nm lm
.Nd NatSemi LM78/79/81 and Winbond Super I/O Hardware Monitor
.Sh SYNOPSIS
.Cd "device isa"
.Cd "device lm"
.Pp
In
.Pa /boot/device.hints :
.Cd hint.lm.0.at="isa"
.Cd hint.lm.0.port="0x290"
.Cd hint.lm.1.at="isa"
.Cd hint.lm.1.port="0x280"
.Cd hint.lm.2.at="isa"
.Cd hint.lm.2.port="0x310"
.Sh DESCRIPTION
The
.Nm
driver provides support for the
.Tn National Semiconductor
LM 78/79/81 and
.Tn Winbond
Super I/O
hardware monitors,
and registers compatible chips under the
.Va HW_SENSORS
.Xr sysctl 3
tree.
.Sh HARDWARE
Chips supported by the
.Nm
driver include:
.Pp
.Bl -dash -offset indent -compact
.It
National Semiconductor LM78 and LM78-J
.It
National Semiconductor LM79
.It
National Semiconductor LM81
.It
Winbond W83627HF, W83627THF, W83637HF and W83697HF
.It
Winbond W83627DHG and W83627EHF
.It
Winbond W83781D, W83782D and W83783S
.It
Winbond W83791D, W83791SD and W83792D
.It
ASUS AS99127F
.El
.Sh SEE ALSO
.Xr systat 1 ,
.Xr sysctl 3 ,
.Xr sensorsd 8 ,
.Xr sysctl 8
.Sh HISTORY
The
.Nm
driver first appeared in
.Nx 1.5 ;
.Ox
support was added in
.Ox 3.4 ;
.Fx
support was added in
.Fx 7.XXX .
.Sh AUTHORS
.An -nosplit
The
.Nm
driver was written by
.An Bill Squier
and ported to
.Ox 3.4
by
.An Alexander Yurchenko Aq grange@openbsd.org .
The driver was largely rewritten for
.Ox 3.9
by
.An Mark Kettenis Aq kettenis@openbsd.org .
The driver was then ported to
.Fx
by
.An Constantine A. Murenin Aq cnst@FreeBSD.org
as a part of a Google Summer of Code 2007 project.
.Sh CAVEATS
Some vendors connect these chips to non-standard thermal diodes and
resistors.
This will result in bogus sensor values.
.Sh BUGS
Interrupt support is unimplemented.
.Pp
There are currently no known pnpbios IDs assigned to LM chips.
.Pp
This driver attaches to the Winbond W83791SD chip even though that
chip does not have any sensors.

View File

@ -33,3 +33,11 @@ hint.sio.3.port="0x2E8"
hint.sio.3.irq="9"
hint.ppc.0.at="isa"
hint.ppc.0.irq="7"
hint.lm.0.at="isa"
hint.lm.0.port="0x290"
hint.it.0.at="isa"
hint.it.0.port="0x290"
hint.it.1.at="isa"
hint.it.1.port="0xc00"
hint.it.2.at="isa"
hint.it.2.port="0xd00"

View File

@ -758,6 +758,8 @@ dev/le/if_le_pci.c optional le pci
dev/le/lance.c optional le
dev/led/led.c standard
dev/lge/if_lge.c optional lge
dev/lm/lm78.c optional lm
dev/lm/lm78_isa.c optional lm isa
dev/lmc/if_lmc.c optional lmc
dev/mc146818/mc146818.c optional mc146818
dev/mca/mca_bus.c optional mca

View File

@ -169,6 +169,7 @@ dev/ipmi/ipmi_smbus.c optional ipmi smbus
dev/ipmi/ipmi_smbios.c optional ipmi
dev/ipmi/ipmi_ssif.c optional ipmi smbus
dev/ipmi/ipmi_pci.c optional ipmi pci
dev/it/it.c optional it isa
dev/fdc/fdc.c optional fdc
dev/fdc/fdc_acpi.c optional fdc
dev/fdc/fdc_isa.c optional fdc isa

View File

@ -204,6 +204,7 @@ dev/ipmi/ipmi_smbus.c optional ipmi smbus
dev/ipmi/ipmi_smbios.c optional ipmi
dev/ipmi/ipmi_ssif.c optional ipmi smbus
dev/ipmi/ipmi_pci.c optional ipmi pci
dev/it/it.c optional it isa
dev/kbd/kbd.c optional atkbd | sc | ukbd | vt
dev/le/if_le_isa.c optional le isa
dev/mem/memutil.c optional mem

346
sys/dev/it/it.c Normal file
View File

@ -0,0 +1,346 @@
/* $FreeBSD$ */
/* $OpenBSD: it.c,v 1.22 2007/03/22 16:55:31 deraadt Exp $ */
/*-
* Copyright (c) 2003 Julien Bordet <zejames@greyhats.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/bus.h>
#include <sys/module.h>
#include <machine/bus.h>
#include <machine/resource.h>
#include <sys/rman.h>
#include <isa/isavar.h>
#include <sys/systm.h>
#include <sys/sensors.h>
#include <dev/it/itvar.h>
#if defined(ITDEBUG)
#define DPRINTF(x) do { printf x; } while (0)
#else
#define DPRINTF(x)
#endif
/*
* IT87-compatible chips can typically measure voltages up to 4.096 V.
* To measure higher voltages the input is attenuated with (external)
* resistors. Negative voltages are measured using a reference
* voltage. So we have to convert the sensor values back to real
* voltages by applying the appropriate resistor factor.
*/
#define RFACT_NONE 10000
#define RFACT(x, y) (RFACT_NONE * ((x) + (y)) / (y))
int it_probe(struct device *);
int it_attach(struct device *);
int it_detach(struct device *);
u_int8_t it_readreg(struct it_softc *, int);
void it_writereg(struct it_softc *, int, int);
void it_setup_volt(struct it_softc *, int, int);
void it_setup_temp(struct it_softc *, int, int);
void it_setup_fan(struct it_softc *, int, int);
void it_generic_stemp(struct it_softc *, struct ksensor *);
void it_generic_svolt(struct it_softc *, struct ksensor *);
void it_generic_fanrpm(struct it_softc *, struct ksensor *);
void it_refresh_sensor_data(struct it_softc *);
void it_refresh(void *);
extern struct cfdriver it_cd;
static device_method_t it_methods[] = {
/* Methods from the device interface */
DEVMETHOD(device_probe, it_probe),
DEVMETHOD(device_attach, it_attach),
DEVMETHOD(device_detach, it_detach),
/* Terminate method list */
{ 0, 0 }
};
static driver_t it_driver = {
"it",
it_methods,
sizeof (struct it_softc)
};
static devclass_t it_devclass;
DRIVER_MODULE(it, isa, it_driver, it_devclass, NULL, NULL);
const int it_vrfact[] = {
RFACT_NONE,
RFACT_NONE,
RFACT_NONE,
RFACT(68, 100),
RFACT(30, 10),
RFACT(21, 10),
RFACT(83, 20),
RFACT(68, 100),
RFACT_NONE
};
int
it_probe(struct device *dev)
{
struct resource *iores;
int iorid = 0;
bus_space_tag_t iot;
bus_space_handle_t ioh;
u_int8_t cr;
iores = bus_alloc_resource(dev, SYS_RES_IOPORT, &iorid,
0ul, ~0ul, 8, RF_ACTIVE);
if (iores == NULL) {
DPRINTF(("%s: can't map i/o space\n", __func__));
return 1;
}
iot = rman_get_bustag(iores);
ioh = rman_get_bushandle(iores);
/* Check Vendor ID */
bus_space_write_1(iot, ioh, ITC_ADDR, ITD_CHIPID);
cr = bus_space_read_1(iot, ioh, ITC_DATA);
bus_release_resource(dev, SYS_RES_IOPORT, iorid, iores);
DPRINTF(("it: vendor id 0x%x\n", cr));
if (cr != IT_ID_IT87)
return 1;
return 0;
}
int
it_attach(struct device *dev)
{
struct it_softc *sc = device_get_softc(dev);
int i;
u_int8_t cr;
sc->sc_dev = dev;
sc->sc_iores = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->sc_iorid,
0ul, ~0ul, 8, RF_ACTIVE);
if (sc->sc_iores == NULL) {
device_printf(dev, "can't map i/o space\n");
return 1;
}
sc->sc_iot = rman_get_bustag(sc->sc_iores);
sc->sc_ioh = rman_get_bushandle(sc->sc_iores);
sc->numsensors = IT_NUM_SENSORS;
it_setup_fan(sc, 0, 3);
it_setup_volt(sc, 3, 9);
it_setup_temp(sc, 12, 3);
if (sensor_task_register(sc, it_refresh, 5)) {
device_printf(sc->sc_dev, "unable to register update task\n");
return 1;
}
/* Activate monitoring */
cr = it_readreg(sc, ITD_CONFIG);
cr |= 0x01 | 0x08;
it_writereg(sc, ITD_CONFIG, cr);
/* Initialize sensors */
strlcpy(sc->sensordev.xname, device_get_nameunit(sc->sc_dev),
sizeof(sc->sensordev.xname));
for (i = 0; i < sc->numsensors; ++i)
sensor_attach(&sc->sensordev, &sc->sensors[i]);
sensordev_install(&sc->sensordev);
return 0;
}
int
it_detach(struct device *dev)
{
struct it_softc *sc = device_get_softc(dev);
int error;
sensordev_deinstall(&sc->sensordev);
sensor_task_unregister(sc);
error = bus_release_resource(dev, SYS_RES_IOPORT, sc->sc_iorid,
sc->sc_iores);
if (error)
return error;
return 0;
}
u_int8_t
it_readreg(struct it_softc *sc, int reg)
{
bus_space_write_1(sc->sc_iot, sc->sc_ioh, ITC_ADDR, reg);
return (bus_space_read_1(sc->sc_iot, sc->sc_ioh, ITC_DATA));
}
void
it_writereg(struct it_softc *sc, int reg, int val)
{
bus_space_write_1(sc->sc_iot, sc->sc_ioh, ITC_ADDR, reg);
bus_space_write_1(sc->sc_iot, sc->sc_ioh, ITC_DATA, val);
}
void
it_setup_volt(struct it_softc *sc, int start, int n)
{
int i;
for (i = 0; i < n; ++i) {
sc->sensors[start + i].type = SENSOR_VOLTS_DC;
}
snprintf(sc->sensors[start + 0].desc, sizeof(sc->sensors[0].desc),
"VCORE_A");
snprintf(sc->sensors[start + 1].desc, sizeof(sc->sensors[1].desc),
"VCORE_B");
snprintf(sc->sensors[start + 2].desc, sizeof(sc->sensors[2].desc),
"+3.3V");
snprintf(sc->sensors[start + 3].desc, sizeof(sc->sensors[3].desc),
"+5V");
snprintf(sc->sensors[start + 4].desc, sizeof(sc->sensors[4].desc),
"+12V");
snprintf(sc->sensors[start + 5].desc, sizeof(sc->sensors[5].desc),
"Unused");
snprintf(sc->sensors[start + 6].desc, sizeof(sc->sensors[6].desc),
"-12V");
snprintf(sc->sensors[start + 7].desc, sizeof(sc->sensors[7].desc),
"+5VSB");
snprintf(sc->sensors[start + 8].desc, sizeof(sc->sensors[8].desc),
"VBAT");
}
void
it_setup_temp(struct it_softc *sc, int start, int n)
{
int i;
for (i = 0; i < n; ++i)
sc->sensors[start + i].type = SENSOR_TEMP;
}
void
it_setup_fan(struct it_softc *sc, int start, int n)
{
int i;
for (i = 0; i < n; ++i)
sc->sensors[start + i].type = SENSOR_FANRPM;
}
void
it_generic_stemp(struct it_softc *sc, struct ksensor *sensors)
{
int i, sdata;
for (i = 0; i < 3; i++) {
sdata = it_readreg(sc, ITD_SENSORTEMPBASE + i);
/* Convert temperature to Fahrenheit degres */
sensors[i].value = sdata * 1000000 + 273150000;
}
}
void
it_generic_svolt(struct it_softc *sc, struct ksensor *sensors)
{
int i, sdata;
for (i = 0; i < 9; i++) {
sdata = it_readreg(sc, ITD_SENSORVOLTBASE + i);
DPRINTF(("sdata[volt%d] 0x%x\n", i, sdata));
/* voltage returned as (mV >> 4) */
sensors[i].value = (sdata << 4);
/* these two values are negative and formula is different */
if (i == 5 || i == 6)
sensors[i].value = ((sdata << 4) - IT_VREF);
/* rfact is (factor * 10^4) */
sensors[i].value *= it_vrfact[i];
/* division by 10 gets us back to uVDC */
sensors[i].value /= 10;
if (i == 5 || i == 6)
sensors[i].value += IT_VREF * 1000;
}
}
void
it_generic_fanrpm(struct it_softc *sc, struct ksensor *sensors)
{
int i, sdata, divisor, odivisor, ndivisor;
odivisor = ndivisor = divisor = it_readreg(sc, ITD_FAN);
for (i = 0; i < 3; i++, divisor >>= 3) {
sensors[i].flags &= ~SENSOR_FINVALID;
if ((sdata = it_readreg(sc, ITD_SENSORFANBASE + i)) == 0xff) {
sensors[i].flags |= SENSOR_FINVALID;
if (i == 2)
ndivisor ^= 0x40;
else {
ndivisor &= ~(7 << (i * 3));
ndivisor |= ((divisor + 1) & 7) << (i * 3);
}
} else if (sdata == 0) {
sensors[i].value = 0;
} else {
if (i == 2)
divisor = divisor & 1 ? 3 : 1;
sensors[i].value = 1350000 / (sdata << (divisor & 7));
}
}
if (ndivisor != odivisor)
it_writereg(sc, ITD_FAN, ndivisor);
}
/*
* pre: last read occurred >= 1.5 seconds ago
* post: sensors[] current data are the latest from the chip
*/
void
it_refresh_sensor_data(struct it_softc *sc)
{
/* Refresh our stored data for every sensor */
it_generic_stemp(sc, &sc->sensors[12]);
it_generic_svolt(sc, &sc->sensors[3]);
it_generic_fanrpm(sc, &sc->sensors[0]);
}
void
it_refresh(void *arg)
{
struct it_softc *sc = (struct it_softc *)arg;
it_refresh_sensor_data(sc);
}

95
sys/dev/it/itvar.h Normal file
View File

@ -0,0 +1,95 @@
/* $FreeBSD$ */
/* $OpenBSD: itvar.h,v 1.4 2007/03/22 16:55:31 deraadt Exp $ */
/*-
* Copyright (c) 2003 Julien Bordet <zejames@greyhats.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _DEV_ISA_ITVAR_H
#define _DEV_ISA_ITVAR_H
#define IT_NUM_SENSORS 15
/* chip ids */
#define IT_ID_IT87 0x90
/* ctl registers */
#define ITC_ADDR 0x05
#define ITC_DATA 0x06
/* data registers */
#define ITD_CONFIG 0x00
#define ITD_ISR1 0x01
#define ITD_ISR2 0x02
#define ITD_ISR3 0x03
#define ITD_SMI1 0x04
#define ITD_SMI2 0x05
#define ITD_SMI3 0x06
#define ITD_IMR1 0x07
#define ITD_IMR2 0x08
#define ITD_IMR3 0x09
#define ITD_VID 0x0a
#define ITD_FAN 0x0b
#define ITD_FANMINBASE 0x10
#define ITD_FANENABLE 0x13
#define ITD_SENSORFANBASE 0x0d /* Fan from 0x0d to 0x0f */
#define ITD_SENSORVOLTBASE 0x20 /* Fan from 0x20 to 0x28 */
#define ITD_SENSORTEMPBASE 0x29 /* Fan from 0x29 to 0x2b */
#define ITD_VOLTMAXBASE 0x30
#define ITD_VOLTMINBASE 0x31
#define ITD_TEMPMAXBASE 0x40
#define ITD_TEMPMINBASE 0x41
#define ITD_SBUSADDR 0x48
#define ITD_VOLTENABLE 0x50
#define ITD_TEMPENABLE 0x51
#define ITD_CHIPID 0x58
#define IT_VREF (4096) /* Vref = 4.096 V */
struct it_softc {
struct device *sc_dev;
struct resource *sc_iores;
int sc_iorid;
bus_space_tag_t sc_iot;
bus_space_handle_t sc_ioh;
struct ksensor sensors[IT_NUM_SENSORS];
struct ksensordev sensordev;
u_int numsensors;
void (*refresh_sensor_data)(struct it_softc *);
u_int8_t (*it_readreg)(struct it_softc *, int);
void (*it_writereg)(struct it_softc *, int, int);
};
#endif

909
sys/dev/lm/lm78.c Normal file
View File

@ -0,0 +1,909 @@
/* $FreeBSD$ */
/* $OpenBSD: lm78.c,v 1.18 2007/05/26 22:47:39 cnst Exp $ */
/*-
* Copyright (c) 2005, 2006 Mark Kettenis
* Copyright (c) 2006, 2007 Constantine A. Murenin
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
#include <sys/sensors.h>
#include <machine/bus.h>
#include <dev/lm/lm78var.h>
#if defined(LMDEBUG)
#define DPRINTF(x) do { printf x; } while (0)
#else
#define DPRINTF(x)
#endif
/*
* LM78-compatible chips can typically measure voltages up to 4.096 V.
* To measure higher voltages the input is attenuated with (external)
* resistors. Negative voltages are measured using inverting op amps
* and resistors. So we have to convert the sensor values back to
* real voltages by applying the appropriate resistor factor.
*/
#define RFACT_NONE 10000
#define RFACT(x, y) (RFACT_NONE * ((x) + (y)) / (y))
#define NRFACT(x, y) (-RFACT_NONE * (x) / (y))
int lm_match(struct lm_softc *);
int wb_match(struct lm_softc *);
int def_match(struct lm_softc *);
void lm_setup_sensors(struct lm_softc *, struct lm_sensor *);
void lm_refresh(void *);
void lm_refresh_sensor_data(struct lm_softc *);
void lm_refresh_volt(struct lm_softc *, int);
void lm_refresh_temp(struct lm_softc *, int);
void lm_refresh_fanrpm(struct lm_softc *, int);
void wb_refresh_sensor_data(struct lm_softc *);
void wb_w83637hf_refresh_vcore(struct lm_softc *, int);
void wb_refresh_nvolt(struct lm_softc *, int);
void wb_w83627ehf_refresh_nvolt(struct lm_softc *, int);
void wb_refresh_temp(struct lm_softc *, int);
void wb_refresh_fanrpm(struct lm_softc *, int);
void wb_w83792d_refresh_fanrpm(struct lm_softc *, int);
void as_refresh_temp(struct lm_softc *, int);
struct lm_chip {
int (*chip_match)(struct lm_softc *);
};
struct lm_chip lm_chips[] = {
{ wb_match },
{ lm_match },
{ def_match } /* Must be last */
};
struct lm_sensor lm78_sensors[] = {
/* Voltage */
{ "VCore A", SENSOR_VOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE },
{ "VCore B", SENSOR_VOLTS_DC, 0, 0x21, lm_refresh_volt, RFACT_NONE },
{ "+3.3V", SENSOR_VOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT_NONE },
{ "+5V", SENSOR_VOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(68, 100) },
{ "+12V", SENSOR_VOLTS_DC, 0, 0x24, lm_refresh_volt, RFACT(30, 10) },
{ "-12V", SENSOR_VOLTS_DC, 0, 0x25, lm_refresh_volt, NRFACT(240, 60) },
{ "-5V", SENSOR_VOLTS_DC, 0, 0x26, lm_refresh_volt, NRFACT(100, 60) },
/* Temperature */
{ "", SENSOR_TEMP, 0, 0x27, lm_refresh_temp },
/* Fans */
{ "", SENSOR_FANRPM, 0, 0x28, lm_refresh_fanrpm },
{ "", SENSOR_FANRPM, 0, 0x29, lm_refresh_fanrpm },
{ "", SENSOR_FANRPM, 0, 0x2a, lm_refresh_fanrpm },
{ NULL }
};
struct lm_sensor w83627hf_sensors[] = {
/* Voltage */
{ "VCore A", SENSOR_VOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE },
{ "VCore B", SENSOR_VOLTS_DC, 0, 0x21, lm_refresh_volt, RFACT_NONE },
{ "+3.3V", SENSOR_VOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT_NONE },
{ "+5V", SENSOR_VOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 50) },
{ "+12V", SENSOR_VOLTS_DC, 0, 0x24, lm_refresh_volt, RFACT(28, 10) },
{ "-12V", SENSOR_VOLTS_DC, 0, 0x25, wb_refresh_nvolt, RFACT(232, 56) },
{ "-5V", SENSOR_VOLTS_DC, 0, 0x26, wb_refresh_nvolt, RFACT(120, 56) },
{ "5VSB", SENSOR_VOLTS_DC, 5, 0x50, lm_refresh_volt, RFACT(17, 33) },
{ "VBAT", SENSOR_VOLTS_DC, 5, 0x51, lm_refresh_volt, RFACT_NONE },
/* Temperature */
{ "", SENSOR_TEMP, 0, 0x27, lm_refresh_temp },
{ "", SENSOR_TEMP, 1, 0x50, wb_refresh_temp },
{ "", SENSOR_TEMP, 2, 0x50, wb_refresh_temp },
/* Fans */
{ "", SENSOR_FANRPM, 0, 0x28, wb_refresh_fanrpm },
{ "", SENSOR_FANRPM, 0, 0x29, wb_refresh_fanrpm },
{ "", SENSOR_FANRPM, 0, 0x2a, wb_refresh_fanrpm },
{ NULL }
};
/*
* The W83627EHF can measure voltages up to 2.048 V instead of the
* traditional 4.096 V. For measuring positive voltages, this can be
* accounted for by halving the resistor factor. Negative voltages
* need special treatment, also because the reference voltage is 2.048 V
* instead of the traditional 3.6 V.
*/
struct lm_sensor w83627ehf_sensors[] = {
/* Voltage */
{ "VCore", SENSOR_VOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE / 2},
{ "+12V", SENSOR_VOLTS_DC, 0, 0x21, lm_refresh_volt, RFACT(56, 10) / 2 },
{ "+3.3V", SENSOR_VOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT(34, 34) / 2 },
{ "+3.3V", SENSOR_VOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 34) / 2 },
{ "-12V", SENSOR_VOLTS_DC, 0, 0x24, wb_w83627ehf_refresh_nvolt },
{ "", SENSOR_VOLTS_DC, 0, 0x25, lm_refresh_volt, RFACT_NONE / 2 },
{ "", SENSOR_VOLTS_DC, 0, 0x26, lm_refresh_volt, RFACT_NONE / 2 },
{ "3.3VSB", SENSOR_VOLTS_DC, 5, 0x50, lm_refresh_volt, RFACT(34, 34) / 2 },
{ "VBAT", SENSOR_VOLTS_DC, 5, 0x51, lm_refresh_volt, RFACT_NONE / 2 },
{ "", SENSOR_VOLTS_DC, 5, 0x52, lm_refresh_volt, RFACT_NONE / 2 },
/* Temperature */
{ "", SENSOR_TEMP, 0, 0x27, lm_refresh_temp },
{ "", SENSOR_TEMP, 1, 0x50, wb_refresh_temp },
{ "", SENSOR_TEMP, 2, 0x50, wb_refresh_temp },
/* Fans */
{ "", SENSOR_FANRPM, 0, 0x28, wb_refresh_fanrpm },
{ "", SENSOR_FANRPM, 0, 0x29, wb_refresh_fanrpm },
{ "", SENSOR_FANRPM, 0, 0x2a, wb_refresh_fanrpm },
{ NULL }
};
/*
* w83627dhg is almost identical to w83627ehf, except that
* it has 9 instead of 10 voltage sensors
*/
struct lm_sensor w83627dhg_sensors[] = {
/* Voltage */
{ "VCore", SENSOR_VOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE / 2},
{ "+12V", SENSOR_VOLTS_DC, 0, 0x21, lm_refresh_volt, RFACT(56, 10) / 2 },
{ "+3.3V", SENSOR_VOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT(34, 34) / 2 },
{ "+3.3V", SENSOR_VOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 34) / 2 },
{ "-12V", SENSOR_VOLTS_DC, 0, 0x24, wb_w83627ehf_refresh_nvolt },
{ "", SENSOR_VOLTS_DC, 0, 0x25, lm_refresh_volt, RFACT_NONE / 2 },
{ "", SENSOR_VOLTS_DC, 0, 0x26, lm_refresh_volt, RFACT_NONE / 2 },
{ "3.3VSB", SENSOR_VOLTS_DC, 5, 0x50, lm_refresh_volt, RFACT(34, 34) / 2 },
{ "VBAT", SENSOR_VOLTS_DC, 5, 0x51, lm_refresh_volt, RFACT_NONE / 2 },
/* Temperature */
{ "", SENSOR_TEMP, 0, 0x27, lm_refresh_temp },
{ "", SENSOR_TEMP, 1, 0x50, wb_refresh_temp },
{ "", SENSOR_TEMP, 2, 0x50, wb_refresh_temp },
/* Fans */
{ "", SENSOR_FANRPM, 0, 0x28, wb_refresh_fanrpm },
{ "", SENSOR_FANRPM, 0, 0x29, wb_refresh_fanrpm },
{ "", SENSOR_FANRPM, 0, 0x2a, wb_refresh_fanrpm },
{ NULL }
};
struct lm_sensor w83637hf_sensors[] = {
/* Voltage */
{ "VCore", SENSOR_VOLTS_DC, 0, 0x20, wb_w83637hf_refresh_vcore },
{ "+12V", SENSOR_VOLTS_DC, 0, 0x21, lm_refresh_volt, RFACT(28, 10) },
{ "+3.3V", SENSOR_VOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT_NONE },
{ "+5V", SENSOR_VOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 51) },
{ "-12V", SENSOR_VOLTS_DC, 0, 0x24, wb_refresh_nvolt, RFACT(232, 56) },
{ "5VSB", SENSOR_VOLTS_DC, 5, 0x50, lm_refresh_volt, RFACT(34, 51) },
{ "VBAT", SENSOR_VOLTS_DC, 5, 0x51, lm_refresh_volt, RFACT_NONE },
/* Temperature */
{ "", SENSOR_TEMP, 0, 0x27, lm_refresh_temp },
{ "", SENSOR_TEMP, 1, 0x50, wb_refresh_temp },
{ "", SENSOR_TEMP, 2, 0x50, wb_refresh_temp },
/* Fans */
{ "", SENSOR_FANRPM, 0, 0x28, wb_refresh_fanrpm },
{ "", SENSOR_FANRPM, 0, 0x29, wb_refresh_fanrpm },
{ "", SENSOR_FANRPM, 0, 0x2a, wb_refresh_fanrpm },
{ NULL }
};
struct lm_sensor w83697hf_sensors[] = {
/* Voltage */
{ "VCore", SENSOR_VOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE },
{ "+3.3V", SENSOR_VOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT_NONE },
{ "+5V", SENSOR_VOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 50) },
{ "+12V", SENSOR_VOLTS_DC, 0, 0x24, lm_refresh_volt, RFACT(28, 10) },
{ "-12V", SENSOR_VOLTS_DC, 0, 0x25, wb_refresh_nvolt, RFACT(232, 56) },
{ "-5V", SENSOR_VOLTS_DC, 0, 0x26, wb_refresh_nvolt, RFACT(120, 56) },
{ "5VSB", SENSOR_VOLTS_DC, 5, 0x50, lm_refresh_volt, RFACT(17, 33) },
{ "VBAT", SENSOR_VOLTS_DC, 5, 0x51, lm_refresh_volt, RFACT_NONE },
/* Temperature */
{ "", SENSOR_TEMP, 0, 0x27, lm_refresh_temp },
{ "", SENSOR_TEMP, 1, 0x50, wb_refresh_temp },
/* Fans */
{ "", SENSOR_FANRPM, 0, 0x28, wb_refresh_fanrpm },
{ "", SENSOR_FANRPM, 0, 0x29, wb_refresh_fanrpm },
{ NULL }
};
/*
* The datasheet doesn't mention the (internal) resistors used for the
* +5V, but using the values from the W83782D datasheets seems to
* provide sensible results.
*/
struct lm_sensor w83781d_sensors[] = {
/* Voltage */
{ "VCore A", SENSOR_VOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE },
{ "VCore B", SENSOR_VOLTS_DC, 0, 0x21, lm_refresh_volt, RFACT_NONE },
{ "+3.3V", SENSOR_VOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT_NONE },
{ "+5V", SENSOR_VOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 50) },
{ "+12V", SENSOR_VOLTS_DC, 0, 0x24, lm_refresh_volt, RFACT(28, 10) },
{ "-12V", SENSOR_VOLTS_DC, 0, 0x25, lm_refresh_volt, NRFACT(2100, 604) },
{ "-5V", SENSOR_VOLTS_DC, 0, 0x26, lm_refresh_volt, NRFACT(909, 604) },
/* Temperature */
{ "", SENSOR_TEMP, 0, 0x27, lm_refresh_temp },
{ "", SENSOR_TEMP, 1, 0x50, wb_refresh_temp },
{ "", SENSOR_TEMP, 2, 0x50, wb_refresh_temp },
/* Fans */
{ "", SENSOR_FANRPM, 0, 0x28, lm_refresh_fanrpm },
{ "", SENSOR_FANRPM, 0, 0x29, lm_refresh_fanrpm },
{ "", SENSOR_FANRPM, 0, 0x2a, lm_refresh_fanrpm },
{ NULL }
};
struct lm_sensor w83782d_sensors[] = {
/* Voltage */
{ "VCore", SENSOR_VOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE },
{ "VINR0", SENSOR_VOLTS_DC, 0, 0x21, lm_refresh_volt, RFACT_NONE },
{ "+3.3V", SENSOR_VOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT_NONE },
{ "+5V", SENSOR_VOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 50) },
{ "+12V", SENSOR_VOLTS_DC, 0, 0x24, lm_refresh_volt, RFACT(28, 10) },
{ "-12V", SENSOR_VOLTS_DC, 0, 0x25, wb_refresh_nvolt, RFACT(232, 56) },
{ "-5V", SENSOR_VOLTS_DC, 0, 0x26, wb_refresh_nvolt, RFACT(120, 56) },
{ "5VSB", SENSOR_VOLTS_DC, 5, 0x50, lm_refresh_volt, RFACT(17, 33) },
{ "VBAT", SENSOR_VOLTS_DC, 5, 0x51, lm_refresh_volt, RFACT_NONE },
/* Temperature */
{ "", SENSOR_TEMP, 0, 0x27, lm_refresh_temp },
{ "", SENSOR_TEMP, 1, 0x50, wb_refresh_temp },
{ "", SENSOR_TEMP, 2, 0x50, wb_refresh_temp },
/* Fans */
{ "", SENSOR_FANRPM, 0, 0x28, wb_refresh_fanrpm },
{ "", SENSOR_FANRPM, 0, 0x29, wb_refresh_fanrpm },
{ "", SENSOR_FANRPM, 0, 0x2a, wb_refresh_fanrpm },
{ NULL }
};
struct lm_sensor w83783s_sensors[] = {
/* Voltage */
{ "VCore", SENSOR_VOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE },
{ "+3.3V", SENSOR_VOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT_NONE },
{ "+5V", SENSOR_VOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 50) },
{ "+12V", SENSOR_VOLTS_DC, 0, 0x24, lm_refresh_volt, RFACT(28, 10) },
{ "-12V", SENSOR_VOLTS_DC, 0, 0x25, wb_refresh_nvolt, RFACT(232, 56) },
{ "-5V", SENSOR_VOLTS_DC, 0, 0x26, wb_refresh_nvolt, RFACT(120, 56) },
/* Temperature */
{ "", SENSOR_TEMP, 0, 0x27, lm_refresh_temp },
{ "", SENSOR_TEMP, 1, 0x50, wb_refresh_temp },
/* Fans */
{ "", SENSOR_FANRPM, 0, 0x28, wb_refresh_fanrpm },
{ "", SENSOR_FANRPM, 0, 0x29, wb_refresh_fanrpm },
{ "", SENSOR_FANRPM, 0, 0x2a, wb_refresh_fanrpm },
{ NULL }
};
struct lm_sensor w83791d_sensors[] = {
/* Voltage */
{ "VCore", SENSOR_VOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE },
{ "VINR0", SENSOR_VOLTS_DC, 0, 0x21, lm_refresh_volt, RFACT_NONE },
{ "+3.3V", SENSOR_VOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT_NONE },
{ "+5V", SENSOR_VOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 50) },
{ "+12V", SENSOR_VOLTS_DC, 0, 0x24, lm_refresh_volt, RFACT(28, 10) },
{ "-12V", SENSOR_VOLTS_DC, 0, 0x25, wb_refresh_nvolt, RFACT(232, 56) },
{ "-5V", SENSOR_VOLTS_DC, 0, 0x26, wb_refresh_nvolt, RFACT(120, 56) },
{ "5VSB", SENSOR_VOLTS_DC, 0, 0xb0, lm_refresh_volt, RFACT(17, 33) },
{ "VBAT", SENSOR_VOLTS_DC, 0, 0xb1, lm_refresh_volt, RFACT_NONE },
{ "VINR1", SENSOR_VOLTS_DC, 0, 0xb2, lm_refresh_volt, RFACT_NONE },
/* Temperature */
{ "", SENSOR_TEMP, 0, 0x27, lm_refresh_temp },
{ "", SENSOR_TEMP, 0, 0xc0, wb_refresh_temp },
{ "", SENSOR_TEMP, 0, 0xc8, wb_refresh_temp },
/* Fans */
{ "", SENSOR_FANRPM, 0, 0x28, wb_refresh_fanrpm },
{ "", SENSOR_FANRPM, 0, 0x29, wb_refresh_fanrpm },
{ "", SENSOR_FANRPM, 0, 0x2a, wb_refresh_fanrpm },
{ "", SENSOR_FANRPM, 0, 0xba, wb_refresh_fanrpm },
{ "", SENSOR_FANRPM, 0, 0xbb, wb_refresh_fanrpm },
{ NULL }
};
struct lm_sensor w83792d_sensors[] = {
/* Voltage */
{ "VCore A", SENSOR_VOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE },
{ "VCore B", SENSOR_VOLTS_DC, 0, 0x21, lm_refresh_volt, RFACT_NONE },
{ "+3.3V", SENSOR_VOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT_NONE },
{ "-5V", SENSOR_VOLTS_DC, 0, 0x23, wb_refresh_nvolt, RFACT(120, 56) },
{ "+12V", SENSOR_VOLTS_DC, 0, 0x24, lm_refresh_volt, RFACT(28, 10) },
{ "-12V", SENSOR_VOLTS_DC, 0, 0x25, wb_refresh_nvolt, RFACT(232, 56) },
{ "+5V", SENSOR_VOLTS_DC, 0, 0x26, lm_refresh_volt, RFACT(34, 50) },
{ "5VSB", SENSOR_VOLTS_DC, 0, 0xb0, lm_refresh_volt, RFACT(17, 33) },
{ "VBAT", SENSOR_VOLTS_DC, 0, 0xb1, lm_refresh_volt, RFACT_NONE },
/* Temperature */
{ "", SENSOR_TEMP, 0, 0x27, lm_refresh_temp },
{ "", SENSOR_TEMP, 0, 0xc0, wb_refresh_temp },
{ "", SENSOR_TEMP, 0, 0xc8, wb_refresh_temp },
/* Fans */
{ "", SENSOR_FANRPM, 0, 0x28, wb_w83792d_refresh_fanrpm },
{ "", SENSOR_FANRPM, 0, 0x29, wb_w83792d_refresh_fanrpm },
{ "", SENSOR_FANRPM, 0, 0x2a, wb_w83792d_refresh_fanrpm },
{ "", SENSOR_FANRPM, 0, 0xb8, wb_w83792d_refresh_fanrpm },
{ "", SENSOR_FANRPM, 0, 0xb9, wb_w83792d_refresh_fanrpm },
{ "", SENSOR_FANRPM, 0, 0xba, wb_w83792d_refresh_fanrpm },
{ "", SENSOR_FANRPM, 0, 0xbe, wb_w83792d_refresh_fanrpm },
{ NULL }
};
struct lm_sensor as99127f_sensors[] = {
/* Voltage */
{ "VCore A", SENSOR_VOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE },
{ "VCore B", SENSOR_VOLTS_DC, 0, 0x21, lm_refresh_volt, RFACT_NONE },
{ "+3.3V", SENSOR_VOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT_NONE },
{ "+5V", SENSOR_VOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 50) },
{ "+12V", SENSOR_VOLTS_DC, 0, 0x24, lm_refresh_volt, RFACT(28, 10) },
{ "-12V", SENSOR_VOLTS_DC, 0, 0x25, wb_refresh_nvolt, RFACT(232, 56) },
{ "-5V", SENSOR_VOLTS_DC, 0, 0x26, wb_refresh_nvolt, RFACT(120, 56) },
/* Temperature */
{ "", SENSOR_TEMP, 0, 0x27, lm_refresh_temp },
{ "", SENSOR_TEMP, 1, 0x50, as_refresh_temp },
{ "", SENSOR_TEMP, 2, 0x50, as_refresh_temp },
/* Fans */
{ "", SENSOR_FANRPM, 0, 0x28, lm_refresh_fanrpm },
{ "", SENSOR_FANRPM, 0, 0x29, lm_refresh_fanrpm },
{ "", SENSOR_FANRPM, 0, 0x2a, lm_refresh_fanrpm },
{ NULL }
};
void
lm_probe(struct lm_softc *sc)
{
int i;
for (i = 0; i < sizeof(lm_chips) / sizeof(lm_chips[0]); i++)
if (lm_chips[i].chip_match(sc))
break;
}
void
lm_attach(struct lm_softc *sc)
{
u_int i, config;
/* No point in doing anything if we don't have any sensors. */
if (sc->numsensors == 0)
return;
if (sensor_task_register(sc, lm_refresh, 5)) {
device_printf(sc->sc_dev, "unable to register update task\n");
return;
}
/* Start the monitoring loop */
config = sc->lm_readreg(sc, LM_CONFIG);
sc->lm_writereg(sc, LM_CONFIG, config | 0x01);
/* Add sensors */
strlcpy(sc->sensordev.xname, device_get_nameunit(sc->sc_dev),
sizeof(sc->sensordev.xname));
for (i = 0; i < sc->numsensors; ++i)
sensor_attach(&sc->sensordev, &sc->sensors[i]);
sensordev_install(&sc->sensordev);
}
int
lm_detach(struct lm_softc *sc)
{
int i;
/* Remove sensors */
sensordev_deinstall(&sc->sensordev);
for (i = 0; i < sc->numsensors; i++)
sensor_detach(&sc->sensordev, &sc->sensors[i]);
sensor_task_unregister(sc);
return 0;
}
int
lm_match(struct lm_softc *sc)
{
int chipid;
const char *cdesc;
char fulldesc[64];
/* See if we have an LM78 or LM79. */
chipid = sc->lm_readreg(sc, LM_CHIPID) & LM_CHIPID_MASK;
switch(chipid) {
case LM_CHIPID_LM78:
cdesc = "LM78";
break;
case LM_CHIPID_LM78J:
cdesc = "LM78J";
break;
case LM_CHIPID_LM79:
cdesc = "LM79";
break;
case LM_CHIPID_LM81:
cdesc = "LM81";
break;
default:
return 0;
}
snprintf(fulldesc, sizeof(fulldesc),
"National Semiconductor %s Hardware Monitor", cdesc);
device_set_desc_copy(sc->sc_dev, fulldesc);
lm_setup_sensors(sc, lm78_sensors);
sc->refresh_sensor_data = lm_refresh_sensor_data;
return 1;
}
int
def_match(struct lm_softc *sc)
{
int chipid;
char fulldesc[64];
chipid = sc->lm_readreg(sc, LM_CHIPID) & LM_CHIPID_MASK;
snprintf(fulldesc, sizeof(fulldesc),
"unknown Hardware Monitor (ID 0x%x)", chipid);
device_set_desc_copy(sc->sc_dev, fulldesc);
lm_setup_sensors(sc, lm78_sensors);
sc->refresh_sensor_data = lm_refresh_sensor_data;
return 1;
}
int
wb_match(struct lm_softc *sc)
{
int banksel, vendid, devid;
const char *cdesc;
char desc[64];
char fulldesc[64];
/* Read vendor ID */
banksel = sc->lm_readreg(sc, WB_BANKSEL);
sc->lm_writereg(sc, WB_BANKSEL, WB_BANKSEL_HBAC);
vendid = sc->lm_readreg(sc, WB_VENDID) << 8;
sc->lm_writereg(sc, WB_BANKSEL, 0);
vendid |= sc->lm_readreg(sc, WB_VENDID);
sc->lm_writereg(sc, WB_BANKSEL, banksel);
DPRINTF((" winbond vend id 0x%x\n", vendid));
if (vendid != WB_VENDID_WINBOND && vendid != WB_VENDID_ASUS)
return 0;
/* Read device/chip ID */
sc->lm_writereg(sc, WB_BANKSEL, WB_BANKSEL_B0);
devid = sc->lm_readreg(sc, LM_CHIPID);
sc->chipid = sc->lm_readreg(sc, WB_BANK0_CHIPID);
sc->lm_writereg(sc, WB_BANKSEL, banksel);
DPRINTF((" winbond chip id 0x%x\n", sc->chipid));
switch(sc->chipid) {
case WB_CHIPID_W83627HF:
cdesc = "W83627HF";
lm_setup_sensors(sc, w83627hf_sensors);
break;
case WB_CHIPID_W83627THF:
cdesc = "W83627THF";
lm_setup_sensors(sc, w83637hf_sensors);
break;
case WB_CHIPID_W83627EHF:
cdesc = "W83627EHF";
lm_setup_sensors(sc, w83627ehf_sensors);
break;
case WB_CHIPID_W83627DHG:
cdesc = "W83627DHG";
lm_setup_sensors(sc, w83627dhg_sensors);
break;
case WB_CHIPID_W83637HF:
cdesc = "W83637HF";
sc->lm_writereg(sc, WB_BANKSEL, WB_BANKSEL_B0);
if (sc->lm_readreg(sc, WB_BANK0_CONFIG) & WB_CONFIG_VMR9)
sc->vrm9 = 1;
sc->lm_writereg(sc, WB_BANKSEL, banksel);
lm_setup_sensors(sc, w83637hf_sensors);
break;
case WB_CHIPID_W83697HF:
cdesc = "W83697HF";
lm_setup_sensors(sc, w83697hf_sensors);
break;
case WB_CHIPID_W83781D:
case WB_CHIPID_W83781D_2:
cdesc = "W83781D";
lm_setup_sensors(sc, w83781d_sensors);
break;
case WB_CHIPID_W83782D:
cdesc = "W83782D";
lm_setup_sensors(sc, w83782d_sensors);
break;
case WB_CHIPID_W83783S:
cdesc = "W83783S";
lm_setup_sensors(sc, w83783s_sensors);
break;
case WB_CHIPID_W83791D:
cdesc = "W83791D";
lm_setup_sensors(sc, w83791d_sensors);
break;
case WB_CHIPID_W83791SD:
cdesc = "W83791SD";
break;
case WB_CHIPID_W83792D:
if (devid >= 0x10 && devid <= 0x29)
snprintf(desc, sizeof(desc),
"W83792D rev %c", 'A' + devid - 0x10);
else
snprintf(desc, sizeof(desc),
"W83792D rev 0x%x", devid);
cdesc = desc;
lm_setup_sensors(sc, w83792d_sensors);
break;
case WB_CHIPID_AS99127F:
if (vendid == WB_VENDID_ASUS) {
cdesc = "AS99127F";
lm_setup_sensors(sc, w83781d_sensors);
} else {
cdesc = "AS99127F rev 2";
lm_setup_sensors(sc, as99127f_sensors);
}
break;
default:
snprintf(fulldesc, sizeof(fulldesc),
"unknown Winbond Hardware Monitor (Chip ID 0x%x)",
sc->chipid);
device_set_desc_copy(sc->sc_dev, fulldesc);
/* Handle as a standard LM78. */
lm_setup_sensors(sc, lm78_sensors);
sc->refresh_sensor_data = lm_refresh_sensor_data;
return 1;
}
if (cdesc[0] == 'W')
snprintf(fulldesc, sizeof(fulldesc),
"Winbond %s Hardware Monitor", cdesc);
else
snprintf(fulldesc, sizeof(fulldesc),
"ASUS %s Hardware Monitor", cdesc);
device_set_desc_copy(sc->sc_dev, fulldesc);
sc->refresh_sensor_data = wb_refresh_sensor_data;
return 1;
}
void
lm_setup_sensors(struct lm_softc *sc, struct lm_sensor *sensors)
{
int i;
for (i = 0; sensors[i].desc; i++) {
sc->sensors[i].type = sensors[i].type;
strlcpy(sc->sensors[i].desc, sensors[i].desc,
sizeof(sc->sensors[i].desc));
sc->numsensors++;
}
sc->lm_sensors = sensors;
}
void
lm_refresh(void *arg)
{
struct lm_softc *sc = arg;
sc->refresh_sensor_data(sc);
}
void
lm_refresh_sensor_data(struct lm_softc *sc)
{
int i;
for (i = 0; i < sc->numsensors; i++)
sc->lm_sensors[i].refresh(sc, i);
}
void
lm_refresh_volt(struct lm_softc *sc, int n)
{
struct ksensor *sensor = &sc->sensors[n];
int data;
data = sc->lm_readreg(sc, sc->lm_sensors[n].reg);
sensor->value = (data << 4);
sensor->value *= sc->lm_sensors[n].rfact;
sensor->value /= 10;
}
void
lm_refresh_temp(struct lm_softc *sc, int n)
{
struct ksensor *sensor = &sc->sensors[n];
int sdata;
/*
* The data sheet suggests that the range of the temperature
* sensor is between -55 degC and +125 degC.
*/
sdata = sc->lm_readreg(sc, sc->lm_sensors[n].reg);
if (sdata > 0x7d && sdata < 0xc9) {
sensor->flags |= SENSOR_FINVALID;
sensor->value = 0;
} else {
if (sdata & 0x80)
sdata -= 0x100;
sensor->flags &= ~SENSOR_FINVALID;
sensor->value = sdata * 1000000 + 273150000;
}
}
void
lm_refresh_fanrpm(struct lm_softc *sc, int n)
{
struct ksensor *sensor = &sc->sensors[n];
int data, divisor = 1;
/*
* We might get more accurate fan readings by adjusting the
* divisor, but that might interfere with APM or other SMM
* BIOS code reading the fan speeds.
*/
/* FAN3 has a fixed fan divisor. */
if (sc->lm_sensors[n].reg == LM_FAN1 ||
sc->lm_sensors[n].reg == LM_FAN2) {
data = sc->lm_readreg(sc, LM_VIDFAN);
if (sc->lm_sensors[n].reg == LM_FAN1)
divisor = (data >> 4) & 0x03;
else
divisor = (data >> 6) & 0x03;
}
data = sc->lm_readreg(sc, sc->lm_sensors[n].reg);
if (data == 0xff || data == 0x00) {
sensor->flags |= SENSOR_FINVALID;
sensor->value = 0;
} else {
sensor->flags &= ~SENSOR_FINVALID;
sensor->value = 1350000 / (data << divisor);
}
}
void
wb_refresh_sensor_data(struct lm_softc *sc)
{
int banksel, bank, i;
/*
* Properly save and restore bank selection register.
*/
banksel = bank = sc->lm_readreg(sc, WB_BANKSEL);
for (i = 0; i < sc->numsensors; i++) {
if (bank != sc->lm_sensors[i].bank) {
bank = sc->lm_sensors[i].bank;
sc->lm_writereg(sc, WB_BANKSEL, bank);
}
sc->lm_sensors[i].refresh(sc, i);
}
sc->lm_writereg(sc, WB_BANKSEL, banksel);
}
void
wb_w83637hf_refresh_vcore(struct lm_softc *sc, int n)
{
struct ksensor *sensor = &sc->sensors[n];
int data;
data = sc->lm_readreg(sc, sc->lm_sensors[n].reg);
/*
* Depending on the voltage detection method,
* one of the following formulas is used:
* VRM8 method: value = raw * 0.016V
* VRM9 method: value = raw * 0.00488V + 0.70V
*/
if (sc->vrm9)
sensor->value = (data * 4880) + 700000;
else
sensor->value = (data * 16000);
}
void
wb_refresh_nvolt(struct lm_softc *sc, int n)
{
struct ksensor *sensor = &sc->sensors[n];
int data;
data = sc->lm_readreg(sc, sc->lm_sensors[n].reg);
sensor->value = ((data << 4) - WB_VREF);
sensor->value *= sc->lm_sensors[n].rfact;
sensor->value /= 10;
sensor->value += WB_VREF * 1000;
}
void
wb_w83627ehf_refresh_nvolt(struct lm_softc *sc, int n)
{
struct ksensor *sensor = &sc->sensors[n];
int data;
data = sc->lm_readreg(sc, sc->lm_sensors[n].reg);
sensor->value = ((data << 3) - WB_W83627EHF_VREF);
sensor->value *= RFACT(232, 10);
sensor->value /= 10;
sensor->value += WB_W83627EHF_VREF * 1000;
}
void
wb_refresh_temp(struct lm_softc *sc, int n)
{
struct ksensor *sensor = &sc->sensors[n];
int sdata;
/*
* The data sheet suggests that the range of the temperature
* sensor is between -55 degC and +125 degC. However, values
* around -48 degC seem to be a very common bogus values.
* Since such values are unreasonably low, we use -45 degC for
* the lower limit instead.
*/
sdata = sc->lm_readreg(sc, sc->lm_sensors[n].reg) << 1;
sdata += sc->lm_readreg(sc, sc->lm_sensors[n].reg + 1) >> 7;
if (sdata > 0x0fa && sdata < 0x1a6) {
sensor->flags |= SENSOR_FINVALID;
sensor->value = 0;
} else {
if (sdata & 0x100)
sdata -= 0x200;
sensor->flags &= ~SENSOR_FINVALID;
sensor->value = sdata * 500000 + 273150000;
}
}
void
wb_refresh_fanrpm(struct lm_softc *sc, int n)
{
struct ksensor *sensor = &sc->sensors[n];
int fan, data, divisor = 0;
/*
* This is madness; the fan divisor bits are scattered all
* over the place.
*/
if (sc->lm_sensors[n].reg == LM_FAN1 ||
sc->lm_sensors[n].reg == LM_FAN2 ||
sc->lm_sensors[n].reg == LM_FAN3) {
data = sc->lm_readreg(sc, WB_BANK0_VBAT);
fan = (sc->lm_sensors[n].reg - LM_FAN1);
if ((data >> 5) & (1 << fan))
divisor |= 0x04;
}
if (sc->lm_sensors[n].reg == LM_FAN1 ||
sc->lm_sensors[n].reg == LM_FAN2) {
data = sc->lm_readreg(sc, LM_VIDFAN);
if (sc->lm_sensors[n].reg == LM_FAN1)
divisor |= (data >> 4) & 0x03;
else
divisor |= (data >> 6) & 0x03;
} else if (sc->lm_sensors[n].reg == LM_FAN3) {
data = sc->lm_readreg(sc, WB_PIN);
divisor |= (data >> 6) & 0x03;
} else if (sc->lm_sensors[n].reg == WB_BANK0_FAN4 ||
sc->lm_sensors[n].reg == WB_BANK0_FAN5) {
data = sc->lm_readreg(sc, WB_BANK0_FAN45);
if (sc->lm_sensors[n].reg == WB_BANK0_FAN4)
divisor |= (data >> 0) & 0x07;
else
divisor |= (data >> 4) & 0x07;
}
data = sc->lm_readreg(sc, sc->lm_sensors[n].reg);
if (data == 0xff || data == 0x00) {
sensor->flags |= SENSOR_FINVALID;
sensor->value = 0;
} else {
sensor->flags &= ~SENSOR_FINVALID;
sensor->value = 1350000 / (data << divisor);
}
}
void
wb_w83792d_refresh_fanrpm(struct lm_softc *sc, int n)
{
struct ksensor *sensor = &sc->sensors[n];
int reg, shift, data, divisor = 1;
switch (sc->lm_sensors[n].reg) {
case 0x28:
reg = 0x47; shift = 0;
break;
case 0x29:
reg = 0x47; shift = 4;
break;
case 0x2a:
reg = 0x5b; shift = 0;
break;
case 0xb8:
reg = 0x5b; shift = 4;
break;
case 0xb9:
reg = 0x5c; shift = 0;
break;
case 0xba:
reg = 0x5c; shift = 4;
break;
case 0xbe:
reg = 0x9e; shift = 0;
break;
default:
reg = 0; shift = 0;
break;
}
data = sc->lm_readreg(sc, sc->lm_sensors[n].reg);
if (data == 0xff || data == 0x00) {
sensor->flags |= SENSOR_FINVALID;
sensor->value = 0;
} else {
if (reg != 0)
divisor = (sc->lm_readreg(sc, reg) >> shift) & 0x7;
sensor->flags &= ~SENSOR_FINVALID;
sensor->value = 1350000 / (data << divisor);
}
}
void
as_refresh_temp(struct lm_softc *sc, int n)
{
struct ksensor *sensor = &sc->sensors[n];
int sdata;
/*
* It seems a shorted temperature diode produces an all-ones
* bit pattern.
*/
sdata = sc->lm_readreg(sc, sc->lm_sensors[n].reg) << 1;
sdata += sc->lm_readreg(sc, sc->lm_sensors[n].reg + 1) >> 7;
if (sdata == 0x1ff) {
sensor->flags |= SENSOR_FINVALID;
sensor->value = 0;
} else {
if (sdata & 0x100)
sdata -= 0x200;
sensor->flags &= ~SENSOR_FINVALID;
sensor->value = sdata * 500000 + 273150000;
}
}

251
sys/dev/lm/lm78_isa.c Normal file
View File

@ -0,0 +1,251 @@
/* $FreeBSD$ */
/* $OpenBSD: lm78_isa.c,v 1.2 2007/07/01 21:48:57 cnst Exp $ */
/*-
* Copyright (c) 2005, 2006 Mark Kettenis
* Copyright (c) 2007 Constantine A. Murenin, Google Summer of Code
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/bus.h>
#include <sys/module.h>
#include <sys/module.h>
#include <sys/bus.h>
#include <machine/bus.h>
#include <machine/resource.h>
#include <sys/rman.h>
#include <isa/isavar.h>
#include <sys/systm.h>
#include <sys/sensors.h>
#include <dev/lm/lm78var.h>
/* ISA registers */
#define LMC_ADDR 0x05
#define LMC_DATA 0x06
extern struct cfdriver lm_cd;
#if defined(LMDEBUG)
#define DPRINTF(x) do { printf x; } while (0)
#else
#define DPRINTF(x)
#endif
struct lm_isa_softc {
struct lm_softc sc_lmsc;
struct resource *sc_iores;
int sc_iorid;
bus_space_tag_t sc_iot;
bus_space_handle_t sc_ioh;
};
static int lm_isa_probe(struct device *);
static int lm_isa_attach(struct device *);
static int lm_isa_detach(struct device *);
u_int8_t lm_isa_readreg(struct lm_softc *, int);
void lm_isa_writereg(struct lm_softc *, int, int);
static device_method_t lm_isa_methods[] = {
/* Methods from the device interface */
DEVMETHOD(device_probe, lm_isa_probe),
DEVMETHOD(device_attach, lm_isa_attach),
DEVMETHOD(device_detach, lm_isa_detach),
/* Terminate method list */
{ 0, 0 }
};
static driver_t lm_isa_driver = {
"lm",
lm_isa_methods,
sizeof (struct lm_isa_softc)
};
static devclass_t lm_devclass;
DRIVER_MODULE(lm, isa, lm_isa_driver, lm_devclass, NULL, NULL);
int
lm_isa_probe(struct device *dev)
{
struct lm_isa_softc *sc = device_get_softc(dev);
struct resource *iores;
int iorid = 0;
bus_space_tag_t iot;
bus_space_handle_t ioh;
int banksel, vendid, chipid, addr;
iores = bus_alloc_resource(dev, SYS_RES_IOPORT, &iorid,
0ul, ~0ul, 8, RF_ACTIVE);
if (iores == NULL) {
DPRINTF(("%s: can't map i/o space\n", __func__));
return (1);
}
iot = rman_get_bustag(iores);
ioh = rman_get_bushandle(iores);
/* Probe for Winbond chips. */
bus_space_write_1(iot, ioh, LMC_ADDR, WB_BANKSEL);
banksel = bus_space_read_1(iot, ioh, LMC_DATA);
bus_space_write_1(iot, ioh, LMC_ADDR, WB_VENDID);
vendid = bus_space_read_1(iot, ioh, LMC_DATA);
if (((banksel & 0x80) && vendid == (WB_VENDID_WINBOND >> 8)) ||
(!(banksel & 0x80) && vendid == (WB_VENDID_WINBOND & 0xff)))
goto found;
/* Probe for ITE chips (and don't attach if we find one). */
bus_space_write_1(iot, ioh, LMC_ADDR, 0x58 /*ITD_CHIPID*/);
vendid = bus_space_read_1(iot, ioh, LMC_DATA);
if (vendid == 0x90 /*IT_ID_IT87*/)
goto notfound;
/*
* Probe for National Semiconductor LM78/79/81.
*
* XXX This assumes the address has not been changed from the
* power up default. This is probably a reasonable
* assumption, and if it isn't true, we should be able to
* access the chip using the serial bus.
*/
bus_space_write_1(iot, ioh, LMC_ADDR, LM_SBUSADDR);
addr = bus_space_read_1(iot, ioh, LMC_DATA);
if ((addr & 0xfc) == 0x2c) {
bus_space_write_1(iot, ioh, LMC_ADDR, LM_CHIPID);
chipid = bus_space_read_1(iot, ioh, LMC_DATA);
switch (chipid & LM_CHIPID_MASK) {
case LM_CHIPID_LM78:
case LM_CHIPID_LM78J:
case LM_CHIPID_LM79:
case LM_CHIPID_LM81:
goto found;
}
}
notfound:
bus_release_resource(dev, SYS_RES_IOPORT, iorid, iores);
return (1);
found:
/* Bus-independent probe */
sc->sc_lmsc.sc_dev = dev;
sc->sc_iot = iot;
sc->sc_ioh = ioh;
sc->sc_lmsc.lm_writereg = lm_isa_writereg;
sc->sc_lmsc.lm_readreg = lm_isa_readreg;
lm_probe(&sc->sc_lmsc);
bus_release_resource(dev, SYS_RES_IOPORT, iorid, iores);
sc->sc_iot = 0;
sc->sc_ioh = 0;
return (0);
}
int
lm_isa_attach(struct device *dev)
{
struct lm_isa_softc *sc = device_get_softc(dev);
#ifdef notyet
struct lm_softc *lmsc;
int i;
u_int8_t sbusaddr;
#endif
sc->sc_iores = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->sc_iorid,
0ul, ~0ul, 8, RF_ACTIVE);
if (sc->sc_iores == NULL) {
device_printf(dev, "can't map i/o space\n");
return (1);
}
sc->sc_iot = rman_get_bustag(sc->sc_iores);
sc->sc_ioh = rman_get_bushandle(sc->sc_iores);
/* Bus-independent attachment */
lm_attach(&sc->sc_lmsc);
#ifdef notyet
/*
* Most devices supported by this driver can attach to iic(4)
* as well. However, we prefer to attach them to isa(4) since
* that causes less overhead and is more reliable. We look
* through all previously attached devices, and if we find an
* identical chip at the same serial bus address, we stop
* updating its sensors and mark them as invalid.
*/
sbusaddr = lm_isa_readreg(&sc->sc_lmsc, LM_SBUSADDR);
if (sbusaddr == 0)
return (0);
for (i = 0; i < lm_cd.cd_ndevs; i++) {
lmsc = lm_cd.cd_devs[i];
if (lmsc == &sc->sc_lmsc)
continue;
if (lmsc && lmsc->sbusaddr == sbusaddr &&
lmsc->chipid == sc->sc_lmsc.chipid)
config_detach(&lmsc->sc_dev, 0);
}
#endif
return (0);
}
int
lm_isa_detach(struct device *dev)
{
struct lm_isa_softc *sc = device_get_softc(dev);
int error;
/* Bus-independent detachment */
error = lm_detach(&sc->sc_lmsc);
if (error)
return (error);
error = bus_release_resource(dev, SYS_RES_IOPORT, sc->sc_iorid,
sc->sc_iores);
if (error)
return (error);
return (0);
}
u_int8_t
lm_isa_readreg(struct lm_softc *lmsc, int reg)
{
struct lm_isa_softc *sc = (struct lm_isa_softc *)lmsc;
bus_space_write_1(sc->sc_iot, sc->sc_ioh, LMC_ADDR, reg);
return (bus_space_read_1(sc->sc_iot, sc->sc_ioh, LMC_DATA));
}
void
lm_isa_writereg(struct lm_softc *lmsc, int reg, int val)
{
struct lm_isa_softc *sc = (struct lm_isa_softc *)lmsc;
bus_space_write_1(sc->sc_iot, sc->sc_ioh, LMC_ADDR, reg);
bus_space_write_1(sc->sc_iot, sc->sc_ioh, LMC_DATA, val);
}

158
sys/dev/lm/lm78var.h Normal file
View File

@ -0,0 +1,158 @@
/* $FreeBSD$ */
/* $OpenBSD: lm78var.h,v 1.12 2007/05/25 02:26:43 cnst Exp $ */
/*-
* Copyright (c) 2005, 2006 Mark Kettenis
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/*
* National Semiconductor LM78/79/81 registers
*/
#define LM_POST_RAM 0x00 /* POST RAM occupies 0x00 -- 0x1f */
#define LM_VALUE_RAM 0x20 /* Value RAM occupies 0x20 -- 0x3f */
#define LM_FAN1 0x28 /* FAN1 reading */
#define LM_FAN2 0x29 /* FAN2 reading */
#define LM_FAN3 0x2a /* FAN3 reading */
#define LM_CONFIG 0x40 /* Configuration */
#define LM_ISR1 0x41 /* Interrupt Status 1 */
#define LM_ISR2 0x42 /* Interrupt Status 2 */
#define LM_SMI1 0x43 /* SMI# Mask 1 */
#define LM_SMI2 0x44 /* SMI# Mask 2 */
#define LM_NMI1 0x45 /* NMI Mask 1 */
#define LM_NMI2 0x46 /* NMI Mask 2 */
#define LM_VIDFAN 0x47 /* VID/Fan Divisor */
#define LM_SBUSADDR 0x48 /* Serial Bus Address */
#define LM_CHIPID 0x49 /* Chip Reset/ID */
/* Chip IDs */
#define LM_CHIPID_LM78 0x00
#define LM_CHIPID_LM78J 0x40
#define LM_CHIPID_LM79 0xC0
#define LM_CHIPID_LM81 0x80
#define LM_CHIPID_MASK 0xfe
/*
* Winbond registers
*
* Several models exists. The W83781D is mostly compatible with the
* LM78, but has two extra temperatures. Later models add extra
* voltage sensors, fans and bigger fan divisors to accomodate slow
* running fans. To accomodate the extra sensors some models have
* different memory banks.
*/
#define WB_T23ADDR 0x4a /* Temperature 2 and 3 Serial Bus Address */
#define WB_PIN 0x4b /* Pin Control */
#define WB_BANKSEL 0x4e /* Bank Select */
#define WB_VENDID 0x4f /* Vendor ID */
/* Bank 0 regs */
#define WB_BANK0_CHIPID 0x58 /* Chip ID */
#define WB_BANK0_FAN45 0x5c /* Fan 4/5 Divisor Control (W83791D only) */
#define WB_BANK0_VBAT 0x5d /* VBAT Monitor Control */
#define WB_BANK0_FAN4 0xba /* Fan 4 reading (W83791D only) */
#define WB_BANK0_FAN5 0xbb /* Fan 5 reading (W83791D only) */
#define WB_BANK0_CONFIG 0x18 /* VRM & OVT Config (W83627THF/W83637HF) */
/* Bank 1 registers */
#define WB_BANK1_T2H 0x50 /* Temperature 2 High Byte */
#define WB_BANK1_T2L 0x51 /* Temperature 2 Low Byte */
/* Bank 2 registers */
#define WB_BANK2_T3H 0x50 /* Temperature 3 High Byte */
#define WB_BANK2_T3L 0x51 /* Temperature 3 Low Byte */
/* Bank 4 registers (W83782D/W83627HF and later models only) */
#define WB_BANK4_T1OFF 0x54 /* Temperature 1 Offset */
#define WB_BANK4_T2OFF 0x55 /* Temperature 2 Offset */
#define WB_BANK4_T3OFF 0x56 /* Temperature 3 Offset */
/* Bank 5 registers (W83782D/W83627HF and later models only) */
#define WB_BANK5_5VSB 0x50 /* 5VSB reading */
#define WB_BANK5_VBAT 0x51 /* VBAT reading */
/* Bank selection */
#define WB_BANKSEL_B0 0x00 /* Bank 0 */
#define WB_BANKSEL_B1 0x01 /* Bank 1 */
#define WB_BANKSEL_B2 0x02 /* Bank 2 */
#define WB_BANKSEL_B3 0x03 /* Bank 3 */
#define WB_BANKSEL_B4 0x04 /* Bank 4 */
#define WB_BANKSEL_B5 0x05 /* Bank 5 */
#define WB_BANKSEL_HBAC 0x80 /* Register 0x4f High Byte Access */
/* Vendor IDs */
#define WB_VENDID_WINBOND 0x5ca3 /* Winbond */
#define WB_VENDID_ASUS 0x12c3 /* ASUS */
/* Chip IDs */
#define WB_CHIPID_W83781D 0x10
#define WB_CHIPID_W83781D_2 0x11
#define WB_CHIPID_W83627HF 0x21
#define WB_CHIPID_AS99127F 0x31 /* Asus W83781D clone */
#define WB_CHIPID_W83782D 0x30
#define WB_CHIPID_W83783S 0x40
#define WB_CHIPID_W83697HF 0x60
#define WB_CHIPID_W83791D 0x71
#define WB_CHIPID_W83791SD 0x72
#define WB_CHIPID_W83792D 0x7a
#define WB_CHIPID_W83637HF 0x80
#define WB_CHIPID_W83627THF 0x90
#define WB_CHIPID_W83627EHF 0xa1
#define WB_CHIPID_W83627DHG 0xc1
/* Config bits */
#define WB_CONFIG_VMR9 0x01
/* Reference voltage (mV) */
#define WB_VREF 3600
#define WB_W83627EHF_VREF 2048
#define WB_MAX_SENSORS 19
struct lm_softc;
struct lm_sensor {
char *desc;
enum sensor_type type;
u_int8_t bank;
u_int8_t reg;
void (*refresh)(struct lm_softc *, int);
int rfact;
};
struct lm_softc {
struct device *sc_dev;
struct ksensor sensors[WB_MAX_SENSORS];
struct ksensordev sensordev;
struct lm_sensor *lm_sensors;
u_int numsensors;
void (*refresh_sensor_data) (struct lm_softc *);
u_int8_t (*lm_readreg)(struct lm_softc *, int);
void (*lm_writereg)(struct lm_softc *, int, int);
u_int8_t sbusaddr;
u_int8_t chipid;
u_int8_t vrm9;
};
void lm_probe(struct lm_softc *);
void lm_attach(struct lm_softc *);
int lm_detach(struct lm_softc *);

View File

@ -76,3 +76,11 @@ hint.le.0.disabled="1"
hint.le.0.port="0x280"
hint.le.0.irq="10"
hint.le.0.drq="0"
hint.lm.0.at="isa"
hint.lm.0.port="0x290"
hint.it.0.at="isa"
hint.it.0.port="0x290"
hint.it.1.at="isa"
hint.it.1.port="0xc00"
hint.it.2.at="isa"
hint.it.2.port="0xd00"

View File

@ -131,6 +131,7 @@ SUBDIR= ${_3dfx} \
iscsi \
isp \
ispfw \
${_it} \
${_iwi} \
${_iwifw} \
${_ixgb} \
@ -146,6 +147,7 @@ SUBDIR= ${_3dfx} \
${_linprocfs} \
${_linsysfs} \
${_linux} \
${_lm} \
lmc \
lpt \
mac_biba \
@ -453,9 +455,11 @@ _ipmi= ipmi
_ips= ips
_ipw= ipw
_ipwfw= ipwfw
_it= it
_iwi= iwi
_iwifw= iwifw
_ixgb= ixgb
_lm= lm
_mly= mly
_nfe= nfe
_nve= nve
@ -511,10 +515,12 @@ _ipmi= ipmi
_ips= ips
_ipw= ipw
_ipwfw= ipwfw
_it= it
_ixgb= ixgb
_linprocfs= linprocfs
_linsysfs= linsysfs
_linux= linux
_lm= lm
_mly= mly
_ndis= ndis
_nfe= nfe

9
sys/modules/it/Makefile Normal file
View File

@ -0,0 +1,9 @@
# $FreeBSD$
.PATH: ${.CURDIR}/../../dev/it
KMOD= it
SRCS= it.c
SRCS+= device_if.h bus_if.h isa_if.h
.include <bsd.kmod.mk>

9
sys/modules/lm/Makefile Normal file
View File

@ -0,0 +1,9 @@
# $FreeBSD$
.PATH: ${.CURDIR}/../../dev/lm
KMOD= lm
SRCS= lm78.c lm78_isa.c
SRCS+= device_if.h bus_if.h isa_if.h
.include <bsd.kmod.mk>