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 #include <machine/_inttypes.h>
22bbe4a97dSRui Paulo #include <sys/param.h>
23bbe4a97dSRui Paulo #include <sys/systm.h>
24bbe4a97dSRui Paulo #include <sys/kernel.h>
25bbe4a97dSRui Paulo #include <sys/bus.h>
26bbe4a97dSRui Paulo #include <sys/module.h>
27bbe4a97dSRui Paulo #include <sys/malloc.h>
28bbe4a97dSRui Paulo #include <sys/sysctl.h>
292698bbbbSAndriy Gapon #include <sys/stdint.h>
30bbe4a97dSRui Paulo
31bbe4a97dSRui Paulo #include <contrib/dev/acpica/include/acpi.h>
32bbe4a97dSRui Paulo #include <dev/acpica/acpivar.h>
33bbe4a97dSRui Paulo
34bbe4a97dSRui Paulo /*
35bbe4a97dSRui Paulo * ASUSTeK AI Booster (ACPI ASOC ATK0110).
36bbe4a97dSRui Paulo *
37bbe4a97dSRui Paulo * This code was originally written for OpenBSD after the techniques
38bbe4a97dSRui Paulo * described in the Linux's asus_atk0110.c and FreeBSD's Takanori Watanabe's
39bbe4a97dSRui Paulo * acpi_aiboost.c were verified to be accurate on the actual hardware kindly
40bbe4a97dSRui Paulo * provided by Sam Fourman Jr. It was subsequently ported from OpenBSD to
41bbe4a97dSRui Paulo * DragonFly BSD, to NetBSD's sysmon_envsys(9) and to FreeBSD's sysctl(9).
42bbe4a97dSRui Paulo *
43bbe4a97dSRui Paulo * -- Constantine A. Murenin <http://cnst.su/>
44bbe4a97dSRui Paulo */
45bbe4a97dSRui Paulo
46bbe4a97dSRui Paulo #define _COMPONENT ACPI_OEM
47bbe4a97dSRui Paulo ACPI_MODULE_NAME("aibs");
48bbe4a97dSRui Paulo ACPI_SERIAL_DECL(aibs, "aibs");
49bbe4a97dSRui Paulo
50bbe4a97dSRui Paulo #define AIBS_MORE_SENSORS
51bbe4a97dSRui Paulo #define AIBS_VERBOSE
52bbe4a97dSRui Paulo
532698bbbbSAndriy Gapon #define AIBS_GROUP_SENSORS 0x06
542698bbbbSAndriy Gapon
552698bbbbSAndriy Gapon #define AIBS_SENS_TYPE(x) (((x) >> 16) & 0xff)
562698bbbbSAndriy Gapon #define AIBS_SENS_TYPE_VOLT 2
572698bbbbSAndriy Gapon #define AIBS_SENS_TYPE_TEMP 3
582698bbbbSAndriy Gapon #define AIBS_SENS_TYPE_FAN 4
592698bbbbSAndriy Gapon
602698bbbbSAndriy Gapon #define AIBS_SENS_TYPE_VOLT_NAME "volt"
612698bbbbSAndriy Gapon #define AIBS_SENS_TYPE_VOLT_TEMP "temp"
622698bbbbSAndriy Gapon #define AIBS_SENS_TYPE_VOLT_FAN "fan"
63bbe4a97dSRui Paulo
64bbe4a97dSRui Paulo struct aibs_sensor {
65bbe4a97dSRui Paulo ACPI_INTEGER v;
66bbe4a97dSRui Paulo ACPI_INTEGER i;
67bbe4a97dSRui Paulo ACPI_INTEGER l;
68bbe4a97dSRui Paulo ACPI_INTEGER h;
692698bbbbSAndriy Gapon int t;
70bbe4a97dSRui Paulo };
71bbe4a97dSRui Paulo
72bbe4a97dSRui Paulo struct aibs_softc {
73a8cd0393SAdrian Chadd device_t sc_dev;
74bbe4a97dSRui Paulo ACPI_HANDLE sc_ah;
75bbe4a97dSRui Paulo
76bbe4a97dSRui Paulo struct aibs_sensor *sc_asens_volt;
77bbe4a97dSRui Paulo struct aibs_sensor *sc_asens_temp;
78bbe4a97dSRui Paulo struct aibs_sensor *sc_asens_fan;
792698bbbbSAndriy Gapon struct aibs_sensor *sc_asens_all;
802698bbbbSAndriy Gapon
812698bbbbSAndriy Gapon struct sysctl_oid *sc_volt_sysctl;
822698bbbbSAndriy Gapon struct sysctl_oid *sc_temp_sysctl;
832698bbbbSAndriy Gapon struct sysctl_oid *sc_fan_sysctl;
842698bbbbSAndriy Gapon
852698bbbbSAndriy Gapon bool sc_ggrp_method;
86bbe4a97dSRui Paulo };
87bbe4a97dSRui Paulo
88bbe4a97dSRui Paulo static int aibs_probe(device_t);
89bbe4a97dSRui Paulo static int aibs_attach(device_t);
90bbe4a97dSRui Paulo static int aibs_detach(device_t);
91bbe4a97dSRui Paulo static int aibs_sysctl(SYSCTL_HANDLER_ARGS);
922698bbbbSAndriy Gapon static int aibs_sysctl_ggrp(SYSCTL_HANDLER_ARGS);
93bbe4a97dSRui Paulo
942698bbbbSAndriy Gapon static int aibs_attach_ggrp(struct aibs_softc *);
952698bbbbSAndriy Gapon static int aibs_attach_sif(struct aibs_softc *, int);
96bbe4a97dSRui Paulo
97bbe4a97dSRui Paulo static device_method_t aibs_methods[] = {
98bbe4a97dSRui Paulo DEVMETHOD(device_probe, aibs_probe),
99bbe4a97dSRui Paulo DEVMETHOD(device_attach, aibs_attach),
100bbe4a97dSRui Paulo DEVMETHOD(device_detach, aibs_detach),
101bbe4a97dSRui Paulo { NULL, NULL }
102bbe4a97dSRui Paulo };
103bbe4a97dSRui Paulo
104bbe4a97dSRui Paulo static driver_t aibs_driver = {
105bbe4a97dSRui Paulo "aibs",
106bbe4a97dSRui Paulo aibs_methods,
107bbe4a97dSRui Paulo sizeof(struct aibs_softc)
108bbe4a97dSRui Paulo };
109bbe4a97dSRui Paulo
110*90161e72SJohn Baldwin DRIVER_MODULE(aibs, acpi, aibs_driver, NULL, NULL);
111bbdf953eSKevin Lo MODULE_DEPEND(aibs, acpi, 1, 1, 1);
112bbe4a97dSRui Paulo
113bbe4a97dSRui Paulo static char* aibs_hids[] = {
114bbe4a97dSRui Paulo "ATK0110",
115bbe4a97dSRui Paulo NULL
116bbe4a97dSRui Paulo };
117bbe4a97dSRui Paulo
118bbe4a97dSRui Paulo static int
aibs_probe(device_t dev)119bbe4a97dSRui Paulo aibs_probe(device_t dev)
120bbe4a97dSRui Paulo {
1215efca36fSTakanori Watanabe int rv;
122bbe4a97dSRui Paulo
1235efca36fSTakanori Watanabe if (acpi_disabled("aibs"))
1245efca36fSTakanori Watanabe return (ENXIO);
1255efca36fSTakanori Watanabe rv = ACPI_ID_PROBE(device_get_parent(dev), dev, aibs_hids, NULL);
1265efca36fSTakanori Watanabe if (rv <= 0 )
127bbe4a97dSRui Paulo device_set_desc(dev, "ASUSTeK AI Booster (ACPI ASOC ATK0110)");
128f01b5ed9SAndriy Gapon return (rv);
129bbe4a97dSRui Paulo }
130bbe4a97dSRui Paulo
131bbe4a97dSRui Paulo static int
aibs_attach(device_t dev)132bbe4a97dSRui Paulo aibs_attach(device_t dev)
133bbe4a97dSRui Paulo {
134bbe4a97dSRui Paulo struct aibs_softc *sc = device_get_softc(dev);
1352698bbbbSAndriy Gapon int err;
136bbe4a97dSRui Paulo
137bbe4a97dSRui Paulo sc->sc_dev = dev;
138bbe4a97dSRui Paulo sc->sc_ah = acpi_get_handle(dev);
139bbe4a97dSRui Paulo
1402698bbbbSAndriy Gapon sc->sc_ggrp_method = false;
1412698bbbbSAndriy Gapon err = aibs_attach_sif(sc, AIBS_SENS_TYPE_VOLT);
1422698bbbbSAndriy Gapon if (err == 0)
1432698bbbbSAndriy Gapon err = aibs_attach_sif(sc, AIBS_SENS_TYPE_TEMP);
1442698bbbbSAndriy Gapon if (err == 0)
1452698bbbbSAndriy Gapon err = aibs_attach_sif(sc, AIBS_SENS_TYPE_FAN);
146bbe4a97dSRui Paulo
1472698bbbbSAndriy Gapon if (err == 0)
1482698bbbbSAndriy Gapon return (0);
1492698bbbbSAndriy Gapon
1502698bbbbSAndriy Gapon /* Clean up whatever was allocated earlier. */
1512698bbbbSAndriy Gapon if (sc->sc_volt_sysctl != NULL)
1522698bbbbSAndriy Gapon sysctl_remove_oid(sc->sc_volt_sysctl, true, true);
1532698bbbbSAndriy Gapon if (sc->sc_temp_sysctl != NULL)
1542698bbbbSAndriy Gapon sysctl_remove_oid(sc->sc_temp_sysctl, true, true);
1552698bbbbSAndriy Gapon if (sc->sc_fan_sysctl != NULL)
1562698bbbbSAndriy Gapon sysctl_remove_oid(sc->sc_fan_sysctl, true, true);
1572698bbbbSAndriy Gapon aibs_detach(dev);
1582698bbbbSAndriy Gapon
1592698bbbbSAndriy Gapon sc->sc_ggrp_method = true;
1602698bbbbSAndriy Gapon err = aibs_attach_ggrp(sc);
1612698bbbbSAndriy Gapon return (err);
1622698bbbbSAndriy Gapon }
1632698bbbbSAndriy Gapon
1642698bbbbSAndriy Gapon static int
aibs_add_sensor(struct aibs_softc * sc,ACPI_OBJECT * o,struct aibs_sensor * sensor,const char ** descr)1652698bbbbSAndriy Gapon aibs_add_sensor(struct aibs_softc *sc, ACPI_OBJECT *o,
1662698bbbbSAndriy Gapon struct aibs_sensor* sensor, const char ** descr)
1672698bbbbSAndriy Gapon {
1682698bbbbSAndriy Gapon int off;
1692698bbbbSAndriy Gapon
1702698bbbbSAndriy Gapon /*
1712698bbbbSAndriy Gapon * Packages for the old and new methods are quite
1722698bbbbSAndriy Gapon * similar except that the new package has two
1732698bbbbSAndriy Gapon * new (unknown / unused) fields after the name field.
1742698bbbbSAndriy Gapon */
1752698bbbbSAndriy Gapon if (sc->sc_ggrp_method)
1762698bbbbSAndriy Gapon off = 4;
1772698bbbbSAndriy Gapon else
1782698bbbbSAndriy Gapon off = 2;
1792698bbbbSAndriy Gapon
1802698bbbbSAndriy Gapon if (o->Type != ACPI_TYPE_PACKAGE) {
1812698bbbbSAndriy Gapon device_printf(sc->sc_dev,
1822698bbbbSAndriy Gapon "sensor object is not a package: %i type\n",
1832698bbbbSAndriy Gapon o->Type);
1842698bbbbSAndriy Gapon return (ENXIO);
1852698bbbbSAndriy Gapon }
1862698bbbbSAndriy Gapon if (o[0].Package.Count != (off + 3) ||
1872698bbbbSAndriy Gapon o->Package.Elements[0].Type != ACPI_TYPE_INTEGER ||
1882698bbbbSAndriy Gapon o->Package.Elements[1].Type != ACPI_TYPE_STRING ||
1892698bbbbSAndriy Gapon o->Package.Elements[off].Type != ACPI_TYPE_INTEGER ||
1902698bbbbSAndriy Gapon o->Package.Elements[off + 1].Type != ACPI_TYPE_INTEGER ||
1912698bbbbSAndriy Gapon o->Package.Elements[off + 2].Type != ACPI_TYPE_INTEGER) {
1922698bbbbSAndriy Gapon device_printf(sc->sc_dev, "unexpected package content\n");
1932698bbbbSAndriy Gapon return (ENXIO);
1942698bbbbSAndriy Gapon }
1952698bbbbSAndriy Gapon
1962698bbbbSAndriy Gapon sensor->i = o->Package.Elements[0].Integer.Value;
1972698bbbbSAndriy Gapon *descr = o->Package.Elements[1].String.Pointer;
1982698bbbbSAndriy Gapon sensor->l = o->Package.Elements[off].Integer.Value;
1992698bbbbSAndriy Gapon sensor->h = o->Package.Elements[off + 1].Integer.Value;
2002698bbbbSAndriy Gapon /* For the new method the second value is a range size. */
2012698bbbbSAndriy Gapon if (sc->sc_ggrp_method)
2022698bbbbSAndriy Gapon sensor->h += sensor->l;
2032698bbbbSAndriy Gapon sensor->t = AIBS_SENS_TYPE(sensor->i);
2042698bbbbSAndriy Gapon
2052698bbbbSAndriy Gapon switch (sensor->t) {
2062698bbbbSAndriy Gapon case AIBS_SENS_TYPE_VOLT:
2072698bbbbSAndriy Gapon case AIBS_SENS_TYPE_TEMP:
2082698bbbbSAndriy Gapon case AIBS_SENS_TYPE_FAN:
2092698bbbbSAndriy Gapon return (0);
2102698bbbbSAndriy Gapon default:
2112698bbbbSAndriy Gapon device_printf(sc->sc_dev, "unknown sensor type 0x%x",
2122698bbbbSAndriy Gapon sensor->t);
2132698bbbbSAndriy Gapon return (ENXIO);
2142698bbbbSAndriy Gapon }
215bbe4a97dSRui Paulo }
216bbe4a97dSRui Paulo
217bbe4a97dSRui Paulo static void
aibs_sensor_added(struct aibs_softc * sc,struct sysctl_oid * so,const char * type_name,int idx,struct aibs_sensor * sensor,const char * descr)2182698bbbbSAndriy Gapon aibs_sensor_added(struct aibs_softc *sc, struct sysctl_oid *so,
2192698bbbbSAndriy Gapon const char *type_name, int idx, struct aibs_sensor *sensor,
2202698bbbbSAndriy Gapon const char *descr)
221bbe4a97dSRui Paulo {
2222698bbbbSAndriy Gapon char sysctl_name[8];
2232698bbbbSAndriy Gapon
2242698bbbbSAndriy Gapon snprintf(sysctl_name, sizeof(sysctl_name), "%i", idx);
2252698bbbbSAndriy Gapon #ifdef AIBS_VERBOSE
2262698bbbbSAndriy Gapon device_printf(sc->sc_dev, "%c%i: 0x%08jx %20s %5jd / %5jd\n",
2272698bbbbSAndriy Gapon type_name[0], idx,
2282698bbbbSAndriy Gapon (uintmax_t)sensor->i, descr, (intmax_t)sensor->l,
2292698bbbbSAndriy Gapon (intmax_t)sensor->h);
2302698bbbbSAndriy Gapon #endif
2312698bbbbSAndriy Gapon SYSCTL_ADD_PROC(device_get_sysctl_ctx(sc->sc_dev),
2322698bbbbSAndriy Gapon SYSCTL_CHILDREN(so), idx, sysctl_name,
2336237a1ccSAlexander Motin CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, (uintptr_t)sensor,
2342698bbbbSAndriy Gapon sc->sc_ggrp_method ? aibs_sysctl_ggrp : aibs_sysctl,
2352698bbbbSAndriy Gapon sensor->t == AIBS_SENS_TYPE_TEMP ? "IK" : "I", descr);
2362698bbbbSAndriy Gapon }
2372698bbbbSAndriy Gapon
2382698bbbbSAndriy Gapon static int
aibs_attach_ggrp(struct aibs_softc * sc)2392698bbbbSAndriy Gapon aibs_attach_ggrp(struct aibs_softc *sc)
2402698bbbbSAndriy Gapon {
2412698bbbbSAndriy Gapon ACPI_STATUS s;
2422698bbbbSAndriy Gapon ACPI_BUFFER buf;
2432698bbbbSAndriy Gapon ACPI_HANDLE h;
2442698bbbbSAndriy Gapon ACPI_OBJECT id;
2452698bbbbSAndriy Gapon ACPI_OBJECT *bp;
2462698bbbbSAndriy Gapon ACPI_OBJECT_LIST arg;
2472698bbbbSAndriy Gapon int i;
2482698bbbbSAndriy Gapon int t, v, f;
2492698bbbbSAndriy Gapon int err;
2502698bbbbSAndriy Gapon int *s_idx;
2512698bbbbSAndriy Gapon const char *name;
2522698bbbbSAndriy Gapon const char *descr;
2532698bbbbSAndriy Gapon struct aibs_sensor *sensor;
2542698bbbbSAndriy Gapon struct sysctl_oid **so;
2552698bbbbSAndriy Gapon
2562698bbbbSAndriy Gapon /* First see if GITM is available. */
2572698bbbbSAndriy Gapon s = AcpiGetHandle(sc->sc_ah, "GITM", &h);
2582698bbbbSAndriy Gapon if (ACPI_FAILURE(s)) {
2592698bbbbSAndriy Gapon if (bootverbose)
2602698bbbbSAndriy Gapon device_printf(sc->sc_dev, "GITM not found\n");
2612698bbbbSAndriy Gapon return (ENXIO);
2622698bbbbSAndriy Gapon }
2632698bbbbSAndriy Gapon
2642698bbbbSAndriy Gapon /*
2652698bbbbSAndriy Gapon * Now call GGRP with the appropriate argument to list sensors.
2662698bbbbSAndriy Gapon * The method lists different groups of entities depending on
2672698bbbbSAndriy Gapon * the argument.
2682698bbbbSAndriy Gapon */
2692698bbbbSAndriy Gapon id.Integer.Value = AIBS_GROUP_SENSORS;
2702698bbbbSAndriy Gapon id.Type = ACPI_TYPE_INTEGER;
2712698bbbbSAndriy Gapon arg.Count = 1;
2722698bbbbSAndriy Gapon arg.Pointer = &id;
2732698bbbbSAndriy Gapon buf.Length = ACPI_ALLOCATE_BUFFER;
2742698bbbbSAndriy Gapon buf.Pointer = NULL;
2752698bbbbSAndriy Gapon s = AcpiEvaluateObjectTyped(sc->sc_ah, "GGRP", &arg, &buf,
2762698bbbbSAndriy Gapon ACPI_TYPE_PACKAGE);
2772698bbbbSAndriy Gapon if (ACPI_FAILURE(s)) {
2782698bbbbSAndriy Gapon device_printf(sc->sc_dev, "GGRP not found\n");
2792698bbbbSAndriy Gapon return (ENXIO);
2802698bbbbSAndriy Gapon }
2812698bbbbSAndriy Gapon
2822698bbbbSAndriy Gapon bp = buf.Pointer;
2832698bbbbSAndriy Gapon sc->sc_asens_all = malloc(sizeof(*sc->sc_asens_all) * bp->Package.Count,
2842698bbbbSAndriy Gapon M_DEVBUF, M_WAITOK | M_ZERO);
2852698bbbbSAndriy Gapon v = t = f = 0;
2862698bbbbSAndriy Gapon for (i = 0; i < bp->Package.Count; i++) {
2872698bbbbSAndriy Gapon sensor = &sc->sc_asens_all[i];
2882698bbbbSAndriy Gapon err = aibs_add_sensor(sc, &bp->Package.Elements[i], sensor,
2892698bbbbSAndriy Gapon &descr);
2902698bbbbSAndriy Gapon if (err != 0)
2912698bbbbSAndriy Gapon continue;
2922698bbbbSAndriy Gapon
2932698bbbbSAndriy Gapon switch (sensor->t) {
2942698bbbbSAndriy Gapon case AIBS_SENS_TYPE_VOLT:
2952698bbbbSAndriy Gapon name = "volt";
2962698bbbbSAndriy Gapon so = &sc->sc_volt_sysctl;
2972698bbbbSAndriy Gapon s_idx = &v;
2982698bbbbSAndriy Gapon break;
2992698bbbbSAndriy Gapon case AIBS_SENS_TYPE_TEMP:
3002698bbbbSAndriy Gapon name = "temp";
3012698bbbbSAndriy Gapon so = &sc->sc_temp_sysctl;
3022698bbbbSAndriy Gapon s_idx = &t;
3032698bbbbSAndriy Gapon break;
3042698bbbbSAndriy Gapon case AIBS_SENS_TYPE_FAN:
3052698bbbbSAndriy Gapon name = "fan";
3062698bbbbSAndriy Gapon so = &sc->sc_fan_sysctl;
3072698bbbbSAndriy Gapon s_idx = &f;
3082698bbbbSAndriy Gapon break;
3092698bbbbSAndriy Gapon default:
3102698bbbbSAndriy Gapon panic("add_sensor succeeded for unknown sensor type %d",
3112698bbbbSAndriy Gapon sensor->t);
3122698bbbbSAndriy Gapon }
3132698bbbbSAndriy Gapon
3142698bbbbSAndriy Gapon if (*so == NULL) {
3152698bbbbSAndriy Gapon /* sysctl subtree for sensors of this type */
3162698bbbbSAndriy Gapon *so = SYSCTL_ADD_NODE(device_get_sysctl_ctx(sc->sc_dev),
3172698bbbbSAndriy Gapon SYSCTL_CHILDREN(device_get_sysctl_tree(sc->sc_dev)),
3187029da5cSPawel Biernacki sensor->t, name, CTLFLAG_RD | CTLFLAG_MPSAFE,
3197029da5cSPawel Biernacki NULL, NULL);
3202698bbbbSAndriy Gapon }
3212698bbbbSAndriy Gapon aibs_sensor_added(sc, *so, name, *s_idx, sensor, descr);
3222698bbbbSAndriy Gapon *s_idx += 1;
3232698bbbbSAndriy Gapon }
3242698bbbbSAndriy Gapon
3252698bbbbSAndriy Gapon AcpiOsFree(buf.Pointer);
3262698bbbbSAndriy Gapon return (0);
3272698bbbbSAndriy Gapon }
3282698bbbbSAndriy Gapon
3292698bbbbSAndriy Gapon static int
aibs_attach_sif(struct aibs_softc * sc,int st)3302698bbbbSAndriy Gapon aibs_attach_sif(struct aibs_softc *sc, int st)
3312698bbbbSAndriy Gapon {
3322698bbbbSAndriy Gapon char name[] = "?SIF";
333bbe4a97dSRui Paulo ACPI_STATUS s;
334bbe4a97dSRui Paulo ACPI_BUFFER b;
335bbe4a97dSRui Paulo ACPI_OBJECT *bp, *o;
336bbe4a97dSRui Paulo const char *node;
337bbe4a97dSRui Paulo struct aibs_sensor *as;
3382698bbbbSAndriy Gapon struct sysctl_oid **so;
3392698bbbbSAndriy Gapon int i, n;
3402698bbbbSAndriy Gapon int err;
341bbe4a97dSRui Paulo
342bbe4a97dSRui Paulo switch (st) {
3432698bbbbSAndriy Gapon case AIBS_SENS_TYPE_VOLT:
344bbe4a97dSRui Paulo node = "volt";
345bbe4a97dSRui Paulo name[0] = 'V';
3462698bbbbSAndriy Gapon so = &sc->sc_volt_sysctl;
347bbe4a97dSRui Paulo break;
3482698bbbbSAndriy Gapon case AIBS_SENS_TYPE_TEMP:
349bbe4a97dSRui Paulo node = "temp";
350bbe4a97dSRui Paulo name[0] = 'T';
3512698bbbbSAndriy Gapon so = &sc->sc_temp_sysctl;
352bbe4a97dSRui Paulo break;
3532698bbbbSAndriy Gapon case AIBS_SENS_TYPE_FAN:
354bbe4a97dSRui Paulo node = "fan";
355bbe4a97dSRui Paulo name[0] = 'F';
3562698bbbbSAndriy Gapon so = &sc->sc_fan_sysctl;
357bbe4a97dSRui Paulo break;
358bbe4a97dSRui Paulo default:
3592698bbbbSAndriy Gapon panic("Unsupported sensor type %d", st);
360bbe4a97dSRui Paulo }
361bbe4a97dSRui Paulo
362bbe4a97dSRui Paulo b.Length = ACPI_ALLOCATE_BUFFER;
363bbe4a97dSRui Paulo s = AcpiEvaluateObjectTyped(sc->sc_ah, name, NULL, &b,
364bbe4a97dSRui Paulo ACPI_TYPE_PACKAGE);
365bbe4a97dSRui Paulo if (ACPI_FAILURE(s)) {
366bbe4a97dSRui Paulo device_printf(sc->sc_dev, "%s not found\n", name);
3672698bbbbSAndriy Gapon return (ENXIO);
368bbe4a97dSRui Paulo }
369bbe4a97dSRui Paulo
370bbe4a97dSRui Paulo bp = b.Pointer;
371bbe4a97dSRui Paulo o = bp->Package.Elements;
372bbe4a97dSRui Paulo if (o[0].Type != ACPI_TYPE_INTEGER) {
373bbe4a97dSRui Paulo device_printf(sc->sc_dev, "%s[0]: invalid type\n", name);
374bbe4a97dSRui Paulo AcpiOsFree(b.Pointer);
3752698bbbbSAndriy Gapon return (ENXIO);
376bbe4a97dSRui Paulo }
377bbe4a97dSRui Paulo
378bbe4a97dSRui Paulo n = o[0].Integer.Value;
379bbe4a97dSRui Paulo if (bp->Package.Count - 1 < n) {
380bbe4a97dSRui Paulo device_printf(sc->sc_dev, "%s: invalid package\n", name);
381bbe4a97dSRui Paulo AcpiOsFree(b.Pointer);
3822698bbbbSAndriy Gapon return (ENXIO);
383bbe4a97dSRui Paulo } else if (bp->Package.Count - 1 > n) {
384bbe4a97dSRui Paulo int on = n;
385bbe4a97dSRui Paulo
386bbe4a97dSRui Paulo #ifdef AIBS_MORE_SENSORS
387bbe4a97dSRui Paulo n = bp->Package.Count - 1;
388bbe4a97dSRui Paulo #endif
389bbe4a97dSRui Paulo device_printf(sc->sc_dev, "%s: malformed package: %i/%i"
390bbe4a97dSRui Paulo ", assume %i\n", name, on, bp->Package.Count - 1, n);
391bbe4a97dSRui Paulo }
392bbe4a97dSRui Paulo if (n < 1) {
393bbe4a97dSRui Paulo device_printf(sc->sc_dev, "%s: no members in the package\n",
394bbe4a97dSRui Paulo name);
395bbe4a97dSRui Paulo AcpiOsFree(b.Pointer);
3962698bbbbSAndriy Gapon return (ENXIO);
397bbe4a97dSRui Paulo }
398bbe4a97dSRui Paulo
3992698bbbbSAndriy Gapon as = malloc(sizeof(*as) * n, M_DEVBUF, M_WAITOK | M_ZERO);
400bbe4a97dSRui Paulo switch (st) {
4012698bbbbSAndriy Gapon case AIBS_SENS_TYPE_VOLT:
402bbe4a97dSRui Paulo sc->sc_asens_volt = as;
403bbe4a97dSRui Paulo break;
4042698bbbbSAndriy Gapon case AIBS_SENS_TYPE_TEMP:
405bbe4a97dSRui Paulo sc->sc_asens_temp = as;
406bbe4a97dSRui Paulo break;
4072698bbbbSAndriy Gapon case AIBS_SENS_TYPE_FAN:
408bbe4a97dSRui Paulo sc->sc_asens_fan = as;
409bbe4a97dSRui Paulo break;
410bbe4a97dSRui Paulo }
411bbe4a97dSRui Paulo
412bbe4a97dSRui Paulo /* sysctl subtree for sensors of this type */
4132698bbbbSAndriy Gapon *so = SYSCTL_ADD_NODE(device_get_sysctl_ctx(sc->sc_dev),
414bbe4a97dSRui Paulo SYSCTL_CHILDREN(device_get_sysctl_tree(sc->sc_dev)), st,
4157029da5cSPawel Biernacki node, CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, NULL);
416bbe4a97dSRui Paulo
417bbe4a97dSRui Paulo for (i = 0, o++; i < n; i++, o++) {
4182698bbbbSAndriy Gapon const char *descr;
419bbe4a97dSRui Paulo
4202698bbbbSAndriy Gapon err = aibs_add_sensor(sc, o, &as[i], &descr);
4212698bbbbSAndriy Gapon if (err == 0)
4222698bbbbSAndriy Gapon aibs_sensor_added(sc, *so, node, i, &as[i], descr);
423bbe4a97dSRui Paulo }
424bbe4a97dSRui Paulo
425bbe4a97dSRui Paulo AcpiOsFree(b.Pointer);
4262698bbbbSAndriy Gapon return (0);
427bbe4a97dSRui Paulo }
428bbe4a97dSRui Paulo
429bbe4a97dSRui Paulo static int
aibs_detach(device_t dev)430bbe4a97dSRui Paulo aibs_detach(device_t dev)
431bbe4a97dSRui Paulo {
432bbe4a97dSRui Paulo struct aibs_softc *sc = device_get_softc(dev);
433bbe4a97dSRui Paulo
434bbe4a97dSRui Paulo if (sc->sc_asens_volt != NULL)
435bbe4a97dSRui Paulo free(sc->sc_asens_volt, M_DEVBUF);
436bbe4a97dSRui Paulo if (sc->sc_asens_temp != NULL)
437bbe4a97dSRui Paulo free(sc->sc_asens_temp, M_DEVBUF);
438bbe4a97dSRui Paulo if (sc->sc_asens_fan != NULL)
439bbe4a97dSRui Paulo free(sc->sc_asens_fan, M_DEVBUF);
4402698bbbbSAndriy Gapon if (sc->sc_asens_all != NULL)
4412698bbbbSAndriy Gapon free(sc->sc_asens_all, M_DEVBUF);
4422698bbbbSAndriy Gapon return (0);
443bbe4a97dSRui Paulo }
444bbe4a97dSRui Paulo
445bbe4a97dSRui Paulo #ifdef AIBS_VERBOSE
446bbe4a97dSRui Paulo #define ddevice_printf(x...) device_printf(x)
447bbe4a97dSRui Paulo #else
448bbe4a97dSRui Paulo #define ddevice_printf(x...)
449bbe4a97dSRui Paulo #endif
450bbe4a97dSRui Paulo
451bbe4a97dSRui Paulo static int
aibs_sysctl(SYSCTL_HANDLER_ARGS)452bbe4a97dSRui Paulo aibs_sysctl(SYSCTL_HANDLER_ARGS)
453bbe4a97dSRui Paulo {
454bbe4a97dSRui Paulo struct aibs_softc *sc = arg1;
455a1e2190cSDimitry Andric struct aibs_sensor *sensor = (void *)(intptr_t)arg2;
456bbe4a97dSRui Paulo int i = oidp->oid_number;
457bbe4a97dSRui Paulo ACPI_STATUS rs;
458bbe4a97dSRui Paulo ACPI_OBJECT p, *bp;
459bbe4a97dSRui Paulo ACPI_OBJECT_LIST mp;
460bbe4a97dSRui Paulo ACPI_BUFFER b;
461bbe4a97dSRui Paulo char *name;
462bbe4a97dSRui Paulo ACPI_INTEGER v, l, h;
463bbe4a97dSRui Paulo int so[3];
464bbe4a97dSRui Paulo
4652698bbbbSAndriy Gapon switch (sensor->t) {
4662698bbbbSAndriy Gapon case AIBS_SENS_TYPE_VOLT:
467bbe4a97dSRui Paulo name = "RVLT";
468bbe4a97dSRui Paulo break;
4692698bbbbSAndriy Gapon case AIBS_SENS_TYPE_TEMP:
470bbe4a97dSRui Paulo name = "RTMP";
471bbe4a97dSRui Paulo break;
4722698bbbbSAndriy Gapon case AIBS_SENS_TYPE_FAN:
473bbe4a97dSRui Paulo name = "RFAN";
474bbe4a97dSRui Paulo break;
475bbe4a97dSRui Paulo default:
4762698bbbbSAndriy Gapon return (ENOENT);
477bbe4a97dSRui Paulo }
4782698bbbbSAndriy Gapon l = sensor->l;
4792698bbbbSAndriy Gapon h = sensor->h;
480bbe4a97dSRui Paulo p.Type = ACPI_TYPE_INTEGER;
4812698bbbbSAndriy Gapon p.Integer.Value = sensor->i;
482bbe4a97dSRui Paulo mp.Count = 1;
483bbe4a97dSRui Paulo mp.Pointer = &p;
484bbe4a97dSRui Paulo b.Length = ACPI_ALLOCATE_BUFFER;
485bbe4a97dSRui Paulo ACPI_SERIAL_BEGIN(aibs);
486bbe4a97dSRui Paulo rs = AcpiEvaluateObjectTyped(sc->sc_ah, name, &mp, &b,
487bbe4a97dSRui Paulo ACPI_TYPE_INTEGER);
488bbe4a97dSRui Paulo if (ACPI_FAILURE(rs)) {
489bbe4a97dSRui Paulo ddevice_printf(sc->sc_dev,
490bbe4a97dSRui Paulo "%s: %i: evaluation failed\n",
491bbe4a97dSRui Paulo name, i);
492bbe4a97dSRui Paulo ACPI_SERIAL_END(aibs);
4932698bbbbSAndriy Gapon return (EIO);
494bbe4a97dSRui Paulo }
495bbe4a97dSRui Paulo bp = b.Pointer;
496bbe4a97dSRui Paulo v = bp->Integer.Value;
497bbe4a97dSRui Paulo AcpiOsFree(b.Pointer);
498bbe4a97dSRui Paulo ACPI_SERIAL_END(aibs);
499bbe4a97dSRui Paulo
5002698bbbbSAndriy Gapon switch (sensor->t) {
5012698bbbbSAndriy Gapon case AIBS_SENS_TYPE_VOLT:
502bbe4a97dSRui Paulo break;
5032698bbbbSAndriy Gapon case AIBS_SENS_TYPE_TEMP:
5049d6672e1SLuiz Otavio O Souza v += 2731;
5059d6672e1SLuiz Otavio O Souza l += 2731;
5069d6672e1SLuiz Otavio O Souza h += 2731;
507bbe4a97dSRui Paulo break;
5082698bbbbSAndriy Gapon case AIBS_SENS_TYPE_FAN:
509bbe4a97dSRui Paulo break;
510bbe4a97dSRui Paulo }
511bbe4a97dSRui Paulo so[0] = v;
512bbe4a97dSRui Paulo so[1] = l;
513bbe4a97dSRui Paulo so[2] = h;
5142698bbbbSAndriy Gapon return (sysctl_handle_opaque(oidp, &so, sizeof(so), req));
5152698bbbbSAndriy Gapon }
5162698bbbbSAndriy Gapon
5172698bbbbSAndriy Gapon static int
aibs_sysctl_ggrp(SYSCTL_HANDLER_ARGS)5182698bbbbSAndriy Gapon aibs_sysctl_ggrp(SYSCTL_HANDLER_ARGS)
5192698bbbbSAndriy Gapon {
5202698bbbbSAndriy Gapon struct aibs_softc *sc = arg1;
521a1e2190cSDimitry Andric struct aibs_sensor *sensor = (void *)(intptr_t)arg2;
5222698bbbbSAndriy Gapon ACPI_STATUS rs;
5232698bbbbSAndriy Gapon ACPI_OBJECT p, *bp;
5242698bbbbSAndriy Gapon ACPI_OBJECT_LIST arg;
5252698bbbbSAndriy Gapon ACPI_BUFFER buf;
5262698bbbbSAndriy Gapon ACPI_INTEGER v, l, h;
5272698bbbbSAndriy Gapon int so[3];
5282698bbbbSAndriy Gapon uint32_t *ret;
5292698bbbbSAndriy Gapon uint32_t cmd[3];
5302698bbbbSAndriy Gapon
5312698bbbbSAndriy Gapon cmd[0] = sensor->i;
5322698bbbbSAndriy Gapon cmd[1] = 0;
5332698bbbbSAndriy Gapon cmd[2] = 0;
5342698bbbbSAndriy Gapon p.Type = ACPI_TYPE_BUFFER;
5352698bbbbSAndriy Gapon p.Buffer.Pointer = (void *)cmd;
5362698bbbbSAndriy Gapon p.Buffer.Length = sizeof(cmd);
5372698bbbbSAndriy Gapon arg.Count = 1;
5382698bbbbSAndriy Gapon arg.Pointer = &p;
5392698bbbbSAndriy Gapon buf.Pointer = NULL;
5402698bbbbSAndriy Gapon buf.Length = ACPI_ALLOCATE_BUFFER;
5412698bbbbSAndriy Gapon ACPI_SERIAL_BEGIN(aibs);
5422698bbbbSAndriy Gapon rs = AcpiEvaluateObjectTyped(sc->sc_ah, "GITM", &arg, &buf,
5432698bbbbSAndriy Gapon ACPI_TYPE_BUFFER);
5442698bbbbSAndriy Gapon ACPI_SERIAL_END(aibs);
5452698bbbbSAndriy Gapon if (ACPI_FAILURE(rs)) {
5462698bbbbSAndriy Gapon device_printf(sc->sc_dev, "GITM evaluation failed\n");
5472698bbbbSAndriy Gapon return (EIO);
5482698bbbbSAndriy Gapon }
5492698bbbbSAndriy Gapon bp = buf.Pointer;
5502698bbbbSAndriy Gapon if (bp->Buffer.Length < 8) {
5512698bbbbSAndriy Gapon device_printf(sc->sc_dev, "GITM returned short buffer\n");
5522698bbbbSAndriy Gapon return (EIO);
5532698bbbbSAndriy Gapon }
5542698bbbbSAndriy Gapon ret = (uint32_t *)bp->Buffer.Pointer;
5552698bbbbSAndriy Gapon if (ret[0] == 0) {
5562698bbbbSAndriy Gapon device_printf(sc->sc_dev, "GITM returned error status\n");
5572698bbbbSAndriy Gapon return (EINVAL);
5582698bbbbSAndriy Gapon }
5592698bbbbSAndriy Gapon v = ret[1];
5602698bbbbSAndriy Gapon AcpiOsFree(buf.Pointer);
5612698bbbbSAndriy Gapon
5622698bbbbSAndriy Gapon l = sensor->l;
5632698bbbbSAndriy Gapon h = sensor->h;
5642698bbbbSAndriy Gapon
5652698bbbbSAndriy Gapon switch (sensor->t) {
5662698bbbbSAndriy Gapon case AIBS_SENS_TYPE_VOLT:
5672698bbbbSAndriy Gapon break;
5682698bbbbSAndriy Gapon case AIBS_SENS_TYPE_TEMP:
5692698bbbbSAndriy Gapon v += 2731;
5702698bbbbSAndriy Gapon l += 2731;
5712698bbbbSAndriy Gapon h += 2731;
5722698bbbbSAndriy Gapon break;
5732698bbbbSAndriy Gapon case AIBS_SENS_TYPE_FAN:
5742698bbbbSAndriy Gapon break;
5752698bbbbSAndriy Gapon }
5762698bbbbSAndriy Gapon so[0] = v;
5772698bbbbSAndriy Gapon so[1] = l;
5782698bbbbSAndriy Gapon so[2] = h;
5792698bbbbSAndriy Gapon return (sysctl_handle_opaque(oidp, &so, sizeof(so), req));
580bbe4a97dSRui Paulo }
581