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