Module Name: src Committed By: jruoho Date: Sun Jun 12 07:25:44 UTC 2011
Modified Files: src/share/man/man4: aibs.4 src/sys/dev/acpi: files.acpi src/sys/modules/aibs: Makefile Added Files: src/sys/dev/acpi: aibs_acpi.c Removed Files: src/sys/dev/acpi: atk0110.c Log Message: Rewrite the aibs(4) driver in order to support new models. Draws from the revision 1.6 (claudio@) of the OpenBSD's equivalent driver. Tested by mrg@. To generate a diff of this commit: cvs rdiff -u -r1.6 -r1.7 src/share/man/man4/aibs.4 cvs rdiff -u -r0 -r1.1 src/sys/dev/acpi/aibs_acpi.c cvs rdiff -u -r1.16 -r0 src/sys/dev/acpi/atk0110.c cvs rdiff -u -r1.88 -r1.89 src/sys/dev/acpi/files.acpi cvs rdiff -u -r1.3 -r1.4 src/sys/modules/aibs/Makefile Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/share/man/man4/aibs.4 diff -u src/share/man/man4/aibs.4:1.6 src/share/man/man4/aibs.4:1.7 --- src/share/man/man4/aibs.4:1.6 Sat Mar 6 19:53:33 2010 +++ src/share/man/man4/aibs.4 Sun Jun 12 07:25:43 2011 @@ -1,4 +1,4 @@ -.\" $NetBSD: aibs.4,v 1.6 2010/03/06 19:53:33 cnst Exp $ +.\" $NetBSD: aibs.4,v 1.7 2011/06/12 07:25:43 jruoho Exp $ .\" $OpenBSD: aibs.4,v 1.4 2009/07/30 06:30:45 jmc Exp $ .\" .\" Copyright (c) 2009 Constantine A. Murenin <cnst+net...@bugmail.mojo.ru> @@ -15,24 +15,21 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd February 8, 2010 +.Dd June 12, 2011 .Dt AIBS 4 .Os .Sh NAME .Nm aibs -.Nd ASUSTeK AI Booster ACPI ATK0110 voltage, temperature, and fan sensor +.Nd ASUSTeK AI Booster voltage, temperature, and fan sensor .Sh SYNOPSIS .Cd "aibs* at acpi?" .Sh DESCRIPTION The .Nm -driver provides support for the voltage, temperature and fan sensors -available through the -.Tn ATK0110 -.Tn ASOC +driver provides support for voltage, temperature, and fan sensors +available as an .Tn ACPI -device -on +device on .Tn ASUSTeK motherboards. The number of sensors of each type, @@ -53,43 +50,43 @@ .Bl -bullet .It Voltage sensors can have a state of -.Dv valid , -.Dv critunder , +.Sq valid , +.Sq critunder , or -.Dv critover ; +.Sq critover ; temperature sensors can have a state of -.Dv valid , -.Dv warnover , -.Dv critover , +.Sq valid , +.Sq warnover , +.Sq critover , or -.Dv invalid ; +.Sq invalid ; and fan sensors can have a state of -.Dv valid , -.Dv warnunder , +.Sq valid , +.Sq warnunder , or -.Dv warnover . +.Sq warnover . .It Temperature sensors that have a reading of 0 are marked -.Dv invalid , +.Sq invalid , whereas all other sensors are always assumed valid. .It -Voltage sensors have a lower and an upper limit -.Dv ( critunder +Voltage sensors have a lower and an upper limit, +.Sq critunder and -.Dv critover ) , -temperature sensors have two upper limits -.Dv ( warnover +.Sq critover , +temperature sensors have two upper limits, +.Sq warnover and -.Dv critover ) , +.Sq critover , whereas fan sensors may either have only the lower limit -.Dv ( warnunder ) , -or, depending on the -.Tn DSDT , -one lower and one upper limit -.Dv ( warnunder +.Sq warnunder , +or, depending on the vendor's +.Tn ACPI +implementation, one lower and one upper limit, +.Sq warnunder and -.Dv warnover ) . +.Sq warnover . .El .Pp Sensor values and limits are made available through the @@ -189,6 +186,7 @@ the hardware monitoring chip through .Tn ACPI . .Sh SEE ALSO +.Xr acpi 4 , .Xr envsys 4 , .Xr envstat 8 .Sh HISTORY @@ -199,8 +197,7 @@ DragonFly 2.4.1 and .Nx 6.0 . -.Pp -An earlier version of the driver, +An earlier version of the driver, named .Nm aiboost , first appeared in .Fx 7.0 @@ -212,16 +209,19 @@ .Nm driver was written for .Ox , -DragonFly -and +DragonFly BSD, and .Nx by .An Constantine A. Murenin Aq http://cnst.su/ , Raouf Boutaba Research Group, David R. Cheriton School of Computer Science, University of Waterloo. -.Pp -An earlier version of the driver, named +.An Jukka Ruohonen +.Aq jruoho...@iki.fi +later reworked and adjusted the driver to support new +.Tn ASUSTeK +motherboards. +The earlier version of the driver, .Nm aiboost , was written for .Fx Index: src/sys/dev/acpi/files.acpi diff -u src/sys/dev/acpi/files.acpi:1.88 src/sys/dev/acpi/files.acpi:1.89 --- src/sys/dev/acpi/files.acpi:1.88 Sun Feb 27 17:10:33 2011 +++ src/sys/dev/acpi/files.acpi Sun Jun 12 07:25:43 2011 @@ -1,4 +1,4 @@ -# $NetBSD: files.acpi,v 1.88 2011/02/27 17:10:33 jruoho Exp $ +# $NetBSD: files.acpi,v 1.89 2011/06/12 07:25:43 jruoho Exp $ include "dev/acpi/acpica/files.acpica" @@ -180,10 +180,10 @@ attach wb at acpinodebus with wb_acpi file dev/acpi/wb_acpi.c wb_acpi -# ASUSTeK AI Booster ATK0110 +# ASUSTeK AI Booster device aibs: sysmon_envsys attach aibs at acpinodebus -file dev/acpi/atk0110.c aibs +file dev/acpi/aibs_acpi.c aibs # ACPI SMBus controller device acpismbus: i2cbus Index: src/sys/modules/aibs/Makefile diff -u src/sys/modules/aibs/Makefile:1.3 src/sys/modules/aibs/Makefile:1.4 --- src/sys/modules/aibs/Makefile:1.3 Wed Feb 16 08:08:14 2011 +++ src/sys/modules/aibs/Makefile Sun Jun 12 07:25:43 2011 @@ -1,4 +1,4 @@ -# $NetBSD: Makefile,v 1.3 2011/02/16 08:08:14 jruoho Exp $ +# $NetBSD: Makefile,v 1.4 2011/06/12 07:25:43 jruoho Exp $ .include "../Makefile.inc" @@ -6,7 +6,7 @@ KMOD= aibs IOCONF= aibs.ioconf -SRCS= atk0110.c +SRCS= aibs_acpi.c WARNS= 4 Added files: Index: src/sys/dev/acpi/aibs_acpi.c diff -u /dev/null src/sys/dev/acpi/aibs_acpi.c:1.1 --- /dev/null Sun Jun 12 07:25:44 2011 +++ src/sys/dev/acpi/aibs_acpi.c Sun Jun 12 07:25:43 2011 @@ -0,0 +1,742 @@ +/* $NetBSD: aibs_acpi.c,v 1.1 2011/06/12 07:25:43 jruoho Exp $ */ + +/*- + * Copyright (c) 2011 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jukka Ruohonen. + * + * 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 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. + */ + +/* $OpenBSD: atk0110.c,v 1.1 2009/07/23 01:38:16 cnst Exp $ */ +/* + * Copyright (c) 2009 Constantine A. Murenin <cnst+net...@bugmail.mojo.ru> + * + * 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> +__KERNEL_RCSID(0, "$NetBSD: aibs_acpi.c,v 1.1 2011/06/12 07:25:43 jruoho Exp $"); + +#include <sys/param.h> +#include <sys/kmem.h> +#include <sys/module.h> + +#include <dev/acpi/acpireg.h> +#include <dev/acpi/acpivar.h> + +/* + * ASUSTeK AI Booster (ACPI ASOC 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, + * and then to the NetBSD's sysmon_envsys(9) framework. + * + * -- Constantine A. Murenin <http://cnst.su/> + */ + +#define _COMPONENT ACPI_RESOURCE_COMPONENT +ACPI_MODULE_NAME ("acpi_aibs") + +#define AIBS_MUX_HWMON 0x00000006 +#define AIBS_MUX_MGMT 0x00000011 + +#define AIBS_TYPE(x) (((x) >> 16) & 0xff) +#define AIBS_TYPE_VOLT 2 +#define AIBS_TYPE_TEMP 3 +#define AIBS_TYPE_FAN 4 + +struct aibs_sensor { + envsys_data_t as_sensor; + uint64_t as_type; + uint64_t as_liml; + uint64_t as_limh; + + SIMPLEQ_ENTRY(aibs_sensor) as_list; +}; + +struct aibs_softc { + device_t sc_dev; + struct acpi_devnode *sc_node; + struct sysmon_envsys *sc_sme; + bool sc_model; /* new model = true */ + + SIMPLEQ_HEAD(, aibs_sensor) as_head; +}; + +static int aibs_match(device_t, cfdata_t, void *); +static void aibs_attach(device_t, device_t, void *); +static int aibs_detach(device_t, int); + +static void aibs_init(device_t); +static void aibs_init_new(device_t); +static void aibs_init_old(device_t, int); + +static void aibs_sensor_add(device_t, ACPI_OBJECT *); +static bool aibs_sensor_value(device_t, struct aibs_sensor *, uint64_t *); +static void aibs_sensor_refresh(struct sysmon_envsys *, envsys_data_t *); +static void aibs_sensor_limits(struct sysmon_envsys *, envsys_data_t *, + sysmon_envsys_lim_t *, uint32_t *); + +CFATTACH_DECL_NEW(aibs, sizeof(struct aibs_softc), + aibs_match, aibs_attach, aibs_detach, NULL); + +static const char* const aibs_hid[] = { + "ATK0110", + NULL +}; + +static int +aibs_match(device_t parent, cfdata_t match, void *aux) +{ + struct acpi_attach_args *aa = aux; + + if (aa->aa_node->ad_type != ACPI_TYPE_DEVICE) + return 0; + + return acpi_match_hid(aa->aa_node->ad_devinfo, aibs_hid); +} + +static void +aibs_attach(device_t parent, device_t self, void *aux) +{ + struct aibs_softc *sc = device_private(self); + struct acpi_attach_args *aa = aux; + + sc->sc_dev = self; + sc->sc_node = aa->aa_node; + + aprint_naive("\n"); + aprint_normal(": ASUSTeK AI Booster\n"); + + sc->sc_sme = sysmon_envsys_create(); + + sc->sc_sme->sme_cookie = sc; + sc->sc_sme->sme_name = device_xname(self); + sc->sc_sme->sme_refresh = aibs_sensor_refresh; + sc->sc_sme->sme_get_limits = aibs_sensor_limits; + + aibs_init(self); + SIMPLEQ_INIT(&sc->as_head); + + if (sc->sc_model != false) + aibs_init_new(self); + else { + aibs_init_old(self, AIBS_TYPE_FAN); + aibs_init_old(self, AIBS_TYPE_TEMP); + aibs_init_old(self, AIBS_TYPE_VOLT); + } + + (void)pmf_device_register(self, NULL, NULL); + + if (sc->sc_sme->sme_nsensors == 0) { + aprint_error_dev(self, "no sensors found\n"); + sysmon_envsys_destroy(sc->sc_sme); + sc->sc_sme = NULL; + return; + } + + if (sysmon_envsys_register(sc->sc_sme) != 0) + aprint_error_dev(self, "failed to register with sysmon\n"); +} + +static int +aibs_detach(device_t self, int flags) +{ + struct aibs_softc *sc = device_private(self); + struct aibs_sensor *as; + + pmf_device_deregister(self); + + if (sc->sc_sme != NULL) + sysmon_envsys_unregister(sc->sc_sme); + + while (SIMPLEQ_FIRST(&sc->as_head) != NULL) { + as = SIMPLEQ_FIRST(&sc->as_head); + SIMPLEQ_REMOVE_HEAD(&sc->as_head, as_list); + kmem_free(as, sizeof(*as)); + } + + return 0; +} + +static void +aibs_init(device_t self) +{ + struct aibs_softc *sc = device_private(self); + ACPI_HANDLE tmp; + ACPI_STATUS rv; + + /* + * Old model uses the tuple { TSIF, VSIF, FSIF } to + * enumerate the sensors and { RTMP, RVLT, RFAN } + * to obtain the values. New mode uses GGRP for the + * enumeration and { GITM, SITM } as accessors. + */ + rv = AcpiGetHandle(sc->sc_node->ad_handle, "GGRP", &tmp); + + if (ACPI_FAILURE(rv)) { + sc->sc_model = false; + return; + } + + rv = AcpiGetHandle(sc->sc_node->ad_handle, "GITM", &tmp); + + if (ACPI_FAILURE(rv)) { + sc->sc_model = false; + return; + } + + rv = AcpiGetHandle(sc->sc_node->ad_handle, "SITM", &tmp); + + if (ACPI_FAILURE(rv)) { + sc->sc_model = false; + return; + } + + sc->sc_model = true; +} + +static void +aibs_init_new(device_t self) +{ + struct aibs_softc *sc = device_private(self); + ACPI_OBJECT_LIST arg; + ACPI_OBJECT id, *obj; + ACPI_BUFFER buf; + ACPI_STATUS rv; + uint32_t i, n; + + arg.Count = 1; + arg.Pointer = &id; + + id.Type = ACPI_TYPE_INTEGER; + id.Integer.Value = AIBS_MUX_HWMON; + + buf.Pointer = NULL; + buf.Length = ACPI_ALLOCATE_LOCAL_BUFFER; + + rv = AcpiEvaluateObject(sc->sc_node->ad_handle, "GGRP", &arg, &buf); + + if (ACPI_FAILURE(rv)) + goto out; + + obj = buf.Pointer; + + if (obj->Type != ACPI_TYPE_PACKAGE) { + rv = AE_TYPE; + goto out; + } + + if (obj->Package.Count > UINT32_MAX) { + rv = AE_AML_NUMERIC_OVERFLOW; + goto out; + } + + n = obj->Package.Count; + + if (n == 0) { + rv = AE_NOT_EXIST; + goto out; + } + + for (i = 0; i < n; i++) + aibs_sensor_add(self, &obj->Package.Elements[i]); + +out: + if (buf.Pointer != NULL) + ACPI_FREE(buf.Pointer); + + if (ACPI_FAILURE(rv)) { + + aprint_error_dev(self, "failed to evaluate " + "GGRP: %s\n", AcpiFormatException(rv)); + } +} + +static void +aibs_init_old(device_t self, int type) +{ + struct aibs_softc *sc = device_private(self); + char path[] = "?SIF"; + ACPI_OBJECT *elm, *obj; + ACPI_BUFFER buf; + ACPI_STATUS rv; + uint32_t i, n; + + switch (type) { + + case AIBS_TYPE_FAN: + path[0] = 'F'; + break; + + case AIBS_TYPE_TEMP: + path[0] = 'T'; + break; + + case AIBS_TYPE_VOLT: + path[0] = 'V'; + break; + + default: + return; + } + + rv = acpi_eval_struct(sc->sc_node->ad_handle, path, &buf); + + if (ACPI_FAILURE(rv)) + goto out; + + obj = buf.Pointer; + + if (obj->Type != ACPI_TYPE_PACKAGE) { + rv = AE_TYPE; + goto out; + } + + elm = obj->Package.Elements; + + if (elm[0].Type != ACPI_TYPE_INTEGER) { + rv = AE_TYPE; + goto out; + } + + if (elm[0].Integer.Value > UINT32_MAX) { + rv = AE_AML_NUMERIC_OVERFLOW; + goto out; + } + + n = elm[0].Integer.Value; + + if (n == 0) { + rv = AE_NOT_EXIST; + goto out; + } + + if (obj->Package.Count - 1 != n) { + rv = AE_BAD_VALUE; + goto out; + } + + for (i = 1; i < obj->Package.Count; i++) { + + if (elm[i].Type != ACPI_TYPE_PACKAGE) + continue; + + aibs_sensor_add(self, &elm[i]); + } + +out: + if (buf.Pointer != NULL) + ACPI_FREE(buf.Pointer); + + if (ACPI_FAILURE(rv)) { + + aprint_error_dev(self, "failed to evaluate " + "%s: %s\n", path, AcpiFormatException(rv)); + } +} + +static void +aibs_sensor_add(device_t self, ACPI_OBJECT *obj) +{ + struct aibs_softc *sc = device_private(self); + struct aibs_sensor *as; + int ena, len, lhi, llo; + const char *name; + ACPI_STATUS rv; + + as = NULL; + rv = AE_OK; + + if (obj->Type != ACPI_TYPE_PACKAGE) { + rv = AE_TYPE; + goto out; + } + + /* + * The known formats are: + * + * index type old new + * ----- ---- --- --- + * 0 integer flags flags + * 1 string name name + * 2 integer limit1 unknown + * 3 integer limit2 unknown + * 4 integer enable limit1 + * 5 integer - limit2 + * 6 integer - enable + */ + if (sc->sc_model != false) { + len = 7; + llo = 4; + lhi = 5; + ena = 6; + } else { + len = 5; + llo = 2; + lhi = 3; + ena = 4; + } + + if (obj->Package.Count != (uint32_t)len) { + rv = AE_LIMIT; + goto out; + } + + if (obj->Package.Elements[0].Type != ACPI_TYPE_INTEGER || + obj->Package.Elements[1].Type != ACPI_TYPE_STRING || + obj->Package.Elements[llo].Type != ACPI_TYPE_INTEGER || + obj->Package.Elements[lhi].Type != ACPI_TYPE_INTEGER || + obj->Package.Elements[ena].Type != ACPI_TYPE_INTEGER) { + rv = AE_TYPE; + goto out; + } + + as = kmem_zalloc(sizeof(*as), KM_SLEEP); + + if (as == NULL) { + rv = AE_NO_MEMORY; + goto out; + } + + name = obj->Package.Elements[1].String.Pointer; + + as->as_type = obj->Package.Elements[0].Integer.Value; + as->as_liml = obj->Package.Elements[llo].Integer.Value; + as->as_limh = obj->Package.Elements[lhi].Integer.Value; + + if (sc->sc_model != false) + as->as_limh += as->as_liml; /* A range in the new model. */ + + switch (AIBS_TYPE(as->as_type)) { + + case AIBS_TYPE_FAN: + as->as_sensor.units = ENVSYS_SFANRPM; + as->as_sensor.flags |= ENVSYS_FMONLIMITS; + break; + + case AIBS_TYPE_TEMP: + as->as_sensor.units = ENVSYS_STEMP; + as->as_sensor.flags |= ENVSYS_FMONLIMITS; + break; + + case AIBS_TYPE_VOLT: + as->as_sensor.units = ENVSYS_SVOLTS_DC; + as->as_sensor.flags |= ENVSYS_FMONLIMITS; + break; + + default: + rv = AE_TYPE; + goto out; + } + + (void)strlcpy(as->as_sensor.desc, name, sizeof(as->as_sensor.desc)); + + if (sysmon_envsys_sensor_attach(sc->sc_sme, &as->as_sensor) != 0) { + rv = AE_AML_INTERNAL; + goto out; + } + + SIMPLEQ_INSERT_TAIL(&sc->as_head, as, as_list); + +out: + if (ACPI_FAILURE(rv)) { + + if (as != NULL) + kmem_free(as, sizeof(*as)); + + aprint_error_dev(self, "failed to add " + "sensor: %s\n", AcpiFormatException(rv)); + } +} + +static bool +aibs_sensor_value(device_t self, struct aibs_sensor *as, uint64_t *val) +{ + struct aibs_softc *sc = device_private(self); + uint32_t type, *ret, cmb[3]; + ACPI_OBJECT_LIST arg; + ACPI_OBJECT cmi, tmp; + ACPI_OBJECT *obj; + ACPI_BUFFER buf; + ACPI_STATUS rv; + const char *path; + + if (sc->sc_model != false) { + + path = "GITM"; + + cmb[0] = as->as_type; + cmb[1] = 0; + cmb[2] = 0; + + arg.Count = 1; + arg.Pointer = &tmp; + + tmp.Buffer.Length = sizeof(cmb); + tmp.Buffer.Pointer = (uint8_t *)cmb; + tmp.Type = type = ACPI_TYPE_BUFFER; + + } else { + + arg.Count = 1; + arg.Pointer = &cmi; + + cmi.Integer.Value = as->as_type; + cmi.Type = type = ACPI_TYPE_INTEGER; + + switch (AIBS_TYPE(as->as_type)) { + + case AIBS_TYPE_FAN: + path = "RFAN"; + break; + + case AIBS_TYPE_TEMP: + path = "RTMP"; + break; + + case AIBS_TYPE_VOLT: + path = "RVLT"; + break; + + default: + return false; + } + } + + buf.Pointer = NULL; + buf.Length = ACPI_ALLOCATE_LOCAL_BUFFER; + + rv = AcpiEvaluateObject(sc->sc_node->ad_handle, path, &arg, &buf); + + if (ACPI_FAILURE(rv)) + goto out; + + obj = buf.Pointer; + + if (obj->Type != type) { + rv = AE_TYPE; + goto out; + } + + if (sc->sc_model != true) + *val = obj->Integer.Value; + else { + /* + * The return buffer contains at least: + * + * uint32_t buf[0] flags + * uint32_t buf[1] return value + * uint8_t buf[2-] unknown + */ + if (obj->Buffer.Length < 8) { + rv = AE_BUFFER_OVERFLOW; + goto out; + } + + ret = (uint32_t *)obj->Buffer.Pointer; + + if (ret[0] == 0) { + rv = AE_BAD_VALUE; + goto out; + } + + *val = ret[1]; + } + +out: + if (buf.Pointer != NULL) + ACPI_FREE(buf.Pointer); + + if (ACPI_FAILURE(rv)) { + + aprint_error_dev(self, "failed to evaluate " + "%s: %s\n", path, AcpiFormatException(rv)); + + return false; + } + + return true; +} + +static void +aibs_sensor_refresh(struct sysmon_envsys *sme, envsys_data_t *edata) +{ + struct aibs_softc *sc = sme->sme_cookie; + struct aibs_sensor *tmp, *as = NULL; + envsys_data_t *s = edata; + uint64_t val = 0; + + SIMPLEQ_FOREACH(tmp, &sc->as_head, as_list) { + + if (tmp->as_sensor.sensor == s->sensor) { + as = tmp; + break; + } + } + + if (as == NULL) { + aprint_debug_dev(sc->sc_dev, "failed to find sensor\n"); + return; + } + + as->as_sensor.state = ENVSYS_SINVALID; + as->as_sensor.flags |= ENVSYS_FMONNOTSUPP; + + if (aibs_sensor_value(sc->sc_dev, as, &val) != true) + return; + + switch (as->as_sensor.units) { + + case ENVSYS_SFANRPM: + as->as_sensor.value_cur = val; + break; + + case ENVSYS_STEMP: + + if (val == 0) + return; + + as->as_sensor.value_cur = val * 100 * 1000 + 273150000; + break; + + case ENVSYS_SVOLTS_DC: + as->as_sensor.value_cur = val * 1000; + break; + + default: + return; + } + + as->as_sensor.state = ENVSYS_SVALID; + as->as_sensor.flags &= ~ENVSYS_FMONNOTSUPP; +} + +static void +aibs_sensor_limits(struct sysmon_envsys *sme, envsys_data_t *edata, + sysmon_envsys_lim_t *limits, uint32_t *props) +{ + struct aibs_softc *sc = sme->sme_cookie; + struct aibs_sensor *tmp, *as = NULL; + sysmon_envsys_lim_t *lim = limits; + envsys_data_t *s = edata; + + SIMPLEQ_FOREACH(tmp, &sc->as_head, as_list) { + + if (tmp->as_sensor.sensor == s->sensor) { + as = tmp; + break; + } + } + + if (as == NULL) { + aprint_debug_dev(sc->sc_dev, "failed to find sensor\n"); + return; + } + + switch (as->as_sensor.units) { + + case ENVSYS_SFANRPM: + + /* + * Some boards have strange limits for fans. + */ + if (as->as_liml == 0) { + lim->sel_warnmin = as->as_limh; + *props = PROP_WARNMIN; + + } else { + lim->sel_warnmin = as->as_liml; + lim->sel_warnmax = as->as_limh; + *props = PROP_WARNMIN | PROP_WARNMAX; + } + + break; + + case ENVSYS_STEMP: + lim->sel_critmax = as->as_limh * 100 * 1000 + 273150000; + lim->sel_warnmax = as->as_liml * 100 * 1000 + 273150000; + + *props = PROP_CRITMAX | PROP_WARNMAX; + break; + + case ENVSYS_SVOLTS_DC: + lim->sel_critmin = as->as_liml * 1000; + lim->sel_critmax = as->as_limh * 1000; + *props = PROP_CRITMIN | PROP_CRITMAX; + break; + + default: + return; + } +} + +MODULE(MODULE_CLASS_DRIVER, aibs, NULL); + +#ifdef _MODULE +#include "ioconf.c" +#endif + +static int +aibs_modcmd(modcmd_t cmd, void *aux) +{ + int rv = 0; + + switch (cmd) { + + case MODULE_CMD_INIT: + +#ifdef _MODULE + rv = config_init_component(cfdriver_ioconf_aibs, + cfattach_ioconf_aibs, cfdata_ioconf_aibs); +#endif + break; + + case MODULE_CMD_FINI: + +#ifdef _MODULE + rv = config_fini_component(cfdriver_ioconf_aibs, + cfattach_ioconf_aibs, cfdata_ioconf_aibs); +#endif + break; + + default: + rv = ENOTTY; + } + + return rv; +}