1 /* $OpenBSD: acpibat.c,v 1.67 2018/07/01 19:40:49 mlarkin 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 #include <sys/sensors.h> 23 24 #include <machine/apmvar.h> 25 26 #include <dev/acpi/acpireg.h> 27 #include <dev/acpi/acpivar.h> 28 #include <dev/acpi/acpidev.h> 29 #include <dev/acpi/amltypes.h> 30 #include <dev/acpi/dsdt.h> 31 32 int acpibat_match(struct device *, void *, void *); 33 void acpibat_attach(struct device *, struct device *, void *); 34 35 struct cfattach acpibat_ca = { 36 sizeof(struct acpibat_softc), acpibat_match, acpibat_attach 37 }; 38 39 struct cfdriver acpibat_cd = { 40 NULL, "acpibat", DV_DULL 41 }; 42 43 const char *acpibat_hids[] = { 44 ACPI_DEV_CMB, 45 NULL 46 }; 47 48 void acpibat_monitor(struct acpibat_softc *); 49 void acpibat_refresh(void *); 50 int acpibat_getbix(struct acpibat_softc *); 51 int acpibat_getbst(struct acpibat_softc *); 52 int acpibat_notify(struct aml_node *, int, void *); 53 54 int 55 acpibat_match(struct device *parent, void *match, void *aux) 56 { 57 struct acpi_attach_args *aa = aux; 58 struct cfdata *cf = match; 59 60 if (((struct acpi_softc *)parent)->sc_havesbs) 61 return (0); 62 63 /* sanity */ 64 return (acpi_matchhids(aa, acpibat_hids, cf->cf_driver->cd_name)); 65 } 66 67 void 68 acpibat_attach(struct device *parent, struct device *self, void *aux) 69 { 70 struct acpibat_softc *sc = (struct acpibat_softc *)self; 71 struct acpi_attach_args *aa = aux; 72 int64_t sta; 73 74 sc->sc_acpi = (struct acpi_softc *)parent; 75 sc->sc_devnode = aa->aaa_node; 76 77 if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "_STA", 0, NULL, &sta)) { 78 dnprintf(10, "%s: no _STA\n", DEVNAME(sc)); 79 return; 80 } 81 82 if ((sta & STA_BATTERY) != 0) { 83 sc->sc_bat_present = 1; 84 acpibat_getbix(sc); 85 acpibat_getbst(sc); 86 87 printf(": %s", sc->sc_devnode->name); 88 if (sc->sc_bix.bix_model[0]) 89 printf(" model \"%s\"", sc->sc_bix.bix_model); 90 if (sc->sc_bix.bix_serial[0]) 91 printf(" serial %s", sc->sc_bix.bix_serial); 92 if (sc->sc_bix.bix_type[0]) 93 printf(" type %s", sc->sc_bix.bix_type); 94 if (sc->sc_bix.bix_oem[0]) 95 printf(" oem \"%s\"", sc->sc_bix.bix_oem); 96 97 printf("\n"); 98 } else { 99 sc->sc_bat_present = 0; 100 printf(": %s not present\n", sc->sc_devnode->name); 101 } 102 103 /* create sensors */ 104 acpibat_monitor(sc); 105 106 /* populate sensors */ 107 acpibat_refresh(sc); 108 109 aml_register_notify(sc->sc_devnode, aa->aaa_dev, 110 acpibat_notify, sc, ACPIDEV_POLL); 111 } 112 113 void 114 acpibat_monitor(struct acpibat_softc *sc) 115 { 116 int type; 117 118 /* assume _BIF/_BIX and _BST have been called */ 119 strlcpy(sc->sc_sensdev.xname, DEVNAME(sc), 120 sizeof(sc->sc_sensdev.xname)); 121 122 type = sc->sc_bix.bix_power_unit ? SENSOR_AMPHOUR : SENSOR_WATTHOUR; 123 124 strlcpy(sc->sc_sens[0].desc, "last full capacity", 125 sizeof(sc->sc_sens[0].desc)); 126 sc->sc_sens[0].type = type; 127 sensor_attach(&sc->sc_sensdev, &sc->sc_sens[0]); 128 sc->sc_sens[0].value = sc->sc_bix.bix_last_capacity * 1000; 129 130 strlcpy(sc->sc_sens[1].desc, "warning capacity", 131 sizeof(sc->sc_sens[1].desc)); 132 sc->sc_sens[1].type = type; 133 sensor_attach(&sc->sc_sensdev, &sc->sc_sens[1]); 134 sc->sc_sens[1].value = sc->sc_bix.bix_warning * 1000; 135 136 strlcpy(sc->sc_sens[2].desc, "low capacity", 137 sizeof(sc->sc_sens[2].desc)); 138 sc->sc_sens[2].type = type; 139 sensor_attach(&sc->sc_sensdev, &sc->sc_sens[2]); 140 sc->sc_sens[2].value = sc->sc_bix.bix_low * 1000; 141 142 strlcpy(sc->sc_sens[3].desc, "voltage", sizeof(sc->sc_sens[3].desc)); 143 sc->sc_sens[3].type = SENSOR_VOLTS_DC; 144 sensor_attach(&sc->sc_sensdev, &sc->sc_sens[3]); 145 sc->sc_sens[3].value = sc->sc_bix.bix_voltage * 1000; 146 147 strlcpy(sc->sc_sens[4].desc, "battery unknown", 148 sizeof(sc->sc_sens[4].desc)); 149 sc->sc_sens[4].type = SENSOR_INTEGER; 150 sensor_attach(&sc->sc_sensdev, &sc->sc_sens[4]); 151 sc->sc_sens[4].value = sc->sc_bst.bst_state; 152 153 strlcpy(sc->sc_sens[5].desc, "rate", sizeof(sc->sc_sens[5].desc)); 154 sc->sc_sens[5].type = 155 sc->sc_bix.bix_power_unit ? SENSOR_AMPS : SENSOR_WATTS; 156 sensor_attach(&sc->sc_sensdev, &sc->sc_sens[5]); 157 sc->sc_sens[5].value = sc->sc_bst.bst_rate * 1000; 158 159 strlcpy(sc->sc_sens[6].desc, "remaining capacity", 160 sizeof(sc->sc_sens[6].desc)); 161 sc->sc_sens[6].type = type; 162 sensor_attach(&sc->sc_sensdev, &sc->sc_sens[6]); 163 sc->sc_sens[6].value = sc->sc_bix.bix_capacity * 1000; 164 165 strlcpy(sc->sc_sens[7].desc, "current voltage", 166 sizeof(sc->sc_sens[7].desc)); 167 sc->sc_sens[7].type = SENSOR_VOLTS_DC; 168 sensor_attach(&sc->sc_sensdev, &sc->sc_sens[7]); 169 sc->sc_sens[7].value = sc->sc_bix.bix_voltage * 1000; 170 171 strlcpy(sc->sc_sens[8].desc, "design capacity", 172 sizeof(sc->sc_sens[8].desc)); 173 sc->sc_sens[8].type = type; 174 sensor_attach(&sc->sc_sensdev, &sc->sc_sens[8]); 175 sc->sc_sens[8].value = sc->sc_bix.bix_capacity * 1000; 176 177 if (!sc->sc_use_bif) { 178 strlcpy(sc->sc_sens[9].desc, "discharge cycles", 179 sizeof(sc->sc_sens[9].desc)); 180 sc->sc_sens[9].type = SENSOR_INTEGER; 181 sensor_attach(&sc->sc_sensdev, &sc->sc_sens[9]); 182 sc->sc_sens[9].value = sc->sc_bix.bix_cycle_count; 183 } 184 185 sensordev_install(&sc->sc_sensdev); 186 } 187 188 void 189 acpibat_refresh(void *arg) 190 { 191 struct acpibat_softc *sc = arg; 192 int i; 193 194 dnprintf(30, "%s: %s: refresh\n", DEVNAME(sc), 195 sc->sc_devnode->name); 196 197 if (!sc->sc_bat_present) { 198 for (i = 0; i < nitems(sc->sc_sens); i++) { 199 sc->sc_sens[i].value = 0; 200 sc->sc_sens[i].status = SENSOR_S_UNSPEC; 201 sc->sc_sens[i].flags = SENSOR_FINVALID; 202 } 203 /* override state */ 204 strlcpy(sc->sc_sens[4].desc, "battery removed", 205 sizeof(sc->sc_sens[4].desc)); 206 return; 207 } 208 209 /* _BIF/_BIX values are static, sensor 0..3 */ 210 if (sc->sc_bix.bix_last_capacity == BIX_UNKNOWN) { 211 sc->sc_sens[0].value = 0; 212 sc->sc_sens[0].status = SENSOR_S_UNKNOWN; 213 sc->sc_sens[0].flags = SENSOR_FUNKNOWN; 214 } else { 215 sc->sc_sens[0].value = sc->sc_bix.bix_last_capacity * 1000; 216 sc->sc_sens[0].status = SENSOR_S_UNSPEC; 217 sc->sc_sens[0].flags = 0; 218 } 219 sc->sc_sens[1].value = sc->sc_bix.bix_warning * 1000; 220 sc->sc_sens[1].flags = 0; 221 sc->sc_sens[2].value = sc->sc_bix.bix_low * 1000; 222 sc->sc_sens[2].flags = 0; 223 if (sc->sc_bix.bix_voltage == BIX_UNKNOWN) { 224 sc->sc_sens[3].value = 0; 225 sc->sc_sens[3].status = SENSOR_S_UNKNOWN; 226 sc->sc_sens[3].flags = SENSOR_FUNKNOWN; 227 } else { 228 sc->sc_sens[3].value = sc->sc_bix.bix_voltage * 1000; 229 sc->sc_sens[3].status = SENSOR_S_UNSPEC; 230 sc->sc_sens[3].flags = 0; 231 } 232 233 /* _BST values are dynamic, sensor 4..7 */ 234 sc->sc_sens[4].status = SENSOR_S_OK; 235 sc->sc_sens[4].flags = 0; 236 if (sc->sc_bix.bix_last_capacity == BIX_UNKNOWN || 237 sc->sc_bst.bst_capacity == BST_UNKNOWN) { 238 sc->sc_sens[4].status = SENSOR_S_UNKNOWN; 239 sc->sc_sens[4].flags = SENSOR_FUNKNOWN; 240 strlcpy(sc->sc_sens[4].desc, "battery unknown", 241 sizeof(sc->sc_sens[4].desc)); 242 } else if (sc->sc_bst.bst_capacity >= sc->sc_bix.bix_last_capacity) 243 strlcpy(sc->sc_sens[4].desc, "battery full", 244 sizeof(sc->sc_sens[4].desc)); 245 else if (sc->sc_bst.bst_state & BST_DISCHARGE) 246 strlcpy(sc->sc_sens[4].desc, "battery discharging", 247 sizeof(sc->sc_sens[4].desc)); 248 else if (sc->sc_bst.bst_state & BST_CHARGE) 249 strlcpy(sc->sc_sens[4].desc, "battery charging", 250 sizeof(sc->sc_sens[4].desc)); 251 else if (sc->sc_bst.bst_state & BST_CRITICAL) { 252 strlcpy(sc->sc_sens[4].desc, "battery critical", 253 sizeof(sc->sc_sens[4].desc)); 254 sc->sc_sens[4].status = SENSOR_S_CRIT; 255 } else 256 strlcpy(sc->sc_sens[4].desc, "battery idle", 257 sizeof(sc->sc_sens[4].desc)); 258 sc->sc_sens[4].value = sc->sc_bst.bst_state; 259 260 if (sc->sc_bst.bst_rate == BST_UNKNOWN) { 261 sc->sc_sens[5].value = 0; 262 sc->sc_sens[5].status = SENSOR_S_UNKNOWN; 263 sc->sc_sens[5].flags = SENSOR_FUNKNOWN; 264 } else { 265 sc->sc_sens[5].value = sc->sc_bst.bst_rate * 1000; 266 sc->sc_sens[5].status = SENSOR_S_UNSPEC; 267 sc->sc_sens[5].flags = 0; 268 } 269 270 if (sc->sc_bst.bst_capacity == BST_UNKNOWN) { 271 sc->sc_sens[6].value = 0; 272 sc->sc_sens[6].status = SENSOR_S_UNKNOWN; 273 sc->sc_sens[6].flags = SENSOR_FUNKNOWN; 274 } else { 275 sc->sc_sens[6].value = sc->sc_bst.bst_capacity * 1000; 276 sc->sc_sens[6].flags = 0; 277 278 if (sc->sc_bst.bst_capacity < sc->sc_bix.bix_low) 279 /* XXX we should shutdown the system */ 280 sc->sc_sens[6].status = SENSOR_S_CRIT; 281 else if (sc->sc_bst.bst_capacity < sc->sc_bix.bix_warning) 282 sc->sc_sens[6].status = SENSOR_S_WARN; 283 else 284 sc->sc_sens[6].status = SENSOR_S_OK; 285 } 286 287 if (sc->sc_bst.bst_voltage == BST_UNKNOWN) { 288 sc->sc_sens[7].value = 0; 289 sc->sc_sens[7].status = SENSOR_S_UNKNOWN; 290 sc->sc_sens[7].flags = SENSOR_FUNKNOWN; 291 } else { 292 sc->sc_sens[7].value = sc->sc_bst.bst_voltage * 1000; 293 sc->sc_sens[7].status = SENSOR_S_UNSPEC; 294 sc->sc_sens[7].flags = 0; 295 } 296 297 if (sc->sc_bix.bix_capacity == BIX_UNKNOWN) { 298 sc->sc_sens[8].value = 0; 299 sc->sc_sens[8].status = SENSOR_S_UNKNOWN; 300 sc->sc_sens[8].flags = SENSOR_FUNKNOWN; 301 } else { 302 sc->sc_sens[8].value = sc->sc_bix.bix_capacity * 1000; 303 sc->sc_sens[8].status = SENSOR_S_UNSPEC; 304 sc->sc_sens[8].flags = 0; 305 } 306 307 if (!sc->sc_use_bif) { 308 if (sc->sc_bix.bix_capacity == BIX_UNKNOWN) { 309 sc->sc_sens[9].value = 0; 310 sc->sc_sens[9].status = SENSOR_S_UNKNOWN; 311 sc->sc_sens[9].flags = SENSOR_FUNKNOWN; 312 } else { 313 sc->sc_sens[9].value = sc->sc_bix.bix_cycle_count; 314 sc->sc_sens[9].status = SENSOR_S_UNSPEC; 315 sc->sc_sens[9].flags = 0; 316 } 317 } 318 319 acpi_record_event(sc->sc_acpi, APM_POWER_CHANGE); 320 } 321 322 int 323 acpibat_getbix(struct acpibat_softc *sc) 324 { 325 struct aml_value res; 326 int rv = EINVAL; 327 int n = 0; 328 329 if (!sc->sc_bat_present) { 330 memset(&sc->sc_bix, 0, sizeof(sc->sc_bix)); 331 return (0); 332 } 333 334 sc->sc_use_bif = 1; 335 336 if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_BIX", 0, NULL, 337 &res) == 0) { 338 if (res.length >= 20) 339 sc->sc_use_bif = 0; 340 else 341 dnprintf(10, "%s: invalid _BIX (%d < 20)\n", 342 DEVNAME(sc), res.length); 343 } 344 345 if (sc->sc_use_bif) { 346 if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_BIF", 0, NULL, 347 &res)) { 348 dnprintf(10, "%s: no _BIX or _BIF\n", DEVNAME(sc)); 349 goto out; 350 } 351 352 if (res.length != 13) { 353 dnprintf(10, "%s: invalid _BIF (%d != 13)\n", 354 DEVNAME(sc), res.length); 355 goto out; 356 } 357 } 358 359 if (!sc->sc_use_bif) 360 sc->sc_bix.bix_revision = aml_val2int(res.v_package[n++]); 361 362 sc->sc_bix.bix_power_unit = aml_val2int(res.v_package[n++]); 363 sc->sc_bix.bix_capacity = aml_val2int(res.v_package[n++]); 364 sc->sc_bix.bix_last_capacity = aml_val2int(res.v_package[n++]); 365 sc->sc_bix.bix_technology = aml_val2int(res.v_package[n++]); 366 sc->sc_bix.bix_voltage = aml_val2int(res.v_package[n++]); 367 sc->sc_bix.bix_warning = aml_val2int(res.v_package[n++]); 368 sc->sc_bix.bix_low = aml_val2int(res.v_package[n++]); 369 370 if (!sc->sc_use_bif) { 371 sc->sc_bix.bix_cycle_count = aml_val2int(res.v_package[n++]); 372 sc->sc_bix.bix_accuracy = aml_val2int(res.v_package[n++]); 373 sc->sc_bix.bix_max_sample = aml_val2int(res.v_package[n++]); 374 sc->sc_bix.bix_min_sample = aml_val2int(res.v_package[n++]); 375 sc->sc_bix.bix_max_avg = aml_val2int(res.v_package[n++]); 376 sc->sc_bix.bix_min_avg = aml_val2int(res.v_package[n++]); 377 } 378 379 sc->sc_bix.bix_cap_granu1 = aml_val2int(res.v_package[n++]); 380 sc->sc_bix.bix_cap_granu2 = aml_val2int(res.v_package[n++]); 381 382 strlcpy(sc->sc_bix.bix_model, aml_val_to_string(res.v_package[n++]), 383 sizeof(sc->sc_bix.bix_model)); 384 strlcpy(sc->sc_bix.bix_serial, aml_val_to_string(res.v_package[n++]), 385 sizeof(sc->sc_bix.bix_serial)); 386 strlcpy(sc->sc_bix.bix_type, aml_val_to_string(res.v_package[n++]), 387 sizeof(sc->sc_bix.bix_type)); 388 strlcpy(sc->sc_bix.bix_oem, aml_val_to_string(res.v_package[n++]), 389 sizeof(sc->sc_bix.bix_oem)); 390 391 if (!sc->sc_use_bif) 392 dnprintf(60, "revision: %u ", sc->sc_bix.bix_revision); 393 394 dnprintf(60, "power_unit: %u capacity: %u last_cap: %u " 395 "tech: %u volt: %u warn: %u low: %u ", 396 sc->sc_bix.bix_power_unit, 397 sc->sc_bix.bix_capacity, 398 sc->sc_bix.bix_last_capacity, 399 sc->sc_bix.bix_technology, 400 sc->sc_bix.bix_voltage, 401 sc->sc_bix.bix_warning, 402 sc->sc_bix.bix_low); 403 404 if (!sc->sc_use_bif) 405 dnprintf(60, "cycles: %u accuracy: %u max_sample: %u " 406 "min_sample: %u max_avg: %u min_avg: %u ", 407 sc->sc_bix.bix_cycle_count, 408 sc->sc_bix.bix_accuracy, 409 sc->sc_bix.bix_max_sample, 410 sc->sc_bix.bix_min_sample, 411 sc->sc_bix.bix_max_avg, 412 sc->sc_bix.bix_min_avg); 413 414 dnprintf(60, "gran1: %u gran2: %d model: %s serial: %s type: %s " 415 "oem: %s\n", 416 sc->sc_bix.bix_cap_granu1, 417 sc->sc_bix.bix_cap_granu2, 418 sc->sc_bix.bix_model, 419 sc->sc_bix.bix_serial, 420 sc->sc_bix.bix_type, 421 sc->sc_bix.bix_oem); 422 423 rv = 0; 424 out: 425 aml_freevalue(&res); 426 return (rv); 427 } 428 429 int 430 acpibat_getbst(struct acpibat_softc *sc) 431 { 432 struct aml_value res; 433 int rv = EINVAL; 434 435 if (!sc->sc_bat_present) { 436 memset(&sc->sc_bst, 0, sizeof(sc->sc_bst)); 437 return (0); 438 } 439 440 if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_BST", 0, NULL, &res)) { 441 dnprintf(10, "%s: no _BST\n", DEVNAME(sc)); 442 goto out; 443 } 444 445 if (res.length != 4) { 446 dnprintf(10, "%s: invalid _BST, battery status not saved\n", 447 DEVNAME(sc)); 448 goto out; 449 } 450 451 sc->sc_bst.bst_state = aml_val2int(res.v_package[0]); 452 sc->sc_bst.bst_rate = aml_val2int(res.v_package[1]); 453 sc->sc_bst.bst_capacity = aml_val2int(res.v_package[2]); 454 sc->sc_bst.bst_voltage = aml_val2int(res.v_package[3]); 455 456 dnprintf(60, "state: %u rate: %u cap: %u volt: %u ", 457 sc->sc_bst.bst_state, 458 sc->sc_bst.bst_rate, 459 sc->sc_bst.bst_capacity, 460 sc->sc_bst.bst_voltage); 461 462 rv = 0; 463 out: 464 aml_freevalue(&res); 465 return (rv); 466 } 467 468 /* 469 * XXX it has been observed that some systems do not propagate battery 470 * insertion events up to the driver. What seems to happen is that DSDT 471 * does receive an interrupt however the originator bit is not set. 472 * This seems to happen when one inserts a 100% full battery. Removal 473 * of the power cord or insertion of a not 100% full battery breaks this 474 * behavior and all events will then be sent upwards. Currently there 475 * is no known work-around for it. 476 */ 477 478 int 479 acpibat_notify(struct aml_node *node, int notify_type, void *arg) 480 { 481 struct acpibat_softc *sc = arg; 482 int64_t sta; 483 484 dnprintf(10, "acpibat_notify: %.2x %s\n", notify_type, 485 sc->sc_devnode->name); 486 487 /* Check if installed state of battery has changed */ 488 if (aml_evalinteger(sc->sc_acpi, node, "_STA", 0, NULL, &sta) == 0) { 489 if (sta & STA_BATTERY) 490 sc->sc_bat_present = 1; 491 else 492 sc->sc_bat_present = 0; 493 } 494 495 switch (notify_type) { 496 case 0x00: /* Poll sensors */ 497 case 0x80: /* _BST changed */ 498 acpibat_getbst(sc); 499 break; 500 case 0x81: /* _BIF/_BIX changed */ 501 acpibat_getbix(sc); 502 break; 503 default: 504 break; 505 } 506 507 acpibat_refresh(sc); 508 509 return (0); 510 } 511