diff options
author | Marco Peereboom <marco@cvs.openbsd.org> | 2006-02-22 15:29:24 +0000 |
---|---|---|
committer | Marco Peereboom <marco@cvs.openbsd.org> | 2006-02-22 15:29:24 +0000 |
commit | 23b49a8ff45c1b8b287f587df5db45c2c40f9311 (patch) | |
tree | 2df3d557c4c4f7ad290f3f64e0436b7b72d55ba4 /sys/dev/acpi/acpibat.c | |
parent | 21b89cec9f8cb149f33153595940683fd70163b9 (diff) |
Add insertion and removal events for batteries.
Some cleanup & KNF.
Diffstat (limited to 'sys/dev/acpi/acpibat.c')
-rw-r--r-- | sys/dev/acpi/acpibat.c | 218 |
1 files changed, 177 insertions, 41 deletions
diff --git a/sys/dev/acpi/acpibat.c b/sys/dev/acpi/acpibat.c index 85d674729ae..f42bf4559fb 100644 --- a/sys/dev/acpi/acpibat.c +++ b/sys/dev/acpi/acpibat.c @@ -1,4 +1,4 @@ -/* $OpenBSD: acpibat.c,v 1.17 2006/02/21 20:25:26 marco Exp $ */ +/* $OpenBSD: acpibat.c,v 1.18 2006/02/22 15:29:23 marco Exp $ */ /* * Copyright (c) 2005 Marco Peereboom <marco@openbsd.org> * @@ -16,8 +16,10 @@ */ #include <sys/param.h> +#include <sys/proc.h> #include <sys/systm.h> #include <sys/device.h> +#include <sys/lock.h> #include <sys/malloc.h> #include <machine/bus.h> @@ -42,8 +44,10 @@ struct acpibat_softc { struct acpi_softc *sc_acpi; struct aml_node *sc_devnode; + struct lock sc_lock; struct acpibat_bif sc_bif; struct acpibat_bst sc_bst; + volatile int sc_bat_present; struct sensor sc_sens[8]; /* XXX debug only */ }; @@ -56,9 +60,11 @@ struct cfdriver acpibat_cd = { NULL, "acpibat", DV_DULL }; +void acpibat_monitor(struct acpibat_softc *); void acpibat_refresh(void *); int acpibat_getbif(struct acpibat_softc *); int acpibat_getbst(struct acpibat_softc *); +int acpibat_notify(struct aml_node *, int, void *); int acpibat_match(struct device *parent, void *match, void *aux) @@ -80,42 +86,87 @@ acpibat_attach(struct device *parent, struct device *self, void *aux) { struct acpibat_softc *sc = (struct acpibat_softc *)self; struct acpi_attach_args *aa = aux; - int i; + struct aml_value res, env; + struct acpi_context *ctx; sc->sc_acpi = (struct acpi_softc *)parent; sc->sc_devnode = aa->aaa_node->child; - if (acpibat_getbif(sc)) - return; + lockinit(&sc->sc_lock, PZERO, DEVNAME(sc), 0, 0); - acpibat_getbst(sc); + memset(&res, 0, sizeof(res)); + memset(&env, 0, sizeof(env)); - printf(": model: %s serial: %s type: %s oem: %s\n", - sc->sc_bif.bif_model, - sc->sc_bif.bif_serial, - sc->sc_bif.bif_type, - sc->sc_bif.bif_oem); + /* XXX this trick seems to only work during boot */ + ctx = NULL; + if (aml_eval_name(sc->sc_acpi, sc->sc_devnode, "_STA", &res, &env)) + dnprintf(10, "%s: no _STA\n", + DEVNAME(sc)); + + if (!(res.v_integer & STA_BATTERY)) { + sc->sc_bat_present = 0; + printf(": %s: not present\n", sc->sc_devnode->parent->name); + acpibat_monitor(sc); + } else { + sc->sc_bat_present = 1; + + acpibat_getbif(sc); + acpibat_getbst(sc); + + printf(": %s: model: %s serial: %s type: %s oem: %s\n", + sc->sc_devnode->parent->name, + sc->sc_bif.bif_model, + sc->sc_bif.bif_serial, + sc->sc_bif.bif_type, + sc->sc_bif.bif_oem); + + if (sensor_task_register(sc, acpibat_refresh, 10)) + printf(", unable to register update task\n"); + + acpibat_monitor(sc); + + } + + aml_register_notify(sc->sc_devnode->parent, acpibat_notify, sc); +} + +/* XXX this is for debug only, remove later */ +void +acpibat_monitor(struct acpibat_softc *sc) +{ + int i; + + /* assume _BIF and _BST have been called */ memset(sc->sc_sens, 0, sizeof(sc->sc_sens)); + for (i = 0; i < 8; i++) + strlcpy(sc->sc_sens[i].device, DEVNAME(sc), + sizeof(sc->sc_sens[i].device)); - /* XXX this is for debug only, remove later */ - for (i = 0; i < 13; i++) - strlcpy(sc->sc_sens[i].device, DEVNAME(sc), sizeof(sc->sc_sens[i].device)); + /* XXX ugh but make sure */ + if (!sc->sc_bif.bif_cap_granu1) + sc->sc_bif.bif_cap_granu1 = 1; - strlcpy(sc->sc_sens[0].desc, "last full capacity", sizeof(sc->sc_sens[2].desc)); + strlcpy(sc->sc_sens[0].desc, "last full capacity", + sizeof(sc->sc_sens[2].desc)); sc->sc_sens[0].type = SENSOR_PERCENT; sensor_add(&sc->sc_sens[0]); - sc->sc_sens[0].value = sc->sc_bif.bif_last_capacity / sc->sc_bif.bif_cap_granu1 * 1000; + sc->sc_sens[0].value = sc->sc_bif.bif_last_capacity / + sc->sc_bif.bif_cap_granu1 * 1000; - strlcpy(sc->sc_sens[1].desc, "warning capacity", sizeof(sc->sc_sens[1].desc)); + strlcpy(sc->sc_sens[1].desc, "warning capacity", + sizeof(sc->sc_sens[1].desc)); sc->sc_sens[1].type = SENSOR_PERCENT; sensor_add(&sc->sc_sens[1]); - sc->sc_sens[1].value = sc->sc_bif.bif_warning / sc->sc_bif.bif_cap_granu1 * 1000; + sc->sc_sens[1].value = sc->sc_bif.bif_warning / + sc->sc_bif.bif_cap_granu1 * 1000; - strlcpy(sc->sc_sens[2].desc, "low capacity", sizeof(sc->sc_sens[2].desc)); + strlcpy(sc->sc_sens[2].desc, "low capacity", + sizeof(sc->sc_sens[2].desc)); sc->sc_sens[2].type = SENSOR_PERCENT; sensor_add(&sc->sc_sens[2]); - sc->sc_sens[2].value = sc->sc_bif.bif_warning / sc->sc_bif.bif_cap_granu1 * 1000; + sc->sc_sens[2].value = sc->sc_bif.bif_warning / + sc->sc_bif.bif_cap_granu1 * 1000; strlcpy(sc->sc_sens[3].desc, "voltage", sizeof(sc->sc_sens[3].desc)); sc->sc_sens[3].type = SENSOR_VOLTS_DC; @@ -134,47 +185,65 @@ acpibat_attach(struct device *parent, struct device *self, void *aux) sensor_add(&sc->sc_sens[5]); sc->sc_sens[5].value = sc->sc_bst.bst_rate; - strlcpy(sc->sc_sens[6].desc, "remaining capacity", sizeof(sc->sc_sens[6].desc)); + strlcpy(sc->sc_sens[6].desc, "remaining capacity", + sizeof(sc->sc_sens[6].desc)); sc->sc_sens[6].type = SENSOR_PERCENT; sensor_add(&sc->sc_sens[6]); - sc->sc_sens[6].value = sc->sc_bst.bst_capacity / sc->sc_bif.bif_cap_granu1 * 1000; + sc->sc_sens[6].value = sc->sc_bst.bst_capacity / + sc->sc_bif.bif_cap_granu1 * 1000; - strlcpy(sc->sc_sens[7].desc, "current voltage", sizeof(sc->sc_sens[7].desc)); + strlcpy(sc->sc_sens[7].desc, "current voltage", + sizeof(sc->sc_sens[7].desc)); sc->sc_sens[7].type = SENSOR_VOLTS_DC; sensor_add(&sc->sc_sens[7]); sc->sc_sens[7].status = SENSOR_S_OK; sc->sc_sens[7].value = sc->sc_bst.bst_voltage * 1000; - - if (sensor_task_register(sc, acpibat_refresh, 10)) - printf(", unable to register update task\n"); } -/* XXX this is for debug only, remove later */ void acpibat_refresh(void *arg) { struct acpibat_softc *sc = arg; + dnprintf(30, "%s: %s: refresh\n", DEVNAME(sc), + sc->sc_devnode->parent->name); + acpibat_getbif(sc); acpibat_getbst(sc); - sc->sc_sens[0].value = sc->sc_bif.bif_last_capacity / sc->sc_bif.bif_cap_granu1 * 1000; - sc->sc_sens[1].value = sc->sc_bif.bif_warning / sc->sc_bif.bif_cap_granu1 * 1000; - sc->sc_sens[2].value = sc->sc_bif.bif_warning / sc->sc_bif.bif_cap_granu1 * 1000; + lockmgr(&sc->sc_lock, LK_EXCLUSIVE, NULL); + + /* XXX ugh but make sure */ + if (!sc->sc_bif.bif_cap_granu1) + sc->sc_bif.bif_cap_granu1 = 1; + + sc->sc_sens[0].value = sc->sc_bif.bif_last_capacity / + sc->sc_bif.bif_cap_granu1 * 1000; + sc->sc_sens[1].value = sc->sc_bif.bif_warning / + sc->sc_bif.bif_cap_granu1 * 1000; + sc->sc_sens[2].value = sc->sc_bif.bif_warning / + sc->sc_bif.bif_cap_granu1 * 1000; sc->sc_sens[3].value = sc->sc_bif.bif_voltage * 1000; sc->sc_sens[4].status = SENSOR_S_OK; if (sc->sc_bst.bst_state & BST_DISCHARGE) - strlcpy(sc->sc_sens[4].desc, "battery discharging", sizeof(sc->sc_sens[4].desc)); + strlcpy(sc->sc_sens[4].desc, "battery discharging", + sizeof(sc->sc_sens[4].desc)); else if (sc->sc_bst.bst_state & BST_CHARGE) - strlcpy(sc->sc_sens[4].desc, "battery charging", sizeof(sc->sc_sens[4].desc)); + strlcpy(sc->sc_sens[4].desc, "battery charging", + sizeof(sc->sc_sens[4].desc)); else if (sc->sc_bst.bst_state & BST_CRITICAL) { - strlcpy(sc->sc_sens[4].desc, "battery critical", sizeof(sc->sc_sens[4].desc)); + strlcpy(sc->sc_sens[4].desc, "battery critical", + sizeof(sc->sc_sens[4].desc)); sc->sc_sens[4].status = SENSOR_S_CRIT; } sc->sc_sens[4].value = sc->sc_bst.bst_state; sc->sc_sens[5].value = sc->sc_bst.bst_rate; - sc->sc_sens[6].value = sc->sc_bst.bst_capacity / sc->sc_bif.bif_cap_granu1 * 1000; + sc->sc_sens[6].value = sc->sc_bst.bst_capacity / + sc->sc_bif.bif_cap_granu1 * 1000; + sc->sc_sens[7].value = sc->sc_bst.bst_voltage * 1000; + + lockmgr(&sc->sc_lock, LK_RELEASE, NULL); } int @@ -182,6 +251,9 @@ acpibat_getbif(struct acpibat_softc *sc) { struct aml_value res, env; struct acpi_context *ctx; + int rv = 1; + + lockmgr(&sc->sc_lock, LK_EXCLUSIVE, NULL); memset(&res, 0, sizeof(res)); memset(&env, 0, sizeof(env)); @@ -190,26 +262,32 @@ acpibat_getbif(struct acpibat_softc *sc) if (aml_eval_name(sc->sc_acpi, sc->sc_devnode, "_STA", &res, &env)) { dnprintf(10, "%s: no _STA\n", DEVNAME(sc)); - return (1); + goto out; } + /* XXX this is broken, it seems to only work during boot */ + /* if (!(res.v_integer & STA_BATTERY)) { - printf(": battery not present\n"); + sc->sc_bat_present = 0; return (1); - } + } else + sc->sc_bat_present = 1; + */ if (aml_eval_name(sc->sc_acpi, sc->sc_devnode, "_BIF", &res, &env)) { dnprintf(10, "%s: no _BIF\n", DEVNAME(sc)); - return (1); + printf("bif fails\n"); + goto out; } if (res.length != 13) { printf("%s: invalid _BIF, battery information not saved\n", DEVNAME(sc)); - return (1); + goto out; } + memset(&sc->sc_bif, 0, sizeof sc->sc_bif); sc->sc_bif.bif_power_unit = aml_val2int(ctx, res.v_package[0]); sc->sc_bif.bif_capacity = aml_val2int(ctx, res.v_package[1]); sc->sc_bif.bif_last_capacity = aml_val2int(ctx, res.v_package[2]); @@ -241,7 +319,9 @@ acpibat_getbif(struct acpibat_softc *sc) sc->sc_bif.bif_type, sc->sc_bif.bif_oem); - return (0); +out: + lockmgr(&sc->sc_lock, LK_RELEASE, NULL); + return (rv); } int @@ -249,6 +329,9 @@ acpibat_getbst(struct acpibat_softc *sc) { struct aml_value res, env; struct acpi_context *ctx; + int rv; + + lockmgr(&sc->sc_lock, LK_EXCLUSIVE, NULL); memset(&res, 0, sizeof(res)); memset(&env, 0, sizeof(env)); @@ -257,13 +340,14 @@ acpibat_getbst(struct acpibat_softc *sc) if (aml_eval_name(sc->sc_acpi, sc->sc_devnode, "_BST", &res, &env)) { dnprintf(10, "%s: no _BST\n", DEVNAME(sc)); - return (1); + printf("_bst fails\n"); + goto out; } if (res.length != 4) { printf("%s: invalid _BST, battery status not saved\n", DEVNAME(sc)); - return (1); + goto out; } sc->sc_bst.bst_state = aml_val2int(ctx, res.v_package[0]); @@ -276,6 +360,58 @@ acpibat_getbst(struct acpibat_softc *sc) sc->sc_bst.bst_rate, sc->sc_bst.bst_capacity, sc->sc_bst.bst_voltage); +out: + lockmgr(&sc->sc_lock, LK_RELEASE, NULL); + return (rv); +} + +/* XXX it has been observed that some systemts do not propagate battery + * inserion events up to the driver. What seems to happen is that DSDT + * does receive an interrupt however the originator bit is not set. + * This seems to happen when one inserts a 100% full battery. Removal + * of the power cord or insertion of a not 100% full battery breaks this + * behavior and all events will then be sent upwards. Currently there + * is no known work-around for it. + */ + +int +acpibat_notify(struct aml_node *node, int notify_type, void *arg) +{ + struct acpibat_softc *sc = arg; + + dnprintf(10, "acpibat_notify: %.2x %s\n", notify_type, + sc->sc_devnode->parent->name); + + switch (notify_type) { + case 0x80: /* _BST changed */ + if (sc->sc_bat_present == 0) { + printf("%s: %s: inserted\n", DEVNAME(sc), + sc->sc_devnode->parent->name); + + if (sensor_task_register(sc, acpibat_refresh, 10)) + printf(", unable to register update task\n"); + } + + sc->sc_bat_present = 1; + acpibat_getbif(sc); + acpibat_getbst(sc); + + break; + case 0x81: /* _BIF changed */ + /* XXX consider this a device removal */ + sensor_task_unregister(sc); + sc->sc_bat_present = 0; + strlcpy(sc->sc_sens[4].desc, "battery removed", + sizeof(sc->sc_sens[4].desc)); + printf("%s: %s: removed\n", DEVNAME(sc), + sc->sc_devnode->parent->name); + + break; + default: + printf("%s: unhandled battery event %x\n", DEVNAME(sc), + notify_type); + break; + } return (0); } |