Home | History | Annotate | Line # | Download | only in acpi
aibs_acpi.c revision 1.4.2.1
      1  1.4.2.1  jdolecek /* $NetBSD: aibs_acpi.c,v 1.4.2.1 2017/12/03 11:36:58 jdolecek 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.2.1  jdolecek __KERNEL_RCSID(0, "$NetBSD: aibs_acpi.c,v 1.4.2.1 2017/12/03 11:36:58 jdolecek 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 	name = obj->Package.Elements[1].String.Pointer;
    468      1.1    jruoho 
    469      1.1    jruoho 	as->as_type = obj->Package.Elements[0].Integer.Value;
    470      1.1    jruoho 	as->as_liml = obj->Package.Elements[llo].Integer.Value;
    471      1.1    jruoho 	as->as_limh = obj->Package.Elements[lhi].Integer.Value;
    472      1.1    jruoho 
    473      1.1    jruoho 	if (sc->sc_model != false)
    474      1.1    jruoho 		as->as_limh += as->as_liml;	/* A range in the new model. */
    475      1.1    jruoho 
    476      1.4    jruoho 	as->as_sensor.state = ENVSYS_SINVALID;
    477      1.4    jruoho 
    478      1.1    jruoho 	switch (AIBS_TYPE(as->as_type)) {
    479      1.1    jruoho 
    480      1.1    jruoho 	case AIBS_TYPE_FAN:
    481      1.1    jruoho 		as->as_sensor.units = ENVSYS_SFANRPM;
    482      1.4    jruoho 		as->as_sensor.flags = ENVSYS_FMONLIMITS | ENVSYS_FHAS_ENTROPY;
    483      1.1    jruoho 		break;
    484      1.1    jruoho 
    485      1.1    jruoho 	case AIBS_TYPE_TEMP:
    486      1.1    jruoho 		as->as_sensor.units = ENVSYS_STEMP;
    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_VOLT:
    491      1.1    jruoho 		as->as_sensor.units = ENVSYS_SVOLTS_DC;
    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 	default:
    496      1.1    jruoho 		rv = AE_TYPE;
    497      1.1    jruoho 		goto out;
    498      1.1    jruoho 	}
    499      1.1    jruoho 
    500      1.1    jruoho 	(void)strlcpy(as->as_sensor.desc, name, sizeof(as->as_sensor.desc));
    501      1.1    jruoho 
    502      1.1    jruoho 	if (sysmon_envsys_sensor_attach(sc->sc_sme, &as->as_sensor) != 0) {
    503      1.1    jruoho 		rv = AE_AML_INTERNAL;
    504      1.1    jruoho 		goto out;
    505      1.1    jruoho 	}
    506      1.1    jruoho 
    507      1.1    jruoho 	SIMPLEQ_INSERT_TAIL(&sc->as_head, as, as_list);
    508      1.1    jruoho 
    509      1.1    jruoho out:
    510      1.1    jruoho 	if (ACPI_FAILURE(rv)) {
    511      1.1    jruoho 
    512      1.1    jruoho 		if (as != NULL)
    513      1.1    jruoho 			kmem_free(as, sizeof(*as));
    514      1.1    jruoho 
    515      1.1    jruoho 		aprint_error_dev(self, "failed to add "
    516      1.1    jruoho 		    "sensor: %s\n",  AcpiFormatException(rv));
    517      1.1    jruoho 	}
    518      1.1    jruoho }
    519      1.1    jruoho 
    520      1.1    jruoho static bool
    521      1.1    jruoho aibs_sensor_value(device_t self, struct aibs_sensor *as, uint64_t *val)
    522      1.1    jruoho {
    523      1.1    jruoho 	struct aibs_softc *sc = device_private(self);
    524      1.1    jruoho 	uint32_t type, *ret, cmb[3];
    525      1.1    jruoho 	ACPI_OBJECT_LIST arg;
    526      1.1    jruoho 	ACPI_OBJECT cmi, tmp;
    527      1.1    jruoho 	ACPI_OBJECT *obj;
    528      1.1    jruoho 	ACPI_BUFFER buf;
    529      1.1    jruoho 	ACPI_STATUS rv;
    530      1.1    jruoho 	const char *path;
    531      1.1    jruoho 
    532      1.1    jruoho 	if (sc->sc_model != false) {
    533      1.1    jruoho 
    534      1.1    jruoho 		path = "GITM";
    535      1.1    jruoho 
    536      1.1    jruoho 		cmb[0] = as->as_type;
    537      1.1    jruoho 		cmb[1] = 0;
    538      1.1    jruoho 		cmb[2] = 0;
    539      1.1    jruoho 
    540      1.1    jruoho 		arg.Count = 1;
    541      1.1    jruoho 		arg.Pointer = &tmp;
    542      1.1    jruoho 
    543      1.1    jruoho 		tmp.Buffer.Length = sizeof(cmb);
    544      1.1    jruoho 		tmp.Buffer.Pointer = (uint8_t *)cmb;
    545      1.1    jruoho 		tmp.Type = type = ACPI_TYPE_BUFFER;
    546      1.1    jruoho 
    547      1.1    jruoho 	} else {
    548      1.1    jruoho 
    549      1.1    jruoho 		arg.Count = 1;
    550      1.1    jruoho 		arg.Pointer = &cmi;
    551      1.1    jruoho 
    552      1.1    jruoho 		cmi.Integer.Value = as->as_type;
    553      1.1    jruoho 		cmi.Type = type = ACPI_TYPE_INTEGER;
    554      1.1    jruoho 
    555      1.1    jruoho 		switch (AIBS_TYPE(as->as_type)) {
    556      1.1    jruoho 
    557      1.1    jruoho 		case AIBS_TYPE_FAN:
    558      1.1    jruoho 			path = "RFAN";
    559      1.1    jruoho 			break;
    560      1.1    jruoho 
    561      1.1    jruoho 		case AIBS_TYPE_TEMP:
    562      1.1    jruoho 			path = "RTMP";
    563      1.1    jruoho 			break;
    564      1.1    jruoho 
    565      1.1    jruoho 		case AIBS_TYPE_VOLT:
    566      1.1    jruoho 			path = "RVLT";
    567      1.1    jruoho 			break;
    568      1.1    jruoho 
    569      1.1    jruoho 		default:
    570      1.1    jruoho 			return false;
    571      1.1    jruoho 		}
    572      1.1    jruoho 	}
    573      1.1    jruoho 
    574      1.1    jruoho 	buf.Pointer = NULL;
    575      1.1    jruoho 	buf.Length = ACPI_ALLOCATE_LOCAL_BUFFER;
    576      1.1    jruoho 
    577      1.1    jruoho 	rv = AcpiEvaluateObject(sc->sc_node->ad_handle, path, &arg, &buf);
    578      1.1    jruoho 
    579      1.1    jruoho 	if (ACPI_FAILURE(rv))
    580      1.1    jruoho 		goto out;
    581      1.1    jruoho 
    582      1.1    jruoho 	obj = buf.Pointer;
    583      1.1    jruoho 
    584      1.1    jruoho 	if (obj->Type != type) {
    585      1.1    jruoho 		rv = AE_TYPE;
    586      1.1    jruoho 		goto out;
    587      1.1    jruoho 	}
    588      1.1    jruoho 
    589      1.1    jruoho 	if (sc->sc_model != true)
    590      1.1    jruoho 		*val = obj->Integer.Value;
    591      1.1    jruoho 	else {
    592      1.1    jruoho 		/*
    593      1.1    jruoho 		 * The return buffer contains at least:
    594      1.1    jruoho 		 *
    595      1.1    jruoho 		 *	uint32_t buf[0]	 flags
    596      1.1    jruoho 		 *	uint32_t buf[1]	 return value
    597      1.1    jruoho 		 *	uint8_t  buf[2-] unknown
    598      1.1    jruoho 		 */
    599      1.1    jruoho 		if (obj->Buffer.Length < 8) {
    600      1.1    jruoho 			rv = AE_BUFFER_OVERFLOW;
    601      1.1    jruoho 			goto out;
    602      1.1    jruoho 		}
    603      1.1    jruoho 
    604      1.1    jruoho 		ret = (uint32_t *)obj->Buffer.Pointer;
    605      1.1    jruoho 
    606      1.1    jruoho 		if (ret[0] == 0) {
    607      1.1    jruoho 			rv = AE_BAD_VALUE;
    608      1.1    jruoho 			goto out;
    609      1.1    jruoho 		}
    610      1.1    jruoho 
    611      1.1    jruoho 		*val = ret[1];
    612      1.1    jruoho 	}
    613      1.1    jruoho 
    614      1.1    jruoho out:
    615      1.1    jruoho 	if (buf.Pointer != NULL)
    616      1.1    jruoho 		ACPI_FREE(buf.Pointer);
    617      1.1    jruoho 
    618      1.1    jruoho 	if (ACPI_FAILURE(rv)) {
    619      1.1    jruoho 
    620      1.1    jruoho 		aprint_error_dev(self, "failed to evaluate "
    621      1.1    jruoho 		    "%s: %s\n", path, AcpiFormatException(rv));
    622      1.1    jruoho 
    623      1.1    jruoho 		return false;
    624      1.1    jruoho 	}
    625      1.1    jruoho 
    626      1.1    jruoho 	return true;
    627      1.1    jruoho }
    628      1.1    jruoho 
    629      1.1    jruoho static void
    630      1.1    jruoho aibs_sensor_refresh(struct sysmon_envsys *sme, envsys_data_t *edata)
    631      1.1    jruoho {
    632      1.1    jruoho 	struct aibs_softc *sc = sme->sme_cookie;
    633      1.1    jruoho 	struct aibs_sensor *tmp, *as = NULL;
    634      1.1    jruoho 	envsys_data_t *s = edata;
    635      1.1    jruoho 	uint64_t val = 0;
    636      1.1    jruoho 
    637      1.1    jruoho 	SIMPLEQ_FOREACH(tmp, &sc->as_head, as_list) {
    638      1.1    jruoho 
    639      1.1    jruoho 		if (tmp->as_sensor.sensor == s->sensor) {
    640      1.1    jruoho 			as = tmp;
    641      1.1    jruoho 			break;
    642      1.1    jruoho 		}
    643      1.1    jruoho 	}
    644      1.1    jruoho 
    645      1.1    jruoho 	if (as == NULL) {
    646      1.1    jruoho 		aprint_debug_dev(sc->sc_dev, "failed to find sensor\n");
    647      1.1    jruoho 		return;
    648      1.1    jruoho 	}
    649      1.1    jruoho 
    650      1.1    jruoho 	as->as_sensor.state = ENVSYS_SINVALID;
    651      1.1    jruoho 	as->as_sensor.flags |= ENVSYS_FMONNOTSUPP;
    652      1.1    jruoho 
    653      1.1    jruoho 	if (aibs_sensor_value(sc->sc_dev, as, &val) != true)
    654      1.1    jruoho 		return;
    655      1.1    jruoho 
    656      1.1    jruoho 	switch (as->as_sensor.units) {
    657      1.1    jruoho 
    658      1.1    jruoho 	case ENVSYS_SFANRPM:
    659      1.1    jruoho 		as->as_sensor.value_cur = val;
    660      1.1    jruoho 		break;
    661      1.1    jruoho 
    662      1.1    jruoho 	case ENVSYS_STEMP:
    663      1.1    jruoho 
    664      1.1    jruoho 		if (val == 0)
    665      1.1    jruoho 			return;
    666      1.1    jruoho 
    667      1.1    jruoho 		as->as_sensor.value_cur = val * 100 * 1000 + 273150000;
    668      1.1    jruoho 		break;
    669      1.1    jruoho 
    670      1.1    jruoho 	case ENVSYS_SVOLTS_DC:
    671      1.1    jruoho 		as->as_sensor.value_cur = val * 1000;
    672      1.1    jruoho 		break;
    673      1.1    jruoho 
    674      1.1    jruoho 	default:
    675      1.1    jruoho 		return;
    676      1.1    jruoho 	}
    677      1.1    jruoho 
    678      1.1    jruoho 	as->as_sensor.state = ENVSYS_SVALID;
    679      1.1    jruoho 	as->as_sensor.flags &= ~ENVSYS_FMONNOTSUPP;
    680      1.1    jruoho }
    681      1.1    jruoho 
    682      1.1    jruoho static void
    683      1.1    jruoho aibs_sensor_limits(struct sysmon_envsys *sme, envsys_data_t *edata,
    684      1.1    jruoho     sysmon_envsys_lim_t *limits, uint32_t *props)
    685      1.1    jruoho {
    686      1.1    jruoho 	struct aibs_softc *sc = sme->sme_cookie;
    687      1.1    jruoho 	struct aibs_sensor *tmp, *as = NULL;
    688      1.1    jruoho 	sysmon_envsys_lim_t *lim = limits;
    689      1.1    jruoho 	envsys_data_t *s = edata;
    690      1.1    jruoho 
    691      1.1    jruoho 	SIMPLEQ_FOREACH(tmp, &sc->as_head, as_list) {
    692      1.1    jruoho 
    693      1.1    jruoho 		if (tmp->as_sensor.sensor == s->sensor) {
    694      1.1    jruoho 			as = tmp;
    695      1.1    jruoho 			break;
    696      1.1    jruoho 		}
    697      1.1    jruoho 	}
    698      1.1    jruoho 
    699      1.1    jruoho 	if (as == NULL) {
    700      1.1    jruoho 		aprint_debug_dev(sc->sc_dev, "failed to find sensor\n");
    701      1.1    jruoho 		return;
    702      1.1    jruoho 	}
    703      1.1    jruoho 
    704      1.1    jruoho 	switch (as->as_sensor.units) {
    705      1.1    jruoho 
    706      1.1    jruoho 	case ENVSYS_SFANRPM:
    707      1.1    jruoho 
    708      1.1    jruoho 		/*
    709      1.1    jruoho 		 * Some boards have strange limits for fans.
    710      1.1    jruoho 		 */
    711      1.1    jruoho 		if (as->as_liml == 0) {
    712      1.1    jruoho 			lim->sel_warnmin = as->as_limh;
    713      1.1    jruoho 			*props = PROP_WARNMIN;
    714      1.1    jruoho 
    715      1.1    jruoho 		} else {
    716      1.1    jruoho 			lim->sel_warnmin = as->as_liml;
    717      1.1    jruoho 			lim->sel_warnmax = as->as_limh;
    718      1.1    jruoho 			*props = PROP_WARNMIN | PROP_WARNMAX;
    719      1.1    jruoho 		}
    720      1.1    jruoho 
    721      1.1    jruoho 		break;
    722      1.1    jruoho 
    723      1.1    jruoho 	case ENVSYS_STEMP:
    724      1.1    jruoho 		lim->sel_critmax = as->as_limh * 100 * 1000 + 273150000;
    725      1.1    jruoho 		lim->sel_warnmax = as->as_liml * 100 * 1000 + 273150000;
    726      1.1    jruoho 
    727      1.1    jruoho 		*props = PROP_CRITMAX | PROP_WARNMAX;
    728      1.1    jruoho 		break;
    729      1.1    jruoho 
    730      1.1    jruoho 	case ENVSYS_SVOLTS_DC:
    731      1.1    jruoho 		lim->sel_critmin = as->as_liml * 1000;
    732      1.1    jruoho 		lim->sel_critmax = as->as_limh * 1000;
    733      1.1    jruoho 		*props = PROP_CRITMIN | PROP_CRITMAX;
    734      1.1    jruoho 		break;
    735      1.1    jruoho 
    736      1.1    jruoho 	default:
    737      1.1    jruoho 		return;
    738      1.1    jruoho 	}
    739      1.1    jruoho }
    740      1.1    jruoho 
    741  1.4.2.1  jdolecek MODULE(MODULE_CLASS_DRIVER, aibs, "sysmon_envsys");
    742      1.1    jruoho 
    743      1.1    jruoho #ifdef _MODULE
    744      1.1    jruoho #include "ioconf.c"
    745      1.1    jruoho #endif
    746      1.1    jruoho 
    747      1.1    jruoho static int
    748      1.1    jruoho aibs_modcmd(modcmd_t cmd, void *aux)
    749      1.1    jruoho {
    750      1.1    jruoho 	int rv = 0;
    751      1.1    jruoho 
    752      1.1    jruoho 	switch (cmd) {
    753      1.1    jruoho 
    754      1.1    jruoho 	case MODULE_CMD_INIT:
    755      1.1    jruoho 
    756      1.1    jruoho #ifdef _MODULE
    757      1.1    jruoho 		rv = config_init_component(cfdriver_ioconf_aibs,
    758      1.1    jruoho 		    cfattach_ioconf_aibs, cfdata_ioconf_aibs);
    759      1.1    jruoho #endif
    760      1.1    jruoho 		break;
    761      1.1    jruoho 
    762      1.1    jruoho 	case MODULE_CMD_FINI:
    763      1.1    jruoho 
    764      1.1    jruoho #ifdef _MODULE
    765      1.1    jruoho 		rv = config_fini_component(cfdriver_ioconf_aibs,
    766      1.1    jruoho 		    cfattach_ioconf_aibs, cfdata_ioconf_aibs);
    767      1.1    jruoho #endif
    768      1.1    jruoho 		break;
    769      1.1    jruoho 
    770      1.1    jruoho 	default:
    771      1.1    jruoho 		rv = ENOTTY;
    772      1.1    jruoho 	}
    773      1.1    jruoho 
    774      1.1    jruoho 	return rv;
    775      1.1    jruoho }
    776