1 /* $NetBSD: acpi_bat.c,v 1.115 2015/04/23 23:23:00 pgoyette Exp $ */ 2 3 /*- 4 * Copyright (c) 2003 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Charles M. Hannum of By Noon Software, Inc. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* 33 * Copyright 2001 Bill Sommerfeld. 34 * All rights reserved. 35 * 36 * Redistribution and use in source and binary forms, with or without 37 * modification, are permitted provided that the following conditions 38 * are met: 39 * 1. Redistributions of source code must retain the above copyright 40 * notice, this list of conditions and the following disclaimer. 41 * 2. Redistributions in binary form must reproduce the above copyright 42 * notice, this list of conditions and the following disclaimer in the 43 * documentation and/or other materials provided with the distribution. 44 * 3. All advertising materials mentioning features or use of this software 45 * must display the following acknowledgement: 46 * This product includes software developed for the NetBSD Project by 47 * Wasabi Systems, Inc. 48 * 4. The name of Wasabi Systems, Inc. may not be used to endorse 49 * or promote products derived from this software without specific prior 50 * written permission. 51 * 52 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 53 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 54 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 55 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 56 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 57 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 58 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 59 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 60 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 61 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 62 * POSSIBILITY OF SUCH DAMAGE. 63 */ 64 65 /* 66 * ACPI Battery Driver. 67 * 68 * ACPI defines two different battery device interfaces: "Control 69 * Method" batteries, in which AML methods are defined in order to get 70 * battery status and set battery alarm thresholds, and a "Smart 71 * Battery" device, which is an SMbus device accessed through the ACPI 72 * Embedded Controller device. 73 * 74 * This driver is for the "Control Method"-style battery only. 75 */ 76 77 #include <sys/cdefs.h> 78 __KERNEL_RCSID(0, "$NetBSD: acpi_bat.c,v 1.115 2015/04/23 23:23:00 pgoyette Exp $"); 79 80 #include <sys/param.h> 81 #include <sys/condvar.h> 82 #include <sys/device.h> 83 #include <sys/kernel.h> 84 #include <sys/kmem.h> 85 #include <sys/module.h> 86 #include <sys/mutex.h> 87 #include <sys/systm.h> 88 89 #include <dev/acpi/acpireg.h> 90 #include <dev/acpi/acpivar.h> 91 92 #define _COMPONENT ACPI_BAT_COMPONENT 93 ACPI_MODULE_NAME ("acpi_bat") 94 95 #define ACPI_NOTIFY_BAT_STATUS 0x80 96 #define ACPI_NOTIFY_BAT_INFO 0x81 97 98 /* 99 * Sensor indexes. 100 */ 101 enum { 102 ACPIBAT_PRESENT = 0, 103 ACPIBAT_DVOLTAGE = 1, 104 ACPIBAT_VOLTAGE = 2, 105 ACPIBAT_DCAPACITY = 3, 106 ACPIBAT_LFCCAPACITY = 4, 107 ACPIBAT_CAPACITY = 5, 108 ACPIBAT_CHARGERATE = 6, 109 ACPIBAT_DISCHARGERATE = 7, 110 ACPIBAT_CHARGING = 8, 111 ACPIBAT_CHARGE_STATE = 9, 112 ACPIBAT_COUNT = 10 113 }; 114 115 /* 116 * Battery Information, _BIF 117 * (ACPI 3.0, sec. 10.2.2.1). 118 */ 119 enum { 120 ACPIBAT_BIF_UNIT = 0, 121 ACPIBAT_BIF_DCAPACITY = 1, 122 ACPIBAT_BIF_LFCCAPACITY = 2, 123 ACPIBAT_BIF_TECHNOLOGY = 3, 124 ACPIBAT_BIF_DVOLTAGE = 4, 125 ACPIBAT_BIF_WCAPACITY = 5, 126 ACPIBAT_BIF_LCAPACITY = 6, 127 ACPIBAT_BIF_GRANULARITY1 = 7, 128 ACPIBAT_BIF_GRANULARITY2 = 8, 129 ACPIBAT_BIF_MODEL = 9, 130 ACPIBAT_BIF_SERIAL = 10, 131 ACPIBAT_BIF_TYPE = 11, 132 ACPIBAT_BIF_OEM = 12, 133 ACPIBAT_BIF_COUNT = 13 134 }; 135 136 /* 137 * Battery Status, _BST 138 * (ACPI 3.0, sec. 10.2.2.3). 139 */ 140 enum { 141 ACPIBAT_BST_STATE = 0, 142 ACPIBAT_BST_RATE = 1, 143 ACPIBAT_BST_CAPACITY = 2, 144 ACPIBAT_BST_VOLTAGE = 3, 145 ACPIBAT_BST_COUNT = 4 146 }; 147 148 struct acpibat_softc { 149 struct acpi_devnode *sc_node; 150 struct sysmon_envsys *sc_sme; 151 struct timeval sc_last; 152 envsys_data_t *sc_sensor; 153 kmutex_t sc_mutex; 154 kcondvar_t sc_condvar; 155 int32_t sc_dcapacity; 156 int32_t sc_dvoltage; 157 int32_t sc_lcapacity; 158 int32_t sc_wcapacity; 159 int sc_present; 160 }; 161 162 static const char * const bat_hid[] = { 163 "PNP0C0A", 164 NULL 165 }; 166 167 #define ACPIBAT_PWRUNIT_MA 0x00000001 /* mA not mW */ 168 #define ACPIBAT_ST_DISCHARGING 0x00000001 /* battery is discharging */ 169 #define ACPIBAT_ST_CHARGING 0x00000002 /* battery is charging */ 170 #define ACPIBAT_ST_CRITICAL 0x00000004 /* battery is critical */ 171 172 /* 173 * A value used when _BST or _BIF is temporarily unknown. 174 */ 175 #define ACPIBAT_VAL_UNKNOWN 0xFFFFFFFF 176 177 #define ACPIBAT_VAL_ISVALID(x) \ 178 (((x) != ACPIBAT_VAL_UNKNOWN) ? ENVSYS_SVALID : ENVSYS_SINVALID) 179 180 static int acpibat_match(device_t, cfdata_t, void *); 181 static void acpibat_attach(device_t, device_t, void *); 182 static int acpibat_detach(device_t, int); 183 static int acpibat_get_sta(device_t); 184 static ACPI_OBJECT *acpibat_get_object(ACPI_HANDLE, const char *, uint32_t); 185 static void acpibat_get_info(device_t); 186 static void acpibat_print_info(device_t, ACPI_OBJECT *); 187 static void acpibat_get_status(device_t); 188 static void acpibat_update_info(void *); 189 static void acpibat_update_status(void *); 190 static void acpibat_init_envsys(device_t); 191 static void acpibat_notify_handler(ACPI_HANDLE, uint32_t, void *); 192 static void acpibat_refresh(struct sysmon_envsys *, envsys_data_t *); 193 static bool acpibat_resume(device_t, const pmf_qual_t *); 194 static void acpibat_get_limits(struct sysmon_envsys *, envsys_data_t *, 195 sysmon_envsys_lim_t *, uint32_t *); 196 197 CFATTACH_DECL_NEW(acpibat, sizeof(struct acpibat_softc), 198 acpibat_match, acpibat_attach, acpibat_detach, NULL); 199 200 /* 201 * acpibat_match: 202 * 203 * Autoconfiguration `match' routine. 204 */ 205 static int 206 acpibat_match(device_t parent, cfdata_t match, void *aux) 207 { 208 struct acpi_attach_args *aa = aux; 209 210 if (aa->aa_node->ad_type != ACPI_TYPE_DEVICE) 211 return 0; 212 213 return acpi_match_hid(aa->aa_node->ad_devinfo, bat_hid); 214 } 215 216 /* 217 * acpibat_attach: 218 * 219 * Autoconfiguration `attach' routine. 220 */ 221 static void 222 acpibat_attach(device_t parent, device_t self, void *aux) 223 { 224 struct acpibat_softc *sc = device_private(self); 225 struct acpi_attach_args *aa = aux; 226 ACPI_HANDLE tmp; 227 ACPI_STATUS rv; 228 229 aprint_naive(": ACPI Battery\n"); 230 aprint_normal(": ACPI Battery\n"); 231 232 sc->sc_node = aa->aa_node; 233 234 sc->sc_present = 0; 235 sc->sc_dvoltage = 0; 236 sc->sc_dcapacity = 0; 237 sc->sc_lcapacity = 0; 238 sc->sc_wcapacity = 0; 239 240 sc->sc_sme = NULL; 241 sc->sc_sensor = NULL; 242 243 mutex_init(&sc->sc_mutex, MUTEX_DEFAULT, IPL_NONE); 244 cv_init(&sc->sc_condvar, device_xname(self)); 245 246 (void)pmf_device_register(self, NULL, acpibat_resume); 247 (void)acpi_register_notify(sc->sc_node, acpibat_notify_handler); 248 249 sc->sc_sensor = kmem_zalloc(ACPIBAT_COUNT * 250 sizeof(*sc->sc_sensor), KM_SLEEP); 251 252 if (sc->sc_sensor == NULL) 253 return; 254 255 acpibat_init_envsys(self); 256 257 /* 258 * If this is ever seen, the driver should be extended. 259 */ 260 rv = AcpiGetHandle(sc->sc_node->ad_handle, "_BIX", &tmp); 261 262 if (ACPI_SUCCESS(rv)) 263 aprint_verbose_dev(self, "ACPI 4.0 functionality present\n"); 264 } 265 266 /* 267 * acpibat_detach: 268 * 269 * Autoconfiguration `detach' routine. 270 */ 271 static int 272 acpibat_detach(device_t self, int flags) 273 { 274 struct acpibat_softc *sc = device_private(self); 275 276 acpi_deregister_notify(sc->sc_node); 277 278 cv_destroy(&sc->sc_condvar); 279 mutex_destroy(&sc->sc_mutex); 280 281 if (sc->sc_sme != NULL) 282 sysmon_envsys_unregister(sc->sc_sme); 283 284 if (sc->sc_sensor != NULL) 285 kmem_free(sc->sc_sensor, ACPIBAT_COUNT * 286 sizeof(*sc->sc_sensor)); 287 288 pmf_device_deregister(self); 289 290 return 0; 291 } 292 293 /* 294 * acpibat_get_sta: 295 * 296 * Evaluate whether the battery is present or absent. 297 * 298 * Returns: 0 for no battery, 1 for present, and -1 on error. 299 */ 300 static int 301 acpibat_get_sta(device_t dv) 302 { 303 struct acpibat_softc *sc = device_private(dv); 304 ACPI_INTEGER val; 305 ACPI_STATUS rv; 306 307 rv = acpi_eval_integer(sc->sc_node->ad_handle, "_STA", &val); 308 309 if (ACPI_FAILURE(rv)) { 310 aprint_error_dev(dv, "failed to evaluate _STA\n"); 311 return -1; 312 } 313 314 sc->sc_sensor[ACPIBAT_PRESENT].state = ENVSYS_SVALID; 315 316 if ((val & ACPI_STA_BATTERY_PRESENT) == 0) { 317 sc->sc_sensor[ACPIBAT_PRESENT].value_cur = 0; 318 return 0; 319 } 320 321 sc->sc_sensor[ACPIBAT_PRESENT].value_cur = 1; 322 323 return 1; 324 } 325 326 static ACPI_OBJECT * 327 acpibat_get_object(ACPI_HANDLE hdl, const char *pth, uint32_t count) 328 { 329 ACPI_OBJECT *obj; 330 ACPI_BUFFER buf; 331 ACPI_STATUS rv; 332 333 rv = acpi_eval_struct(hdl, pth, &buf); 334 335 if (ACPI_FAILURE(rv)) 336 return NULL; 337 338 obj = buf.Pointer; 339 340 if (obj->Type != ACPI_TYPE_PACKAGE) { 341 ACPI_FREE(buf.Pointer); 342 return NULL; 343 } 344 345 if (obj->Package.Count != count) { 346 ACPI_FREE(buf.Pointer); 347 return NULL; 348 } 349 350 return obj; 351 } 352 353 /* 354 * acpibat_get_info: 355 * 356 * Get the battery info. 357 */ 358 static void 359 acpibat_get_info(device_t dv) 360 { 361 struct acpibat_softc *sc = device_private(dv); 362 ACPI_HANDLE hdl = sc->sc_node->ad_handle; 363 ACPI_OBJECT *elm, *obj; 364 ACPI_STATUS rv = AE_OK; 365 int capunit, i, rateunit; 366 uint64_t val; 367 368 obj = acpibat_get_object(hdl, "_BIF", ACPIBAT_BIF_COUNT); 369 370 if (obj == NULL) { 371 rv = AE_ERROR; 372 goto out; 373 } 374 375 elm = obj->Package.Elements; 376 377 for (i = ACPIBAT_BIF_UNIT; i < ACPIBAT_BIF_MODEL; i++) { 378 379 if (elm[i].Type != ACPI_TYPE_INTEGER) { 380 rv = AE_TYPE; 381 goto out; 382 } 383 384 if (elm[i].Integer.Value != ACPIBAT_VAL_UNKNOWN && 385 elm[i].Integer.Value >= INT_MAX) { 386 rv = AE_LIMIT; 387 goto out; 388 } 389 } 390 391 switch (elm[ACPIBAT_BIF_UNIT].Integer.Value) { 392 case ACPIBAT_PWRUNIT_MA: 393 capunit = ENVSYS_SAMPHOUR; 394 rateunit = ENVSYS_SAMPS; 395 break; 396 default: 397 capunit = ENVSYS_SWATTHOUR; 398 rateunit = ENVSYS_SWATTS; 399 break; 400 } 401 402 sc->sc_sensor[ACPIBAT_DCAPACITY].units = capunit; 403 sc->sc_sensor[ACPIBAT_LFCCAPACITY].units = capunit; 404 sc->sc_sensor[ACPIBAT_CHARGERATE].units = rateunit; 405 sc->sc_sensor[ACPIBAT_DISCHARGERATE].units = rateunit; 406 sc->sc_sensor[ACPIBAT_CAPACITY].units = capunit; 407 408 /* Design capacity. */ 409 val = elm[ACPIBAT_BIF_DCAPACITY].Integer.Value; 410 sc->sc_sensor[ACPIBAT_DCAPACITY].value_cur = val * 1000; 411 sc->sc_sensor[ACPIBAT_DCAPACITY].state = ACPIBAT_VAL_ISVALID(val); 412 413 /* Last full charge capacity. */ 414 val = elm[ACPIBAT_BIF_LFCCAPACITY].Integer.Value; 415 sc->sc_sensor[ACPIBAT_LFCCAPACITY].value_cur = val * 1000; 416 sc->sc_sensor[ACPIBAT_LFCCAPACITY].state = ACPIBAT_VAL_ISVALID(val); 417 418 /* Design voltage. */ 419 val = elm[ACPIBAT_BIF_DVOLTAGE].Integer.Value; 420 sc->sc_sensor[ACPIBAT_DVOLTAGE].value_cur = val * 1000; 421 sc->sc_sensor[ACPIBAT_DVOLTAGE].state = ACPIBAT_VAL_ISVALID(val); 422 423 /* Design low and warning capacity. */ 424 sc->sc_lcapacity = elm[ACPIBAT_BIF_LCAPACITY].Integer.Value * 1000; 425 sc->sc_wcapacity = elm[ACPIBAT_BIF_WCAPACITY].Integer.Value * 1000; 426 427 /* 428 * Initialize the maximum of current capacity 429 * to the last known full charge capacity. 430 */ 431 val = sc->sc_sensor[ACPIBAT_LFCCAPACITY].value_cur; 432 sc->sc_sensor[ACPIBAT_CAPACITY].value_max = val; 433 434 acpibat_print_info(dv, elm); 435 436 out: 437 if (obj != NULL) 438 ACPI_FREE(obj); 439 440 if (ACPI_FAILURE(rv)) 441 aprint_error_dev(dv, "failed to evaluate _BIF: %s\n", 442 AcpiFormatException(rv)); 443 } 444 445 /* 446 * acpibat_print_info: 447 * 448 * Display the battery info. 449 */ 450 static void 451 acpibat_print_info(device_t dv, ACPI_OBJECT *elm) 452 { 453 struct acpibat_softc *sc = device_private(dv); 454 const char *tech, *unit; 455 int32_t dcap, dvol; 456 int i; 457 458 for (i = ACPIBAT_BIF_OEM; i > ACPIBAT_BIF_GRANULARITY2; i--) { 459 460 if (elm[i].Type != ACPI_TYPE_STRING) 461 return; 462 463 if (elm[i].String.Pointer == NULL) 464 return; 465 466 if (elm[i].String.Pointer[0] == '\0') 467 return; 468 } 469 470 dcap = elm[ACPIBAT_BIF_DCAPACITY].Integer.Value; 471 dvol = elm[ACPIBAT_BIF_DVOLTAGE].Integer.Value; 472 473 /* 474 * Try to detect whether the battery was switched. 475 */ 476 if (sc->sc_dcapacity == dcap && sc->sc_dvoltage == dvol) 477 return; 478 else { 479 sc->sc_dcapacity = dcap; 480 sc->sc_dvoltage = dvol; 481 } 482 483 tech = (elm[ACPIBAT_BIF_TECHNOLOGY].Integer.Value != 0) ? 484 "rechargeable" : "non-rechargeable"; 485 486 aprint_normal_dev(dv, "%s %s %s battery\n", 487 elm[ACPIBAT_BIF_OEM].String.Pointer, 488 elm[ACPIBAT_BIF_TYPE].String.Pointer, tech); 489 490 aprint_debug_dev(dv, "model number %s, serial number %s\n", 491 elm[ACPIBAT_BIF_MODEL].String.Pointer, 492 elm[ACPIBAT_BIF_SERIAL].String.Pointer); 493 494 #define SCALE(x) (((int)x) / 1000000), ((((int)x) % 1000000) / 1000) 495 496 /* 497 * These values are defined as follows (ACPI 4.0, p. 388): 498 * 499 * Granularity 1. "Battery capacity granularity between low 500 * and warning in [mAh] or [mWh]. That is, 501 * this is the smallest increment in capacity 502 * that the battery is capable of measuring." 503 * 504 * Granularity 2. "Battery capacity granularity between warning 505 * and full in [mAh] or [mWh]. [...]" 506 */ 507 switch (elm[ACPIBAT_BIF_UNIT].Integer.Value) { 508 case ACPIBAT_PWRUNIT_MA: 509 unit = "Ah"; 510 break; 511 default: 512 unit = "Wh"; 513 break; 514 } 515 516 aprint_verbose_dev(dv, "granularity: " 517 "low->warn %d.%03d %s, warn->full %d.%03d %s\n", 518 SCALE(elm[ACPIBAT_BIF_GRANULARITY1].Integer.Value * 1000), unit, 519 SCALE(elm[ACPIBAT_BIF_GRANULARITY2].Integer.Value * 1000), unit); 520 } 521 522 /* 523 * acpibat_get_status: 524 * 525 * Get the current battery status. 526 */ 527 static void 528 acpibat_get_status(device_t dv) 529 { 530 struct acpibat_softc *sc = device_private(dv); 531 ACPI_HANDLE hdl = sc->sc_node->ad_handle; 532 ACPI_OBJECT *elm, *obj; 533 ACPI_STATUS rv = AE_OK; 534 int i, rate, state; 535 uint64_t val; 536 537 obj = acpibat_get_object(hdl, "_BST", ACPIBAT_BST_COUNT); 538 539 if (obj == NULL) { 540 rv = AE_ERROR; 541 goto out; 542 } 543 544 elm = obj->Package.Elements; 545 546 for (i = ACPIBAT_BST_STATE; i < ACPIBAT_BST_COUNT; i++) { 547 548 if (elm[i].Type != ACPI_TYPE_INTEGER) { 549 rv = AE_TYPE; 550 goto out; 551 } 552 } 553 554 state = elm[ACPIBAT_BST_STATE].Integer.Value; 555 556 if ((state & ACPIBAT_ST_CHARGING) != 0) { 557 /* XXX rate can be invalid */ 558 rate = elm[ACPIBAT_BST_RATE].Integer.Value; 559 sc->sc_sensor[ACPIBAT_CHARGERATE].state = ENVSYS_SVALID; 560 sc->sc_sensor[ACPIBAT_CHARGERATE].value_cur = rate * 1000; 561 sc->sc_sensor[ACPIBAT_DISCHARGERATE].state = ENVSYS_SINVALID; 562 sc->sc_sensor[ACPIBAT_CHARGING].state = ENVSYS_SVALID; 563 sc->sc_sensor[ACPIBAT_CHARGING].value_cur = 1; 564 } else if ((state & ACPIBAT_ST_DISCHARGING) != 0) { 565 rate = elm[ACPIBAT_BST_RATE].Integer.Value; 566 sc->sc_sensor[ACPIBAT_DISCHARGERATE].state = ENVSYS_SVALID; 567 sc->sc_sensor[ACPIBAT_DISCHARGERATE].value_cur = rate * 1000; 568 sc->sc_sensor[ACPIBAT_CHARGERATE].state = ENVSYS_SINVALID; 569 sc->sc_sensor[ACPIBAT_CHARGING].state = ENVSYS_SVALID; 570 sc->sc_sensor[ACPIBAT_CHARGING].value_cur = 0; 571 } else { 572 sc->sc_sensor[ACPIBAT_CHARGING].state = ENVSYS_SVALID; 573 sc->sc_sensor[ACPIBAT_CHARGING].value_cur = 0; 574 sc->sc_sensor[ACPIBAT_CHARGERATE].state = ENVSYS_SINVALID; 575 sc->sc_sensor[ACPIBAT_DISCHARGERATE].state = ENVSYS_SINVALID; 576 } 577 578 /* Remaining capacity. */ 579 val = elm[ACPIBAT_BST_CAPACITY].Integer.Value; 580 sc->sc_sensor[ACPIBAT_CAPACITY].value_cur = val * 1000; 581 sc->sc_sensor[ACPIBAT_CAPACITY].state = ACPIBAT_VAL_ISVALID(val); 582 583 /* Battery voltage. */ 584 val = elm[ACPIBAT_BST_VOLTAGE].Integer.Value; 585 sc->sc_sensor[ACPIBAT_VOLTAGE].value_cur = val * 1000; 586 sc->sc_sensor[ACPIBAT_VOLTAGE].state = ACPIBAT_VAL_ISVALID(val); 587 588 sc->sc_sensor[ACPIBAT_CHARGE_STATE].state = ENVSYS_SVALID; 589 sc->sc_sensor[ACPIBAT_CHARGE_STATE].value_cur = 590 ENVSYS_BATTERY_CAPACITY_NORMAL; 591 592 if (sc->sc_sensor[ACPIBAT_CAPACITY].value_cur < sc->sc_wcapacity) { 593 sc->sc_sensor[ACPIBAT_CAPACITY].state = ENVSYS_SWARNUNDER; 594 sc->sc_sensor[ACPIBAT_CHARGE_STATE].value_cur = 595 ENVSYS_BATTERY_CAPACITY_WARNING; 596 } 597 598 if (sc->sc_sensor[ACPIBAT_CAPACITY].value_cur < sc->sc_lcapacity) { 599 sc->sc_sensor[ACPIBAT_CAPACITY].state = ENVSYS_SCRITUNDER; 600 sc->sc_sensor[ACPIBAT_CHARGE_STATE].value_cur = 601 ENVSYS_BATTERY_CAPACITY_LOW; 602 } 603 604 if ((state & ACPIBAT_ST_CRITICAL) != 0) { 605 sc->sc_sensor[ACPIBAT_CAPACITY].state = ENVSYS_SCRITICAL; 606 sc->sc_sensor[ACPIBAT_CHARGE_STATE].value_cur = 607 ENVSYS_BATTERY_CAPACITY_CRITICAL; 608 } 609 610 out: 611 if (obj != NULL) 612 ACPI_FREE(obj); 613 614 if (ACPI_FAILURE(rv)) 615 aprint_error_dev(dv, "failed to evaluate _BST: %s\n", 616 AcpiFormatException(rv)); 617 } 618 619 static void 620 acpibat_update_info(void *arg) 621 { 622 device_t dv = arg; 623 struct acpibat_softc *sc = device_private(dv); 624 int i, rv; 625 626 mutex_enter(&sc->sc_mutex); 627 628 rv = acpibat_get_sta(dv); 629 630 if (rv > 0) { 631 acpibat_get_info(dv); 632 633 /* 634 * If the status changed, update the limits. 635 */ 636 if (sc->sc_present == 0 && 637 sc->sc_sensor[ACPIBAT_CAPACITY].value_max > 0) 638 sysmon_envsys_update_limits(sc->sc_sme, 639 &sc->sc_sensor[ACPIBAT_CAPACITY]); 640 } else { 641 i = (rv < 0) ? 0 : ACPIBAT_DVOLTAGE; 642 643 while (i < ACPIBAT_COUNT) { 644 sc->sc_sensor[i].state = ENVSYS_SINVALID; 645 i++; 646 } 647 } 648 649 sc->sc_present = rv; 650 651 mutex_exit(&sc->sc_mutex); 652 } 653 654 static void 655 acpibat_update_status(void *arg) 656 { 657 device_t dv = arg; 658 struct acpibat_softc *sc = device_private(dv); 659 int i, rv; 660 661 mutex_enter(&sc->sc_mutex); 662 663 rv = acpibat_get_sta(dv); 664 665 if (rv > 0) { 666 667 if (sc->sc_present == 0) 668 acpibat_get_info(dv); 669 670 acpibat_get_status(dv); 671 } else { 672 i = (rv < 0) ? 0 : ACPIBAT_DVOLTAGE; 673 674 while (i < ACPIBAT_COUNT) { 675 sc->sc_sensor[i].state = ENVSYS_SINVALID; 676 i++; 677 } 678 } 679 680 sc->sc_present = rv; 681 microtime(&sc->sc_last); 682 683 cv_broadcast(&sc->sc_condvar); 684 mutex_exit(&sc->sc_mutex); 685 } 686 687 /* 688 * acpibat_notify_handler: 689 * 690 * Callback from ACPI interrupt handler to notify us of an event. 691 */ 692 static void 693 acpibat_notify_handler(ACPI_HANDLE handle, uint32_t notify, void *context) 694 { 695 static const int handler = OSL_NOTIFY_HANDLER; 696 device_t dv = context; 697 698 switch (notify) { 699 700 case ACPI_NOTIFY_BUS_CHECK: 701 break; 702 703 case ACPI_NOTIFY_BAT_INFO: 704 case ACPI_NOTIFY_DEVICE_CHECK: 705 (void)AcpiOsExecute(handler, acpibat_update_info, dv); 706 break; 707 708 case ACPI_NOTIFY_BAT_STATUS: 709 (void)AcpiOsExecute(handler, acpibat_update_status, dv); 710 break; 711 712 default: 713 aprint_error_dev(dv, "unknown notify: 0x%02X\n", notify); 714 } 715 } 716 717 static void 718 acpibat_init_envsys(device_t dv) 719 { 720 struct acpibat_softc *sc = device_private(dv); 721 int i; 722 723 #define INITDATA(index, unit, string) \ 724 do { \ 725 sc->sc_sensor[index].state = ENVSYS_SVALID; \ 726 sc->sc_sensor[index].units = unit; \ 727 (void)strlcpy(sc->sc_sensor[index].desc, string, \ 728 sizeof(sc->sc_sensor[index].desc)); \ 729 } while (/* CONSTCOND */ 0) 730 731 INITDATA(ACPIBAT_PRESENT, ENVSYS_INDICATOR, "present"); 732 INITDATA(ACPIBAT_DCAPACITY, ENVSYS_SWATTHOUR, "design cap"); 733 INITDATA(ACPIBAT_LFCCAPACITY, ENVSYS_SWATTHOUR, "last full cap"); 734 INITDATA(ACPIBAT_DVOLTAGE, ENVSYS_SVOLTS_DC, "design voltage"); 735 INITDATA(ACPIBAT_VOLTAGE, ENVSYS_SVOLTS_DC, "voltage"); 736 INITDATA(ACPIBAT_CHARGERATE, ENVSYS_SWATTS, "charge rate"); 737 INITDATA(ACPIBAT_DISCHARGERATE, ENVSYS_SWATTS, "discharge rate"); 738 INITDATA(ACPIBAT_CAPACITY, ENVSYS_SWATTHOUR, "charge"); 739 INITDATA(ACPIBAT_CHARGING, ENVSYS_BATTERY_CHARGE, "charging"); 740 INITDATA(ACPIBAT_CHARGE_STATE, ENVSYS_BATTERY_CAPACITY, "charge state"); 741 742 #undef INITDATA 743 744 sc->sc_sensor[ACPIBAT_CHARGE_STATE].value_cur = 745 ENVSYS_BATTERY_CAPACITY_NORMAL; 746 747 sc->sc_sensor[ACPIBAT_CAPACITY].flags |= 748 ENVSYS_FPERCENT | ENVSYS_FVALID_MAX | ENVSYS_FMONLIMITS; 749 750 sc->sc_sensor[ACPIBAT_CHARGE_STATE].flags |= ENVSYS_FMONSTCHANGED; 751 752 /* Disable userland monitoring on these sensors. */ 753 sc->sc_sensor[ACPIBAT_VOLTAGE].flags = ENVSYS_FMONNOTSUPP; 754 sc->sc_sensor[ACPIBAT_CHARGERATE].flags = ENVSYS_FMONNOTSUPP; 755 sc->sc_sensor[ACPIBAT_DISCHARGERATE].flags = ENVSYS_FMONNOTSUPP; 756 sc->sc_sensor[ACPIBAT_DCAPACITY].flags = ENVSYS_FMONNOTSUPP; 757 sc->sc_sensor[ACPIBAT_LFCCAPACITY].flags = ENVSYS_FMONNOTSUPP; 758 sc->sc_sensor[ACPIBAT_DVOLTAGE].flags = ENVSYS_FMONNOTSUPP; 759 760 /* Attach rnd(9) to the (dis)charge rates. */ 761 sc->sc_sensor[ACPIBAT_CHARGERATE].flags |= ENVSYS_FHAS_ENTROPY; 762 sc->sc_sensor[ACPIBAT_DISCHARGERATE].flags |= ENVSYS_FHAS_ENTROPY; 763 764 sc->sc_sme = sysmon_envsys_create(); 765 766 for (i = 0; i < ACPIBAT_COUNT; i++) { 767 768 if (sysmon_envsys_sensor_attach(sc->sc_sme, 769 &sc->sc_sensor[i])) 770 goto fail; 771 } 772 773 sc->sc_sme->sme_name = device_xname(dv); 774 sc->sc_sme->sme_cookie = dv; 775 sc->sc_sme->sme_refresh = acpibat_refresh; 776 sc->sc_sme->sme_class = SME_CLASS_BATTERY; 777 sc->sc_sme->sme_flags = SME_POLL_ONLY | SME_INIT_REFRESH; 778 sc->sc_sme->sme_get_limits = acpibat_get_limits; 779 780 acpibat_update_info(dv); 781 acpibat_update_status(dv); 782 783 if (sysmon_envsys_register(sc->sc_sme)) 784 goto fail; 785 786 return; 787 788 fail: 789 aprint_error_dev(dv, "failed to initialize sysmon\n"); 790 791 sysmon_envsys_destroy(sc->sc_sme); 792 kmem_free(sc->sc_sensor, ACPIBAT_COUNT * sizeof(*sc->sc_sensor)); 793 794 sc->sc_sme = NULL; 795 sc->sc_sensor = NULL; 796 } 797 798 static void 799 acpibat_refresh(struct sysmon_envsys *sme, envsys_data_t *edata) 800 { 801 device_t self = sme->sme_cookie; 802 struct acpibat_softc *sc; 803 struct timeval tv, tmp; 804 ACPI_STATUS rv; 805 806 sc = device_private(self); 807 808 tmp.tv_sec = 10; 809 tmp.tv_usec = 0; 810 811 microtime(&tv); 812 timersub(&tv, &tmp, &tv); 813 814 if (timercmp(&tv, &sc->sc_last, <) != 0) 815 return; 816 817 if (mutex_tryenter(&sc->sc_mutex) == 0) 818 return; 819 820 rv = AcpiOsExecute(OSL_NOTIFY_HANDLER, acpibat_update_status, self); 821 822 if (ACPI_SUCCESS(rv)) 823 cv_timedwait(&sc->sc_condvar, &sc->sc_mutex, hz); 824 825 mutex_exit(&sc->sc_mutex); 826 } 827 828 static bool 829 acpibat_resume(device_t dv, const pmf_qual_t *qual) 830 { 831 832 (void)AcpiOsExecute(OSL_NOTIFY_HANDLER, acpibat_update_info, dv); 833 (void)AcpiOsExecute(OSL_NOTIFY_HANDLER, acpibat_update_status, dv); 834 835 return true; 836 } 837 838 static void 839 acpibat_get_limits(struct sysmon_envsys *sme, envsys_data_t *edata, 840 sysmon_envsys_lim_t *limits, uint32_t *props) 841 { 842 device_t dv = sme->sme_cookie; 843 struct acpibat_softc *sc = device_private(dv); 844 845 if (edata->sensor != ACPIBAT_CAPACITY) 846 return; 847 848 limits->sel_critmin = sc->sc_lcapacity; 849 limits->sel_warnmin = sc->sc_wcapacity; 850 851 *props |= PROP_BATTCAP | PROP_BATTWARN | PROP_DRIVER_LIMITS; 852 } 853 854 MODULE(MODULE_CLASS_DRIVER, acpibat, "sysmon_envsys"); 855 856 #ifdef _MODULE 857 #include "ioconf.c" 858 #endif 859 860 static int 861 acpibat_modcmd(modcmd_t cmd, void *aux) 862 { 863 int rv = 0; 864 865 switch (cmd) { 866 867 case MODULE_CMD_INIT: 868 869 #ifdef _MODULE 870 rv = config_init_component(cfdriver_ioconf_acpibat, 871 cfattach_ioconf_acpibat, cfdata_ioconf_acpibat); 872 #endif 873 break; 874 875 case MODULE_CMD_FINI: 876 877 #ifdef _MODULE 878 rv = config_fini_component(cfdriver_ioconf_acpibat, 879 cfattach_ioconf_acpibat, cfdata_ioconf_acpibat); 880 #endif 881 break; 882 883 default: 884 rv = ENOTTY; 885 } 886 887 return rv; 888 } 889