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@.
This commit is contained in:
jruoho 2011-06-12 07:25:43 +00:00
parent 4ae6ef6285
commit ef74b36d13
5 changed files with 785 additions and 501 deletions

View File

@ -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+netbsd@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 @@ sensor states as follows:
.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 @@ is configured and the system potentially supports
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 @@ driver first appeared in
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 @@ The
.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 jruohonen@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

742
sys/dev/acpi/aibs_acpi.c Normal file
View File

@ -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+netbsd@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;
}

View File

@ -1,458 +0,0 @@
/* $NetBSD: atk0110.c,v 1.16 2011/02/16 09:05:12 jruoho Exp $ */
/* $OpenBSD: atk0110.c,v 1.1 2009/07/23 01:38:16 cnst Exp $ */
/*
* Copyright (c) 2009 Constantine A. Murenin <cnst+netbsd@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: atk0110.c,v 1.16 2011/02/16 09:05:12 jruoho Exp $");
#include <sys/param.h>
#include <sys/kmem.h>
#include <sys/module.h>
#include <sys/systm.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")
struct aibs_sensor {
envsys_data_t s;
ACPI_INTEGER i;
ACPI_INTEGER l;
ACPI_INTEGER h;
};
struct aibs_softc {
struct acpi_devnode *sc_node;
struct sysmon_envsys *sc_sme;
struct aibs_sensor *sc_asens_volt;
struct aibs_sensor *sc_asens_temp;
struct aibs_sensor *sc_asens_fan;
uint32_t sc_asens_volt_count;
uint32_t sc_asens_temp_count;
uint32_t sc_asens_fan_count;
};
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_refresh(struct sysmon_envsys *, envsys_data_t *);
static void aibs_get_limits(struct sysmon_envsys *, envsys_data_t *,
sysmon_envsys_lim_t *, uint32_t *);
static void aibs_attach_sif(device_t, enum envsys_units);
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_node = aa->aa_node;
aprint_naive(": ASUSTeK AI Booster\n");
aprint_normal(": ASUSTeK AI Booster\n");
sc->sc_sme = sysmon_envsys_create();
sc->sc_sme->sme_name = device_xname(self);
sc->sc_sme->sme_cookie = sc;
sc->sc_sme->sme_refresh = aibs_refresh;
sc->sc_sme->sme_get_limits = aibs_get_limits;
aibs_attach_sif(self, ENVSYS_SVOLTS_DC);
aibs_attach_sif(self, ENVSYS_STEMP);
aibs_attach_sif(self, ENVSYS_SFANRPM);
(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);
return;
}
if (sysmon_envsys_register(sc->sc_sme) != 0)
aprint_error_dev(self, "failed to register with sysmon\n");
}
static void
aibs_attach_sif(device_t self, enum envsys_units st)
{
struct aibs_softc *sc = device_private(self);
ACPI_OBJECT *bp, *o, *oi;
ACPI_BUFFER b;
ACPI_STATUS rv;
uint32_t i, n;
char name[] = "?SIF";
struct aibs_sensor *as;
switch (st) {
case ENVSYS_STEMP:
name[0] = 'T';
break;
case ENVSYS_SFANRPM:
name[0] = 'F';
break;
case ENVSYS_SVOLTS_DC:
name[0] = 'V';
break;
default:
return;
}
rv = acpi_eval_struct(sc->sc_node->ad_handle, name, &b);
if (ACPI_FAILURE(rv))
goto out;
bp = b.Pointer;
if (bp->Type != ACPI_TYPE_PACKAGE) {
rv = AE_TYPE;
goto out;
}
o = bp->Package.Elements;
if (o[0].Type != ACPI_TYPE_INTEGER) {
rv = AE_TYPE;
goto out;
}
if (o[0].Integer.Value > UINT32_MAX) {
rv = AE_AML_NUMERIC_OVERFLOW;
goto out;
}
n = o[0].Integer.Value;
if (n == 0) {
rv = AE_LIMIT;
goto out;
}
if (bp->Package.Count - 1 != n) {
rv = AE_BAD_VALUE;
goto out;
}
as = kmem_zalloc(sizeof(*as) * n, KM_SLEEP);
if (as == NULL) {
rv = AE_NO_MEMORY;
goto out;
}
switch (st) {
case ENVSYS_STEMP:
sc->sc_asens_temp = as;
sc->sc_asens_temp_count = n;
break;
case ENVSYS_SFANRPM:
sc->sc_asens_fan = as;
sc->sc_asens_fan_count = n;
break;
case ENVSYS_SVOLTS_DC:
sc->sc_asens_volt = as;
sc->sc_asens_volt_count = n;
break;
default:
return;
}
for (i = 0, o++; i < n; i++, o++) {
if(o[0].Type != ACPI_TYPE_PACKAGE) {
aprint_error_dev(self,
"%s: %i: not a package: %u 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) {
aprint_error_dev(self,
"%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.units = st;
as[i].s.flags |= ENVSYS_FMONLIMITS;
aprint_verbose_dev(self, "%c%i: "
"0x%08"PRIx64" %20s %5"PRIi64" / %5"PRIi64" "
"0x%"PRIx64"\n",
name[0], i,
as[i].i, as[i].s.desc, (int64_t)as[i].l, (int64_t)as[i].h,
oi[4].Integer.Value);
if (sysmon_envsys_sensor_attach(sc->sc_sme, &as[i].s))
aprint_error_dev(self, "%c%i: unable to attach\n",
name[0], i);
}
out:
if (b.Pointer != NULL)
ACPI_FREE(b.Pointer);
if (ACPI_FAILURE(rv))
aprint_error_dev(self, "failed to evaluate %s: %s\n",
name, AcpiFormatException(rv));
}
static int
aibs_detach(device_t self, int flags)
{
static const size_t size = sizeof(struct aibs_sensor);
struct aibs_softc *sc = device_private(self);
pmf_device_deregister(self);
sysmon_envsys_unregister(sc->sc_sme);
if (sc->sc_asens_volt != NULL)
kmem_free(sc->sc_asens_volt, sc->sc_asens_volt_count * size);
if (sc->sc_asens_temp != NULL)
kmem_free(sc->sc_asens_temp, sc->sc_asens_temp_count * size);
if (sc->sc_asens_fan != NULL)
kmem_free(sc->sc_asens_fan, sc->sc_asens_fan_count * size);
return 0;
}
static void
aibs_refresh(struct sysmon_envsys *sme, envsys_data_t *edata)
{
struct aibs_softc *sc = sme->sme_cookie;
device_t self = sc->sc_node->ad_device;
envsys_data_t *s = edata;
enum envsys_units st = s->units;
ACPI_STATUS rs;
ACPI_OBJECT p, *bp;
ACPI_OBJECT_LIST mp;
ACPI_BUFFER b;
int i;
const char *name;
struct aibs_sensor *as;
ACPI_INTEGER v;
switch (st) {
case ENVSYS_STEMP:
name = "RTMP";
as = sc->sc_asens_temp;
break;
case ENVSYS_SFANRPM:
name = "RFAN";
as = sc->sc_asens_fan;
break;
case ENVSYS_SVOLTS_DC:
name = "RVLT";
as = sc->sc_asens_volt;
break;
default:
return;
}
if (as == NULL)
return;
for (i = 0; as[i].s.sensor != s->sensor; i++)
;
p.Type = ACPI_TYPE_INTEGER;
p.Integer.Value = as[i].i;
mp.Count = 1;
mp.Pointer = &p;
b.Length = ACPI_ALLOCATE_BUFFER;
rs = AcpiEvaluateObjectTyped(sc->sc_node->ad_handle, name, &mp, &b,
ACPI_TYPE_INTEGER);
if (ACPI_FAILURE(rs)) {
aprint_debug_dev(self,
"%s: %i: evaluation failed\n",
name, i);
s->state = ENVSYS_SINVALID;
s->flags |= ENVSYS_FMONNOTSUPP;
return;
}
bp = b.Pointer;
v = bp->Integer.Value;
ACPI_FREE(b.Pointer);
switch (st) {
case ENVSYS_STEMP:
s->value_cur = v * 100 * 1000 + 273150000;
if (v == 0) {
s->state = ENVSYS_SINVALID;
s->flags |= ENVSYS_FMONNOTSUPP;
return;
}
break;
case ENVSYS_SFANRPM:
s->value_cur = v;
break;
case ENVSYS_SVOLTS_DC:
s->value_cur = v * 1000;
break;
default:
/* NOTREACHED */
break;
}
if (s->state == 0 || s->state == ENVSYS_SINVALID)
s->state = ENVSYS_SVALID;
s->flags &= ~ENVSYS_FMONNOTSUPP;
}
static void
aibs_get_limits(struct sysmon_envsys *sme, envsys_data_t *edata,
sysmon_envsys_lim_t *limits, uint32_t *props)
{
struct aibs_softc *sc = sme->sme_cookie;
envsys_data_t *s = edata;
sysmon_envsys_lim_t *li = limits;
enum envsys_units st = s->units;
int i;
struct aibs_sensor *as;
ACPI_INTEGER l, h;
switch (st) {
case ENVSYS_STEMP:
as = sc->sc_asens_temp;
break;
case ENVSYS_SFANRPM:
as = sc->sc_asens_fan;
break;
case ENVSYS_SVOLTS_DC:
as = sc->sc_asens_volt;
break;
default:
return;
}
if (as == NULL)
return;
for (i = 0; as[i].s.sensor != s->sensor; i++)
;
l = as[i].l;
h = as[i].h;
switch (st) {
case ENVSYS_STEMP:
li->sel_critmax = h * 100 * 1000 + 273150000;
li->sel_warnmax = l * 100 * 1000 + 273150000;
*props = PROP_CRITMAX | PROP_WARNMAX;
break;
case ENVSYS_SFANRPM:
/* some boards have strange limits for fans */
if (l == 0) {
li->sel_warnmin = h;
*props = PROP_WARNMIN;
} else {
li->sel_warnmin = l;
li->sel_warnmax = h;
*props = PROP_WARNMIN | PROP_WARNMAX;
}
break;
case ENVSYS_SVOLTS_DC:
li->sel_critmin = l * 1000;
li->sel_critmax = h * 1000;
*props = PROP_CRITMIN | PROP_CRITMAX;
break;
default:
/* NOTREACHED */
break;
}
}
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;
}

View File

@ -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 @@ file dev/acpi/dalb_acpi.c acpidalb
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

View File

@ -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