[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

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