acpibat.c revision 1.17
1/* $OpenBSD: acpibat.c,v 1.17 2006/02/21 20:25:26 marco 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/systm.h> 20#include <sys/device.h> 21#include <sys/malloc.h> 22 23#include <machine/bus.h> 24 25#include <dev/acpi/acpireg.h> 26#include <dev/acpi/acpivar.h> 27#include <dev/acpi/acpidev.h> 28#include <dev/acpi/amltypes.h> 29#include <dev/acpi/dsdt.h> 30 31#include <sys/sensors.h> 32 33int acpibat_match(struct device *, void *, void *); 34void acpibat_attach(struct device *, struct device *, void *); 35 36struct acpibat_softc { 37 struct device sc_dev; 38 39 bus_space_tag_t sc_iot; 40 bus_space_handle_t sc_ioh; 41 42 struct acpi_softc *sc_acpi; 43 struct aml_node *sc_devnode; 44 45 struct acpibat_bif sc_bif; 46 struct acpibat_bst sc_bst; 47 48 struct sensor sc_sens[8]; /* XXX debug only */ 49}; 50 51struct cfattach acpibat_ca = { 52 sizeof(struct acpibat_softc), acpibat_match, acpibat_attach 53}; 54 55struct cfdriver acpibat_cd = { 56 NULL, "acpibat", DV_DULL 57}; 58 59void acpibat_refresh(void *); 60int acpibat_getbif(struct acpibat_softc *); 61int acpibat_getbst(struct acpibat_softc *); 62 63int 64acpibat_match(struct device *parent, void *match, void *aux) 65{ 66 struct acpi_attach_args *aa = aux; 67 struct cfdata *cf = match; 68 69 /* sanity */ 70 if (aa->aaa_name == NULL || 71 strcmp(aa->aaa_name, cf->cf_driver->cd_name) != 0 || 72 aa->aaa_table != NULL) 73 return (0); 74 75 return (1); 76} 77 78void 79acpibat_attach(struct device *parent, struct device *self, void *aux) 80{ 81 struct acpibat_softc *sc = (struct acpibat_softc *)self; 82 struct acpi_attach_args *aa = aux; 83 int i; 84 85 sc->sc_acpi = (struct acpi_softc *)parent; 86 sc->sc_devnode = aa->aaa_node->child; 87 88 if (acpibat_getbif(sc)) 89 return; 90 91 acpibat_getbst(sc); 92 93 printf(": model: %s serial: %s type: %s oem: %s\n", 94 sc->sc_bif.bif_model, 95 sc->sc_bif.bif_serial, 96 sc->sc_bif.bif_type, 97 sc->sc_bif.bif_oem); 98 99 memset(sc->sc_sens, 0, sizeof(sc->sc_sens)); 100 101 /* XXX this is for debug only, remove later */ 102 for (i = 0; i < 13; i++) 103 strlcpy(sc->sc_sens[i].device, DEVNAME(sc), sizeof(sc->sc_sens[i].device)); 104 105 strlcpy(sc->sc_sens[0].desc, "last full capacity", sizeof(sc->sc_sens[2].desc)); 106 sc->sc_sens[0].type = SENSOR_PERCENT; 107 sensor_add(&sc->sc_sens[0]); 108 sc->sc_sens[0].value = sc->sc_bif.bif_last_capacity / sc->sc_bif.bif_cap_granu1 * 1000; 109 110 strlcpy(sc->sc_sens[1].desc, "warning capacity", sizeof(sc->sc_sens[1].desc)); 111 sc->sc_sens[1].type = SENSOR_PERCENT; 112 sensor_add(&sc->sc_sens[1]); 113 sc->sc_sens[1].value = sc->sc_bif.bif_warning / sc->sc_bif.bif_cap_granu1 * 1000; 114 115 strlcpy(sc->sc_sens[2].desc, "low capacity", sizeof(sc->sc_sens[2].desc)); 116 sc->sc_sens[2].type = SENSOR_PERCENT; 117 sensor_add(&sc->sc_sens[2]); 118 sc->sc_sens[2].value = sc->sc_bif.bif_warning / sc->sc_bif.bif_cap_granu1 * 1000; 119 120 strlcpy(sc->sc_sens[3].desc, "voltage", sizeof(sc->sc_sens[3].desc)); 121 sc->sc_sens[3].type = SENSOR_VOLTS_DC; 122 sensor_add(&sc->sc_sens[3]); 123 sc->sc_sens[3].status = SENSOR_S_OK; 124 sc->sc_sens[3].value = sc->sc_bif.bif_voltage * 1000; 125 126 strlcpy(sc->sc_sens[4].desc, "state", sizeof(sc->sc_sens[4].desc)); 127 sc->sc_sens[4].type = SENSOR_INTEGER; 128 sensor_add(&sc->sc_sens[4]); 129 sc->sc_sens[4].status = SENSOR_S_OK; 130 sc->sc_sens[4].value = sc->sc_bst.bst_state; 131 132 strlcpy(sc->sc_sens[5].desc, "rate", sizeof(sc->sc_sens[5].desc)); 133 sc->sc_sens[5].type = SENSOR_INTEGER; 134 sensor_add(&sc->sc_sens[5]); 135 sc->sc_sens[5].value = sc->sc_bst.bst_rate; 136 137 strlcpy(sc->sc_sens[6].desc, "remaining capacity", sizeof(sc->sc_sens[6].desc)); 138 sc->sc_sens[6].type = SENSOR_PERCENT; 139 sensor_add(&sc->sc_sens[6]); 140 sc->sc_sens[6].value = sc->sc_bst.bst_capacity / sc->sc_bif.bif_cap_granu1 * 1000; 141 142 strlcpy(sc->sc_sens[7].desc, "current voltage", sizeof(sc->sc_sens[7].desc)); 143 sc->sc_sens[7].type = SENSOR_VOLTS_DC; 144 sensor_add(&sc->sc_sens[7]); 145 sc->sc_sens[7].status = SENSOR_S_OK; 146 sc->sc_sens[7].value = sc->sc_bst.bst_voltage * 1000; 147 148 if (sensor_task_register(sc, acpibat_refresh, 10)) 149 printf(", unable to register update task\n"); 150} 151 152/* XXX this is for debug only, remove later */ 153void 154acpibat_refresh(void *arg) 155{ 156 struct acpibat_softc *sc = arg; 157 158 acpibat_getbif(sc); 159 acpibat_getbst(sc); 160 161 sc->sc_sens[0].value = sc->sc_bif.bif_last_capacity / sc->sc_bif.bif_cap_granu1 * 1000; 162 sc->sc_sens[1].value = sc->sc_bif.bif_warning / sc->sc_bif.bif_cap_granu1 * 1000; 163 sc->sc_sens[2].value = sc->sc_bif.bif_warning / sc->sc_bif.bif_cap_granu1 * 1000; 164 sc->sc_sens[3].value = sc->sc_bif.bif_voltage * 1000; 165 166 sc->sc_sens[4].status = SENSOR_S_OK; 167 if (sc->sc_bst.bst_state & BST_DISCHARGE) 168 strlcpy(sc->sc_sens[4].desc, "battery discharging", sizeof(sc->sc_sens[4].desc)); 169 else if (sc->sc_bst.bst_state & BST_CHARGE) 170 strlcpy(sc->sc_sens[4].desc, "battery charging", sizeof(sc->sc_sens[4].desc)); 171 else if (sc->sc_bst.bst_state & BST_CRITICAL) { 172 strlcpy(sc->sc_sens[4].desc, "battery critical", sizeof(sc->sc_sens[4].desc)); 173 sc->sc_sens[4].status = SENSOR_S_CRIT; 174 } 175 sc->sc_sens[4].value = sc->sc_bst.bst_state; 176 sc->sc_sens[5].value = sc->sc_bst.bst_rate; 177 sc->sc_sens[6].value = sc->sc_bst.bst_capacity / sc->sc_bif.bif_cap_granu1 * 1000; 178} 179 180int 181acpibat_getbif(struct acpibat_softc *sc) 182{ 183 struct aml_value res, env; 184 struct acpi_context *ctx; 185 186 memset(&res, 0, sizeof(res)); 187 memset(&env, 0, sizeof(env)); 188 189 ctx = NULL; 190 if (aml_eval_name(sc->sc_acpi, sc->sc_devnode, "_STA", &res, &env)) { 191 dnprintf(10, "%s: no _STA\n", 192 DEVNAME(sc)); 193 return (1); 194 } 195 196 if (!(res.v_integer & STA_BATTERY)) { 197 printf(": battery not present\n"); 198 return (1); 199 } 200 201 if (aml_eval_name(sc->sc_acpi, sc->sc_devnode, "_BIF", &res, &env)) { 202 dnprintf(10, "%s: no _BIF\n", 203 DEVNAME(sc)); 204 return (1); 205 } 206 207 if (res.length != 13) { 208 printf("%s: invalid _BIF, battery information not saved\n", 209 DEVNAME(sc)); 210 return (1); 211 } 212 213 sc->sc_bif.bif_power_unit = aml_val2int(ctx, res.v_package[0]); 214 sc->sc_bif.bif_capacity = aml_val2int(ctx, res.v_package[1]); 215 sc->sc_bif.bif_last_capacity = aml_val2int(ctx, res.v_package[2]); 216 sc->sc_bif.bif_technology = aml_val2int(ctx, res.v_package[3]); 217 sc->sc_bif.bif_voltage = aml_val2int(ctx, res.v_package[4]); 218 sc->sc_bif.bif_warning = aml_val2int(ctx, res.v_package[5]); 219 sc->sc_bif.bif_low = aml_val2int(ctx, res.v_package[6]); 220 sc->sc_bif.bif_cap_granu1 = aml_val2int(ctx, res.v_package[7]); 221 sc->sc_bif.bif_cap_granu2 = aml_val2int(ctx, res.v_package[8]); 222 sc->sc_bif.bif_model = aml_strval(res.v_package[9]); 223 sc->sc_bif.bif_serial = aml_strval(res.v_package[10]); 224 sc->sc_bif.bif_type = aml_strval(res.v_package[11]); 225 sc->sc_bif.bif_oem = aml_strval(res.v_package[12]); 226 227 dnprintf(60, "power_unit: %u capacity: %u last_cap: %u tech: %u " 228 "volt: %u warn: %u low: %u gran1: %u gran2: %d model: %s " 229 "serial: %s type: %s oem: %s\n", 230 sc->sc_bif.bif_power_unit, 231 sc->sc_bif.bif_capacity, 232 sc->sc_bif.bif_last_capacity, 233 sc->sc_bif.bif_technology, 234 sc->sc_bif.bif_voltage, 235 sc->sc_bif.bif_warning, 236 sc->sc_bif.bif_low, 237 sc->sc_bif.bif_cap_granu1, 238 sc->sc_bif.bif_cap_granu2, 239 sc->sc_bif.bif_model, 240 sc->sc_bif.bif_serial, 241 sc->sc_bif.bif_type, 242 sc->sc_bif.bif_oem); 243 244 return (0); 245} 246 247int 248acpibat_getbst(struct acpibat_softc *sc) 249{ 250 struct aml_value res, env; 251 struct acpi_context *ctx; 252 253 memset(&res, 0, sizeof(res)); 254 memset(&env, 0, sizeof(env)); 255 256 ctx = NULL; 257 if (aml_eval_name(sc->sc_acpi, sc->sc_devnode, "_BST", &res, &env)) { 258 dnprintf(10, "%s: no _BST\n", 259 DEVNAME(sc)); 260 return (1); 261 } 262 263 if (res.length != 4) { 264 printf("%s: invalid _BST, battery status not saved\n", 265 DEVNAME(sc)); 266 return (1); 267 } 268 269 sc->sc_bst.bst_state = aml_val2int(ctx, res.v_package[0]); 270 sc->sc_bst.bst_rate = aml_val2int(ctx, res.v_package[1]); 271 sc->sc_bst.bst_capacity = aml_val2int(ctx, res.v_package[2]); 272 sc->sc_bst.bst_voltage = aml_val2int(ctx, res.v_package[3]); 273 274 dnprintf(60, "state: %u rate: %u cap: %u volt: %u ", 275 sc->sc_bst.bst_state, 276 sc->sc_bst.bst_rate, 277 sc->sc_bst.bst_capacity, 278 sc->sc_bst.bst_voltage); 279 280 return (0); 281} 282