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