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