Home | History | Annotate | Line # | Download | only in acpi
aibs_acpi.c revision 1.4.16.1
      1  1.4.16.1   skrll /* $NetBSD: aibs_acpi.c,v 1.4.16.1 2015/06/06 14:40:06 skrll Exp $ */
      2       1.1  jruoho 
      3       1.1  jruoho /*-
      4       1.1  jruoho  * Copyright (c) 2011 The NetBSD Foundation, Inc.
      5       1.1  jruoho  * All rights reserved.
      6       1.1  jruoho  *
      7       1.1  jruoho  * This code is derived from software contributed to The NetBSD Foundation
      8       1.1  jruoho  * by Jukka Ruohonen.
      9       1.1  jruoho  *
     10       1.1  jruoho  * Redistribution and use in source and binary forms, with or without
     11       1.1  jruoho  * modification, are permitted provided that the following conditions
     12       1.1  jruoho  * are met:
     13       1.1  jruoho  * 1. Redistributions of source code must retain the above copyright
     14       1.1  jruoho  *    notice, this list of conditions and the following disclaimer.
     15       1.1  jruoho  * 2. Redistributions in binary form must reproduce the above copyright
     16       1.1  jruoho  *    notice, this list of conditions and the following disclaimer in the
     17       1.1  jruoho  *    documentation and/or other materials provided with the distribution.
     18       1.1  jruoho  *
     19       1.1  jruoho  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20       1.1  jruoho  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21       1.1  jruoho  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22       1.1  jruoho  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23       1.1  jruoho  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24       1.1  jruoho  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25       1.1  jruoho  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26       1.1  jruoho  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27       1.1  jruoho  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28       1.1  jruoho  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29       1.1  jruoho  * POSSIBILITY OF SUCH DAMAGE.
     30       1.1  jruoho  */
     31       1.1  jruoho 
     32       1.1  jruoho /*	$OpenBSD: atk0110.c,v 1.1 2009/07/23 01:38:16 cnst Exp $	*/
     33       1.1  jruoho /*
     34       1.1  jruoho  * Copyright (c) 2009 Constantine A. Murenin <cnst+netbsd (at) bugmail.mojo.ru>
     35       1.1  jruoho  *
     36       1.1  jruoho  * Permission to use, copy, modify, and distribute this software for any
     37       1.1  jruoho  * purpose with or without fee is hereby granted, provided that the above
     38       1.1  jruoho  * copyright notice and this permission notice appear in all copies.
     39       1.1  jruoho  *
     40       1.1  jruoho  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     41       1.1  jruoho  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     42       1.1  jruoho  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     43       1.1  jruoho  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     44       1.1  jruoho  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     45       1.1  jruoho  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     46       1.1  jruoho  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     47       1.1  jruoho  */
     48       1.1  jruoho 
     49       1.1  jruoho #include <sys/cdefs.h>
     50  1.4.16.1   skrll __KERNEL_RCSID(0, "$NetBSD: aibs_acpi.c,v 1.4.16.1 2015/06/06 14:40:06 skrll Exp $");
     51       1.1  jruoho 
     52       1.1  jruoho #include <sys/param.h>
     53       1.1  jruoho #include <sys/kmem.h>
     54       1.1  jruoho #include <sys/module.h>
     55       1.1  jruoho 
     56       1.1  jruoho #include <dev/acpi/acpireg.h>
     57       1.1  jruoho #include <dev/acpi/acpivar.h>
     58       1.1  jruoho 
     59       1.1  jruoho /*
     60       1.1  jruoho  * ASUSTeK AI Booster (ACPI ASOC ATK0110).
     61       1.1  jruoho  *
     62       1.1  jruoho  * This code was originally written for OpenBSD after the techniques
     63       1.1  jruoho  * described in the Linux's asus_atk0110.c and FreeBSD's acpi_aiboost.c
     64       1.1  jruoho  * were verified to be accurate on the actual hardware kindly provided by
     65       1.1  jruoho  * Sam Fourman Jr.  It was subsequently ported from OpenBSD to DragonFly BSD,
     66       1.1  jruoho  * and then to the NetBSD's sysmon_envsys(9) framework.
     67       1.1  jruoho  *
     68       1.1  jruoho  *				  -- Constantine A. Murenin <http://cnst.su/>
     69       1.1  jruoho  */
     70       1.1  jruoho 
     71       1.1  jruoho #define _COMPONENT		 ACPI_RESOURCE_COMPONENT
     72       1.1  jruoho ACPI_MODULE_NAME		 ("acpi_aibs")
     73       1.1  jruoho 
     74       1.1  jruoho #define AIBS_MUX_HWMON		 0x00000006
     75       1.1  jruoho #define AIBS_MUX_MGMT		 0x00000011
     76       1.1  jruoho 
     77       1.1  jruoho #define AIBS_TYPE(x)		 (((x) >> 16) & 0xff)
     78       1.1  jruoho #define AIBS_TYPE_VOLT		 2
     79       1.1  jruoho #define AIBS_TYPE_TEMP		 3
     80       1.1  jruoho #define AIBS_TYPE_FAN		 4
     81       1.1  jruoho 
     82       1.1  jruoho struct aibs_sensor {
     83       1.1  jruoho 	envsys_data_t			 as_sensor;
     84       1.1  jruoho 	uint64_t			 as_type;
     85       1.1  jruoho 	uint64_t			 as_liml;
     86       1.1  jruoho 	uint64_t			 as_limh;
     87       1.1  jruoho 
     88       1.1  jruoho 	SIMPLEQ_ENTRY(aibs_sensor)	 as_list;
     89       1.1  jruoho };
     90       1.1  jruoho 
     91       1.1  jruoho struct aibs_softc {
     92       1.1  jruoho 	device_t			 sc_dev;
     93       1.1  jruoho 	struct acpi_devnode		*sc_node;
     94       1.1  jruoho 	struct sysmon_envsys		*sc_sme;
     95       1.1  jruoho 	bool				 sc_model;	/* new model = true */
     96       1.1  jruoho 
     97       1.1  jruoho 	SIMPLEQ_HEAD(, aibs_sensor)	 as_head;
     98       1.1  jruoho };
     99       1.1  jruoho 
    100       1.1  jruoho static int	aibs_match(device_t, cfdata_t, void *);
    101       1.1  jruoho static void	aibs_attach(device_t, device_t, void *);
    102       1.1  jruoho static int	aibs_detach(device_t, int);
    103       1.1  jruoho 
    104       1.1  jruoho static void	aibs_init(device_t);
    105       1.1  jruoho static void	aibs_init_new(device_t);
    106       1.1  jruoho static void	aibs_init_old(device_t, int);
    107       1.1  jruoho 
    108       1.1  jruoho static void	aibs_sensor_add(device_t, ACPI_OBJECT *);
    109       1.1  jruoho static bool	aibs_sensor_value(device_t, struct aibs_sensor *, uint64_t *);
    110       1.1  jruoho static void	aibs_sensor_refresh(struct sysmon_envsys *, envsys_data_t *);
    111       1.1  jruoho static void	aibs_sensor_limits(struct sysmon_envsys *, envsys_data_t *,
    112       1.1  jruoho 				   sysmon_envsys_lim_t *, uint32_t *);
    113       1.1  jruoho 
    114       1.1  jruoho CFATTACH_DECL_NEW(aibs, sizeof(struct aibs_softc),
    115       1.1  jruoho     aibs_match, aibs_attach, aibs_detach, NULL);
    116       1.1  jruoho 
    117       1.1  jruoho static const char* const aibs_hid[] = {
    118       1.1  jruoho 	"ATK0110",
    119       1.1  jruoho 	NULL
    120       1.1  jruoho };
    121       1.1  jruoho 
    122       1.1  jruoho static int
    123       1.1  jruoho aibs_match(device_t parent, cfdata_t match, void *aux)
    124       1.1  jruoho {
    125       1.1  jruoho 	struct acpi_attach_args *aa = aux;
    126       1.1  jruoho 
    127       1.1  jruoho 	if (aa->aa_node->ad_type != ACPI_TYPE_DEVICE)
    128       1.1  jruoho 		return 0;
    129       1.1  jruoho 
    130       1.1  jruoho 	return acpi_match_hid(aa->aa_node->ad_devinfo, aibs_hid);
    131       1.1  jruoho }
    132       1.1  jruoho 
    133       1.1  jruoho static void
    134       1.1  jruoho aibs_attach(device_t parent, device_t self, void *aux)
    135       1.1  jruoho {
    136       1.1  jruoho 	struct aibs_softc *sc = device_private(self);
    137       1.1  jruoho 	struct acpi_attach_args *aa = aux;
    138       1.1  jruoho 
    139       1.1  jruoho 	sc->sc_dev = self;
    140       1.1  jruoho 	sc->sc_node = aa->aa_node;
    141       1.1  jruoho 
    142       1.1  jruoho 	aprint_naive("\n");
    143       1.1  jruoho 	aprint_normal(": ASUSTeK AI Booster\n");
    144       1.1  jruoho 
    145       1.1  jruoho 	sc->sc_sme = sysmon_envsys_create();
    146       1.1  jruoho 
    147       1.1  jruoho 	sc->sc_sme->sme_cookie = sc;
    148       1.1  jruoho 	sc->sc_sme->sme_name = device_xname(self);
    149       1.1  jruoho 	sc->sc_sme->sme_refresh = aibs_sensor_refresh;
    150       1.1  jruoho 	sc->sc_sme->sme_get_limits = aibs_sensor_limits;
    151       1.1  jruoho 
    152       1.1  jruoho 	aibs_init(self);
    153       1.1  jruoho 	SIMPLEQ_INIT(&sc->as_head);
    154       1.1  jruoho 
    155       1.1  jruoho 	if (sc->sc_model != false)
    156       1.1  jruoho 		aibs_init_new(self);
    157       1.1  jruoho 	else {
    158       1.1  jruoho 		aibs_init_old(self, AIBS_TYPE_FAN);
    159       1.1  jruoho 		aibs_init_old(self, AIBS_TYPE_TEMP);
    160       1.1  jruoho 		aibs_init_old(self, AIBS_TYPE_VOLT);
    161       1.1  jruoho 	}
    162       1.1  jruoho 
    163       1.1  jruoho 	(void)pmf_device_register(self, NULL, NULL);
    164       1.1  jruoho 
    165       1.1  jruoho 	if (sc->sc_sme->sme_nsensors == 0) {
    166       1.1  jruoho 		aprint_error_dev(self, "no sensors found\n");
    167       1.1  jruoho 		sysmon_envsys_destroy(sc->sc_sme);
    168       1.1  jruoho 		sc->sc_sme = NULL;
    169       1.1  jruoho 		return;
    170       1.1  jruoho 	}
    171       1.1  jruoho 
    172       1.1  jruoho 	if (sysmon_envsys_register(sc->sc_sme) != 0)
    173       1.1  jruoho 		aprint_error_dev(self, "failed to register with sysmon\n");
    174       1.1  jruoho }
    175       1.1  jruoho 
    176       1.1  jruoho static int
    177       1.1  jruoho aibs_detach(device_t self, int flags)
    178       1.1  jruoho {
    179       1.1  jruoho 	struct aibs_softc *sc = device_private(self);
    180       1.1  jruoho 	struct aibs_sensor *as;
    181       1.1  jruoho 
    182       1.1  jruoho 	pmf_device_deregister(self);
    183       1.1  jruoho 
    184       1.1  jruoho 	if (sc->sc_sme != NULL)
    185       1.1  jruoho 		sysmon_envsys_unregister(sc->sc_sme);
    186       1.1  jruoho 
    187       1.1  jruoho 	while (SIMPLEQ_FIRST(&sc->as_head) != NULL) {
    188       1.1  jruoho 		as = SIMPLEQ_FIRST(&sc->as_head);
    189       1.1  jruoho 		SIMPLEQ_REMOVE_HEAD(&sc->as_head, as_list);
    190       1.1  jruoho 		kmem_free(as, sizeof(*as));
    191       1.1  jruoho 	}
    192       1.1  jruoho 
    193       1.1  jruoho 	return 0;
    194       1.1  jruoho }
    195       1.1  jruoho 
    196       1.1  jruoho static void
    197       1.1  jruoho aibs_init(device_t self)
    198       1.1  jruoho {
    199       1.1  jruoho 	struct aibs_softc *sc = device_private(self);
    200       1.1  jruoho 	ACPI_HANDLE tmp;
    201       1.1  jruoho 	ACPI_STATUS rv;
    202       1.1  jruoho 
    203       1.1  jruoho 	/*
    204       1.1  jruoho 	 * Old model uses the tuple { TSIF, VSIF, FSIF } to
    205       1.1  jruoho 	 * enumerate the sensors and { RTMP, RVLT, RFAN }
    206       1.1  jruoho 	 * to obtain the values. New mode uses GGRP for the
    207       1.1  jruoho 	 * enumeration and { GITM, SITM } as accessors.
    208       1.1  jruoho 	 */
    209       1.1  jruoho 	rv = AcpiGetHandle(sc->sc_node->ad_handle, "GGRP", &tmp);
    210       1.1  jruoho 
    211       1.1  jruoho 	if (ACPI_FAILURE(rv)) {
    212       1.1  jruoho 		sc->sc_model = false;
    213       1.1  jruoho 		return;
    214       1.1  jruoho 	}
    215       1.1  jruoho 
    216       1.1  jruoho 	rv = AcpiGetHandle(sc->sc_node->ad_handle, "GITM", &tmp);
    217       1.1  jruoho 
    218       1.1  jruoho 	if (ACPI_FAILURE(rv)) {
    219       1.1  jruoho 		sc->sc_model = false;
    220       1.1  jruoho 		return;
    221       1.1  jruoho 	}
    222       1.1  jruoho 
    223       1.1  jruoho 	rv = AcpiGetHandle(sc->sc_node->ad_handle, "SITM", &tmp);
    224       1.1  jruoho 
    225       1.1  jruoho 	if (ACPI_FAILURE(rv)) {
    226       1.1  jruoho 		sc->sc_model = false;
    227       1.1  jruoho 		return;
    228       1.1  jruoho 	}
    229       1.1  jruoho 
    230       1.1  jruoho 	sc->sc_model = true;
    231       1.3  jruoho 
    232       1.3  jruoho 	/*
    233       1.3  jruoho 	 * If both the new and the old methods are present, prefer
    234       1.3  jruoho 	 * the old one; GGRP/GITM may not be functional in this case.
    235       1.3  jruoho 	 */
    236       1.3  jruoho 	rv = AcpiGetHandle(sc->sc_node->ad_handle, "FSIF", &tmp);
    237       1.3  jruoho 
    238       1.3  jruoho 	if (ACPI_FAILURE(rv))
    239       1.3  jruoho 		return;
    240       1.3  jruoho 
    241       1.3  jruoho 	rv = AcpiGetHandle(sc->sc_node->ad_handle, "TSIF", &tmp);
    242       1.3  jruoho 
    243       1.3  jruoho 	if (ACPI_FAILURE(rv))
    244       1.3  jruoho 		return;
    245       1.3  jruoho 
    246       1.3  jruoho 	rv = AcpiGetHandle(sc->sc_node->ad_handle, "VSIF", &tmp);
    247       1.3  jruoho 
    248       1.3  jruoho 	if (ACPI_FAILURE(rv))
    249       1.3  jruoho 		return;
    250       1.3  jruoho 
    251       1.3  jruoho 	rv = AcpiGetHandle(sc->sc_node->ad_handle, "RFAN", &tmp);
    252       1.3  jruoho 
    253       1.3  jruoho 	if (ACPI_FAILURE(rv))
    254       1.3  jruoho 		return;
    255       1.3  jruoho 
    256       1.3  jruoho 	rv = AcpiGetHandle(sc->sc_node->ad_handle, "RTMP", &tmp);
    257       1.3  jruoho 
    258       1.3  jruoho 	if (ACPI_FAILURE(rv))
    259       1.3  jruoho 		return;
    260       1.3  jruoho 
    261       1.3  jruoho 	rv = AcpiGetHandle(sc->sc_node->ad_handle, "RVLT", &tmp);
    262       1.3  jruoho 
    263       1.3  jruoho 	if (ACPI_FAILURE(rv))
    264       1.3  jruoho 		return;
    265       1.3  jruoho 
    266       1.3  jruoho 	sc->sc_model = false;
    267       1.1  jruoho }
    268       1.1  jruoho 
    269       1.1  jruoho static void
    270       1.1  jruoho aibs_init_new(device_t self)
    271       1.1  jruoho {
    272       1.1  jruoho 	struct aibs_softc *sc = device_private(self);
    273       1.1  jruoho 	ACPI_OBJECT_LIST arg;
    274       1.1  jruoho 	ACPI_OBJECT id, *obj;
    275       1.1  jruoho 	ACPI_BUFFER buf;
    276       1.1  jruoho 	ACPI_STATUS rv;
    277       1.1  jruoho 	uint32_t i, n;
    278       1.1  jruoho 
    279       1.1  jruoho 	arg.Count = 1;
    280       1.1  jruoho 	arg.Pointer = &id;
    281       1.1  jruoho 
    282       1.1  jruoho 	id.Type = ACPI_TYPE_INTEGER;
    283       1.1  jruoho 	id.Integer.Value = AIBS_MUX_HWMON;
    284       1.1  jruoho 
    285       1.1  jruoho 	buf.Pointer = NULL;
    286       1.1  jruoho 	buf.Length = ACPI_ALLOCATE_LOCAL_BUFFER;
    287       1.1  jruoho 
    288       1.1  jruoho 	rv = AcpiEvaluateObject(sc->sc_node->ad_handle, "GGRP", &arg, &buf);
    289       1.1  jruoho 
    290       1.1  jruoho 	if (ACPI_FAILURE(rv))
    291       1.1  jruoho 		goto out;
    292       1.1  jruoho 
    293       1.1  jruoho 	obj = buf.Pointer;
    294       1.1  jruoho 
    295       1.1  jruoho 	if (obj->Type != ACPI_TYPE_PACKAGE) {
    296       1.1  jruoho 		rv = AE_TYPE;
    297       1.1  jruoho 		goto out;
    298       1.1  jruoho 	}
    299       1.1  jruoho 
    300       1.1  jruoho 	if (obj->Package.Count > UINT32_MAX) {
    301       1.1  jruoho 		rv = AE_AML_NUMERIC_OVERFLOW;
    302       1.1  jruoho 		goto out;
    303       1.1  jruoho 	}
    304       1.1  jruoho 
    305       1.1  jruoho 	n = obj->Package.Count;
    306       1.1  jruoho 
    307       1.1  jruoho 	if (n == 0) {
    308       1.1  jruoho 		rv = AE_NOT_EXIST;
    309       1.1  jruoho 		goto out;
    310       1.1  jruoho 	}
    311       1.1  jruoho 
    312       1.1  jruoho 	for (i = 0; i < n; i++)
    313       1.1  jruoho 		aibs_sensor_add(self, &obj->Package.Elements[i]);
    314       1.1  jruoho 
    315       1.1  jruoho out:
    316       1.1  jruoho 	if (buf.Pointer != NULL)
    317       1.1  jruoho 		ACPI_FREE(buf.Pointer);
    318       1.1  jruoho 
    319       1.1  jruoho 	if (ACPI_FAILURE(rv)) {
    320       1.1  jruoho 
    321       1.1  jruoho 		aprint_error_dev(self, "failed to evaluate "
    322       1.1  jruoho 		    "GGRP: %s\n", AcpiFormatException(rv));
    323       1.1  jruoho 	}
    324       1.1  jruoho }
    325       1.1  jruoho 
    326       1.1  jruoho static void
    327       1.1  jruoho aibs_init_old(device_t self, int type)
    328       1.1  jruoho {
    329       1.1  jruoho 	struct aibs_softc *sc = device_private(self);
    330       1.1  jruoho 	char path[] = "?SIF";
    331       1.1  jruoho 	ACPI_OBJECT *elm, *obj;
    332       1.1  jruoho 	ACPI_BUFFER buf;
    333       1.1  jruoho 	ACPI_STATUS rv;
    334       1.1  jruoho 	uint32_t i, n;
    335       1.1  jruoho 
    336       1.1  jruoho 	switch (type) {
    337       1.1  jruoho 
    338       1.1  jruoho 	case AIBS_TYPE_FAN:
    339       1.1  jruoho 		path[0] = 'F';
    340       1.1  jruoho 		break;
    341       1.1  jruoho 
    342       1.1  jruoho 	case AIBS_TYPE_TEMP:
    343       1.1  jruoho 		path[0] = 'T';
    344       1.1  jruoho 		break;
    345       1.1  jruoho 
    346       1.1  jruoho 	case AIBS_TYPE_VOLT:
    347       1.1  jruoho 		path[0] = 'V';
    348       1.1  jruoho 		break;
    349       1.1  jruoho 
    350       1.1  jruoho 	default:
    351       1.1  jruoho 		return;
    352       1.1  jruoho 	}
    353       1.1  jruoho 
    354       1.1  jruoho 	rv = acpi_eval_struct(sc->sc_node->ad_handle, path, &buf);
    355       1.1  jruoho 
    356       1.1  jruoho 	if (ACPI_FAILURE(rv))
    357       1.1  jruoho 		goto out;
    358       1.1  jruoho 
    359       1.1  jruoho 	obj = buf.Pointer;
    360       1.1  jruoho 
    361       1.1  jruoho 	if (obj->Type != ACPI_TYPE_PACKAGE) {
    362       1.1  jruoho 		rv = AE_TYPE;
    363       1.1  jruoho 		goto out;
    364       1.1  jruoho 	}
    365       1.1  jruoho 
    366       1.1  jruoho 	elm = obj->Package.Elements;
    367       1.1  jruoho 
    368       1.1  jruoho 	if (elm[0].Type != ACPI_TYPE_INTEGER) {
    369       1.1  jruoho 		rv = AE_TYPE;
    370       1.1  jruoho 		goto out;
    371       1.1  jruoho 	}
    372       1.1  jruoho 
    373       1.1  jruoho 	if (elm[0].Integer.Value > UINT32_MAX) {
    374       1.1  jruoho 		rv = AE_AML_NUMERIC_OVERFLOW;
    375       1.1  jruoho 		goto out;
    376       1.1  jruoho 	}
    377       1.1  jruoho 
    378       1.1  jruoho 	n = elm[0].Integer.Value;
    379       1.1  jruoho 
    380       1.1  jruoho 	if (n == 0) {
    381       1.1  jruoho 		rv = AE_NOT_EXIST;
    382       1.1  jruoho 		goto out;
    383       1.1  jruoho 	}
    384       1.1  jruoho 
    385       1.1  jruoho 	if (obj->Package.Count - 1 != n) {
    386       1.1  jruoho 		rv = AE_BAD_VALUE;
    387       1.1  jruoho 		goto out;
    388       1.1  jruoho 	}
    389       1.1  jruoho 
    390       1.1  jruoho 	for (i = 1; i < obj->Package.Count; i++) {
    391       1.1  jruoho 
    392       1.1  jruoho 		if (elm[i].Type != ACPI_TYPE_PACKAGE)
    393       1.1  jruoho 			continue;
    394       1.1  jruoho 
    395       1.1  jruoho 		aibs_sensor_add(self, &elm[i]);
    396       1.1  jruoho 	}
    397       1.1  jruoho 
    398       1.1  jruoho out:
    399       1.1  jruoho 	if (buf.Pointer != NULL)
    400       1.1  jruoho 		ACPI_FREE(buf.Pointer);
    401       1.1  jruoho 
    402       1.1  jruoho 	if (ACPI_FAILURE(rv)) {
    403       1.1  jruoho 
    404       1.1  jruoho 		aprint_error_dev(self, "failed to evaluate "
    405       1.1  jruoho 		    "%s: %s\n", path, AcpiFormatException(rv));
    406       1.1  jruoho 	}
    407       1.1  jruoho }
    408       1.1  jruoho 
    409       1.1  jruoho static void
    410       1.1  jruoho aibs_sensor_add(device_t self, ACPI_OBJECT *obj)
    411       1.1  jruoho {
    412       1.1  jruoho 	struct aibs_softc *sc = device_private(self);
    413       1.1  jruoho 	struct aibs_sensor *as;
    414       1.1  jruoho 	int ena, len, lhi, llo;
    415       1.1  jruoho 	const char *name;
    416       1.1  jruoho 	ACPI_STATUS rv;
    417       1.1  jruoho 
    418       1.1  jruoho 	as = NULL;
    419       1.1  jruoho 	rv = AE_OK;
    420       1.1  jruoho 
    421       1.1  jruoho 	if (obj->Type != ACPI_TYPE_PACKAGE) {
    422       1.1  jruoho 		rv = AE_TYPE;
    423       1.1  jruoho 		goto out;
    424       1.1  jruoho 	}
    425       1.1  jruoho 
    426       1.1  jruoho 	/*
    427       1.1  jruoho 	 * The known formats are:
    428       1.1  jruoho 	 *
    429       1.1  jruoho 	 *	index		type		old		new
    430       1.1  jruoho 	 *	-----		----		---		---
    431       1.1  jruoho 	 *	0		integer		flags		flags
    432       1.1  jruoho 	 *	1		string		name		name
    433       1.1  jruoho 	 *	2		integer		limit1		unknown
    434       1.1  jruoho 	 *	3		integer		limit2		unknown
    435       1.1  jruoho 	 *	4		integer		enable		limit1
    436       1.1  jruoho 	 *	5		integer		-		limit2
    437       1.1  jruoho 	 *	6		integer		-		enable
    438       1.1  jruoho 	 */
    439       1.1  jruoho 	if (sc->sc_model != false) {
    440       1.1  jruoho 		len = 7;
    441       1.1  jruoho 		llo = 4;
    442       1.1  jruoho 		lhi = 5;
    443       1.1  jruoho 		ena = 6;
    444       1.1  jruoho 	} else {
    445       1.1  jruoho 		len = 5;
    446       1.1  jruoho 		llo = 2;
    447       1.1  jruoho 		lhi = 3;
    448       1.1  jruoho 		ena = 4;
    449       1.1  jruoho 	}
    450       1.1  jruoho 
    451       1.1  jruoho 	if (obj->Package.Count != (uint32_t)len) {
    452       1.1  jruoho 		rv = AE_LIMIT;
    453       1.1  jruoho 		goto out;
    454       1.1  jruoho 	}
    455       1.1  jruoho 
    456       1.1  jruoho 	if (obj->Package.Elements[0].Type != ACPI_TYPE_INTEGER ||
    457       1.1  jruoho 	    obj->Package.Elements[1].Type != ACPI_TYPE_STRING ||
    458       1.1  jruoho 	    obj->Package.Elements[llo].Type != ACPI_TYPE_INTEGER ||
    459       1.1  jruoho 	    obj->Package.Elements[lhi].Type != ACPI_TYPE_INTEGER ||
    460       1.1  jruoho 	    obj->Package.Elements[ena].Type != ACPI_TYPE_INTEGER) {
    461       1.1  jruoho 		rv = AE_TYPE;
    462       1.1  jruoho 		goto out;
    463       1.1  jruoho 	}
    464       1.1  jruoho 
    465       1.1  jruoho 	as = kmem_zalloc(sizeof(*as), KM_SLEEP);
    466       1.1  jruoho 
    467       1.1  jruoho 	if (as == NULL) {
    468       1.1  jruoho 		rv = AE_NO_MEMORY;
    469       1.1  jruoho 		goto out;
    470       1.1  jruoho 	}
    471       1.1  jruoho 
    472       1.1  jruoho 	name = obj->Package.Elements[1].String.Pointer;
    473       1.1  jruoho 
    474       1.1  jruoho 	as->as_type = obj->Package.Elements[0].Integer.Value;
    475       1.1  jruoho 	as->as_liml = obj->Package.Elements[llo].Integer.Value;
    476       1.1  jruoho 	as->as_limh = obj->Package.Elements[lhi].Integer.Value;
    477       1.1  jruoho 
    478       1.1  jruoho 	if (sc->sc_model != false)
    479       1.1  jruoho 		as->as_limh += as->as_liml;	/* A range in the new model. */
    480       1.1  jruoho 
    481       1.4  jruoho 	as->as_sensor.state = ENVSYS_SINVALID;
    482       1.4  jruoho 
    483       1.1  jruoho 	switch (AIBS_TYPE(as->as_type)) {
    484       1.1  jruoho 
    485       1.1  jruoho 	case AIBS_TYPE_FAN:
    486       1.1  jruoho 		as->as_sensor.units = ENVSYS_SFANRPM;
    487       1.4  jruoho 		as->as_sensor.flags = ENVSYS_FMONLIMITS | ENVSYS_FHAS_ENTROPY;
    488       1.1  jruoho 		break;
    489       1.1  jruoho 
    490       1.1  jruoho 	case AIBS_TYPE_TEMP:
    491       1.1  jruoho 		as->as_sensor.units = ENVSYS_STEMP;
    492       1.4  jruoho 		as->as_sensor.flags = ENVSYS_FMONLIMITS | ENVSYS_FHAS_ENTROPY;
    493       1.1  jruoho 		break;
    494       1.1  jruoho 
    495       1.1  jruoho 	case AIBS_TYPE_VOLT:
    496       1.1  jruoho 		as->as_sensor.units = ENVSYS_SVOLTS_DC;
    497       1.4  jruoho 		as->as_sensor.flags = ENVSYS_FMONLIMITS | ENVSYS_FHAS_ENTROPY;
    498       1.1  jruoho 		break;
    499       1.1  jruoho 
    500       1.1  jruoho 	default:
    501       1.1  jruoho 		rv = AE_TYPE;
    502       1.1  jruoho 		goto out;
    503       1.1  jruoho 	}
    504       1.1  jruoho 
    505       1.1  jruoho 	(void)strlcpy(as->as_sensor.desc, name, sizeof(as->as_sensor.desc));
    506       1.1  jruoho 
    507       1.1  jruoho 	if (sysmon_envsys_sensor_attach(sc->sc_sme, &as->as_sensor) != 0) {
    508       1.1  jruoho 		rv = AE_AML_INTERNAL;
    509       1.1  jruoho 		goto out;
    510       1.1  jruoho 	}
    511       1.1  jruoho 
    512       1.1  jruoho 	SIMPLEQ_INSERT_TAIL(&sc->as_head, as, as_list);
    513       1.1  jruoho 
    514       1.1  jruoho out:
    515       1.1  jruoho 	if (ACPI_FAILURE(rv)) {
    516       1.1  jruoho 
    517       1.1  jruoho 		if (as != NULL)
    518       1.1  jruoho 			kmem_free(as, sizeof(*as));
    519       1.1  jruoho 
    520       1.1  jruoho 		aprint_error_dev(self, "failed to add "
    521       1.1  jruoho 		    "sensor: %s\n",  AcpiFormatException(rv));
    522       1.1  jruoho 	}
    523       1.1  jruoho }
    524       1.1  jruoho 
    525       1.1  jruoho static bool
    526       1.1  jruoho aibs_sensor_value(device_t self, struct aibs_sensor *as, uint64_t *val)
    527       1.1  jruoho {
    528       1.1  jruoho 	struct aibs_softc *sc = device_private(self);
    529       1.1  jruoho 	uint32_t type, *ret, cmb[3];
    530       1.1  jruoho 	ACPI_OBJECT_LIST arg;
    531       1.1  jruoho 	ACPI_OBJECT cmi, tmp;
    532       1.1  jruoho 	ACPI_OBJECT *obj;
    533       1.1  jruoho 	ACPI_BUFFER buf;
    534       1.1  jruoho 	ACPI_STATUS rv;
    535       1.1  jruoho 	const char *path;
    536       1.1  jruoho 
    537       1.1  jruoho 	if (sc->sc_model != false) {
    538       1.1  jruoho 
    539       1.1  jruoho 		path = "GITM";
    540       1.1  jruoho 
    541       1.1  jruoho 		cmb[0] = as->as_type;
    542       1.1  jruoho 		cmb[1] = 0;
    543       1.1  jruoho 		cmb[2] = 0;
    544       1.1  jruoho 
    545       1.1  jruoho 		arg.Count = 1;
    546       1.1  jruoho 		arg.Pointer = &tmp;
    547       1.1  jruoho 
    548       1.1  jruoho 		tmp.Buffer.Length = sizeof(cmb);
    549       1.1  jruoho 		tmp.Buffer.Pointer = (uint8_t *)cmb;
    550       1.1  jruoho 		tmp.Type = type = ACPI_TYPE_BUFFER;
    551       1.1  jruoho 
    552       1.1  jruoho 	} else {
    553       1.1  jruoho 
    554       1.1  jruoho 		arg.Count = 1;
    555       1.1  jruoho 		arg.Pointer = &cmi;
    556       1.1  jruoho 
    557       1.1  jruoho 		cmi.Integer.Value = as->as_type;
    558       1.1  jruoho 		cmi.Type = type = ACPI_TYPE_INTEGER;
    559       1.1  jruoho 
    560       1.1  jruoho 		switch (AIBS_TYPE(as->as_type)) {
    561       1.1  jruoho 
    562       1.1  jruoho 		case AIBS_TYPE_FAN:
    563       1.1  jruoho 			path = "RFAN";
    564       1.1  jruoho 			break;
    565       1.1  jruoho 
    566       1.1  jruoho 		case AIBS_TYPE_TEMP:
    567       1.1  jruoho 			path = "RTMP";
    568       1.1  jruoho 			break;
    569       1.1  jruoho 
    570       1.1  jruoho 		case AIBS_TYPE_VOLT:
    571       1.1  jruoho 			path = "RVLT";
    572       1.1  jruoho 			break;
    573       1.1  jruoho 
    574       1.1  jruoho 		default:
    575       1.1  jruoho 			return false;
    576       1.1  jruoho 		}
    577       1.1  jruoho 	}
    578       1.1  jruoho 
    579       1.1  jruoho 	buf.Pointer = NULL;
    580       1.1  jruoho 	buf.Length = ACPI_ALLOCATE_LOCAL_BUFFER;
    581       1.1  jruoho 
    582       1.1  jruoho 	rv = AcpiEvaluateObject(sc->sc_node->ad_handle, path, &arg, &buf);
    583       1.1  jruoho 
    584       1.1  jruoho 	if (ACPI_FAILURE(rv))
    585       1.1  jruoho 		goto out;
    586       1.1  jruoho 
    587       1.1  jruoho 	obj = buf.Pointer;
    588       1.1  jruoho 
    589       1.1  jruoho 	if (obj->Type != type) {
    590       1.1  jruoho 		rv = AE_TYPE;
    591       1.1  jruoho 		goto out;
    592       1.1  jruoho 	}
    593       1.1  jruoho 
    594       1.1  jruoho 	if (sc->sc_model != true)
    595       1.1  jruoho 		*val = obj->Integer.Value;
    596       1.1  jruoho 	else {
    597       1.1  jruoho 		/*
    598       1.1  jruoho 		 * The return buffer contains at least:
    599       1.1  jruoho 		 *
    600       1.1  jruoho 		 *	uint32_t buf[0]	 flags
    601       1.1  jruoho 		 *	uint32_t buf[1]	 return value
    602       1.1  jruoho 		 *	uint8_t  buf[2-] unknown
    603       1.1  jruoho 		 */
    604       1.1  jruoho 		if (obj->Buffer.Length < 8) {
    605       1.1  jruoho 			rv = AE_BUFFER_OVERFLOW;
    606       1.1  jruoho 			goto out;
    607       1.1  jruoho 		}
    608       1.1  jruoho 
    609       1.1  jruoho 		ret = (uint32_t *)obj->Buffer.Pointer;
    610       1.1  jruoho 
    611       1.1  jruoho 		if (ret[0] == 0) {
    612       1.1  jruoho 			rv = AE_BAD_VALUE;
    613       1.1  jruoho 			goto out;
    614       1.1  jruoho 		}
    615       1.1  jruoho 
    616       1.1  jruoho 		*val = ret[1];
    617       1.1  jruoho 	}
    618       1.1  jruoho 
    619       1.1  jruoho out:
    620       1.1  jruoho 	if (buf.Pointer != NULL)
    621       1.1  jruoho 		ACPI_FREE(buf.Pointer);
    622       1.1  jruoho 
    623       1.1  jruoho 	if (ACPI_FAILURE(rv)) {
    624       1.1  jruoho 
    625       1.1  jruoho 		aprint_error_dev(self, "failed to evaluate "
    626       1.1  jruoho 		    "%s: %s\n", path, AcpiFormatException(rv));
    627       1.1  jruoho 
    628       1.1  jruoho 		return false;
    629       1.1  jruoho 	}
    630       1.1  jruoho 
    631       1.1  jruoho 	return true;
    632       1.1  jruoho }
    633       1.1  jruoho 
    634       1.1  jruoho static void
    635       1.1  jruoho aibs_sensor_refresh(struct sysmon_envsys *sme, envsys_data_t *edata)
    636       1.1  jruoho {
    637       1.1  jruoho 	struct aibs_softc *sc = sme->sme_cookie;
    638       1.1  jruoho 	struct aibs_sensor *tmp, *as = NULL;
    639       1.1  jruoho 	envsys_data_t *s = edata;
    640       1.1  jruoho 	uint64_t val = 0;
    641       1.1  jruoho 
    642       1.1  jruoho 	SIMPLEQ_FOREACH(tmp, &sc->as_head, as_list) {
    643       1.1  jruoho 
    644       1.1  jruoho 		if (tmp->as_sensor.sensor == s->sensor) {
    645       1.1  jruoho 			as = tmp;
    646       1.1  jruoho 			break;
    647       1.1  jruoho 		}
    648       1.1  jruoho 	}
    649       1.1  jruoho 
    650       1.1  jruoho 	if (as == NULL) {
    651       1.1  jruoho 		aprint_debug_dev(sc->sc_dev, "failed to find sensor\n");
    652       1.1  jruoho 		return;
    653       1.1  jruoho 	}
    654       1.1  jruoho 
    655       1.1  jruoho 	as->as_sensor.state = ENVSYS_SINVALID;
    656       1.1  jruoho 	as->as_sensor.flags |= ENVSYS_FMONNOTSUPP;
    657       1.1  jruoho 
    658       1.1  jruoho 	if (aibs_sensor_value(sc->sc_dev, as, &val) != true)
    659       1.1  jruoho 		return;
    660       1.1  jruoho 
    661       1.1  jruoho 	switch (as->as_sensor.units) {
    662       1.1  jruoho 
    663       1.1  jruoho 	case ENVSYS_SFANRPM:
    664       1.1  jruoho 		as->as_sensor.value_cur = val;
    665       1.1  jruoho 		break;
    666       1.1  jruoho 
    667       1.1  jruoho 	case ENVSYS_STEMP:
    668       1.1  jruoho 
    669       1.1  jruoho 		if (val == 0)
    670       1.1  jruoho 			return;
    671       1.1  jruoho 
    672       1.1  jruoho 		as->as_sensor.value_cur = val * 100 * 1000 + 273150000;
    673       1.1  jruoho 		break;
    674       1.1  jruoho 
    675       1.1  jruoho 	case ENVSYS_SVOLTS_DC:
    676       1.1  jruoho 		as->as_sensor.value_cur = val * 1000;
    677       1.1  jruoho 		break;
    678       1.1  jruoho 
    679       1.1  jruoho 	default:
    680       1.1  jruoho 		return;
    681       1.1  jruoho 	}
    682       1.1  jruoho 
    683       1.1  jruoho 	as->as_sensor.state = ENVSYS_SVALID;
    684       1.1  jruoho 	as->as_sensor.flags &= ~ENVSYS_FMONNOTSUPP;
    685       1.1  jruoho }
    686       1.1  jruoho 
    687       1.1  jruoho static void
    688       1.1  jruoho aibs_sensor_limits(struct sysmon_envsys *sme, envsys_data_t *edata,
    689       1.1  jruoho     sysmon_envsys_lim_t *limits, uint32_t *props)
    690       1.1  jruoho {
    691       1.1  jruoho 	struct aibs_softc *sc = sme->sme_cookie;
    692       1.1  jruoho 	struct aibs_sensor *tmp, *as = NULL;
    693       1.1  jruoho 	sysmon_envsys_lim_t *lim = limits;
    694       1.1  jruoho 	envsys_data_t *s = edata;
    695       1.1  jruoho 
    696       1.1  jruoho 	SIMPLEQ_FOREACH(tmp, &sc->as_head, as_list) {
    697       1.1  jruoho 
    698       1.1  jruoho 		if (tmp->as_sensor.sensor == s->sensor) {
    699       1.1  jruoho 			as = tmp;
    700       1.1  jruoho 			break;
    701       1.1  jruoho 		}
    702       1.1  jruoho 	}
    703       1.1  jruoho 
    704       1.1  jruoho 	if (as == NULL) {
    705       1.1  jruoho 		aprint_debug_dev(sc->sc_dev, "failed to find sensor\n");
    706       1.1  jruoho 		return;
    707       1.1  jruoho 	}
    708       1.1  jruoho 
    709       1.1  jruoho 	switch (as->as_sensor.units) {
    710       1.1  jruoho 
    711       1.1  jruoho 	case ENVSYS_SFANRPM:
    712       1.1  jruoho 
    713       1.1  jruoho 		/*
    714       1.1  jruoho 		 * Some boards have strange limits for fans.
    715       1.1  jruoho 		 */
    716       1.1  jruoho 		if (as->as_liml == 0) {
    717       1.1  jruoho 			lim->sel_warnmin = as->as_limh;
    718       1.1  jruoho 			*props = PROP_WARNMIN;
    719       1.1  jruoho 
    720       1.1  jruoho 		} else {
    721       1.1  jruoho 			lim->sel_warnmin = as->as_liml;
    722       1.1  jruoho 			lim->sel_warnmax = as->as_limh;
    723       1.1  jruoho 			*props = PROP_WARNMIN | PROP_WARNMAX;
    724       1.1  jruoho 		}
    725       1.1  jruoho 
    726       1.1  jruoho 		break;
    727       1.1  jruoho 
    728       1.1  jruoho 	case ENVSYS_STEMP:
    729       1.1  jruoho 		lim->sel_critmax = as->as_limh * 100 * 1000 + 273150000;
    730       1.1  jruoho 		lim->sel_warnmax = as->as_liml * 100 * 1000 + 273150000;
    731       1.1  jruoho 
    732       1.1  jruoho 		*props = PROP_CRITMAX | PROP_WARNMAX;
    733       1.1  jruoho 		break;
    734       1.1  jruoho 
    735       1.1  jruoho 	case ENVSYS_SVOLTS_DC:
    736       1.1  jruoho 		lim->sel_critmin = as->as_liml * 1000;
    737       1.1  jruoho 		lim->sel_critmax = as->as_limh * 1000;
    738       1.1  jruoho 		*props = PROP_CRITMIN | PROP_CRITMAX;
    739       1.1  jruoho 		break;
    740       1.1  jruoho 
    741       1.1  jruoho 	default:
    742       1.1  jruoho 		return;
    743       1.1  jruoho 	}
    744       1.1  jruoho }
    745       1.1  jruoho 
    746  1.4.16.1   skrll MODULE(MODULE_CLASS_DRIVER, aibs, "sysmon_envsys");
    747       1.1  jruoho 
    748       1.1  jruoho #ifdef _MODULE
    749       1.1  jruoho #include "ioconf.c"
    750       1.1  jruoho #endif
    751       1.1  jruoho 
    752       1.1  jruoho static int
    753       1.1  jruoho aibs_modcmd(modcmd_t cmd, void *aux)
    754       1.1  jruoho {
    755       1.1  jruoho 	int rv = 0;
    756       1.1  jruoho 
    757       1.1  jruoho 	switch (cmd) {
    758       1.1  jruoho 
    759       1.1  jruoho 	case MODULE_CMD_INIT:
    760       1.1  jruoho 
    761       1.1  jruoho #ifdef _MODULE
    762       1.1  jruoho 		rv = config_init_component(cfdriver_ioconf_aibs,
    763       1.1  jruoho 		    cfattach_ioconf_aibs, cfdata_ioconf_aibs);
    764       1.1  jruoho #endif
    765       1.1  jruoho 		break;
    766       1.1  jruoho 
    767       1.1  jruoho 	case MODULE_CMD_FINI:
    768       1.1  jruoho 
    769       1.1  jruoho #ifdef _MODULE
    770       1.1  jruoho 		rv = config_fini_component(cfdriver_ioconf_aibs,
    771       1.1  jruoho 		    cfattach_ioconf_aibs, cfdata_ioconf_aibs);
    772       1.1  jruoho #endif
    773       1.1  jruoho 		break;
    774       1.1  jruoho 
    775       1.1  jruoho 	default:
    776       1.1  jruoho 		rv = ENOTTY;
    777       1.1  jruoho 	}
    778       1.1  jruoho 
    779       1.1  jruoho 	return rv;
    780       1.1  jruoho }
    781