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