1 /* $NetBSD: acpi_bat.c,v 1.108 2011/01/13 13:05:13 jruoho 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.108 2011/01/13 13:05:13 jruoho 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 char sc_serial[64]; 154 kmutex_t sc_mutex; 155 kcondvar_t sc_condvar; 156 int32_t sc_lcapacity; 157 int32_t sc_wcapacity; 158 int sc_present; 159 }; 160 161 static const char * const bat_hid[] = { 162 "PNP0C0A", 163 NULL 164 }; 165 166 #define ACPIBAT_PWRUNIT_MA 0x00000001 /* mA not mW */ 167 #define ACPIBAT_ST_DISCHARGING 0x00000001 /* battery is discharging */ 168 #define ACPIBAT_ST_CHARGING 0x00000002 /* battery is charging */ 169 #define ACPIBAT_ST_CRITICAL 0x00000004 /* battery is critical */ 170 171 /* 172 * A value used when _BST or _BIF is temporarily unknown. 173 */ 174 #define ACPIBAT_VAL_UNKNOWN 0xFFFFFFFF 175 176 #define ACPIBAT_VAL_ISVALID(x) \ 177 (((x) != ACPIBAT_VAL_UNKNOWN) ? ENVSYS_SVALID : ENVSYS_SINVALID) 178 179 static int acpibat_match(device_t, cfdata_t, void *); 180 static void acpibat_attach(device_t, device_t, void *); 181 static int acpibat_detach(device_t, int); 182 static int acpibat_get_sta(device_t); 183 static ACPI_OBJECT *acpibat_get_object(ACPI_HANDLE, const char *, uint32_t); 184 static void acpibat_get_info(device_t); 185 static void acpibat_print_info(device_t, ACPI_OBJECT *); 186 static void acpibat_get_status(device_t); 187 static void acpibat_update_info(void *); 188 static void acpibat_update_status(void *); 189 static void acpibat_init_envsys(device_t); 190 static void acpibat_notify_handler(ACPI_HANDLE, uint32_t, void *); 191 static void acpibat_refresh(struct sysmon_envsys *, envsys_data_t *); 192 static bool acpibat_resume(device_t, const pmf_qual_t *); 193 static void acpibat_get_limits(struct sysmon_envsys *, envsys_data_t *, 194 sysmon_envsys_lim_t *, uint32_t *); 195 196 CFATTACH_DECL_NEW(acpibat, sizeof(struct acpibat_softc), 197 acpibat_match, acpibat_attach, acpibat_detach, NULL); 198 199 /* 200 * acpibat_match: 201 * 202 * Autoconfiguration `match' routine. 203 */ 204 static int 205 acpibat_match(device_t parent, cfdata_t match, void *aux) 206 { 207 struct acpi_attach_args *aa = aux; 208 209 if (aa->aa_node->ad_type != ACPI_TYPE_DEVICE) 210 return 0; 211 212 return acpi_match_hid(aa->aa_node->ad_devinfo, bat_hid); 213 } 214 215 /* 216 * acpibat_attach: 217 * 218 * Autoconfiguration `attach' routine. 219 */ 220 static void 221 acpibat_attach(device_t parent, device_t self, void *aux) 222 { 223 struct acpibat_softc *sc = device_private(self); 224 struct acpi_attach_args *aa = aux; 225 ACPI_HANDLE tmp; 226 ACPI_STATUS rv; 227 228 aprint_naive(": ACPI Battery\n"); 229 aprint_normal(": ACPI Battery\n"); 230 231 sc->sc_node = aa->aa_node; 232 233 sc->sc_present = 0; 234 sc->sc_lcapacity = 0; 235 sc->sc_wcapacity = 0; 236 237 sc->sc_sme = NULL; 238 sc->sc_sensor = NULL; 239 240 mutex_init(&sc->sc_mutex, MUTEX_DEFAULT, IPL_NONE); 241 cv_init(&sc->sc_condvar, device_xname(self)); 242 243 (void)pmf_device_register(self, NULL, acpibat_resume); 244 (void)memset(sc->sc_serial, '\0', sizeof(sc->sc_serial)); 245 (void)acpi_register_notify(sc->sc_node, acpibat_notify_handler); 246 247 sc->sc_sensor = kmem_zalloc(ACPIBAT_COUNT * 248 sizeof(*sc->sc_sensor), KM_SLEEP); 249 250 if (sc->sc_sensor == NULL) 251 return; 252 253 acpibat_init_envsys(self); 254 255 /* 256 * If this is ever seen, the driver should be extended. 257 */ 258 rv = AcpiGetHandle(sc->sc_node->ad_handle, "_BIX", &tmp); 259 260 if (ACPI_SUCCESS(rv)) 261 aprint_verbose_dev(self, "ACPI 4.0 functionality present\n"); 262 } 263 264 /* 265 * acpibat_detach: 266 * 267 * Autoconfiguration `detach' routine. 268 */ 269 static int 270 acpibat_detach(device_t self, int flags) 271 { 272 struct acpibat_softc *sc = device_private(self); 273 274 acpi_deregister_notify(sc->sc_node); 275 276 cv_destroy(&sc->sc_condvar); 277 mutex_destroy(&sc->sc_mutex); 278 279 if (sc->sc_sme != NULL) 280 sysmon_envsys_unregister(sc->sc_sme); 281 282 if (sc->sc_sensor != NULL) 283 kmem_free(sc->sc_sensor, ACPIBAT_COUNT * 284 sizeof(*sc->sc_sensor)); 285 286 pmf_device_deregister(self); 287 288 return 0; 289 } 290 291 /* 292 * acpibat_get_sta: 293 * 294 * Evaluate whether the battery is present or absent. 295 * 296 * Returns: 0 for no battery, 1 for present, and -1 on error. 297 */ 298 static int 299 acpibat_get_sta(device_t dv) 300 { 301 struct acpibat_softc *sc = device_private(dv); 302 ACPI_INTEGER val; 303 ACPI_STATUS rv; 304 305 rv = acpi_eval_integer(sc->sc_node->ad_handle, "_STA", &val); 306 307 if (ACPI_FAILURE(rv)) { 308 aprint_error_dev(dv, "failed to evaluate _STA\n"); 309 return -1; 310 } 311 312 sc->sc_sensor[ACPIBAT_PRESENT].state = ENVSYS_SVALID; 313 314 if ((val & ACPI_STA_BATTERY_PRESENT) == 0) { 315 sc->sc_sensor[ACPIBAT_PRESENT].value_cur = 0; 316 return 0; 317 } 318 319 sc->sc_sensor[ACPIBAT_PRESENT].value_cur = 1; 320 321 return 1; 322 } 323 324 static ACPI_OBJECT * 325 acpibat_get_object(ACPI_HANDLE hdl, const char *pth, uint32_t count) 326 { 327 ACPI_OBJECT *obj; 328 ACPI_BUFFER buf; 329 ACPI_STATUS rv; 330 331 rv = acpi_eval_struct(hdl, pth, &buf); 332 333 if (ACPI_FAILURE(rv)) 334 return NULL; 335 336 obj = buf.Pointer; 337 338 if (obj->Type != ACPI_TYPE_PACKAGE) { 339 ACPI_FREE(buf.Pointer); 340 return NULL; 341 } 342 343 if (obj->Package.Count != count) { 344 ACPI_FREE(buf.Pointer); 345 return NULL; 346 } 347 348 return obj; 349 } 350 351 /* 352 * acpibat_get_info: 353 * 354 * Get the battery info. 355 */ 356 static void 357 acpibat_get_info(device_t dv) 358 { 359 struct acpibat_softc *sc = device_private(dv); 360 ACPI_HANDLE hdl = sc->sc_node->ad_handle; 361 ACPI_OBJECT *elm, *obj; 362 ACPI_STATUS rv = AE_OK; 363 int capunit, i, rateunit; 364 uint64_t val; 365 366 obj = acpibat_get_object(hdl, "_BIF", ACPIBAT_BIF_COUNT); 367 368 if (obj == NULL) { 369 rv = AE_ERROR; 370 goto out; 371 } 372 373 elm = obj->Package.Elements; 374 375 for (i = ACPIBAT_BIF_UNIT; i < ACPIBAT_BIF_MODEL; i++) { 376 377 if (elm[i].Type != ACPI_TYPE_INTEGER) { 378 rv = AE_TYPE; 379 goto out; 380 } 381 382 KDASSERT((uint64_t)elm[i].Integer.Value < INT_MAX); 383 } 384 385 if ((elm[ACPIBAT_BIF_UNIT].Integer.Value & ACPIBAT_PWRUNIT_MA) != 0) { 386 capunit = ENVSYS_SAMPHOUR; 387 rateunit = ENVSYS_SAMPS; 388 } else { 389 capunit = ENVSYS_SWATTHOUR; 390 rateunit = ENVSYS_SWATTS; 391 } 392 393 sc->sc_sensor[ACPIBAT_DCAPACITY].units = capunit; 394 sc->sc_sensor[ACPIBAT_LFCCAPACITY].units = capunit; 395 sc->sc_sensor[ACPIBAT_CHARGERATE].units = rateunit; 396 sc->sc_sensor[ACPIBAT_DISCHARGERATE].units = rateunit; 397 sc->sc_sensor[ACPIBAT_CAPACITY].units = capunit; 398 399 /* Design capacity. */ 400 val = elm[ACPIBAT_BIF_DCAPACITY].Integer.Value; 401 sc->sc_sensor[ACPIBAT_DCAPACITY].value_cur = val * 1000; 402 sc->sc_sensor[ACPIBAT_DCAPACITY].state = ACPIBAT_VAL_ISVALID(val); 403 404 /* Last full charge capacity. */ 405 val = elm[ACPIBAT_BIF_LFCCAPACITY].Integer.Value; 406 sc->sc_sensor[ACPIBAT_LFCCAPACITY].value_cur = val * 1000; 407 sc->sc_sensor[ACPIBAT_LFCCAPACITY].state = ACPIBAT_VAL_ISVALID(val); 408 409 /* Design voltage. */ 410 val = elm[ACPIBAT_BIF_DVOLTAGE].Integer.Value; 411 sc->sc_sensor[ACPIBAT_DVOLTAGE].value_cur = val * 1000; 412 sc->sc_sensor[ACPIBAT_DVOLTAGE].state = ACPIBAT_VAL_ISVALID(val); 413 414 /* Design low and warning capacity. */ 415 sc->sc_lcapacity = elm[ACPIBAT_BIF_LCAPACITY].Integer.Value * 1000; 416 sc->sc_wcapacity = elm[ACPIBAT_BIF_WCAPACITY].Integer.Value * 1000; 417 418 /* 419 * Initialize the maximum of current capacity 420 * to the last known full charge capacity. 421 */ 422 val = sc->sc_sensor[ACPIBAT_LFCCAPACITY].value_cur; 423 sc->sc_sensor[ACPIBAT_CAPACITY].value_max = val; 424 425 acpibat_print_info(dv, elm); 426 427 out: 428 if (obj != NULL) 429 ACPI_FREE(obj); 430 431 if (ACPI_FAILURE(rv)) 432 aprint_error_dev(dv, "failed to evaluate _BIF: %s\n", 433 AcpiFormatException(rv)); 434 } 435 436 /* 437 * acpibat_print_info: 438 * 439 * Display the battery info. 440 */ 441 static void 442 acpibat_print_info(device_t dv, ACPI_OBJECT *elm) 443 { 444 struct acpibat_softc *sc = device_private(dv); 445 const char *model, *serial, *tech, *unit; 446 int i; 447 448 for (i = ACPIBAT_BIF_OEM; i > ACPIBAT_BIF_GRANULARITY2; i--) { 449 450 if (elm[i].Type != ACPI_TYPE_STRING) 451 return; 452 453 if (elm[i].String.Pointer == NULL) 454 return; 455 456 if (elm[i].String.Pointer[0] == '\0') 457 return; 458 } 459 460 model = elm[ACPIBAT_BIF_MODEL].String.Pointer; 461 serial = elm[ACPIBAT_BIF_SERIAL].String.Pointer; 462 463 if (elm[ACPIBAT_BIF_SERIAL].String.Length > sizeof(sc->sc_serial)) 464 return; 465 466 if (sc->sc_serial[0] == '\0') 467 (void)strlcpy(sc->sc_serial, serial, sizeof(sc->sc_serial)); 468 else { 469 if (strcmp(sc->sc_serial, serial) == 0) 470 return; 471 472 (void)memset(sc->sc_serial, '\0', sizeof(sc->sc_serial)); 473 (void)strlcpy(sc->sc_serial, serial, sizeof(sc->sc_serial)); 474 } 475 476 tech = (elm[ACPIBAT_BIF_TECHNOLOGY].Integer.Value != 0) ? 477 "rechargeable" : "non-rechargeable"; 478 479 aprint_normal_dev(dv, "%s %s %s battery\n", 480 elm[ACPIBAT_BIF_OEM].String.Pointer, 481 elm[ACPIBAT_BIF_TYPE].String.Pointer, tech); 482 483 aprint_verbose_dev(dv, "model number %s, serial number %s\n", 484 model, serial); 485 486 #define SCALE(x) (((int)x) / 1000000), ((((int)x) % 1000000) / 1000) 487 488 /* 489 * These values are defined as follows (ACPI 4.0, p. 388): 490 * 491 * Granularity 1. "Battery capacity granularity between low 492 * and warning in [mAh] or [mWh]. That is, 493 * this is the smallest increment in capacity 494 * that the battery is capable of measuring." 495 * 496 * Granularity 2. "Battery capacity granularity between warning 497 * and full in [mAh] or [mWh]. [...]" 498 */ 499 if ((elm[ACPIBAT_BIF_UNIT].Integer.Value & ACPIBAT_PWRUNIT_MA) != 0) 500 unit = "Ah"; 501 else 502 unit = "Wh"; 503 504 aprint_verbose_dev(dv, "granularity: " 505 "low->warn %d.%03d %s, warn->full %d.%03d %s\n", 506 SCALE(elm[ACPIBAT_BIF_GRANULARITY1].Integer.Value * 1000), unit, 507 SCALE(elm[ACPIBAT_BIF_GRANULARITY2].Integer.Value * 1000), unit); 508 } 509 510 /* 511 * acpibat_get_status: 512 * 513 * Get the current battery status. 514 */ 515 static void 516 acpibat_get_status(device_t dv) 517 { 518 struct acpibat_softc *sc = device_private(dv); 519 ACPI_HANDLE hdl = sc->sc_node->ad_handle; 520 ACPI_OBJECT *elm, *obj; 521 ACPI_STATUS rv = AE_OK; 522 int i, rate, state; 523 uint64_t val; 524 525 obj = acpibat_get_object(hdl, "_BST", ACPIBAT_BST_COUNT); 526 527 if (obj == NULL) { 528 rv = AE_ERROR; 529 goto out; 530 } 531 532 elm = obj->Package.Elements; 533 534 for (i = ACPIBAT_BST_STATE; i < ACPIBAT_BST_COUNT; i++) { 535 536 if (elm[i].Type != ACPI_TYPE_INTEGER) { 537 rv = AE_TYPE; 538 goto out; 539 } 540 } 541 542 state = elm[ACPIBAT_BST_STATE].Integer.Value; 543 544 if ((state & ACPIBAT_ST_CHARGING) != 0) { 545 /* XXX rate can be invalid */ 546 rate = elm[ACPIBAT_BST_RATE].Integer.Value; 547 sc->sc_sensor[ACPIBAT_CHARGERATE].state = ENVSYS_SVALID; 548 sc->sc_sensor[ACPIBAT_CHARGERATE].value_cur = rate * 1000; 549 sc->sc_sensor[ACPIBAT_DISCHARGERATE].state = ENVSYS_SINVALID; 550 sc->sc_sensor[ACPIBAT_CHARGING].state = ENVSYS_SVALID; 551 sc->sc_sensor[ACPIBAT_CHARGING].value_cur = 1; 552 } else if ((state & ACPIBAT_ST_DISCHARGING) != 0) { 553 rate = elm[ACPIBAT_BST_RATE].Integer.Value; 554 sc->sc_sensor[ACPIBAT_DISCHARGERATE].state = ENVSYS_SVALID; 555 sc->sc_sensor[ACPIBAT_DISCHARGERATE].value_cur = rate * 1000; 556 sc->sc_sensor[ACPIBAT_CHARGERATE].state = ENVSYS_SINVALID; 557 sc->sc_sensor[ACPIBAT_CHARGING].state = ENVSYS_SVALID; 558 sc->sc_sensor[ACPIBAT_CHARGING].value_cur = 0; 559 } else { 560 sc->sc_sensor[ACPIBAT_CHARGING].state = ENVSYS_SVALID; 561 sc->sc_sensor[ACPIBAT_CHARGING].value_cur = 0; 562 sc->sc_sensor[ACPIBAT_CHARGERATE].state = ENVSYS_SINVALID; 563 sc->sc_sensor[ACPIBAT_DISCHARGERATE].state = ENVSYS_SINVALID; 564 } 565 566 /* Remaining capacity. */ 567 val = elm[ACPIBAT_BST_CAPACITY].Integer.Value; 568 sc->sc_sensor[ACPIBAT_CAPACITY].value_cur = val * 1000; 569 sc->sc_sensor[ACPIBAT_CAPACITY].state = ACPIBAT_VAL_ISVALID(val); 570 571 /* Battery voltage. */ 572 val = elm[ACPIBAT_BST_VOLTAGE].Integer.Value; 573 sc->sc_sensor[ACPIBAT_VOLTAGE].value_cur = val * 1000; 574 sc->sc_sensor[ACPIBAT_VOLTAGE].state = ACPIBAT_VAL_ISVALID(val); 575 576 sc->sc_sensor[ACPIBAT_CHARGE_STATE].state = ENVSYS_SVALID; 577 sc->sc_sensor[ACPIBAT_CHARGE_STATE].value_cur = 578 ENVSYS_BATTERY_CAPACITY_NORMAL; 579 580 if (sc->sc_sensor[ACPIBAT_CAPACITY].value_cur < sc->sc_wcapacity) { 581 sc->sc_sensor[ACPIBAT_CAPACITY].state = ENVSYS_SWARNUNDER; 582 sc->sc_sensor[ACPIBAT_CHARGE_STATE].value_cur = 583 ENVSYS_BATTERY_CAPACITY_WARNING; 584 } 585 586 if (sc->sc_sensor[ACPIBAT_CAPACITY].value_cur < sc->sc_lcapacity) { 587 sc->sc_sensor[ACPIBAT_CAPACITY].state = ENVSYS_SCRITUNDER; 588 sc->sc_sensor[ACPIBAT_CHARGE_STATE].value_cur = 589 ENVSYS_BATTERY_CAPACITY_LOW; 590 } 591 592 if ((state & ACPIBAT_ST_CRITICAL) != 0) { 593 sc->sc_sensor[ACPIBAT_CAPACITY].state = ENVSYS_SCRITICAL; 594 sc->sc_sensor[ACPIBAT_CHARGE_STATE].value_cur = 595 ENVSYS_BATTERY_CAPACITY_CRITICAL; 596 } 597 598 out: 599 if (obj != NULL) 600 ACPI_FREE(obj); 601 602 if (ACPI_FAILURE(rv)) 603 aprint_error_dev(dv, "failed to evaluate _BST: %s\n", 604 AcpiFormatException(rv)); 605 } 606 607 static void 608 acpibat_update_info(void *arg) 609 { 610 device_t dv = arg; 611 struct acpibat_softc *sc = device_private(dv); 612 int i, rv; 613 614 mutex_enter(&sc->sc_mutex); 615 616 rv = acpibat_get_sta(dv); 617 618 if (rv > 0) { 619 acpibat_get_info(dv); 620 621 /* 622 * If the status changed, update the limits. 623 */ 624 if (sc->sc_present == 0 && 625 sc->sc_sensor[ACPIBAT_CAPACITY].value_max > 0) 626 sysmon_envsys_update_limits(sc->sc_sme, 627 &sc->sc_sensor[ACPIBAT_CAPACITY]); 628 } else { 629 i = (rv < 0) ? 0 : ACPIBAT_DVOLTAGE; 630 631 while (i < ACPIBAT_COUNT) { 632 sc->sc_sensor[i].state = ENVSYS_SINVALID; 633 i++; 634 } 635 } 636 637 sc->sc_present = rv; 638 639 mutex_exit(&sc->sc_mutex); 640 } 641 642 static void 643 acpibat_update_status(void *arg) 644 { 645 device_t dv = arg; 646 struct acpibat_softc *sc = device_private(dv); 647 int i, rv; 648 649 mutex_enter(&sc->sc_mutex); 650 651 rv = acpibat_get_sta(dv); 652 653 if (rv > 0) { 654 655 if (sc->sc_present == 0) 656 acpibat_get_info(dv); 657 658 acpibat_get_status(dv); 659 } else { 660 i = (rv < 0) ? 0 : ACPIBAT_DVOLTAGE; 661 662 while (i < ACPIBAT_COUNT) { 663 sc->sc_sensor[i].state = ENVSYS_SINVALID; 664 i++; 665 } 666 } 667 668 sc->sc_present = rv; 669 microtime(&sc->sc_last); 670 671 cv_broadcast(&sc->sc_condvar); 672 mutex_exit(&sc->sc_mutex); 673 } 674 675 /* 676 * acpibat_notify_handler: 677 * 678 * Callback from ACPI interrupt handler to notify us of an event. 679 */ 680 static void 681 acpibat_notify_handler(ACPI_HANDLE handle, uint32_t notify, void *context) 682 { 683 static const int handler = OSL_NOTIFY_HANDLER; 684 device_t dv = context; 685 686 switch (notify) { 687 688 case ACPI_NOTIFY_BUS_CHECK: 689 break; 690 691 case ACPI_NOTIFY_BAT_INFO: 692 case ACPI_NOTIFY_DEVICE_CHECK: 693 (void)AcpiOsExecute(handler, acpibat_update_info, dv); 694 break; 695 696 case ACPI_NOTIFY_BAT_STATUS: 697 (void)AcpiOsExecute(handler, acpibat_update_status, dv); 698 break; 699 700 default: 701 aprint_error_dev(dv, "unknown notify: 0x%02X\n", notify); 702 } 703 } 704 705 static void 706 acpibat_init_envsys(device_t dv) 707 { 708 struct acpibat_softc *sc = device_private(dv); 709 int i; 710 711 #define INITDATA(index, unit, string) \ 712 do { \ 713 sc->sc_sensor[index].state = ENVSYS_SVALID; \ 714 sc->sc_sensor[index].units = unit; \ 715 (void)strlcpy(sc->sc_sensor[index].desc, string, \ 716 sizeof(sc->sc_sensor[index].desc)); \ 717 } while (/* CONSTCOND */ 0) 718 719 INITDATA(ACPIBAT_PRESENT, ENVSYS_INDICATOR, "present"); 720 INITDATA(ACPIBAT_DCAPACITY, ENVSYS_SWATTHOUR, "design cap"); 721 INITDATA(ACPIBAT_LFCCAPACITY, ENVSYS_SWATTHOUR, "last full cap"); 722 INITDATA(ACPIBAT_DVOLTAGE, ENVSYS_SVOLTS_DC, "design voltage"); 723 INITDATA(ACPIBAT_VOLTAGE, ENVSYS_SVOLTS_DC, "voltage"); 724 INITDATA(ACPIBAT_CHARGERATE, ENVSYS_SWATTS, "charge rate"); 725 INITDATA(ACPIBAT_DISCHARGERATE, ENVSYS_SWATTS, "discharge rate"); 726 INITDATA(ACPIBAT_CAPACITY, ENVSYS_SWATTHOUR, "charge"); 727 INITDATA(ACPIBAT_CHARGING, ENVSYS_BATTERY_CHARGE, "charging"); 728 INITDATA(ACPIBAT_CHARGE_STATE, ENVSYS_BATTERY_CAPACITY, "charge state"); 729 730 #undef INITDATA 731 732 sc->sc_sensor[ACPIBAT_CAPACITY].flags |= 733 ENVSYS_FPERCENT | ENVSYS_FVALID_MAX | ENVSYS_FMONLIMITS; 734 735 sc->sc_sensor[ACPIBAT_CHARGE_STATE].flags |= ENVSYS_FMONSTCHANGED; 736 737 /* Disable userland monitoring on these sensors. */ 738 sc->sc_sensor[ACPIBAT_VOLTAGE].flags = ENVSYS_FMONNOTSUPP; 739 sc->sc_sensor[ACPIBAT_CHARGERATE].flags = ENVSYS_FMONNOTSUPP; 740 sc->sc_sensor[ACPIBAT_DISCHARGERATE].flags = ENVSYS_FMONNOTSUPP; 741 sc->sc_sensor[ACPIBAT_DCAPACITY].flags = ENVSYS_FMONNOTSUPP; 742 sc->sc_sensor[ACPIBAT_LFCCAPACITY].flags = ENVSYS_FMONNOTSUPP; 743 sc->sc_sensor[ACPIBAT_DVOLTAGE].flags = ENVSYS_FMONNOTSUPP; 744 745 sc->sc_sme = sysmon_envsys_create(); 746 747 for (i = 0; i < ACPIBAT_COUNT; i++) { 748 749 if (sysmon_envsys_sensor_attach(sc->sc_sme, 750 &sc->sc_sensor[i])) 751 goto fail; 752 } 753 754 sc->sc_sme->sme_name = device_xname(dv); 755 sc->sc_sme->sme_cookie = dv; 756 sc->sc_sme->sme_refresh = acpibat_refresh; 757 sc->sc_sme->sme_class = SME_CLASS_BATTERY; 758 sc->sc_sme->sme_flags = SME_POLL_ONLY | SME_INIT_REFRESH; 759 sc->sc_sme->sme_get_limits = acpibat_get_limits; 760 761 acpibat_update_info(dv); 762 acpibat_update_status(dv); 763 764 if (sysmon_envsys_register(sc->sc_sme)) 765 goto fail; 766 767 return; 768 769 fail: 770 aprint_error_dev(dv, "failed to initialize sysmon\n"); 771 772 sysmon_envsys_destroy(sc->sc_sme); 773 kmem_free(sc->sc_sensor, ACPIBAT_COUNT * sizeof(*sc->sc_sensor)); 774 775 sc->sc_sme = NULL; 776 sc->sc_sensor = NULL; 777 } 778 779 static void 780 acpibat_refresh(struct sysmon_envsys *sme, envsys_data_t *edata) 781 { 782 device_t self = sme->sme_cookie; 783 struct acpibat_softc *sc; 784 struct timeval tv, tmp; 785 ACPI_STATUS rv; 786 787 sc = device_private(self); 788 789 tmp.tv_sec = 10; 790 tmp.tv_usec = 0; 791 792 microtime(&tv); 793 timersub(&tv, &tmp, &tv); 794 795 if (timercmp(&tv, &sc->sc_last, <) != 0) 796 return; 797 798 if (mutex_tryenter(&sc->sc_mutex) == 0) 799 return; 800 801 rv = AcpiOsExecute(OSL_NOTIFY_HANDLER, acpibat_update_status, self); 802 803 if (ACPI_SUCCESS(rv)) 804 cv_timedwait(&sc->sc_condvar, &sc->sc_mutex, hz); 805 806 mutex_exit(&sc->sc_mutex); 807 } 808 809 static bool 810 acpibat_resume(device_t dv, const pmf_qual_t *qual) 811 { 812 813 (void)AcpiOsExecute(OSL_NOTIFY_HANDLER, acpibat_update_info, dv); 814 (void)AcpiOsExecute(OSL_NOTIFY_HANDLER, acpibat_update_status, dv); 815 816 return true; 817 } 818 819 static void 820 acpibat_get_limits(struct sysmon_envsys *sme, envsys_data_t *edata, 821 sysmon_envsys_lim_t *limits, uint32_t *props) 822 { 823 device_t dv = sme->sme_cookie; 824 struct acpibat_softc *sc = device_private(dv); 825 826 if (edata->sensor != ACPIBAT_CAPACITY) 827 return; 828 829 limits->sel_critmin = sc->sc_lcapacity; 830 limits->sel_warnmin = sc->sc_wcapacity; 831 832 *props |= PROP_BATTCAP | PROP_BATTWARN | PROP_DRIVER_LIMITS; 833 } 834 835 #ifdef _MODULE 836 837 MODULE(MODULE_CLASS_DRIVER, acpibat, NULL); 838 839 #include "ioconf.c" 840 841 static int 842 acpibat_modcmd(modcmd_t cmd, void *context) 843 { 844 845 switch (cmd) { 846 847 case MODULE_CMD_INIT: 848 return config_init_component(cfdriver_ioconf_acpibat, 849 cfattach_ioconf_acpibat, cfdata_ioconf_acpibat); 850 851 case MODULE_CMD_FINI: 852 return config_fini_component(cfdriver_ioconf_acpibat, 853 cfattach_ioconf_acpibat, cfdata_ioconf_acpibat); 854 855 default: 856 return ENOTTY; 857 } 858 } 859 860 #endif /* _MODULE */ 861