1209523Srpaulo/*	$NetBSD: atk0110.c,v 1.4 2010/02/11 06:54:57 cnst Exp $	*/
2209523Srpaulo/*	$OpenBSD: atk0110.c,v 1.1 2009/07/23 01:38:16 cnst Exp $	*/
3209523Srpaulo
4209523Srpaulo/*
5209523Srpaulo * Copyright (c) 2009, 2010 Constantine A. Murenin <cnst++@FreeBSD.org>
6209523Srpaulo *
7209523Srpaulo * Permission to use, copy, modify, and distribute this software for any
8209523Srpaulo * purpose with or without fee is hereby granted, provided that the above
9209523Srpaulo * copyright notice and this permission notice appear in all copies.
10209523Srpaulo *
11209523Srpaulo * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12209523Srpaulo * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13209523Srpaulo * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14209523Srpaulo * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15209523Srpaulo * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16209523Srpaulo * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17209523Srpaulo * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18209523Srpaulo */
19209523Srpaulo
20209523Srpaulo#include <sys/cdefs.h>
21209523Srpaulo__FBSDID("$FreeBSD: stable/11/sys/dev/acpi_support/atk0110.c 335471 2018-06-21 09:41:44Z dim $");
22209523Srpaulo
23209523Srpaulo#include <machine/_inttypes.h>
24209523Srpaulo#include <sys/param.h>
25209523Srpaulo#include <sys/systm.h>
26209523Srpaulo#include <sys/kernel.h>
27209523Srpaulo#include <sys/bus.h>
28209523Srpaulo#include <sys/module.h>
29209523Srpaulo#include <sys/malloc.h>
30209523Srpaulo#include <sys/sysctl.h>
31308368Savg#include <sys/stdint.h>
32209523Srpaulo
33209523Srpaulo#include <contrib/dev/acpica/include/acpi.h>
34209523Srpaulo#include <dev/acpica/acpivar.h>
35209523Srpaulo
36209523Srpaulo/*
37209523Srpaulo * ASUSTeK AI Booster (ACPI ASOC ATK0110).
38209523Srpaulo *
39209523Srpaulo * This code was originally written for OpenBSD after the techniques
40209523Srpaulo * described in the Linux's asus_atk0110.c and FreeBSD's Takanori Watanabe's
41209523Srpaulo * acpi_aiboost.c were verified to be accurate on the actual hardware kindly
42209523Srpaulo * provided by Sam Fourman Jr.  It was subsequently ported from OpenBSD to
43209523Srpaulo * DragonFly BSD, to NetBSD's sysmon_envsys(9) and to FreeBSD's sysctl(9).
44209523Srpaulo *
45209523Srpaulo *				  -- Constantine A. Murenin <http://cnst.su/>
46209523Srpaulo */
47209523Srpaulo
48209523Srpaulo#define _COMPONENT	ACPI_OEM
49209523SrpauloACPI_MODULE_NAME("aibs");
50209523SrpauloACPI_SERIAL_DECL(aibs, "aibs");
51209523Srpaulo
52209523Srpaulo#define AIBS_MORE_SENSORS
53209523Srpaulo#define AIBS_VERBOSE
54209523Srpaulo
55308368Savg#define	AIBS_GROUP_SENSORS	0x06
56209523Srpaulo
57308368Savg#define AIBS_SENS_TYPE(x)	(((x) >> 16) & 0xff)
58308368Savg#define AIBS_SENS_TYPE_VOLT	2
59308368Savg#define AIBS_SENS_TYPE_TEMP	3
60308368Savg#define AIBS_SENS_TYPE_FAN	4
61308368Savg
62308368Savg#define	AIBS_SENS_TYPE_VOLT_NAME		"volt"
63308368Savg#define	AIBS_SENS_TYPE_VOLT_TEMP		"temp"
64308368Savg#define	AIBS_SENS_TYPE_VOLT_FAN		"fan"
65308368Savg
66209523Srpaulostruct aibs_sensor {
67209523Srpaulo	ACPI_INTEGER	v;
68209523Srpaulo	ACPI_INTEGER	i;
69209523Srpaulo	ACPI_INTEGER	l;
70209523Srpaulo	ACPI_INTEGER	h;
71308368Savg	int		t;
72209523Srpaulo};
73209523Srpaulo
74209523Srpaulostruct aibs_softc {
75299052Sadrian	device_t		sc_dev;
76209523Srpaulo	ACPI_HANDLE		sc_ah;
77209523Srpaulo
78209523Srpaulo	struct aibs_sensor	*sc_asens_volt;
79209523Srpaulo	struct aibs_sensor	*sc_asens_temp;
80209523Srpaulo	struct aibs_sensor	*sc_asens_fan;
81308368Savg	struct aibs_sensor	*sc_asens_all;
82308368Savg
83308368Savg	struct sysctl_oid	*sc_volt_sysctl;
84308368Savg	struct sysctl_oid	*sc_temp_sysctl;
85308368Savg	struct sysctl_oid	*sc_fan_sysctl;
86308368Savg
87308368Savg	bool			sc_ggrp_method;
88209523Srpaulo};
89209523Srpaulo
90209523Srpaulostatic int aibs_probe(device_t);
91209523Srpaulostatic int aibs_attach(device_t);
92209523Srpaulostatic int aibs_detach(device_t);
93209523Srpaulostatic int aibs_sysctl(SYSCTL_HANDLER_ARGS);
94308368Savgstatic int aibs_sysctl_ggrp(SYSCTL_HANDLER_ARGS);
95209523Srpaulo
96308368Savgstatic int aibs_attach_ggrp(struct aibs_softc *);
97308368Savgstatic int aibs_attach_sif(struct aibs_softc *, int);
98209523Srpaulo
99209523Srpaulostatic device_method_t aibs_methods[] = {
100209523Srpaulo	DEVMETHOD(device_probe,		aibs_probe),
101209523Srpaulo	DEVMETHOD(device_attach,	aibs_attach),
102209523Srpaulo	DEVMETHOD(device_detach,	aibs_detach),
103209523Srpaulo	{ NULL, NULL }
104209523Srpaulo};
105209523Srpaulo
106209523Srpaulostatic driver_t aibs_driver = {
107209523Srpaulo	"aibs",
108209523Srpaulo	aibs_methods,
109209523Srpaulo	sizeof(struct aibs_softc)
110209523Srpaulo};
111209523Srpaulo
112209523Srpaulostatic devclass_t aibs_devclass;
113209523Srpaulo
114209523SrpauloDRIVER_MODULE(aibs, acpi, aibs_driver, aibs_devclass, NULL, NULL);
115232256SkevloMODULE_DEPEND(aibs, acpi, 1, 1, 1);
116209523Srpaulo
117209523Srpaulostatic char* aibs_hids[] = {
118209523Srpaulo	"ATK0110",
119209523Srpaulo	NULL
120209523Srpaulo};
121209523Srpaulo
122209523Srpaulostatic int
123209523Srpauloaibs_probe(device_t dev)
124209523Srpaulo{
125209523Srpaulo	if (acpi_disabled("aibs") ||
126209523Srpaulo	    ACPI_ID_PROBE(device_get_parent(dev), dev, aibs_hids) == NULL)
127308368Savg		return (ENXIO);
128209523Srpaulo
129209523Srpaulo	device_set_desc(dev, "ASUSTeK AI Booster (ACPI ASOC ATK0110)");
130308368Savg	return (0);
131209523Srpaulo}
132209523Srpaulo
133209523Srpaulostatic int
134209523Srpauloaibs_attach(device_t dev)
135209523Srpaulo{
136209523Srpaulo	struct aibs_softc *sc = device_get_softc(dev);
137308368Savg	int err;
138209523Srpaulo
139209523Srpaulo	sc->sc_dev = dev;
140209523Srpaulo	sc->sc_ah = acpi_get_handle(dev);
141209523Srpaulo
142308368Savg	sc->sc_ggrp_method = false;
143308368Savg	err = aibs_attach_sif(sc, AIBS_SENS_TYPE_VOLT);
144308368Savg	if (err == 0)
145308368Savg		err = aibs_attach_sif(sc, AIBS_SENS_TYPE_TEMP);
146308368Savg	if (err == 0)
147308368Savg		err = aibs_attach_sif(sc, AIBS_SENS_TYPE_FAN);
148209523Srpaulo
149308368Savg	if (err == 0)
150308368Savg		return (0);
151308368Savg
152308368Savg	/* Clean up whatever was allocated earlier. */
153308368Savg	if (sc->sc_volt_sysctl != NULL)
154308368Savg		sysctl_remove_oid(sc->sc_volt_sysctl, true, true);
155308368Savg	if (sc->sc_temp_sysctl != NULL)
156308368Savg		sysctl_remove_oid(sc->sc_temp_sysctl, true, true);
157308368Savg	if (sc->sc_fan_sysctl != NULL)
158308368Savg		sysctl_remove_oid(sc->sc_fan_sysctl, true, true);
159308368Savg	aibs_detach(dev);
160308368Savg
161308368Savg	sc->sc_ggrp_method = true;
162308368Savg	err = aibs_attach_ggrp(sc);
163308368Savg	return (err);
164209523Srpaulo}
165209523Srpaulo
166308368Savgstatic int
167308368Savgaibs_add_sensor(struct aibs_softc *sc, ACPI_OBJECT *o,
168308368Savg    struct aibs_sensor* sensor, const char ** descr)
169308368Savg{
170308368Savg	int		off;
171308368Savg
172308368Savg	/*
173308368Savg	 * Packages for the old and new methods are quite
174308368Savg	 * similar except that the new package has two
175308368Savg	 * new (unknown / unused) fields after the name field.
176308368Savg	 */
177308368Savg	if (sc->sc_ggrp_method)
178308368Savg		off = 4;
179308368Savg	else
180308368Savg		off = 2;
181308368Savg
182308368Savg	if (o->Type != ACPI_TYPE_PACKAGE) {
183308368Savg		device_printf(sc->sc_dev,
184308368Savg		    "sensor object is not a package: %i type\n",
185308368Savg		     o->Type);
186308368Savg		return (ENXIO);
187308368Savg	}
188308368Savg	if (o[0].Package.Count != (off + 3) ||
189308368Savg	    o->Package.Elements[0].Type != ACPI_TYPE_INTEGER ||
190308368Savg	    o->Package.Elements[1].Type != ACPI_TYPE_STRING ||
191308368Savg	    o->Package.Elements[off].Type != ACPI_TYPE_INTEGER ||
192308368Savg	    o->Package.Elements[off + 1].Type != ACPI_TYPE_INTEGER ||
193308368Savg	    o->Package.Elements[off + 2].Type != ACPI_TYPE_INTEGER) {
194308368Savg		device_printf(sc->sc_dev, "unexpected package content\n");
195308368Savg		return (ENXIO);
196308368Savg	}
197308368Savg
198308368Savg	sensor->i = o->Package.Elements[0].Integer.Value;
199308368Savg	*descr = o->Package.Elements[1].String.Pointer;
200308368Savg	sensor->l = o->Package.Elements[off].Integer.Value;
201308368Savg	sensor->h = o->Package.Elements[off + 1].Integer.Value;
202308368Savg	/* For the new method the second value is a range size. */
203308368Savg	if (sc->sc_ggrp_method)
204308368Savg		sensor->h += sensor->l;
205308368Savg	sensor->t = AIBS_SENS_TYPE(sensor->i);
206308368Savg
207308368Savg	switch (sensor->t) {
208308368Savg	case AIBS_SENS_TYPE_VOLT:
209308368Savg	case AIBS_SENS_TYPE_TEMP:
210308368Savg	case AIBS_SENS_TYPE_FAN:
211308368Savg		return (0);
212308368Savg	default:
213308368Savg		device_printf(sc->sc_dev, "unknown sensor type 0x%x",
214308368Savg		    sensor->t);
215308368Savg		return (ENXIO);
216308368Savg	}
217308368Savg}
218308368Savg
219209523Srpaulostatic void
220308368Savgaibs_sensor_added(struct aibs_softc *sc, struct sysctl_oid *so,
221308368Savg    const char *type_name, int idx, struct aibs_sensor *sensor,
222308368Savg    const char *descr)
223209523Srpaulo{
224308368Savg	char	sysctl_name[8];
225308368Savg
226308368Savg	snprintf(sysctl_name, sizeof(sysctl_name), "%i", idx);
227308368Savg#ifdef AIBS_VERBOSE
228308368Savg	device_printf(sc->sc_dev, "%c%i: 0x%08jx %20s %5jd / %5jd\n",
229308368Savg	    type_name[0], idx,
230308368Savg	    (uintmax_t)sensor->i, descr, (intmax_t)sensor->l,
231308368Savg	    (intmax_t)sensor->h);
232308368Savg#endif
233308368Savg	SYSCTL_ADD_PROC(device_get_sysctl_ctx(sc->sc_dev),
234308368Savg	    SYSCTL_CHILDREN(so), idx, sysctl_name,
235308368Savg	    CTLTYPE_INT | CTLFLAG_RD, sc, (uintptr_t)sensor,
236308368Savg	    sc->sc_ggrp_method ? aibs_sysctl_ggrp : aibs_sysctl,
237308368Savg	    sensor->t == AIBS_SENS_TYPE_TEMP ? "IK" : "I", descr);
238308368Savg}
239308368Savg
240308368Savgstatic int
241308368Savgaibs_attach_ggrp(struct aibs_softc *sc)
242308368Savg{
243209523Srpaulo	ACPI_STATUS		s;
244308368Savg	ACPI_BUFFER		buf;
245308368Savg	ACPI_HANDLE		h;
246308368Savg	ACPI_OBJECT		id;
247308368Savg	ACPI_OBJECT		*bp;
248308368Savg	ACPI_OBJECT_LIST	arg;
249308368Savg	int			i;
250308368Savg	int			t, v, f;
251308368Savg	int			err;
252308368Savg	int			*s_idx;
253308368Savg	const char		*name;
254308368Savg	const char		*descr;
255308368Savg	struct aibs_sensor	*sensor;
256308368Savg	struct sysctl_oid	**so;
257308368Savg
258308368Savg	/* First see if GITM is available. */
259308368Savg	s = AcpiGetHandle(sc->sc_ah, "GITM", &h);
260308368Savg	if (ACPI_FAILURE(s)) {
261308368Savg		if (bootverbose)
262308368Savg			device_printf(sc->sc_dev, "GITM not found\n");
263308368Savg		return (ENXIO);
264308368Savg	}
265308368Savg
266308368Savg	/*
267308368Savg	 * Now call GGRP with the appropriate argument to list sensors.
268308368Savg	 * The method lists different groups of entities depending on
269308368Savg	 * the argument.
270308368Savg	 */
271308368Savg	id.Integer.Value = AIBS_GROUP_SENSORS;
272308368Savg	id.Type = ACPI_TYPE_INTEGER;
273308368Savg	arg.Count = 1;
274308368Savg	arg.Pointer = &id;
275308368Savg	buf.Length = ACPI_ALLOCATE_BUFFER;
276308368Savg	buf.Pointer = NULL;
277308368Savg	s = AcpiEvaluateObjectTyped(sc->sc_ah, "GGRP", &arg, &buf,
278308368Savg	    ACPI_TYPE_PACKAGE);
279308368Savg	if (ACPI_FAILURE(s)) {
280308368Savg		device_printf(sc->sc_dev, "GGRP not found\n");
281308368Savg		return (ENXIO);
282308368Savg	}
283308368Savg
284308368Savg	bp = buf.Pointer;
285308368Savg	sc->sc_asens_all = malloc(sizeof(*sc->sc_asens_all) * bp->Package.Count,
286308368Savg	    M_DEVBUF, M_WAITOK | M_ZERO);
287308368Savg	v = t = f = 0;
288308368Savg	for (i = 0; i < bp->Package.Count; i++) {
289308368Savg		sensor = &sc->sc_asens_all[i];
290308368Savg		err = aibs_add_sensor(sc, &bp->Package.Elements[i], sensor,
291308368Savg		    &descr);
292308368Savg		if (err != 0)
293308368Savg			continue;
294308368Savg
295308368Savg		switch (sensor->t) {
296308368Savg		case AIBS_SENS_TYPE_VOLT:
297308368Savg			name = "volt";
298308368Savg			so = &sc->sc_volt_sysctl;
299308368Savg			s_idx = &v;
300308368Savg			break;
301308368Savg		case AIBS_SENS_TYPE_TEMP:
302308368Savg			name = "temp";
303308368Savg			so = &sc->sc_temp_sysctl;
304308368Savg			s_idx = &t;
305308368Savg			break;
306308368Savg		case AIBS_SENS_TYPE_FAN:
307308368Savg			name = "fan";
308308368Savg			so = &sc->sc_fan_sysctl;
309308368Savg			s_idx = &f;
310308368Savg			break;
311308368Savg		default:
312308368Savg			panic("add_sensor succeeded for unknown sensor type %d",
313308368Savg			    sensor->t);
314308368Savg		}
315308368Savg
316308368Savg		if (*so == NULL) {
317308368Savg			/* sysctl subtree for sensors of this type */
318308368Savg			*so = SYSCTL_ADD_NODE(device_get_sysctl_ctx(sc->sc_dev),
319308368Savg			    SYSCTL_CHILDREN(device_get_sysctl_tree(sc->sc_dev)),
320308368Savg			    sensor->t, name, CTLFLAG_RD, NULL, NULL);
321308368Savg		}
322308368Savg		aibs_sensor_added(sc, *so, name, *s_idx, sensor, descr);
323308368Savg		*s_idx += 1;
324308368Savg	}
325308368Savg
326308368Savg	AcpiOsFree(buf.Pointer);
327308368Savg	return (0);
328308368Savg}
329308368Savg
330308368Savgstatic int
331308368Savgaibs_attach_sif(struct aibs_softc *sc, int st)
332308368Savg{
333308368Savg	char			name[] = "?SIF";
334308368Savg	ACPI_STATUS		s;
335209523Srpaulo	ACPI_BUFFER		b;
336209523Srpaulo	ACPI_OBJECT		*bp, *o;
337209523Srpaulo	const char		*node;
338209523Srpaulo	struct aibs_sensor	*as;
339308368Savg	struct sysctl_oid	**so;
340308368Savg	int			i, n;
341308368Savg	int err;
342209523Srpaulo
343209523Srpaulo	switch (st) {
344308368Savg	case AIBS_SENS_TYPE_VOLT:
345209523Srpaulo		node = "volt";
346209523Srpaulo		name[0] = 'V';
347308368Savg		so = &sc->sc_volt_sysctl;
348209523Srpaulo		break;
349308368Savg	case AIBS_SENS_TYPE_TEMP:
350209523Srpaulo		node = "temp";
351209523Srpaulo		name[0] = 'T';
352308368Savg		so = &sc->sc_temp_sysctl;
353209523Srpaulo		break;
354308368Savg	case AIBS_SENS_TYPE_FAN:
355209523Srpaulo		node = "fan";
356209523Srpaulo		name[0] = 'F';
357308368Savg		so = &sc->sc_fan_sysctl;
358209523Srpaulo		break;
359209523Srpaulo	default:
360308368Savg		panic("Unsupported sensor type %d", st);
361209523Srpaulo	}
362209523Srpaulo
363209523Srpaulo	b.Length = ACPI_ALLOCATE_BUFFER;
364209523Srpaulo	s = AcpiEvaluateObjectTyped(sc->sc_ah, name, NULL, &b,
365209523Srpaulo	    ACPI_TYPE_PACKAGE);
366209523Srpaulo	if (ACPI_FAILURE(s)) {
367209523Srpaulo		device_printf(sc->sc_dev, "%s not found\n", name);
368308368Savg		return (ENXIO);
369209523Srpaulo	}
370209523Srpaulo
371209523Srpaulo	bp = b.Pointer;
372209523Srpaulo	o = bp->Package.Elements;
373209523Srpaulo	if (o[0].Type != ACPI_TYPE_INTEGER) {
374209523Srpaulo		device_printf(sc->sc_dev, "%s[0]: invalid type\n", name);
375209523Srpaulo		AcpiOsFree(b.Pointer);
376308368Savg		return (ENXIO);
377209523Srpaulo	}
378209523Srpaulo
379209523Srpaulo	n = o[0].Integer.Value;
380209523Srpaulo	if (bp->Package.Count - 1 < n) {
381209523Srpaulo		device_printf(sc->sc_dev, "%s: invalid package\n", name);
382209523Srpaulo		AcpiOsFree(b.Pointer);
383308368Savg		return (ENXIO);
384209523Srpaulo	} else if (bp->Package.Count - 1 > n) {
385209523Srpaulo		int on = n;
386209523Srpaulo
387209523Srpaulo#ifdef AIBS_MORE_SENSORS
388209523Srpaulo		n = bp->Package.Count - 1;
389209523Srpaulo#endif
390209523Srpaulo		device_printf(sc->sc_dev, "%s: malformed package: %i/%i"
391209523Srpaulo		    ", assume %i\n", name, on, bp->Package.Count - 1, n);
392209523Srpaulo	}
393209523Srpaulo	if (n < 1) {
394209523Srpaulo		device_printf(sc->sc_dev, "%s: no members in the package\n",
395209523Srpaulo		    name);
396209523Srpaulo		AcpiOsFree(b.Pointer);
397308368Savg		return (ENXIO);
398209523Srpaulo	}
399209523Srpaulo
400308368Savg	as = malloc(sizeof(*as) * n, M_DEVBUF, M_WAITOK | M_ZERO);
401209523Srpaulo	switch (st) {
402308368Savg	case AIBS_SENS_TYPE_VOLT:
403209523Srpaulo		sc->sc_asens_volt = as;
404209523Srpaulo		break;
405308368Savg	case AIBS_SENS_TYPE_TEMP:
406209523Srpaulo		sc->sc_asens_temp = as;
407209523Srpaulo		break;
408308368Savg	case AIBS_SENS_TYPE_FAN:
409209523Srpaulo		sc->sc_asens_fan = as;
410209523Srpaulo		break;
411209523Srpaulo	}
412209523Srpaulo
413209523Srpaulo	/* sysctl subtree for sensors of this type */
414308368Savg	*so = SYSCTL_ADD_NODE(device_get_sysctl_ctx(sc->sc_dev),
415209523Srpaulo	    SYSCTL_CHILDREN(device_get_sysctl_tree(sc->sc_dev)), st,
416209523Srpaulo	    node, CTLFLAG_RD, NULL, NULL);
417209523Srpaulo
418209523Srpaulo	for (i = 0, o++; i < n; i++, o++) {
419308368Savg		const char	*descr;
420209523Srpaulo
421308368Savg		err = aibs_add_sensor(sc, o, &as[i], &descr);
422308368Savg		if (err == 0)
423308368Savg			aibs_sensor_added(sc, *so, node, i, &as[i], descr);
424209523Srpaulo	}
425209523Srpaulo
426209523Srpaulo	AcpiOsFree(b.Pointer);
427308368Savg	return (0);
428209523Srpaulo}
429209523Srpaulo
430209523Srpaulostatic int
431209523Srpauloaibs_detach(device_t dev)
432209523Srpaulo{
433209523Srpaulo	struct aibs_softc	*sc = device_get_softc(dev);
434209523Srpaulo
435209523Srpaulo	if (sc->sc_asens_volt != NULL)
436209523Srpaulo		free(sc->sc_asens_volt, M_DEVBUF);
437209523Srpaulo	if (sc->sc_asens_temp != NULL)
438209523Srpaulo		free(sc->sc_asens_temp, M_DEVBUF);
439209523Srpaulo	if (sc->sc_asens_fan != NULL)
440209523Srpaulo		free(sc->sc_asens_fan, M_DEVBUF);
441308368Savg	if (sc->sc_asens_all != NULL)
442308368Savg		free(sc->sc_asens_all, M_DEVBUF);
443308368Savg	return (0);
444209523Srpaulo}
445209523Srpaulo
446209523Srpaulo#ifdef AIBS_VERBOSE
447209523Srpaulo#define ddevice_printf(x...) device_printf(x)
448209523Srpaulo#else
449209523Srpaulo#define ddevice_printf(x...)
450209523Srpaulo#endif
451209523Srpaulo
452209523Srpaulostatic int
453209523Srpauloaibs_sysctl(SYSCTL_HANDLER_ARGS)
454209523Srpaulo{
455209523Srpaulo	struct aibs_softc	*sc = arg1;
456335471Sdim	struct aibs_sensor	*sensor = (void *)(intptr_t)arg2;
457209523Srpaulo	int			i = oidp->oid_number;
458209523Srpaulo	ACPI_STATUS		rs;
459209523Srpaulo	ACPI_OBJECT		p, *bp;
460209523Srpaulo	ACPI_OBJECT_LIST	mp;
461209523Srpaulo	ACPI_BUFFER		b;
462209523Srpaulo	char			*name;
463209523Srpaulo	ACPI_INTEGER		v, l, h;
464209523Srpaulo	int			so[3];
465209523Srpaulo
466308368Savg	switch (sensor->t) {
467308368Savg	case AIBS_SENS_TYPE_VOLT:
468209523Srpaulo		name = "RVLT";
469209523Srpaulo		break;
470308368Savg	case AIBS_SENS_TYPE_TEMP:
471209523Srpaulo		name = "RTMP";
472209523Srpaulo		break;
473308368Savg	case AIBS_SENS_TYPE_FAN:
474209523Srpaulo		name = "RFAN";
475209523Srpaulo		break;
476209523Srpaulo	default:
477308368Savg		return (ENOENT);
478209523Srpaulo	}
479308368Savg	l = sensor->l;
480308368Savg	h = sensor->h;
481209523Srpaulo	p.Type = ACPI_TYPE_INTEGER;
482308368Savg	p.Integer.Value = sensor->i;
483209523Srpaulo	mp.Count = 1;
484209523Srpaulo	mp.Pointer = &p;
485209523Srpaulo	b.Length = ACPI_ALLOCATE_BUFFER;
486209523Srpaulo	ACPI_SERIAL_BEGIN(aibs);
487209523Srpaulo	rs = AcpiEvaluateObjectTyped(sc->sc_ah, name, &mp, &b,
488209523Srpaulo	    ACPI_TYPE_INTEGER);
489209523Srpaulo	if (ACPI_FAILURE(rs)) {
490209523Srpaulo		ddevice_printf(sc->sc_dev,
491209523Srpaulo		    "%s: %i: evaluation failed\n",
492209523Srpaulo		    name, i);
493209523Srpaulo		ACPI_SERIAL_END(aibs);
494308368Savg		return (EIO);
495209523Srpaulo	}
496209523Srpaulo	bp = b.Pointer;
497209523Srpaulo	v = bp->Integer.Value;
498209523Srpaulo	AcpiOsFree(b.Pointer);
499209523Srpaulo	ACPI_SERIAL_END(aibs);
500209523Srpaulo
501308368Savg	switch (sensor->t) {
502308368Savg	case AIBS_SENS_TYPE_VOLT:
503209523Srpaulo		break;
504308368Savg	case AIBS_SENS_TYPE_TEMP:
505300421Sloos		v += 2731;
506300421Sloos		l += 2731;
507300421Sloos		h += 2731;
508209523Srpaulo		break;
509308368Savg	case AIBS_SENS_TYPE_FAN:
510209523Srpaulo		break;
511209523Srpaulo	}
512209523Srpaulo	so[0] = v;
513209523Srpaulo	so[1] = l;
514209523Srpaulo	so[2] = h;
515308368Savg	return (sysctl_handle_opaque(oidp, &so, sizeof(so), req));
516209523Srpaulo}
517308368Savg
518308368Savgstatic int
519308368Savgaibs_sysctl_ggrp(SYSCTL_HANDLER_ARGS)
520308368Savg{
521308368Savg	struct aibs_softc	*sc = arg1;
522335471Sdim	struct aibs_sensor	*sensor = (void *)(intptr_t)arg2;
523308368Savg	ACPI_STATUS		rs;
524308368Savg	ACPI_OBJECT		p, *bp;
525308368Savg	ACPI_OBJECT_LIST	arg;
526308368Savg	ACPI_BUFFER		buf;
527308368Savg	ACPI_INTEGER		v, l, h;
528308368Savg	int			so[3];
529308368Savg	uint32_t		*ret;
530308368Savg	uint32_t		cmd[3];
531308368Savg
532308368Savg	cmd[0] = sensor->i;
533308368Savg	cmd[1] = 0;
534308368Savg	cmd[2] = 0;
535308368Savg	p.Type = ACPI_TYPE_BUFFER;
536308368Savg	p.Buffer.Pointer = (void *)cmd;
537308368Savg	p.Buffer.Length = sizeof(cmd);
538308368Savg	arg.Count = 1;
539308368Savg	arg.Pointer = &p;
540308368Savg	buf.Pointer = NULL;
541308368Savg	buf.Length = ACPI_ALLOCATE_BUFFER;
542308368Savg	ACPI_SERIAL_BEGIN(aibs);
543308368Savg	rs = AcpiEvaluateObjectTyped(sc->sc_ah, "GITM", &arg, &buf,
544308368Savg	    ACPI_TYPE_BUFFER);
545308368Savg	ACPI_SERIAL_END(aibs);
546308368Savg	if (ACPI_FAILURE(rs)) {
547308368Savg		device_printf(sc->sc_dev, "GITM evaluation failed\n");
548308368Savg		return (EIO);
549308368Savg	}
550308368Savg	bp = buf.Pointer;
551308368Savg	if (bp->Buffer.Length < 8) {
552308368Savg		device_printf(sc->sc_dev, "GITM returned short buffer\n");
553308368Savg		return (EIO);
554308368Savg	}
555308368Savg	ret = (uint32_t *)bp->Buffer.Pointer;
556308368Savg	if (ret[0] == 0) {
557308368Savg		device_printf(sc->sc_dev, "GITM returned error status\n");
558308368Savg		return (EINVAL);
559308368Savg	}
560308368Savg	v = ret[1];
561308368Savg	AcpiOsFree(buf.Pointer);
562308368Savg
563308368Savg	l = sensor->l;
564308368Savg	h = sensor->h;
565308368Savg
566308368Savg	switch (sensor->t) {
567308368Savg	case AIBS_SENS_TYPE_VOLT:
568308368Savg		break;
569308368Savg	case AIBS_SENS_TYPE_TEMP:
570308368Savg		v += 2731;
571308368Savg		l += 2731;
572308368Savg		h += 2731;
573308368Savg		break;
574308368Savg	case AIBS_SENS_TYPE_FAN:
575308368Savg		break;
576308368Savg	}
577308368Savg	so[0] = v;
578308368Savg	so[1] = l;
579308368Savg	so[2] = h;
580308368Savg	return (sysctl_handle_opaque(oidp, &so, sizeof(so), req));
581308368Savg}
582