From ca767207dbf70e5e9343d919cbbd75b42443b57f Mon Sep 17 00:00:00 2001 From: Thomas Nikolajsen Date: Sun, 27 Sep 2009 23:04:57 +0200 Subject: [PATCH] aibs: Add ASUSTeK AI Booster ACPI ATK0110 sensors Submitted-by: Constantine A. Murenin DragonFly bugs: --- share/man/man4/Makefile | 1 + share/man/man4/aibs.4 | 222 ++++++++++++++++++ sys/conf/files | 1 + sys/config/LINT | 1 + sys/dev/acpica5/Makefile | 2 +- sys/dev/acpica5/aibs/Makefile | 6 + sys/dev/acpica5/aibs/atk0110.c | 401 +++++++++++++++++++++++++++++++++ 7 files changed, 633 insertions(+), 1 deletion(-) create mode 100644 share/man/man4/aibs.4 create mode 100644 sys/dev/acpica5/aibs/Makefile create mode 100644 sys/dev/acpica5/aibs/atk0110.c diff --git a/share/man/man4/Makefile b/share/man/man4/Makefile index b3bca7beff..6b1160a936 100644 --- a/share/man/man4/Makefile +++ b/share/man/man4/Makefile @@ -20,6 +20,7 @@ MAN= aac.4 \ ahc.4 \ ahci.4 \ ahd.4 \ + aibs.4 \ ale.4 \ altq.4 \ amd.4 \ diff --git a/share/man/man4/aibs.4 b/share/man/man4/aibs.4 new file mode 100644 index 0000000000..aca806517c --- /dev/null +++ b/share/man/man4/aibs.4 @@ -0,0 +1,222 @@ +.\" $OpenBSD: aibs.4,v 1.4 2009/07/30 06:30:45 jmc Exp $ +.\" +.\" Copyright (c) 2009 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. +.\" +.Dd September 23, 2009 +.Dt AIBS 4 +.Os +.Sh NAME +.Nm aibs +.Nd "ASUSTeK AI Booster ACPI ATK0110 voltage, temperature and fan sensor" +.Sh SYNOPSIS +To compile this driver into the kernel, +place the following lines in your +kernel configuration file: +.Bd -ragged -offset indent +.Cd "device acpi" +.Cd "device aibs" +.Ed +.Pp +Alternatively, to load the driver as a +module at boot time, place the following lines in +.Xr loader.conf 5 : +.Bd -literal -offset indent +acpi_load="YES" +aibs_load="YES" +.Ed +.Sh DESCRIPTION +The +.Nm +driver provides support for the voltage, temperature and fan sensors +available through the +ATK0110 +ASOC +ACPI +device +on ASUSTeK motherboards. +The number of sensors of each type, +as well as the description of each sensor, +varies according to the motherboard. +.Pp +The driver supports an arbitrary set of sensors, +provides descriptions regarding what each sensor is used for, +and reports whether each sensor is within the specifications +as defined by the motherboard manufacturer through ACPI. +.Pp +The +.Nm +driver supports sensor states as follows: +temperature sensors can have a state of +.Dv OK , +.Dv WARN , +.Dv CRIT +or +.Dv UNKNOWN ; +fan and voltage sensors can have a state of +.Dv OK +or +.Dv WARN +only. +Temperature sensors that have a reading of 0 +are marked as invalid and their state is set to +.Dv UNKNOWN , +whereas all other sensors are always assumed valid. +Temperature sensors have two upper limits +.Dv ( WARN +and +.Dv CRIT ) , +fan sensors have either only the lower limit, or +one lower and one upper limit, +and voltage sensors always have a lower and an upper limit. +.Pp +Sensor values are made available through the +.Dv HW_SENSORS +.Xr sysctl 3 +interface, +and can be monitored with the +.Xr systat 1 +.Ar sensors +display, +.Xr sensorsd 8 +and +.Xr sysctl 8 +.Ar hw.sensors . +For example, on an Asus Stricker Extreme motherboard: +.Bd -literal -offset indent +$ sysctl hw.sensors.aibs0 +hw.sensors.aibs0.temp0=31.00 degC (CPU Temperature), OK +hw.sensors.aibs0.temp1=43.00 degC (MB Temperature), OK +hw.sensors.aibs0.fan0=2490 RPM (CPU FAN Speed), OK +hw.sensors.aibs0.fan1=0 RPM (CHASSIS FAN Speed), WARNING +hw.sensors.aibs0.fan2=0 RPM (OPT1 FAN Speed), WARNING +hw.sensors.aibs0.fan3=0 RPM (OPT2 FAN Speed), WARNING +hw.sensors.aibs0.fan4=0 RPM (OPT3 FAN Speed), WARNING +hw.sensors.aibs0.fan5=0 RPM (OPT4 FAN Speed), WARNING +hw.sensors.aibs0.fan6=0 RPM (OPT5 FAN Speed), WARNING +hw.sensors.aibs0.fan7=0 RPM (PWR FAN Speed), WARNING +hw.sensors.aibs0.volt0=1.26 VDC (Vcore Voltage), OK +hw.sensors.aibs0.volt1=3.25 VDC ( +3.3 Voltage), OK +hw.sensors.aibs0.volt2=4.95 VDC ( +5.0 Voltage), OK +hw.sensors.aibs0.volt3=11.78 VDC (+12.0 Voltage), OK +hw.sensors.aibs0.volt4=1.23 VDC (1.2VHT Voltage), OK +hw.sensors.aibs0.volt5=1.50 VDC (SB CORE Voltage), OK +hw.sensors.aibs0.volt6=1.25 VDC (CPU VTT Voltage), OK +hw.sensors.aibs0.volt7=0.93 VDC (DDR2 TERM Voltage), OK +hw.sensors.aibs0.volt8=1.23 VDC (NB CORE Voltage), OK +hw.sensors.aibs0.volt9=1.87 VDC (MEMORY Voltage), OK +.Ed +.Pp +Generally, sensors provided by the +.Nm +driver may also be supported by a variety of other drivers, +such as +.Xr lm 4 +or +.Xr it 4 . +The precise collection of +.Nm +sensors is comprised of the sensors +specifically utilised in the motherboard +design, which may be supported through +a combination of one or more physical hardware monitoring chips. +.Pp +The +.Nm +driver, however, provides the following advantages +when compared to the native hardware monitoring drivers: +.Bl -bullet +.It +Sensor values from +.Nm +are expected to be more reliable. +For example, voltage sensors in many hardware monitoring chips +can only sense voltage from 0 to 2 or 4 volts, and the excessive +voltage is removed by the resistors, which may vary with the motherboard +and with the voltage that is being sensed. +In +.Nm , +the required resistor factors are provided by +the motherboard manufacturer through ACPI; +in the native drivers, the resistor factors +are encoded into the driver based on the chip manufacturer's recommendations. +In essence, sensor values from +.Nm +are very likely to be identical to the readings from the +Hardware Monitor screen in the BIOS. +.It +Sensor descriptions from +.Nm +are more likely to match the markings on the motherboard. +.It +Sensor status is supported by +.Nm . +The status is reported based on the acceptable range of values +for each individual sensor as suggested by the motherboard manufacturer. +For example, the threshold for the CPU temperature sensor is likely +to be significantly higher than that for the chassis temperature sensor. +.It +Support for newer chips in +.Nm . +Newer chips may miss a native driver, +but should be supported through +.Nm +regardless. +.El +.Pp +As a result, sensor readings from the actual +native hardware monitoring drivers +are redundant when +.Nm +is present, and +may be ignored as appropriate. +Whereas on +.Ox +the native drivers have to be specifically disabled should +their presence be judged unnecessary, +on +.Dx +the +.Xr lm 4 +and +.Xr it 4 +are not probed provided that +.Xr acpi 4 +is configured and the system potentially supports +the hardware monitoring chip through ACPI. +.Sh SEE ALSO +.Xr systat 1 , +.Xr sysctl 3 , +.Xr acpi 4 , +.Xr intro 4 , +.Xr sensorsd 8 , +.Xr sysctl 8 +.Sh HISTORY +The +.Nm +driver first appeared in +.Ox 4.7 +and +.Dx 2.5 . +.Sh AUTHORS +The +.Nm +driver was written for +.Ox +and +.Dx +by +.An Constantine A. Murenin Aq http://cnst.su/ , +David R. Cheriton School of Computer Science, +University of Waterloo. diff --git a/sys/conf/files b/sys/conf/files index 2449b8344b..b3e8e75e72 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -1712,6 +1712,7 @@ ${OSACPI_MI_DIR}/acpi_asus/acpi_asus.c optional acpi_asus acpi ${OSACPI_MI_DIR}/acpi_toshiba/acpi_toshiba.c optional acpi_toshiba acpi ${OSACPI_MI_DIR}/acpi_thinkpad/acpi_thinkpad.c optional acpi_thinkpad acpi ${OSACPI_MI_DIR}/acpi_video/acpi_video.c optional acpi_video acpi +${OSACPI_MI_DIR}/aibs/atk0110.c optional aibs acpi # ACPICA code ${ACPICA_DIR}/debugger/dbcmds.c optional acpi acpi_debug diff --git a/sys/config/LINT b/sys/config/LINT index 5e2995bf7b..f8cee293dd 100644 --- a/sys/config/LINT +++ b/sys/config/LINT @@ -2663,6 +2663,7 @@ device acpi_asus # Asus laptop support device acpi_thinkpad # ThinkPad support device acpi_toshiba # Toshiba laptop support device acpi_video # ACPI video extensions +device aibs # ASUSTeK AI Booster (ACPI ASOC ATK0110) device pmtimer # adjust the system clock after resume # DRM options: diff --git a/sys/dev/acpica5/Makefile b/sys/dev/acpica5/Makefile index 48b9bda532..30574a6986 100644 --- a/sys/dev/acpica5/Makefile +++ b/sys/dev/acpica5/Makefile @@ -115,7 +115,7 @@ acpi_wakecode.h: acpi_wakecode.S ${MAKE} -f ${SYSDIR}/${OSACPI_MD_DIR}/Makefile \ MAKESRCPATH=${SYSDIR}/${OSACPI_MD_DIR} -SUBDIR= acpi_asus acpi_thinkpad acpi_toshiba acpi_video +SUBDIR= acpi_asus acpi_thinkpad acpi_toshiba acpi_video aibs all: ${PROG} ${SUBDIR} .include diff --git a/sys/dev/acpica5/aibs/Makefile b/sys/dev/acpica5/aibs/Makefile new file mode 100644 index 0000000000..d75641a6f2 --- /dev/null +++ b/sys/dev/acpica5/aibs/Makefile @@ -0,0 +1,6 @@ +KMOD= aibs +CFLAGS+= -I${.OBJDIR}/.. -I${.CURDIR}/.. +SRCS= atk0110.c +SRCS+= opt_acpi.h bus_if.h device_if.h + +.include diff --git a/sys/dev/acpica5/aibs/atk0110.c b/sys/dev/acpica5/aibs/atk0110.c new file mode 100644 index 0000000000..9a2978293a --- /dev/null +++ b/sys/dev/acpica5/aibs/atk0110.c @@ -0,0 +1,401 @@ +/* $OpenBSD: atk0110.c,v 1.1 2009/07/23 01:38:16 cnst Exp $ */ + +/* + * Copyright (c) 2009 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 +#include +#include +#include +#include +#include +#include + +#include + +#include "acpi.h" +#include "acpivar.h" + +/* + * ASUSTeK AI Booster (ACPI ATK0110). + * + * This code was originally written for OpenBSD after the techniques + * described in the Linux's asus_atk0110.c and FreeBSD's acpi_aiboost.c + * were verified to be accurate on the actual hardware kindly provided by + * Sam Fourman Jr. It was subsequently ported from OpenBSD to DragonFly BSD. + * + * -- Constantine A. Murenin + */ + +#define AIBS_MORE_SENSORS +#define AIBS_VERBOSE + +struct aibs_sensor { + struct ksensor s; + int64_t i; + int64_t l; + int64_t h; +}; + +struct aibs_softc { + struct device *sc_dev; + ACPI_HANDLE sc_ah; + + struct aibs_sensor *sc_asens_volt; + struct aibs_sensor *sc_asens_temp; + struct aibs_sensor *sc_asens_fan; + + struct ksensordev sc_sensordev; +}; + + +static int aibs_probe(struct device *); +static int aibs_attach(struct device *); +static int aibs_detach(struct device *); +static void aibs_refresh(void *); + +static void aibs_attach_sif(struct aibs_softc *, enum sensor_type); +static void aibs_refresh_r(struct aibs_softc *, enum sensor_type); + + +static device_method_t aibs_methods[] = { + DEVMETHOD(device_probe, aibs_probe), + DEVMETHOD(device_attach, aibs_attach), + DEVMETHOD(device_detach, aibs_detach), + { NULL, NULL } +}; + +static driver_t aibs_driver = { + "aibs", + aibs_methods, + sizeof(struct aibs_softc) +}; + +static devclass_t aibs_devclass; + +DRIVER_MODULE(aibs, acpi, aibs_driver, aibs_devclass, NULL, NULL); + + +static char* aibs_hids[] = { + "ATK0110", + NULL +}; + +static int +aibs_probe(struct device *dev) +{ + + if (acpi_disabled("aibs") || + ACPI_ID_PROBE(device_get_parent(dev), dev, aibs_hids) == NULL) + return ENXIO; + + device_set_desc(dev, "ASUSTeK AI Booster (ACPI ASOC ATK0110)"); + return 0; +} + +static int +aibs_attach(struct device *dev) +{ + struct aibs_softc *sc; + + sc = device_get_softc(dev); + sc->sc_dev = dev; + sc->sc_ah = acpi_get_handle(dev); + + strlcpy(sc->sc_sensordev.xname, device_get_nameunit(dev), + sizeof(sc->sc_sensordev.xname)); + + aibs_attach_sif(sc, SENSOR_VOLTS_DC); + aibs_attach_sif(sc, SENSOR_TEMP); + aibs_attach_sif(sc, SENSOR_FANRPM); + + if (sc->sc_sensordev.sensors_count == 0) { + device_printf(dev, "no sensors found\n"); + return ENXIO; + } + + if (sensor_task_register(sc, aibs_refresh, 5)) { + device_printf(dev, "unable to register update task\n"); + return ENXIO; + } + + sensordev_install(&sc->sc_sensordev); + return 0; +} + +static void +aibs_attach_sif(struct aibs_softc *sc, enum sensor_type st) +{ + ACPI_STATUS s; + ACPI_BUFFER b; + ACPI_OBJECT *bp, *o; + int i, n; + char name[] = "?SIF"; + struct aibs_sensor *as; + + switch (st) { + case SENSOR_TEMP: + name[0] = 'T'; + break; + case SENSOR_FANRPM: + name[0] = 'F'; + break; + case SENSOR_VOLTS_DC: + name[0] = 'V'; + break; + default: + return; + } + + b.Length = ACPI_ALLOCATE_BUFFER; + s = AcpiEvaluateObjectTyped(sc->sc_ah, name, NULL, &b, + ACPI_TYPE_PACKAGE); + if (ACPI_FAILURE(s)) { + device_printf(sc->sc_dev, "%s not found\n", name); + return; + } + + bp = b.Pointer; + o = bp->Package.Elements; + if (o[0].Type != ACPI_TYPE_INTEGER) { + device_printf(sc->sc_dev, "%s[0]: invalid type\n", name); + AcpiOsFree(b.Pointer); + return; + } + + n = o[0].Integer.Value; + if (bp->Package.Count - 1 < n) { + device_printf(sc->sc_dev, "%s: invalid package\n", name); + AcpiOsFree(b.Pointer); + return; + } else if (bp->Package.Count - 1 > n) { + int on = n; + +#ifdef AIBS_MORE_SENSORS + n = bp->Package.Count - 1; +#endif + device_printf(sc->sc_dev, "%s: misformed package: %i/%i" + ", assume %i\n", name, on, bp->Package.Count - 1, n); + } + if (n < 1) { + device_printf(sc->sc_dev, "%s: no members in the package\n", + name); + AcpiOsFree(b.Pointer); + return; + } + + as = kmalloc(sizeof(*as) * n, M_DEVBUF, M_NOWAIT | M_ZERO); + if (as == NULL) { + device_printf(sc->sc_dev, "%s: malloc fail\n", name); + AcpiOsFree(b.Pointer); + return; + } + + switch (st) { + case SENSOR_TEMP: + sc->sc_asens_temp = as; + break; + case SENSOR_FANRPM: + sc->sc_asens_fan = as; + break; + case SENSOR_VOLTS_DC: + sc->sc_asens_volt = as; + break; + default: + /* NOTREACHED */ + return; + } + + for (i = 0, o++; i < n; i++, o++) { + ACPI_OBJECT *oi; + + /* acpica5 automatically evaluates the referenced package */ + if(o[0].Type != ACPI_TYPE_PACKAGE) { + device_printf(sc->sc_dev, + "%s: %i: not a package: %i type\n", + name, i, o[0].Type); + continue; + } + oi = o[0].Package.Elements; + if (o[0].Package.Count != 5 || + oi[0].Type != ACPI_TYPE_INTEGER || + oi[1].Type != ACPI_TYPE_STRING || + oi[2].Type != ACPI_TYPE_INTEGER || + oi[3].Type != ACPI_TYPE_INTEGER || + oi[4].Type != ACPI_TYPE_INTEGER) { + device_printf(sc->sc_dev, + "%s: %i: invalid package\n", + name, i); + continue; + } + as[i].i = oi[0].Integer.Value; + strlcpy(as[i].s.desc, oi[1].String.Pointer, + sizeof(as[i].s.desc)); + as[i].l = oi[2].Integer.Value; + as[i].h = oi[3].Integer.Value; + as[i].s.type = st; +#ifdef AIBS_VERBOSE + device_printf(sc->sc_dev, "%c%i: " + "0x%08llx %20s %5lli / %5lli 0x%llx\n", + name[0], i, + as[i].i, as[i].s.desc, as[i].l, as[i].h, + oi[4].Integer.Value); +#endif + sensor_attach(&sc->sc_sensordev, &as[i].s); + } + + AcpiOsFree(b.Pointer); + return; +} + +static int +aibs_detach(struct device *dev) +{ + struct aibs_softc *sc = device_get_softc(dev); + + sensordev_deinstall(&sc->sc_sensordev); + sensor_task_unregister(sc); + if (sc->sc_asens_volt != NULL) + kfree(sc->sc_asens_volt, M_DEVBUF); + if (sc->sc_asens_temp != NULL) + kfree(sc->sc_asens_temp, M_DEVBUF); + if (sc->sc_asens_fan != NULL) + kfree(sc->sc_asens_fan, M_DEVBUF); + return 0; +} + +#ifdef AIBS_VERBOSE +#define ddevice_printf(x...) device_printf(x) +#else +#define ddevice_printf(x...) +#endif + +static void +aibs_refresh(void *arg) +{ + struct aibs_softc *sc = arg; + + aibs_refresh_r(sc, SENSOR_VOLTS_DC); + aibs_refresh_r(sc, SENSOR_TEMP); + aibs_refresh_r(sc, SENSOR_FANRPM); +} + +static void +aibs_refresh_r(struct aibs_softc *sc, enum sensor_type st) +{ + ACPI_STATUS rs; + ACPI_HANDLE rh; + int i, n = sc->sc_sensordev.maxnumt[st]; + char *name; + struct aibs_sensor *as; + + switch (st) { + case SENSOR_TEMP: + name = "RTMP"; + as = sc->sc_asens_temp; + break; + case SENSOR_FANRPM: + name = "RFAN"; + as = sc->sc_asens_fan; + break; + case SENSOR_VOLTS_DC: + name = "RVLT"; + as = sc->sc_asens_volt; + break; + default: + return; + } + + if (as == NULL) + return; + + rs = AcpiGetHandle(sc->sc_ah, name, &rh); + if (ACPI_FAILURE(rs)) { + ddevice_printf(sc->sc_dev, "%s: method handle not found\n", + name); + for (i = 0; i < n; i++) + as[i].s.flags |= SENSOR_FINVALID; + return; + } + + for (i = 0; i < n; i++) { + ACPI_OBJECT p, *bp; + ACPI_OBJECT_LIST mp; + ACPI_BUFFER b; + int64_t v; + struct ksensor *s = &as[i].s; + const int64_t l = as[i].l, h = as[i].h; + + p.Type = ACPI_TYPE_INTEGER; + p.Integer.Value = as[i].i; + mp.Count = 1; + mp.Pointer = &p; + b.Length = ACPI_ALLOCATE_BUFFER; + rs = AcpiEvaluateObjectTyped(rh, NULL, &mp, &b, + ACPI_TYPE_INTEGER); + if (ACPI_FAILURE(rs)) { + ddevice_printf(sc->sc_dev, + "%s: %i: evaluation failed\n", + name, i); + s->flags |= SENSOR_FINVALID; + continue; + } + bp = b.Pointer; + v = bp->Integer.Value; + AcpiOsFree(b.Pointer); + + switch (st) { + case SENSOR_TEMP: + s->value = v * 100 * 1000 + 273150000; + if (v == 0) { + s->status = SENSOR_S_UNKNOWN; + s->flags |= SENSOR_FINVALID; + } else { + if (v > h) + s->status = SENSOR_S_CRIT; + else if (v > l) + s->status = SENSOR_S_WARN; + else + s->status = SENSOR_S_OK; + s->flags &= ~SENSOR_FINVALID; + } + break; + case SENSOR_FANRPM: + s->value = v; + /* some boards have strange limits for fans */ + if ((l != 0 && l < v && v < h) || + (l == 0 && v > h)) + s->status = SENSOR_S_OK; + else + s->status = SENSOR_S_WARN; + s->flags &= ~SENSOR_FINVALID; + break; + case SENSOR_VOLTS_DC: + s->value = v * 1000; + if (l < v && v < h) + s->status = SENSOR_S_OK; + else + s->status = SENSOR_S_WARN; + s->flags &= ~SENSOR_FINVALID; + break; + default: + /* NOTREACHED */ + break; + } + } + + return; +} -- 2.41.0