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