xref: /freebsd/sys/dev/acpi_support/atk0110.c (revision f01b5ed9c8503b2410ec93b1e2ee4cf731b7e6e9)
1bbe4a97dSRui Paulo /*	$NetBSD: atk0110.c,v 1.4 2010/02/11 06:54:57 cnst Exp $	*/
2bbe4a97dSRui Paulo /*	$OpenBSD: atk0110.c,v 1.1 2009/07/23 01:38:16 cnst Exp $	*/
3bbe4a97dSRui Paulo 
4bbe4a97dSRui Paulo /*
5bbe4a97dSRui Paulo  * Copyright (c) 2009, 2010 Constantine A. Murenin <cnst++@FreeBSD.org>
6bbe4a97dSRui Paulo  *
7bbe4a97dSRui Paulo  * Permission to use, copy, modify, and distribute this software for any
8bbe4a97dSRui Paulo  * purpose with or without fee is hereby granted, provided that the above
9bbe4a97dSRui Paulo  * copyright notice and this permission notice appear in all copies.
10bbe4a97dSRui Paulo  *
11bbe4a97dSRui Paulo  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12bbe4a97dSRui Paulo  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13bbe4a97dSRui Paulo  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14bbe4a97dSRui Paulo  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15bbe4a97dSRui Paulo  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16bbe4a97dSRui Paulo  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17bbe4a97dSRui Paulo  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18bbe4a97dSRui Paulo  */
19bbe4a97dSRui Paulo 
20bbe4a97dSRui Paulo #include <sys/cdefs.h>
21bbe4a97dSRui Paulo __FBSDID("$FreeBSD$");
22bbe4a97dSRui Paulo 
23bbe4a97dSRui Paulo #include <machine/_inttypes.h>
24bbe4a97dSRui Paulo #include <sys/param.h>
25bbe4a97dSRui Paulo #include <sys/systm.h>
26bbe4a97dSRui Paulo #include <sys/kernel.h>
27bbe4a97dSRui Paulo #include <sys/bus.h>
28bbe4a97dSRui Paulo #include <sys/module.h>
29bbe4a97dSRui Paulo #include <sys/malloc.h>
30bbe4a97dSRui Paulo #include <sys/sysctl.h>
312698bbbbSAndriy Gapon #include <sys/stdint.h>
32bbe4a97dSRui Paulo 
33bbe4a97dSRui Paulo #include <contrib/dev/acpica/include/acpi.h>
34bbe4a97dSRui Paulo #include <dev/acpica/acpivar.h>
35bbe4a97dSRui Paulo 
36bbe4a97dSRui Paulo /*
37bbe4a97dSRui Paulo  * ASUSTeK AI Booster (ACPI ASOC ATK0110).
38bbe4a97dSRui Paulo  *
39bbe4a97dSRui Paulo  * This code was originally written for OpenBSD after the techniques
40bbe4a97dSRui Paulo  * described in the Linux's asus_atk0110.c and FreeBSD's Takanori Watanabe's
41bbe4a97dSRui Paulo  * acpi_aiboost.c were verified to be accurate on the actual hardware kindly
42bbe4a97dSRui Paulo  * provided by Sam Fourman Jr.  It was subsequently ported from OpenBSD to
43bbe4a97dSRui Paulo  * DragonFly BSD, to NetBSD's sysmon_envsys(9) and to FreeBSD's sysctl(9).
44bbe4a97dSRui Paulo  *
45bbe4a97dSRui Paulo  *				  -- Constantine A. Murenin <http://cnst.su/>
46bbe4a97dSRui Paulo  */
47bbe4a97dSRui Paulo 
48bbe4a97dSRui Paulo #define _COMPONENT	ACPI_OEM
49bbe4a97dSRui Paulo ACPI_MODULE_NAME("aibs");
50bbe4a97dSRui Paulo ACPI_SERIAL_DECL(aibs, "aibs");
51bbe4a97dSRui Paulo 
52bbe4a97dSRui Paulo #define AIBS_MORE_SENSORS
53bbe4a97dSRui Paulo #define AIBS_VERBOSE
54bbe4a97dSRui Paulo 
552698bbbbSAndriy Gapon #define	AIBS_GROUP_SENSORS	0x06
562698bbbbSAndriy Gapon 
572698bbbbSAndriy Gapon #define AIBS_SENS_TYPE(x)	(((x) >> 16) & 0xff)
582698bbbbSAndriy Gapon #define AIBS_SENS_TYPE_VOLT	2
592698bbbbSAndriy Gapon #define AIBS_SENS_TYPE_TEMP	3
602698bbbbSAndriy Gapon #define AIBS_SENS_TYPE_FAN	4
612698bbbbSAndriy Gapon 
622698bbbbSAndriy Gapon #define	AIBS_SENS_TYPE_VOLT_NAME		"volt"
632698bbbbSAndriy Gapon #define	AIBS_SENS_TYPE_VOLT_TEMP		"temp"
642698bbbbSAndriy Gapon #define	AIBS_SENS_TYPE_VOLT_FAN		"fan"
65bbe4a97dSRui Paulo 
66bbe4a97dSRui Paulo struct aibs_sensor {
67bbe4a97dSRui Paulo 	ACPI_INTEGER	v;
68bbe4a97dSRui Paulo 	ACPI_INTEGER	i;
69bbe4a97dSRui Paulo 	ACPI_INTEGER	l;
70bbe4a97dSRui Paulo 	ACPI_INTEGER	h;
712698bbbbSAndriy Gapon 	int		t;
72bbe4a97dSRui Paulo };
73bbe4a97dSRui Paulo 
74bbe4a97dSRui Paulo struct aibs_softc {
75a8cd0393SAdrian Chadd 	device_t		sc_dev;
76bbe4a97dSRui Paulo 	ACPI_HANDLE		sc_ah;
77bbe4a97dSRui Paulo 
78bbe4a97dSRui Paulo 	struct aibs_sensor	*sc_asens_volt;
79bbe4a97dSRui Paulo 	struct aibs_sensor	*sc_asens_temp;
80bbe4a97dSRui Paulo 	struct aibs_sensor	*sc_asens_fan;
812698bbbbSAndriy Gapon 	struct aibs_sensor	*sc_asens_all;
822698bbbbSAndriy Gapon 
832698bbbbSAndriy Gapon 	struct sysctl_oid	*sc_volt_sysctl;
842698bbbbSAndriy Gapon 	struct sysctl_oid	*sc_temp_sysctl;
852698bbbbSAndriy Gapon 	struct sysctl_oid	*sc_fan_sysctl;
862698bbbbSAndriy Gapon 
872698bbbbSAndriy Gapon 	bool			sc_ggrp_method;
88bbe4a97dSRui Paulo };
89bbe4a97dSRui Paulo 
90bbe4a97dSRui Paulo static int aibs_probe(device_t);
91bbe4a97dSRui Paulo static int aibs_attach(device_t);
92bbe4a97dSRui Paulo static int aibs_detach(device_t);
93bbe4a97dSRui Paulo static int aibs_sysctl(SYSCTL_HANDLER_ARGS);
942698bbbbSAndriy Gapon static int aibs_sysctl_ggrp(SYSCTL_HANDLER_ARGS);
95bbe4a97dSRui Paulo 
962698bbbbSAndriy Gapon static int aibs_attach_ggrp(struct aibs_softc *);
972698bbbbSAndriy Gapon static int aibs_attach_sif(struct aibs_softc *, int);
98bbe4a97dSRui Paulo 
99bbe4a97dSRui Paulo static device_method_t aibs_methods[] = {
100bbe4a97dSRui Paulo 	DEVMETHOD(device_probe,		aibs_probe),
101bbe4a97dSRui Paulo 	DEVMETHOD(device_attach,	aibs_attach),
102bbe4a97dSRui Paulo 	DEVMETHOD(device_detach,	aibs_detach),
103bbe4a97dSRui Paulo 	{ NULL, NULL }
104bbe4a97dSRui Paulo };
105bbe4a97dSRui Paulo 
106bbe4a97dSRui Paulo static driver_t aibs_driver = {
107bbe4a97dSRui Paulo 	"aibs",
108bbe4a97dSRui Paulo 	aibs_methods,
109bbe4a97dSRui Paulo 	sizeof(struct aibs_softc)
110bbe4a97dSRui Paulo };
111bbe4a97dSRui Paulo 
112bbe4a97dSRui Paulo static devclass_t aibs_devclass;
113bbe4a97dSRui Paulo 
114bbe4a97dSRui Paulo DRIVER_MODULE(aibs, acpi, aibs_driver, aibs_devclass, NULL, NULL);
115bbdf953eSKevin Lo MODULE_DEPEND(aibs, acpi, 1, 1, 1);
116bbe4a97dSRui Paulo 
117bbe4a97dSRui Paulo static char* aibs_hids[] = {
118bbe4a97dSRui Paulo 	"ATK0110",
119bbe4a97dSRui Paulo 	NULL
120bbe4a97dSRui Paulo };
121bbe4a97dSRui Paulo 
122bbe4a97dSRui Paulo static int
123bbe4a97dSRui Paulo aibs_probe(device_t dev)
124bbe4a97dSRui Paulo {
1255efca36fSTakanori Watanabe 	int rv;
126bbe4a97dSRui Paulo 
1275efca36fSTakanori Watanabe 	if (acpi_disabled("aibs"))
1285efca36fSTakanori Watanabe 		return (ENXIO);
1295efca36fSTakanori Watanabe 	rv = ACPI_ID_PROBE(device_get_parent(dev), dev, aibs_hids, NULL);
1305efca36fSTakanori Watanabe 	if (rv <= 0 )
131bbe4a97dSRui Paulo 		device_set_desc(dev, "ASUSTeK AI Booster (ACPI ASOC ATK0110)");
132*f01b5ed9SAndriy Gapon 	return (rv);
133bbe4a97dSRui Paulo }
134bbe4a97dSRui Paulo 
135bbe4a97dSRui Paulo static int
136bbe4a97dSRui Paulo aibs_attach(device_t dev)
137bbe4a97dSRui Paulo {
138bbe4a97dSRui Paulo 	struct aibs_softc *sc = device_get_softc(dev);
1392698bbbbSAndriy Gapon 	int err;
140bbe4a97dSRui Paulo 
141bbe4a97dSRui Paulo 	sc->sc_dev = dev;
142bbe4a97dSRui Paulo 	sc->sc_ah = acpi_get_handle(dev);
143bbe4a97dSRui Paulo 
1442698bbbbSAndriy Gapon 	sc->sc_ggrp_method = false;
1452698bbbbSAndriy Gapon 	err = aibs_attach_sif(sc, AIBS_SENS_TYPE_VOLT);
1462698bbbbSAndriy Gapon 	if (err == 0)
1472698bbbbSAndriy Gapon 		err = aibs_attach_sif(sc, AIBS_SENS_TYPE_TEMP);
1482698bbbbSAndriy Gapon 	if (err == 0)
1492698bbbbSAndriy Gapon 		err = aibs_attach_sif(sc, AIBS_SENS_TYPE_FAN);
150bbe4a97dSRui Paulo 
1512698bbbbSAndriy Gapon 	if (err == 0)
1522698bbbbSAndriy Gapon 		return (0);
1532698bbbbSAndriy Gapon 
1542698bbbbSAndriy Gapon 	/* Clean up whatever was allocated earlier. */
1552698bbbbSAndriy Gapon 	if (sc->sc_volt_sysctl != NULL)
1562698bbbbSAndriy Gapon 		sysctl_remove_oid(sc->sc_volt_sysctl, true, true);
1572698bbbbSAndriy Gapon 	if (sc->sc_temp_sysctl != NULL)
1582698bbbbSAndriy Gapon 		sysctl_remove_oid(sc->sc_temp_sysctl, true, true);
1592698bbbbSAndriy Gapon 	if (sc->sc_fan_sysctl != NULL)
1602698bbbbSAndriy Gapon 		sysctl_remove_oid(sc->sc_fan_sysctl, true, true);
1612698bbbbSAndriy Gapon 	aibs_detach(dev);
1622698bbbbSAndriy Gapon 
1632698bbbbSAndriy Gapon 	sc->sc_ggrp_method = true;
1642698bbbbSAndriy Gapon 	err = aibs_attach_ggrp(sc);
1652698bbbbSAndriy Gapon 	return (err);
1662698bbbbSAndriy Gapon }
1672698bbbbSAndriy Gapon 
1682698bbbbSAndriy Gapon static int
1692698bbbbSAndriy Gapon aibs_add_sensor(struct aibs_softc *sc, ACPI_OBJECT *o,
1702698bbbbSAndriy Gapon     struct aibs_sensor* sensor, const char ** descr)
1712698bbbbSAndriy Gapon {
1722698bbbbSAndriy Gapon 	int		off;
1732698bbbbSAndriy Gapon 
1742698bbbbSAndriy Gapon 	/*
1752698bbbbSAndriy Gapon 	 * Packages for the old and new methods are quite
1762698bbbbSAndriy Gapon 	 * similar except that the new package has two
1772698bbbbSAndriy Gapon 	 * new (unknown / unused) fields after the name field.
1782698bbbbSAndriy Gapon 	 */
1792698bbbbSAndriy Gapon 	if (sc->sc_ggrp_method)
1802698bbbbSAndriy Gapon 		off = 4;
1812698bbbbSAndriy Gapon 	else
1822698bbbbSAndriy Gapon 		off = 2;
1832698bbbbSAndriy Gapon 
1842698bbbbSAndriy Gapon 	if (o->Type != ACPI_TYPE_PACKAGE) {
1852698bbbbSAndriy Gapon 		device_printf(sc->sc_dev,
1862698bbbbSAndriy Gapon 		    "sensor object is not a package: %i type\n",
1872698bbbbSAndriy Gapon 		     o->Type);
1882698bbbbSAndriy Gapon 		return (ENXIO);
1892698bbbbSAndriy Gapon 	}
1902698bbbbSAndriy Gapon 	if (o[0].Package.Count != (off + 3) ||
1912698bbbbSAndriy Gapon 	    o->Package.Elements[0].Type != ACPI_TYPE_INTEGER ||
1922698bbbbSAndriy Gapon 	    o->Package.Elements[1].Type != ACPI_TYPE_STRING ||
1932698bbbbSAndriy Gapon 	    o->Package.Elements[off].Type != ACPI_TYPE_INTEGER ||
1942698bbbbSAndriy Gapon 	    o->Package.Elements[off + 1].Type != ACPI_TYPE_INTEGER ||
1952698bbbbSAndriy Gapon 	    o->Package.Elements[off + 2].Type != ACPI_TYPE_INTEGER) {
1962698bbbbSAndriy Gapon 		device_printf(sc->sc_dev, "unexpected package content\n");
1972698bbbbSAndriy Gapon 		return (ENXIO);
1982698bbbbSAndriy Gapon 	}
1992698bbbbSAndriy Gapon 
2002698bbbbSAndriy Gapon 	sensor->i = o->Package.Elements[0].Integer.Value;
2012698bbbbSAndriy Gapon 	*descr = o->Package.Elements[1].String.Pointer;
2022698bbbbSAndriy Gapon 	sensor->l = o->Package.Elements[off].Integer.Value;
2032698bbbbSAndriy Gapon 	sensor->h = o->Package.Elements[off + 1].Integer.Value;
2042698bbbbSAndriy Gapon 	/* For the new method the second value is a range size. */
2052698bbbbSAndriy Gapon 	if (sc->sc_ggrp_method)
2062698bbbbSAndriy Gapon 		sensor->h += sensor->l;
2072698bbbbSAndriy Gapon 	sensor->t = AIBS_SENS_TYPE(sensor->i);
2082698bbbbSAndriy Gapon 
2092698bbbbSAndriy Gapon 	switch (sensor->t) {
2102698bbbbSAndriy Gapon 	case AIBS_SENS_TYPE_VOLT:
2112698bbbbSAndriy Gapon 	case AIBS_SENS_TYPE_TEMP:
2122698bbbbSAndriy Gapon 	case AIBS_SENS_TYPE_FAN:
2132698bbbbSAndriy Gapon 		return (0);
2142698bbbbSAndriy Gapon 	default:
2152698bbbbSAndriy Gapon 		device_printf(sc->sc_dev, "unknown sensor type 0x%x",
2162698bbbbSAndriy Gapon 		    sensor->t);
2172698bbbbSAndriy Gapon 		return (ENXIO);
2182698bbbbSAndriy Gapon 	}
219bbe4a97dSRui Paulo }
220bbe4a97dSRui Paulo 
221bbe4a97dSRui Paulo static void
2222698bbbbSAndriy Gapon aibs_sensor_added(struct aibs_softc *sc, struct sysctl_oid *so,
2232698bbbbSAndriy Gapon     const char *type_name, int idx, struct aibs_sensor *sensor,
2242698bbbbSAndriy Gapon     const char *descr)
225bbe4a97dSRui Paulo {
2262698bbbbSAndriy Gapon 	char	sysctl_name[8];
2272698bbbbSAndriy Gapon 
2282698bbbbSAndriy Gapon 	snprintf(sysctl_name, sizeof(sysctl_name), "%i", idx);
2292698bbbbSAndriy Gapon #ifdef AIBS_VERBOSE
2302698bbbbSAndriy Gapon 	device_printf(sc->sc_dev, "%c%i: 0x%08jx %20s %5jd / %5jd\n",
2312698bbbbSAndriy Gapon 	    type_name[0], idx,
2322698bbbbSAndriy Gapon 	    (uintmax_t)sensor->i, descr, (intmax_t)sensor->l,
2332698bbbbSAndriy Gapon 	    (intmax_t)sensor->h);
2342698bbbbSAndriy Gapon #endif
2352698bbbbSAndriy Gapon 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(sc->sc_dev),
2362698bbbbSAndriy Gapon 	    SYSCTL_CHILDREN(so), idx, sysctl_name,
2372698bbbbSAndriy Gapon 	    CTLTYPE_INT | CTLFLAG_RD, sc, (uintptr_t)sensor,
2382698bbbbSAndriy Gapon 	    sc->sc_ggrp_method ? aibs_sysctl_ggrp : aibs_sysctl,
2392698bbbbSAndriy Gapon 	    sensor->t == AIBS_SENS_TYPE_TEMP ? "IK" : "I", descr);
2402698bbbbSAndriy Gapon }
2412698bbbbSAndriy Gapon 
2422698bbbbSAndriy Gapon static int
2432698bbbbSAndriy Gapon aibs_attach_ggrp(struct aibs_softc *sc)
2442698bbbbSAndriy Gapon {
2452698bbbbSAndriy Gapon 	ACPI_STATUS		s;
2462698bbbbSAndriy Gapon 	ACPI_BUFFER		buf;
2472698bbbbSAndriy Gapon 	ACPI_HANDLE		h;
2482698bbbbSAndriy Gapon 	ACPI_OBJECT		id;
2492698bbbbSAndriy Gapon 	ACPI_OBJECT		*bp;
2502698bbbbSAndriy Gapon 	ACPI_OBJECT_LIST	arg;
2512698bbbbSAndriy Gapon 	int			i;
2522698bbbbSAndriy Gapon 	int			t, v, f;
2532698bbbbSAndriy Gapon 	int			err;
2542698bbbbSAndriy Gapon 	int			*s_idx;
2552698bbbbSAndriy Gapon 	const char		*name;
2562698bbbbSAndriy Gapon 	const char		*descr;
2572698bbbbSAndriy Gapon 	struct aibs_sensor	*sensor;
2582698bbbbSAndriy Gapon 	struct sysctl_oid	**so;
2592698bbbbSAndriy Gapon 
2602698bbbbSAndriy Gapon 	/* First see if GITM is available. */
2612698bbbbSAndriy Gapon 	s = AcpiGetHandle(sc->sc_ah, "GITM", &h);
2622698bbbbSAndriy Gapon 	if (ACPI_FAILURE(s)) {
2632698bbbbSAndriy Gapon 		if (bootverbose)
2642698bbbbSAndriy Gapon 			device_printf(sc->sc_dev, "GITM not found\n");
2652698bbbbSAndriy Gapon 		return (ENXIO);
2662698bbbbSAndriy Gapon 	}
2672698bbbbSAndriy Gapon 
2682698bbbbSAndriy Gapon 	/*
2692698bbbbSAndriy Gapon 	 * Now call GGRP with the appropriate argument to list sensors.
2702698bbbbSAndriy Gapon 	 * The method lists different groups of entities depending on
2712698bbbbSAndriy Gapon 	 * the argument.
2722698bbbbSAndriy Gapon 	 */
2732698bbbbSAndriy Gapon 	id.Integer.Value = AIBS_GROUP_SENSORS;
2742698bbbbSAndriy Gapon 	id.Type = ACPI_TYPE_INTEGER;
2752698bbbbSAndriy Gapon 	arg.Count = 1;
2762698bbbbSAndriy Gapon 	arg.Pointer = &id;
2772698bbbbSAndriy Gapon 	buf.Length = ACPI_ALLOCATE_BUFFER;
2782698bbbbSAndriy Gapon 	buf.Pointer = NULL;
2792698bbbbSAndriy Gapon 	s = AcpiEvaluateObjectTyped(sc->sc_ah, "GGRP", &arg, &buf,
2802698bbbbSAndriy Gapon 	    ACPI_TYPE_PACKAGE);
2812698bbbbSAndriy Gapon 	if (ACPI_FAILURE(s)) {
2822698bbbbSAndriy Gapon 		device_printf(sc->sc_dev, "GGRP not found\n");
2832698bbbbSAndriy Gapon 		return (ENXIO);
2842698bbbbSAndriy Gapon 	}
2852698bbbbSAndriy Gapon 
2862698bbbbSAndriy Gapon 	bp = buf.Pointer;
2872698bbbbSAndriy Gapon 	sc->sc_asens_all = malloc(sizeof(*sc->sc_asens_all) * bp->Package.Count,
2882698bbbbSAndriy Gapon 	    M_DEVBUF, M_WAITOK | M_ZERO);
2892698bbbbSAndriy Gapon 	v = t = f = 0;
2902698bbbbSAndriy Gapon 	for (i = 0; i < bp->Package.Count; i++) {
2912698bbbbSAndriy Gapon 		sensor = &sc->sc_asens_all[i];
2922698bbbbSAndriy Gapon 		err = aibs_add_sensor(sc, &bp->Package.Elements[i], sensor,
2932698bbbbSAndriy Gapon 		    &descr);
2942698bbbbSAndriy Gapon 		if (err != 0)
2952698bbbbSAndriy Gapon 			continue;
2962698bbbbSAndriy Gapon 
2972698bbbbSAndriy Gapon 		switch (sensor->t) {
2982698bbbbSAndriy Gapon 		case AIBS_SENS_TYPE_VOLT:
2992698bbbbSAndriy Gapon 			name = "volt";
3002698bbbbSAndriy Gapon 			so = &sc->sc_volt_sysctl;
3012698bbbbSAndriy Gapon 			s_idx = &v;
3022698bbbbSAndriy Gapon 			break;
3032698bbbbSAndriy Gapon 		case AIBS_SENS_TYPE_TEMP:
3042698bbbbSAndriy Gapon 			name = "temp";
3052698bbbbSAndriy Gapon 			so = &sc->sc_temp_sysctl;
3062698bbbbSAndriy Gapon 			s_idx = &t;
3072698bbbbSAndriy Gapon 			break;
3082698bbbbSAndriy Gapon 		case AIBS_SENS_TYPE_FAN:
3092698bbbbSAndriy Gapon 			name = "fan";
3102698bbbbSAndriy Gapon 			so = &sc->sc_fan_sysctl;
3112698bbbbSAndriy Gapon 			s_idx = &f;
3122698bbbbSAndriy Gapon 			break;
3132698bbbbSAndriy Gapon 		default:
3142698bbbbSAndriy Gapon 			panic("add_sensor succeeded for unknown sensor type %d",
3152698bbbbSAndriy Gapon 			    sensor->t);
3162698bbbbSAndriy Gapon 		}
3172698bbbbSAndriy Gapon 
3182698bbbbSAndriy Gapon 		if (*so == NULL) {
3192698bbbbSAndriy Gapon 			/* sysctl subtree for sensors of this type */
3202698bbbbSAndriy Gapon 			*so = SYSCTL_ADD_NODE(device_get_sysctl_ctx(sc->sc_dev),
3212698bbbbSAndriy Gapon 			    SYSCTL_CHILDREN(device_get_sysctl_tree(sc->sc_dev)),
3222698bbbbSAndriy Gapon 			    sensor->t, name, CTLFLAG_RD, NULL, NULL);
3232698bbbbSAndriy Gapon 		}
3242698bbbbSAndriy Gapon 		aibs_sensor_added(sc, *so, name, *s_idx, sensor, descr);
3252698bbbbSAndriy Gapon 		*s_idx += 1;
3262698bbbbSAndriy Gapon 	}
3272698bbbbSAndriy Gapon 
3282698bbbbSAndriy Gapon 	AcpiOsFree(buf.Pointer);
3292698bbbbSAndriy Gapon 	return (0);
3302698bbbbSAndriy Gapon }
3312698bbbbSAndriy Gapon 
3322698bbbbSAndriy Gapon static int
3332698bbbbSAndriy Gapon aibs_attach_sif(struct aibs_softc *sc, int st)
3342698bbbbSAndriy Gapon {
3352698bbbbSAndriy Gapon 	char			name[] = "?SIF";
336bbe4a97dSRui Paulo 	ACPI_STATUS		s;
337bbe4a97dSRui Paulo 	ACPI_BUFFER		b;
338bbe4a97dSRui Paulo 	ACPI_OBJECT		*bp, *o;
339bbe4a97dSRui Paulo 	const char		*node;
340bbe4a97dSRui Paulo 	struct aibs_sensor	*as;
3412698bbbbSAndriy Gapon 	struct sysctl_oid	**so;
3422698bbbbSAndriy Gapon 	int			i, n;
3432698bbbbSAndriy Gapon 	int err;
344bbe4a97dSRui Paulo 
345bbe4a97dSRui Paulo 	switch (st) {
3462698bbbbSAndriy Gapon 	case AIBS_SENS_TYPE_VOLT:
347bbe4a97dSRui Paulo 		node = "volt";
348bbe4a97dSRui Paulo 		name[0] = 'V';
3492698bbbbSAndriy Gapon 		so = &sc->sc_volt_sysctl;
350bbe4a97dSRui Paulo 		break;
3512698bbbbSAndriy Gapon 	case AIBS_SENS_TYPE_TEMP:
352bbe4a97dSRui Paulo 		node = "temp";
353bbe4a97dSRui Paulo 		name[0] = 'T';
3542698bbbbSAndriy Gapon 		so = &sc->sc_temp_sysctl;
355bbe4a97dSRui Paulo 		break;
3562698bbbbSAndriy Gapon 	case AIBS_SENS_TYPE_FAN:
357bbe4a97dSRui Paulo 		node = "fan";
358bbe4a97dSRui Paulo 		name[0] = 'F';
3592698bbbbSAndriy Gapon 		so = &sc->sc_fan_sysctl;
360bbe4a97dSRui Paulo 		break;
361bbe4a97dSRui Paulo 	default:
3622698bbbbSAndriy Gapon 		panic("Unsupported sensor type %d", st);
363bbe4a97dSRui Paulo 	}
364bbe4a97dSRui Paulo 
365bbe4a97dSRui Paulo 	b.Length = ACPI_ALLOCATE_BUFFER;
366bbe4a97dSRui Paulo 	s = AcpiEvaluateObjectTyped(sc->sc_ah, name, NULL, &b,
367bbe4a97dSRui Paulo 	    ACPI_TYPE_PACKAGE);
368bbe4a97dSRui Paulo 	if (ACPI_FAILURE(s)) {
369bbe4a97dSRui Paulo 		device_printf(sc->sc_dev, "%s not found\n", name);
3702698bbbbSAndriy Gapon 		return (ENXIO);
371bbe4a97dSRui Paulo 	}
372bbe4a97dSRui Paulo 
373bbe4a97dSRui Paulo 	bp = b.Pointer;
374bbe4a97dSRui Paulo 	o = bp->Package.Elements;
375bbe4a97dSRui Paulo 	if (o[0].Type != ACPI_TYPE_INTEGER) {
376bbe4a97dSRui Paulo 		device_printf(sc->sc_dev, "%s[0]: invalid type\n", name);
377bbe4a97dSRui Paulo 		AcpiOsFree(b.Pointer);
3782698bbbbSAndriy Gapon 		return (ENXIO);
379bbe4a97dSRui Paulo 	}
380bbe4a97dSRui Paulo 
381bbe4a97dSRui Paulo 	n = o[0].Integer.Value;
382bbe4a97dSRui Paulo 	if (bp->Package.Count - 1 < n) {
383bbe4a97dSRui Paulo 		device_printf(sc->sc_dev, "%s: invalid package\n", name);
384bbe4a97dSRui Paulo 		AcpiOsFree(b.Pointer);
3852698bbbbSAndriy Gapon 		return (ENXIO);
386bbe4a97dSRui Paulo 	} else if (bp->Package.Count - 1 > n) {
387bbe4a97dSRui Paulo 		int on = n;
388bbe4a97dSRui Paulo 
389bbe4a97dSRui Paulo #ifdef AIBS_MORE_SENSORS
390bbe4a97dSRui Paulo 		n = bp->Package.Count - 1;
391bbe4a97dSRui Paulo #endif
392bbe4a97dSRui Paulo 		device_printf(sc->sc_dev, "%s: malformed package: %i/%i"
393bbe4a97dSRui Paulo 		    ", assume %i\n", name, on, bp->Package.Count - 1, n);
394bbe4a97dSRui Paulo 	}
395bbe4a97dSRui Paulo 	if (n < 1) {
396bbe4a97dSRui Paulo 		device_printf(sc->sc_dev, "%s: no members in the package\n",
397bbe4a97dSRui Paulo 		    name);
398bbe4a97dSRui Paulo 		AcpiOsFree(b.Pointer);
3992698bbbbSAndriy Gapon 		return (ENXIO);
400bbe4a97dSRui Paulo 	}
401bbe4a97dSRui Paulo 
4022698bbbbSAndriy Gapon 	as = malloc(sizeof(*as) * n, M_DEVBUF, M_WAITOK | M_ZERO);
403bbe4a97dSRui Paulo 	switch (st) {
4042698bbbbSAndriy Gapon 	case AIBS_SENS_TYPE_VOLT:
405bbe4a97dSRui Paulo 		sc->sc_asens_volt = as;
406bbe4a97dSRui Paulo 		break;
4072698bbbbSAndriy Gapon 	case AIBS_SENS_TYPE_TEMP:
408bbe4a97dSRui Paulo 		sc->sc_asens_temp = as;
409bbe4a97dSRui Paulo 		break;
4102698bbbbSAndriy Gapon 	case AIBS_SENS_TYPE_FAN:
411bbe4a97dSRui Paulo 		sc->sc_asens_fan = as;
412bbe4a97dSRui Paulo 		break;
413bbe4a97dSRui Paulo 	}
414bbe4a97dSRui Paulo 
415bbe4a97dSRui Paulo 	/* sysctl subtree for sensors of this type */
4162698bbbbSAndriy Gapon 	*so = SYSCTL_ADD_NODE(device_get_sysctl_ctx(sc->sc_dev),
417bbe4a97dSRui Paulo 	    SYSCTL_CHILDREN(device_get_sysctl_tree(sc->sc_dev)), st,
418bbe4a97dSRui Paulo 	    node, CTLFLAG_RD, NULL, NULL);
419bbe4a97dSRui Paulo 
420bbe4a97dSRui Paulo 	for (i = 0, o++; i < n; i++, o++) {
4212698bbbbSAndriy Gapon 		const char	*descr;
422bbe4a97dSRui Paulo 
4232698bbbbSAndriy Gapon 		err = aibs_add_sensor(sc, o, &as[i], &descr);
4242698bbbbSAndriy Gapon 		if (err == 0)
4252698bbbbSAndriy Gapon 			aibs_sensor_added(sc, *so, node, i, &as[i], descr);
426bbe4a97dSRui Paulo 	}
427bbe4a97dSRui Paulo 
428bbe4a97dSRui Paulo 	AcpiOsFree(b.Pointer);
4292698bbbbSAndriy Gapon 	return (0);
430bbe4a97dSRui Paulo }
431bbe4a97dSRui Paulo 
432bbe4a97dSRui Paulo static int
433bbe4a97dSRui Paulo aibs_detach(device_t dev)
434bbe4a97dSRui Paulo {
435bbe4a97dSRui Paulo 	struct aibs_softc	*sc = device_get_softc(dev);
436bbe4a97dSRui Paulo 
437bbe4a97dSRui Paulo 	if (sc->sc_asens_volt != NULL)
438bbe4a97dSRui Paulo 		free(sc->sc_asens_volt, M_DEVBUF);
439bbe4a97dSRui Paulo 	if (sc->sc_asens_temp != NULL)
440bbe4a97dSRui Paulo 		free(sc->sc_asens_temp, M_DEVBUF);
441bbe4a97dSRui Paulo 	if (sc->sc_asens_fan != NULL)
442bbe4a97dSRui Paulo 		free(sc->sc_asens_fan, M_DEVBUF);
4432698bbbbSAndriy Gapon 	if (sc->sc_asens_all != NULL)
4442698bbbbSAndriy Gapon 		free(sc->sc_asens_all, M_DEVBUF);
4452698bbbbSAndriy Gapon 	return (0);
446bbe4a97dSRui Paulo }
447bbe4a97dSRui Paulo 
448bbe4a97dSRui Paulo #ifdef AIBS_VERBOSE
449bbe4a97dSRui Paulo #define ddevice_printf(x...) device_printf(x)
450bbe4a97dSRui Paulo #else
451bbe4a97dSRui Paulo #define ddevice_printf(x...)
452bbe4a97dSRui Paulo #endif
453bbe4a97dSRui Paulo 
454bbe4a97dSRui Paulo static int
455bbe4a97dSRui Paulo aibs_sysctl(SYSCTL_HANDLER_ARGS)
456bbe4a97dSRui Paulo {
457bbe4a97dSRui Paulo 	struct aibs_softc	*sc = arg1;
458a1e2190cSDimitry Andric 	struct aibs_sensor	*sensor = (void *)(intptr_t)arg2;
459bbe4a97dSRui Paulo 	int			i = oidp->oid_number;
460bbe4a97dSRui Paulo 	ACPI_STATUS		rs;
461bbe4a97dSRui Paulo 	ACPI_OBJECT		p, *bp;
462bbe4a97dSRui Paulo 	ACPI_OBJECT_LIST	mp;
463bbe4a97dSRui Paulo 	ACPI_BUFFER		b;
464bbe4a97dSRui Paulo 	char			*name;
465bbe4a97dSRui Paulo 	ACPI_INTEGER		v, l, h;
466bbe4a97dSRui Paulo 	int			so[3];
467bbe4a97dSRui Paulo 
4682698bbbbSAndriy Gapon 	switch (sensor->t) {
4692698bbbbSAndriy Gapon 	case AIBS_SENS_TYPE_VOLT:
470bbe4a97dSRui Paulo 		name = "RVLT";
471bbe4a97dSRui Paulo 		break;
4722698bbbbSAndriy Gapon 	case AIBS_SENS_TYPE_TEMP:
473bbe4a97dSRui Paulo 		name = "RTMP";
474bbe4a97dSRui Paulo 		break;
4752698bbbbSAndriy Gapon 	case AIBS_SENS_TYPE_FAN:
476bbe4a97dSRui Paulo 		name = "RFAN";
477bbe4a97dSRui Paulo 		break;
478bbe4a97dSRui Paulo 	default:
4792698bbbbSAndriy Gapon 		return (ENOENT);
480bbe4a97dSRui Paulo 	}
4812698bbbbSAndriy Gapon 	l = sensor->l;
4822698bbbbSAndriy Gapon 	h = sensor->h;
483bbe4a97dSRui Paulo 	p.Type = ACPI_TYPE_INTEGER;
4842698bbbbSAndriy Gapon 	p.Integer.Value = sensor->i;
485bbe4a97dSRui Paulo 	mp.Count = 1;
486bbe4a97dSRui Paulo 	mp.Pointer = &p;
487bbe4a97dSRui Paulo 	b.Length = ACPI_ALLOCATE_BUFFER;
488bbe4a97dSRui Paulo 	ACPI_SERIAL_BEGIN(aibs);
489bbe4a97dSRui Paulo 	rs = AcpiEvaluateObjectTyped(sc->sc_ah, name, &mp, &b,
490bbe4a97dSRui Paulo 	    ACPI_TYPE_INTEGER);
491bbe4a97dSRui Paulo 	if (ACPI_FAILURE(rs)) {
492bbe4a97dSRui Paulo 		ddevice_printf(sc->sc_dev,
493bbe4a97dSRui Paulo 		    "%s: %i: evaluation failed\n",
494bbe4a97dSRui Paulo 		    name, i);
495bbe4a97dSRui Paulo 		ACPI_SERIAL_END(aibs);
4962698bbbbSAndriy Gapon 		return (EIO);
497bbe4a97dSRui Paulo 	}
498bbe4a97dSRui Paulo 	bp = b.Pointer;
499bbe4a97dSRui Paulo 	v = bp->Integer.Value;
500bbe4a97dSRui Paulo 	AcpiOsFree(b.Pointer);
501bbe4a97dSRui Paulo 	ACPI_SERIAL_END(aibs);
502bbe4a97dSRui Paulo 
5032698bbbbSAndriy Gapon 	switch (sensor->t) {
5042698bbbbSAndriy Gapon 	case AIBS_SENS_TYPE_VOLT:
505bbe4a97dSRui Paulo 		break;
5062698bbbbSAndriy Gapon 	case AIBS_SENS_TYPE_TEMP:
5079d6672e1SLuiz Otavio O Souza 		v += 2731;
5089d6672e1SLuiz Otavio O Souza 		l += 2731;
5099d6672e1SLuiz Otavio O Souza 		h += 2731;
510bbe4a97dSRui Paulo 		break;
5112698bbbbSAndriy Gapon 	case AIBS_SENS_TYPE_FAN:
512bbe4a97dSRui Paulo 		break;
513bbe4a97dSRui Paulo 	}
514bbe4a97dSRui Paulo 	so[0] = v;
515bbe4a97dSRui Paulo 	so[1] = l;
516bbe4a97dSRui Paulo 	so[2] = h;
5172698bbbbSAndriy Gapon 	return (sysctl_handle_opaque(oidp, &so, sizeof(so), req));
5182698bbbbSAndriy Gapon }
5192698bbbbSAndriy Gapon 
5202698bbbbSAndriy Gapon static int
5212698bbbbSAndriy Gapon aibs_sysctl_ggrp(SYSCTL_HANDLER_ARGS)
5222698bbbbSAndriy Gapon {
5232698bbbbSAndriy Gapon 	struct aibs_softc	*sc = arg1;
524a1e2190cSDimitry Andric 	struct aibs_sensor	*sensor = (void *)(intptr_t)arg2;
5252698bbbbSAndriy Gapon 	ACPI_STATUS		rs;
5262698bbbbSAndriy Gapon 	ACPI_OBJECT		p, *bp;
5272698bbbbSAndriy Gapon 	ACPI_OBJECT_LIST	arg;
5282698bbbbSAndriy Gapon 	ACPI_BUFFER		buf;
5292698bbbbSAndriy Gapon 	ACPI_INTEGER		v, l, h;
5302698bbbbSAndriy Gapon 	int			so[3];
5312698bbbbSAndriy Gapon 	uint32_t		*ret;
5322698bbbbSAndriy Gapon 	uint32_t		cmd[3];
5332698bbbbSAndriy Gapon 
5342698bbbbSAndriy Gapon 	cmd[0] = sensor->i;
5352698bbbbSAndriy Gapon 	cmd[1] = 0;
5362698bbbbSAndriy Gapon 	cmd[2] = 0;
5372698bbbbSAndriy Gapon 	p.Type = ACPI_TYPE_BUFFER;
5382698bbbbSAndriy Gapon 	p.Buffer.Pointer = (void *)cmd;
5392698bbbbSAndriy Gapon 	p.Buffer.Length = sizeof(cmd);
5402698bbbbSAndriy Gapon 	arg.Count = 1;
5412698bbbbSAndriy Gapon 	arg.Pointer = &p;
5422698bbbbSAndriy Gapon 	buf.Pointer = NULL;
5432698bbbbSAndriy Gapon 	buf.Length = ACPI_ALLOCATE_BUFFER;
5442698bbbbSAndriy Gapon 	ACPI_SERIAL_BEGIN(aibs);
5452698bbbbSAndriy Gapon 	rs = AcpiEvaluateObjectTyped(sc->sc_ah, "GITM", &arg, &buf,
5462698bbbbSAndriy Gapon 	    ACPI_TYPE_BUFFER);
5472698bbbbSAndriy Gapon 	ACPI_SERIAL_END(aibs);
5482698bbbbSAndriy Gapon 	if (ACPI_FAILURE(rs)) {
5492698bbbbSAndriy Gapon 		device_printf(sc->sc_dev, "GITM evaluation failed\n");
5502698bbbbSAndriy Gapon 		return (EIO);
5512698bbbbSAndriy Gapon 	}
5522698bbbbSAndriy Gapon 	bp = buf.Pointer;
5532698bbbbSAndriy Gapon 	if (bp->Buffer.Length < 8) {
5542698bbbbSAndriy Gapon 		device_printf(sc->sc_dev, "GITM returned short buffer\n");
5552698bbbbSAndriy Gapon 		return (EIO);
5562698bbbbSAndriy Gapon 	}
5572698bbbbSAndriy Gapon 	ret = (uint32_t *)bp->Buffer.Pointer;
5582698bbbbSAndriy Gapon 	if (ret[0] == 0) {
5592698bbbbSAndriy Gapon 		device_printf(sc->sc_dev, "GITM returned error status\n");
5602698bbbbSAndriy Gapon 		return (EINVAL);
5612698bbbbSAndriy Gapon 	}
5622698bbbbSAndriy Gapon 	v = ret[1];
5632698bbbbSAndriy Gapon 	AcpiOsFree(buf.Pointer);
5642698bbbbSAndriy Gapon 
5652698bbbbSAndriy Gapon 	l = sensor->l;
5662698bbbbSAndriy Gapon 	h = sensor->h;
5672698bbbbSAndriy Gapon 
5682698bbbbSAndriy Gapon 	switch (sensor->t) {
5692698bbbbSAndriy Gapon 	case AIBS_SENS_TYPE_VOLT:
5702698bbbbSAndriy Gapon 		break;
5712698bbbbSAndriy Gapon 	case AIBS_SENS_TYPE_TEMP:
5722698bbbbSAndriy Gapon 		v += 2731;
5732698bbbbSAndriy Gapon 		l += 2731;
5742698bbbbSAndriy Gapon 		h += 2731;
5752698bbbbSAndriy Gapon 		break;
5762698bbbbSAndriy Gapon 	case AIBS_SENS_TYPE_FAN:
5772698bbbbSAndriy Gapon 		break;
5782698bbbbSAndriy Gapon 	}
5792698bbbbSAndriy Gapon 	so[0] = v;
5802698bbbbSAndriy Gapon 	so[1] = l;
5812698bbbbSAndriy Gapon 	so[2] = h;
5822698bbbbSAndriy Gapon 	return (sysctl_handle_opaque(oidp, &so, sizeof(so), req));
583bbe4a97dSRui Paulo }
584