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