[BACK]Return to acpibat.c CVS log [TXT][DIR] Up to [local] / sys / dev / acpi

Annotation of sys/dev/acpi/acpibat.c, Revision 1.1

1.1     ! nbrk        1: /* $OpenBSD: acpibat.c,v 1.40 2007/03/20 15:17:21 mk Exp $ */
        !             2: /*
        !             3:  * Copyright (c) 2005 Marco Peereboom <marco@openbsd.org>
        !             4:  *
        !             5:  * Permission to use, copy, modify, and distribute this software for any
        !             6:  * purpose with or without fee is hereby granted, provided that the above
        !             7:  * copyright notice and this permission notice appear in all copies.
        !             8:  *
        !             9:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
        !            10:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
        !            11:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
        !            12:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
        !            13:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
        !            14:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
        !            15:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
        !            16:  */
        !            17:
        !            18: #include <sys/param.h>
        !            19: #include <sys/proc.h>
        !            20: #include <sys/systm.h>
        !            21: #include <sys/device.h>
        !            22: #include <sys/malloc.h>
        !            23: #include <sys/sensors.h>
        !            24:
        !            25: #include <machine/bus.h>
        !            26:
        !            27: #include <dev/acpi/acpireg.h>
        !            28: #include <dev/acpi/acpivar.h>
        !            29: #include <dev/acpi/acpidev.h>
        !            30: #include <dev/acpi/amltypes.h>
        !            31: #include <dev/acpi/dsdt.h>
        !            32:
        !            33: int    acpibat_match(struct device *, void *, void *);
        !            34: void   acpibat_attach(struct device *, struct device *, void *);
        !            35:
        !            36: struct cfattach acpibat_ca = {
        !            37:        sizeof(struct acpibat_softc), acpibat_match, acpibat_attach
        !            38: };
        !            39:
        !            40: struct cfdriver acpibat_cd = {
        !            41:        NULL, "acpibat", DV_DULL
        !            42: };
        !            43:
        !            44: void   acpibat_monitor(struct acpibat_softc *);
        !            45: void   acpibat_refresh(void *);
        !            46: int    acpibat_getbif(struct acpibat_softc *);
        !            47: int    acpibat_getbst(struct acpibat_softc *);
        !            48: int    acpibat_notify(struct aml_node *, int, void *);
        !            49:
        !            50: int
        !            51: acpibat_match(struct device *parent, void *match, void *aux)
        !            52: {
        !            53:        struct acpi_attach_args *aa = aux;
        !            54:        struct cfdata           *cf = match;
        !            55:
        !            56:        /* sanity */
        !            57:        if (aa->aaa_name == NULL ||
        !            58:            strcmp(aa->aaa_name, cf->cf_driver->cd_name) != 0 ||
        !            59:            aa->aaa_table != NULL)
        !            60:                return (0);
        !            61:
        !            62:        return (1);
        !            63: }
        !            64:
        !            65: void
        !            66: acpibat_attach(struct device *parent, struct device *self, void *aux)
        !            67: {
        !            68:        struct acpibat_softc    *sc = (struct acpibat_softc *)self;
        !            69:        struct acpi_attach_args *aa = aux;
        !            70:        struct aml_value        res;
        !            71:
        !            72:        sc->sc_acpi = (struct acpi_softc *)parent;
        !            73:        sc->sc_devnode = aa->aaa_node->child;
        !            74:
        !            75:        if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_STA", 0, NULL, &res)) {
        !            76:                dnprintf(10, "%s: no _STA\n", DEVNAME(sc));
        !            77:                return;
        !            78:        }
        !            79:
        !            80:        if ((sc->sc_bat_present = aml_val2int(&res) & STA_BATTERY) != 0) {
        !            81:                acpibat_getbif(sc);
        !            82:                acpibat_getbst(sc);
        !            83:                printf(": %s: model: %s serial: %s type: %s oem: %s\n",
        !            84:                    sc->sc_devnode->parent->name,
        !            85:                    sc->sc_bif.bif_model,
        !            86:                    sc->sc_bif.bif_serial,
        !            87:                    sc->sc_bif.bif_type,
        !            88:                    sc->sc_bif.bif_oem);
        !            89:        } else
        !            90:                printf(": %s: not present\n", sc->sc_devnode->parent->name);
        !            91:
        !            92:        aml_freevalue(&res);
        !            93:
        !            94:        /* create sensors */
        !            95:        acpibat_monitor(sc);
        !            96:
        !            97:        /* populate sensors */
        !            98:        acpibat_refresh(sc);
        !            99:
        !           100:        aml_register_notify(sc->sc_devnode->parent, aa->aaa_dev,
        !           101:            acpibat_notify, sc, ACPIDEV_POLL);
        !           102: }
        !           103:
        !           104: void
        !           105: acpibat_monitor(struct acpibat_softc *sc)
        !           106: {
        !           107:        int                     type;
        !           108:
        !           109:        /* assume _BIF and _BST have been called */
        !           110:        strlcpy(sc->sc_sensdev.xname, DEVNAME(sc),
        !           111:            sizeof(sc->sc_sensdev.xname));
        !           112:
        !           113:        type = sc->sc_bif.bif_power_unit ? SENSOR_AMPHOUR : SENSOR_WATTHOUR;
        !           114:
        !           115:        strlcpy(sc->sc_sens[0].desc, "last full capacity",
        !           116:            sizeof(sc->sc_sens[0].desc));
        !           117:        sc->sc_sens[0].type = type;
        !           118:        sensor_attach(&sc->sc_sensdev, &sc->sc_sens[0]);
        !           119:        sc->sc_sens[0].value = sc->sc_bif.bif_last_capacity * 1000;
        !           120:
        !           121:        strlcpy(sc->sc_sens[1].desc, "warning capacity",
        !           122:            sizeof(sc->sc_sens[1].desc));
        !           123:        sc->sc_sens[1].type = type;
        !           124:        sensor_attach(&sc->sc_sensdev, &sc->sc_sens[1]);
        !           125:        sc->sc_sens[1].value = sc->sc_bif.bif_warning * 1000;
        !           126:
        !           127:        strlcpy(sc->sc_sens[2].desc, "low capacity",
        !           128:            sizeof(sc->sc_sens[2].desc));
        !           129:        sc->sc_sens[2].type = type;
        !           130:        sensor_attach(&sc->sc_sensdev, &sc->sc_sens[2]);
        !           131:        sc->sc_sens[2].value = sc->sc_bif.bif_low * 1000;
        !           132:
        !           133:        strlcpy(sc->sc_sens[3].desc, "voltage", sizeof(sc->sc_sens[3].desc));
        !           134:        sc->sc_sens[3].type = SENSOR_VOLTS_DC;
        !           135:        sensor_attach(&sc->sc_sensdev, &sc->sc_sens[3]);
        !           136:        sc->sc_sens[3].value = sc->sc_bif.bif_voltage * 1000;
        !           137:
        !           138:        strlcpy(sc->sc_sens[4].desc, "battery unknown",
        !           139:            sizeof(sc->sc_sens[4].desc));
        !           140:        sc->sc_sens[4].type = SENSOR_INTEGER;
        !           141:        sensor_attach(&sc->sc_sensdev, &sc->sc_sens[4]);
        !           142:        sc->sc_sens[4].value = sc->sc_bst.bst_state;
        !           143:
        !           144:        strlcpy(sc->sc_sens[5].desc, "rate", sizeof(sc->sc_sens[5].desc));
        !           145:        sc->sc_sens[5].type = SENSOR_INTEGER;
        !           146:        sensor_attach(&sc->sc_sensdev, &sc->sc_sens[5]);
        !           147:        sc->sc_sens[5].value = sc->sc_bst.bst_rate;
        !           148:
        !           149:        strlcpy(sc->sc_sens[6].desc, "remaining capacity",
        !           150:            sizeof(sc->sc_sens[6].desc));
        !           151:        sc->sc_sens[6].type = type;
        !           152:        sensor_attach(&sc->sc_sensdev, &sc->sc_sens[6]);
        !           153:        sc->sc_sens[6].value = sc->sc_bst.bst_capacity * 1000;
        !           154:
        !           155:        strlcpy(sc->sc_sens[7].desc, "current voltage",
        !           156:            sizeof(sc->sc_sens[7].desc));
        !           157:        sc->sc_sens[7].type = SENSOR_VOLTS_DC;
        !           158:        sensor_attach(&sc->sc_sensdev, &sc->sc_sens[7]);
        !           159:        sc->sc_sens[7].value = sc->sc_bst.bst_voltage * 1000;
        !           160:
        !           161:        sensordev_install(&sc->sc_sensdev);
        !           162: }
        !           163:
        !           164: void
        !           165: acpibat_refresh(void *arg)
        !           166: {
        !           167:        struct acpibat_softc    *sc = arg;
        !           168:        int                     i;
        !           169:
        !           170:        dnprintf(30, "%s: %s: refresh\n", DEVNAME(sc),
        !           171:            sc->sc_devnode->parent->name);
        !           172:
        !           173:        if (!sc->sc_bat_present) {
        !           174:                for (i = 0; i < 8; i++) {
        !           175:                        sc->sc_sens[i].value = 0;
        !           176:                        sc->sc_sens[i].status = SENSOR_S_UNSPEC;
        !           177:                        sc->sc_sens[i].flags = SENSOR_FINVALID;
        !           178:                }
        !           179:                /* override state */
        !           180:                strlcpy(sc->sc_sens[4].desc, "battery removed",
        !           181:                    sizeof(sc->sc_sens[4].desc));
        !           182:                return;
        !           183:        }
        !           184:
        !           185:        /*
        !           186:         * XXX don't really need _BIF but keep it here in case we
        !           187:         * miss an insertion/removal event
        !           188:         */
        !           189:        acpibat_getbif(sc);
        !           190:        acpibat_getbst(sc);
        !           191:
        !           192:        /* _BIF values are static, sensor 0..3 */
        !           193:        if (sc->sc_bif.bif_last_capacity == BIF_UNKNOWN) {
        !           194:                sc->sc_sens[0].value = 0;
        !           195:                sc->sc_sens[0].status = SENSOR_S_UNKNOWN;
        !           196:                sc->sc_sens[0].flags = SENSOR_FUNKNOWN;
        !           197:        } else {
        !           198:                sc->sc_sens[0].value = sc->sc_bif.bif_last_capacity * 1000;
        !           199:                sc->sc_sens[0].status = SENSOR_S_UNSPEC;
        !           200:                sc->sc_sens[0].flags = 0;
        !           201:        }
        !           202:        sc->sc_sens[1].value = sc->sc_bif.bif_warning * 1000;
        !           203:        sc->sc_sens[1].flags = 0;
        !           204:        sc->sc_sens[2].value = sc->sc_bif.bif_low * 1000;
        !           205:        sc->sc_sens[2].flags = 0;
        !           206:        if (sc->sc_bif.bif_voltage == BIF_UNKNOWN) {
        !           207:                sc->sc_sens[3].value = 0;
        !           208:                sc->sc_sens[3].status = SENSOR_S_UNKNOWN;
        !           209:                sc->sc_sens[3].flags = SENSOR_FUNKNOWN;
        !           210:        } else {
        !           211:                sc->sc_sens[3].value = sc->sc_bif.bif_voltage * 1000;
        !           212:                sc->sc_sens[3].status = SENSOR_S_UNSPEC;
        !           213:                sc->sc_sens[3].flags = 0;
        !           214:        }
        !           215:
        !           216:        /* _BST values are dynamic, sensor 4..7 */
        !           217:        sc->sc_sens[4].status = SENSOR_S_OK;
        !           218:        sc->sc_sens[4].flags = 0;
        !           219:        if (sc->sc_bif.bif_last_capacity == BIF_UNKNOWN ||
        !           220:            sc->sc_bst.bst_capacity == BST_UNKNOWN) {
        !           221:                sc->sc_sens[4].status = SENSOR_S_UNKNOWN;
        !           222:                sc->sc_sens[4].flags = SENSOR_FUNKNOWN;
        !           223:                strlcpy(sc->sc_sens[4].desc, "battery unknown",
        !           224:                    sizeof(sc->sc_sens[4].desc));
        !           225:        } else if (sc->sc_bst.bst_capacity >= sc->sc_bif.bif_last_capacity)
        !           226:                strlcpy(sc->sc_sens[4].desc, "battery full",
        !           227:                    sizeof(sc->sc_sens[4].desc));
        !           228:         else if (sc->sc_bst.bst_state & BST_DISCHARGE)
        !           229:                strlcpy(sc->sc_sens[4].desc, "battery discharging",
        !           230:                    sizeof(sc->sc_sens[4].desc));
        !           231:        else if (sc->sc_bst.bst_state & BST_CHARGE)
        !           232:                strlcpy(sc->sc_sens[4].desc, "battery charging",
        !           233:                    sizeof(sc->sc_sens[4].desc));
        !           234:        else if (sc->sc_bst.bst_state & BST_CRITICAL) {
        !           235:                strlcpy(sc->sc_sens[4].desc, "battery critical",
        !           236:                    sizeof(sc->sc_sens[4].desc));
        !           237:                sc->sc_sens[4].status = SENSOR_S_CRIT;
        !           238:        } else
        !           239:                strlcpy(sc->sc_sens[4].desc, "battery idle",
        !           240:                    sizeof(sc->sc_sens[4].desc));
        !           241:        sc->sc_sens[4].value = sc->sc_bst.bst_state;
        !           242:
        !           243:        if (sc->sc_bst.bst_rate == BST_UNKNOWN) {
        !           244:                sc->sc_sens[5].value = 0;
        !           245:                sc->sc_sens[5].status = SENSOR_S_UNKNOWN;
        !           246:                sc->sc_sens[5].flags = SENSOR_FUNKNOWN;
        !           247:        } else {
        !           248:                sc->sc_sens[5].value = sc->sc_bst.bst_rate;
        !           249:                sc->sc_sens[5].status = SENSOR_S_UNSPEC;
        !           250:                sc->sc_sens[5].flags = 0;
        !           251:        }
        !           252:
        !           253:        if (sc->sc_bst.bst_capacity == BST_UNKNOWN) {
        !           254:                sc->sc_sens[6].value = 0;
        !           255:                sc->sc_sens[6].status = SENSOR_S_UNKNOWN;
        !           256:                sc->sc_sens[6].flags = SENSOR_FUNKNOWN;
        !           257:        } else {
        !           258:                sc->sc_sens[6].value = sc->sc_bst.bst_capacity * 1000;
        !           259:                sc->sc_sens[6].flags = 0;
        !           260:
        !           261:                if (sc->sc_bst.bst_capacity < sc->sc_bif.bif_low)
        !           262:                        /* XXX we should shutdown the system */
        !           263:                        sc->sc_sens[6].status = SENSOR_S_CRIT;
        !           264:                else if (sc->sc_bst.bst_capacity < sc->sc_bif.bif_warning)
        !           265:                        sc->sc_sens[6].status = SENSOR_S_WARN;
        !           266:                else
        !           267:                        sc->sc_sens[6].status = SENSOR_S_OK;
        !           268:        }
        !           269:
        !           270:        if(sc->sc_bst.bst_voltage == BST_UNKNOWN) {
        !           271:                sc->sc_sens[7].value = 0;
        !           272:                sc->sc_sens[7].status = SENSOR_S_UNKNOWN;
        !           273:                sc->sc_sens[7].flags = SENSOR_FUNKNOWN;
        !           274:        } else {
        !           275:                sc->sc_sens[7].value = sc->sc_bst.bst_voltage * 1000;
        !           276:                sc->sc_sens[7].status = SENSOR_S_UNSPEC;
        !           277:                sc->sc_sens[7].flags = 0;
        !           278:        }
        !           279: }
        !           280:
        !           281: int
        !           282: acpibat_getbif(struct acpibat_softc *sc)
        !           283: {
        !           284:        struct aml_value        res;
        !           285:        int                     rv = EINVAL;
        !           286:
        !           287:        if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_STA", 0, NULL, &res)) {
        !           288:                dnprintf(10, "%s: no _STA\n", DEVNAME(sc));
        !           289:                goto out;
        !           290:        }
        !           291:        aml_freevalue(&res);
        !           292:
        !           293:        if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_BIF", 0, NULL, &res)) {
        !           294:                dnprintf(10, "%s: no _BIF\n", DEVNAME(sc));
        !           295:                goto out;
        !           296:        }
        !           297:
        !           298:        if (res.length != 13) {
        !           299:                dnprintf(10, "%s: invalid _BIF, battery info not saved\n",
        !           300:                    DEVNAME(sc));
        !           301:                goto out;
        !           302:        }
        !           303:
        !           304:        memset(&sc->sc_bif, 0, sizeof sc->sc_bif);
        !           305:        sc->sc_bif.bif_power_unit = aml_val2int(res.v_package[0]);
        !           306:        sc->sc_bif.bif_capacity = aml_val2int(res.v_package[1]);
        !           307:        sc->sc_bif.bif_last_capacity = aml_val2int(res.v_package[2]);
        !           308:        sc->sc_bif.bif_technology = aml_val2int(res.v_package[3]);
        !           309:        sc->sc_bif.bif_voltage = aml_val2int(res.v_package[4]);
        !           310:        sc->sc_bif.bif_warning = aml_val2int(res.v_package[5]);
        !           311:        sc->sc_bif.bif_low = aml_val2int(res.v_package[6]);
        !           312:        sc->sc_bif.bif_cap_granu1 = aml_val2int(res.v_package[7]);
        !           313:        sc->sc_bif.bif_cap_granu2 = aml_val2int(res.v_package[8]);
        !           314:
        !           315:        strlcpy(sc->sc_bif.bif_model, aml_strval(res.v_package[9]),
        !           316:                sizeof(sc->sc_bif.bif_model));
        !           317:        strlcpy(sc->sc_bif.bif_serial, aml_strval(res.v_package[10]),
        !           318:                sizeof(sc->sc_bif.bif_serial));
        !           319:        strlcpy(sc->sc_bif.bif_type, aml_strval(res.v_package[11]),
        !           320:                sizeof(sc->sc_bif.bif_type));
        !           321:        strlcpy(sc->sc_bif.bif_oem, aml_strval(res.v_package[12]),
        !           322:                sizeof(sc->sc_bif.bif_oem));
        !           323:
        !           324:        dnprintf(60, "power_unit: %u capacity: %u last_cap: %u tech: %u "
        !           325:            "volt: %u warn: %u low: %u gran1: %u gran2: %d model: %s "
        !           326:            "serial: %s type: %s oem: %s\n",
        !           327:            sc->sc_bif.bif_power_unit,
        !           328:            sc->sc_bif.bif_capacity,
        !           329:            sc->sc_bif.bif_last_capacity,
        !           330:            sc->sc_bif.bif_technology,
        !           331:            sc->sc_bif.bif_voltage,
        !           332:            sc->sc_bif.bif_warning,
        !           333:            sc->sc_bif.bif_low,
        !           334:            sc->sc_bif.bif_cap_granu1,
        !           335:            sc->sc_bif.bif_cap_granu2,
        !           336:            sc->sc_bif.bif_model,
        !           337:            sc->sc_bif.bif_serial,
        !           338:            sc->sc_bif.bif_type,
        !           339:            sc->sc_bif.bif_oem);
        !           340:
        !           341:        rv = 0;
        !           342: out:
        !           343:        aml_freevalue(&res);
        !           344:        return (rv);
        !           345: }
        !           346:
        !           347: int
        !           348: acpibat_getbst(struct acpibat_softc *sc)
        !           349: {
        !           350:        struct aml_value        res;
        !           351:        int                     rv = EINVAL;
        !           352:
        !           353:        if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_BST", 0, NULL, &res)) {
        !           354:                dnprintf(10, "%s: no _BST\n", DEVNAME(sc));
        !           355:                goto out;
        !           356:        }
        !           357:
        !           358:        if (res.length != 4) {
        !           359:                dnprintf(10, "%s: invalid _BST, battery status not saved\n",
        !           360:                    DEVNAME(sc));
        !           361:                goto out;
        !           362:        }
        !           363:
        !           364:        sc->sc_bst.bst_state = aml_val2int(res.v_package[0]);
        !           365:        sc->sc_bst.bst_rate = aml_val2int(res.v_package[1]);
        !           366:        sc->sc_bst.bst_capacity = aml_val2int(res.v_package[2]);
        !           367:        sc->sc_bst.bst_voltage = aml_val2int(res.v_package[3]);
        !           368:
        !           369:        dnprintf(60, "state: %u rate: %u cap: %u volt: %u ",
        !           370:            sc->sc_bst.bst_state,
        !           371:            sc->sc_bst.bst_rate,
        !           372:            sc->sc_bst.bst_capacity,
        !           373:            sc->sc_bst.bst_voltage);
        !           374:
        !           375:        rv = 0;
        !           376: out:
        !           377:        aml_freevalue(&res);
        !           378:        return (rv);
        !           379: }
        !           380:
        !           381: /* XXX it has been observed that some systems do not propagate battery
        !           382:  * insertion events up to the driver.  What seems to happen is that DSDT
        !           383:  * does receive an interrupt however the originator bit is not set.
        !           384:  * This seems to happen when one inserts a 100% full battery.  Removal
        !           385:  * of the power cord or insertion of a not 100% full battery breaks this
        !           386:  * behavior and all events will then be sent upwards.  Currently there
        !           387:  * is no known work-around for it.
        !           388:  */
        !           389:
        !           390: int
        !           391: acpibat_notify(struct aml_node *node, int notify_type, void *arg)
        !           392: {
        !           393:        struct acpibat_softc    *sc = arg;
        !           394:
        !           395:        dnprintf(10, "acpibat_notify: %.2x %s\n", notify_type,
        !           396:            sc->sc_devnode->parent->name);
        !           397:
        !           398:        switch (notify_type) {
        !           399:        case 0x80:      /* _BST changed */
        !           400:                if (!sc->sc_bat_present) {
        !           401:                        printf("%s: %s: inserted\n", DEVNAME(sc),
        !           402:                            sc->sc_devnode->parent->name);
        !           403:                        sc->sc_bat_present = 1;
        !           404:                }
        !           405:                break;
        !           406:        case 0x81:      /* _BIF changed */
        !           407:                /* XXX consider this a device removal */
        !           408:                if (sc->sc_bat_present) {
        !           409:                        printf("%s: %s: removed\n", DEVNAME(sc),
        !           410:                            sc->sc_devnode->parent->name);
        !           411:                        sc->sc_bat_present = 0;
        !           412:                }
        !           413:                break;
        !           414:        default:
        !           415:                break;
        !           416:        }
        !           417:
        !           418:        acpibat_refresh(sc);
        !           419:
        !           420:        return (0);
        !           421: }

CVSweb