1 /* $NetBSD: acpi_bat.c,v 1.81 2010/01/31 06:45:09 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.81 2010/01/31 06:45:09 jruoho Exp $"); 79 80 #include <sys/param.h> 81 #include <sys/systm.h> 82 #include <sys/kernel.h> /* for hz */ 83 #include <sys/kmem.h> 84 #include <sys/device.h> 85 #include <sys/mutex.h> 86 87 #include <dev/sysmon/sysmonvar.h> 88 89 #include <dev/acpi/acpica.h> 90 #include <dev/acpi/acpireg.h> 91 #include <dev/acpi/acpivar.h> 92 93 #define _COMPONENT ACPI_BAT_COMPONENT 94 ACPI_MODULE_NAME ("acpi_bat") 95 96 /* 97 * Sensor indexes. 98 */ 99 enum { 100 ACPIBAT_PRESENT = 0, 101 ACPIBAT_DCAPACITY = 1, 102 ACPIBAT_LFCCAPACITY = 2, 103 ACPIBAT_TECHNOLOGY = 3, 104 ACPIBAT_DVOLTAGE = 4, 105 ACPIBAT_WCAPACITY = 5, 106 ACPIBAT_LCAPACITY = 6, 107 ACPIBAT_VOLTAGE = 7, 108 ACPIBAT_CHARGERATE = 8, 109 ACPIBAT_DISCHARGERATE = 9, 110 ACPIBAT_CAPACITY = 10, 111 ACPIBAT_CHARGING = 11, 112 ACPIBAT_CHARGE_STATE = 12, 113 ACPIBAT_COUNT = 13 114 }; 115 116 /* 117 * Battery Information, _BIF 118 * (ACPI 3.0, sec. 10.2.2.1). 119 */ 120 enum { 121 ACPIBAT_BIF_UNIT = 0, 122 ACPIBAT_BIF_DCAPACITY = 1, 123 ACPIBAT_BIF_LFCCAPACITY = 2, 124 ACPIBAT_BIF_TECHNOLOGY = 3, 125 ACPIBAT_BIF_DVOLTAGE = 4, 126 ACPIBAT_BIF_WCAPACITY = 5, 127 ACPIBAT_BIF_LCAPACITY = 6, 128 ACPIBAT_BIF_GRANULARITY1 = 7, 129 ACPIBAT_BIF_GRANULARITY2 = 8, 130 ACPIBAT_BIF_MODEL = 9, 131 ACPIBAT_BIF_SERIAL = 10, 132 ACPIBAT_BIF_TYPE = 11, 133 ACPIBAT_BIF_OEM = 12, 134 ACPIBAT_BIF_COUNT = 13 135 }; 136 137 /* 138 * Battery Status, _BST 139 * (ACPI 3.0, sec. 10.2.2.3). 140 */ 141 enum { 142 ACPIBAT_BST_STATE = 0, 143 ACPIBAT_BST_RATE = 1, 144 ACPIBAT_BST_CAPACITY = 2, 145 ACPIBAT_BST_VOLTAGE = 3, 146 ACPIBAT_BST_COUNT = 4 147 }; 148 149 struct acpibat_softc { 150 struct acpi_devnode *sc_node; 151 struct sysmon_envsys *sc_sme; 152 struct timeval sc_lastupdate; 153 envsys_data_t *sc_sensor; 154 kmutex_t sc_mutex; 155 kcondvar_t sc_condvar; 156 int sc_present; 157 }; 158 159 static const char * const bat_hid[] = { 160 "PNP0C0A", 161 NULL 162 }; 163 164 #define ACPIBAT_PWRUNIT_MA 0x00000001 /* mA not mW */ 165 #define ACPIBAT_ST_DISCHARGING 0x00000001 /* battery is discharging */ 166 #define ACPIBAT_ST_CHARGING 0x00000002 /* battery is charging */ 167 #define ACPIBAT_ST_CRITICAL 0x00000004 /* battery is critical */ 168 169 /* 170 * Flags for battery status from _STA return. Note that 171 * this differs from the conventional evaluation of _STA: 172 * 173 * "Unlike most other devices, when a battery is inserted or 174 * removed from the system, the device itself (the battery bay) 175 * is still considered to be present in the system. For most 176 * systems, the _STA for this device will always return a value 177 * with bits 0-3 set and will toggle bit 4 to indicate the actual 178 * presence of a battery. (ACPI 3.0, sec. 10.2.1, p. 320.)" 179 */ 180 #define ACPIBAT_STA_PRESENT 0x00000010 /* battery present */ 181 182 /* 183 * A value used when _BST or _BIF is teporarily unknown (see ibid.). 184 */ 185 #define ACPIBAT_VAL_UNKNOWN 0xFFFFFFFF 186 187 #define ACPIBAT_VAL_ISVALID(x) \ 188 (((x) != ACPIBAT_VAL_UNKNOWN) ? ENVSYS_SVALID : ENVSYS_SINVALID) 189 190 static int acpibat_match(device_t, cfdata_t, void *); 191 static void acpibat_attach(device_t, device_t, void *); 192 static int acpibat_detach(device_t, int); 193 static int acpibat_get_sta(device_t); 194 static ACPI_OBJECT *acpibat_get_object(ACPI_HANDLE, const char *, int); 195 static void acpibat_get_info(device_t); 196 static void acpibat_get_status(device_t); 197 static void acpibat_update_info(void *); 198 static void acpibat_update_status(void *); 199 static void acpibat_init_envsys(device_t); 200 static void acpibat_notify_handler(ACPI_HANDLE, UINT32, void *); 201 static void acpibat_refresh(struct sysmon_envsys *, envsys_data_t *); 202 static bool acpibat_resume(device_t, pmf_qual_t); 203 204 CFATTACH_DECL_NEW(acpibat, sizeof(struct acpibat_softc), 205 acpibat_match, acpibat_attach, acpibat_detach, NULL); 206 207 /* 208 * acpibat_match: 209 * 210 * Autoconfiguration `match' routine. 211 */ 212 static int 213 acpibat_match(device_t parent, cfdata_t match, void *aux) 214 { 215 struct acpi_attach_args *aa = aux; 216 217 if (aa->aa_node->ad_type != ACPI_TYPE_DEVICE) 218 return 0; 219 220 return acpi_match_hid(aa->aa_node->ad_devinfo, bat_hid); 221 } 222 223 /* 224 * acpibat_attach: 225 * 226 * Autoconfiguration `attach' routine. 227 */ 228 static void 229 acpibat_attach(device_t parent, device_t self, void *aux) 230 { 231 struct acpibat_softc *sc = device_private(self); 232 struct acpi_attach_args *aa = aux; 233 ACPI_STATUS rv; 234 235 aprint_naive(": ACPI Battery\n"); 236 aprint_normal(": ACPI Battery\n"); 237 238 sc->sc_node = aa->aa_node; 239 sc->sc_present = 0; 240 241 sc->sc_sme = NULL; 242 sc->sc_sensor = NULL; 243 244 mutex_init(&sc->sc_mutex, MUTEX_DEFAULT, IPL_NONE); 245 cv_init(&sc->sc_condvar, device_xname(self)); 246 247 if (pmf_device_register(self, NULL, acpibat_resume) != true) 248 aprint_error_dev(self, "couldn't establish power handler\n"); 249 250 rv = AcpiInstallNotifyHandler(sc->sc_node->ad_handle, 251 ACPI_ALL_NOTIFY, acpibat_notify_handler, self); 252 253 if (ACPI_FAILURE(rv)) { 254 aprint_error_dev(self, "couldn't install notify handler\n"); 255 return; 256 } 257 258 sc->sc_sensor = kmem_zalloc(ACPIBAT_COUNT * 259 sizeof(*sc->sc_sensor), KM_SLEEP); 260 261 if (sc->sc_sensor == NULL) 262 return; 263 264 acpibat_init_envsys(self); 265 } 266 267 /* 268 * acpibat_detach: 269 * 270 * Autoconfiguration `detach' routine. 271 */ 272 static int 273 acpibat_detach(device_t self, int flags) 274 { 275 struct acpibat_softc *sc = device_private(self); 276 ACPI_STATUS rv; 277 278 rv = AcpiRemoveNotifyHandler(sc->sc_node->ad_handle, 279 ACPI_ALL_NOTIFY, acpibat_notify_handler); 280 281 if (ACPI_FAILURE(rv)) 282 return EBUSY; 283 284 cv_destroy(&sc->sc_condvar); 285 mutex_destroy(&sc->sc_mutex); 286 287 if (sc->sc_sme != NULL) 288 sysmon_envsys_unregister(sc->sc_sme); 289 290 if (sc->sc_sensor != NULL) 291 kmem_free(sc->sc_sensor, ACPIBAT_COUNT * 292 sizeof(*sc->sc_sensor)); 293 294 pmf_device_deregister(self); 295 296 return 0; 297 } 298 299 /* 300 * acpibat_get_sta: 301 * 302 * Evaluate whether the battery is present or absent. 303 * 304 * Returns: 0 for no battery, 1 for present, and -1 on error. 305 */ 306 static int 307 acpibat_get_sta(device_t dv) 308 { 309 struct acpibat_softc *sc = device_private(dv); 310 ACPI_INTEGER val; 311 ACPI_STATUS rv; 312 313 rv = acpi_eval_integer(sc->sc_node->ad_handle, "_STA", &val); 314 315 if (ACPI_FAILURE(rv)) { 316 aprint_error_dev(dv, "failed to evaluate _STA\n"); 317 return -1; 318 } 319 320 sc->sc_sensor[ACPIBAT_PRESENT].state = ENVSYS_SVALID; 321 322 if ((val & ACPIBAT_STA_PRESENT) == 0) { 323 sc->sc_sensor[ACPIBAT_PRESENT].value_cur = 0; 324 return 0; 325 } 326 327 sc->sc_sensor[ACPIBAT_PRESENT].value_cur = 1; 328 329 return 1; 330 } 331 332 static ACPI_OBJECT * 333 acpibat_get_object(ACPI_HANDLE hdl, const char *pth, int count) 334 { 335 ACPI_OBJECT *obj; 336 ACPI_BUFFER buf; 337 ACPI_STATUS rv; 338 339 rv = acpi_eval_struct(hdl, pth, &buf); 340 341 if (ACPI_FAILURE(rv)) 342 return NULL; 343 344 obj = buf.Pointer; 345 346 if (obj->Type != ACPI_TYPE_PACKAGE) { 347 ACPI_FREE(buf.Pointer); 348 return NULL; 349 } 350 351 if (obj->Package.Count != count) { 352 ACPI_FREE(buf.Pointer); 353 return NULL; 354 } 355 356 return obj; 357 } 358 359 /* 360 * acpibat_get_info: 361 * 362 * Get, and possibly display, the battery info. 363 */ 364 static void 365 acpibat_get_info(device_t dv) 366 { 367 struct acpibat_softc *sc = device_private(dv); 368 ACPI_HANDLE hdl = sc->sc_node->ad_handle; 369 int capunit, i, j, rateunit, val; 370 ACPI_OBJECT *elm, *obj; 371 ACPI_STATUS rv = AE_OK; 372 373 obj = acpibat_get_object(hdl, "_BIF", ACPIBAT_BIF_COUNT); 374 375 if (obj == NULL) { 376 rv = AE_ERROR; 377 goto out; 378 } 379 380 elm = obj->Package.Elements; 381 382 for (i = ACPIBAT_BIF_UNIT; i < ACPIBAT_BIF_MODEL; i++) { 383 384 if (elm[i].Type != ACPI_TYPE_INTEGER) { 385 rv = AE_TYPE; 386 goto out; 387 } 388 389 KDASSERT((uint64_t)elm[i].Integer.Value < INT_MAX); 390 } 391 392 aprint_verbose_dev(dv, "battery info: "); 393 394 for (i = j = ACPIBAT_BIF_OEM; i > ACPIBAT_BIF_GRANULARITY2; i--) { 395 396 if (elm[i].Type != ACPI_TYPE_STRING) 397 continue; 398 399 if (elm[i].String.Pointer == NULL) 400 continue; 401 402 aprint_verbose("%s ", elm[i].String.Pointer); 403 404 j = 0; 405 } 406 407 if (j != 0) 408 aprint_verbose("not available"); 409 410 aprint_verbose("\n"); 411 412 if ((elm[ACPIBAT_BIF_UNIT].Integer.Value & ACPIBAT_PWRUNIT_MA) != 0) { 413 capunit = ENVSYS_SAMPHOUR; 414 rateunit = ENVSYS_SAMPS; 415 } else { 416 capunit = ENVSYS_SWATTHOUR; 417 rateunit = ENVSYS_SWATTS; 418 } 419 420 sc->sc_sensor[ACPIBAT_DCAPACITY].units = capunit; 421 sc->sc_sensor[ACPIBAT_LFCCAPACITY].units = capunit; 422 sc->sc_sensor[ACPIBAT_WCAPACITY].units = capunit; 423 sc->sc_sensor[ACPIBAT_LCAPACITY].units = capunit; 424 sc->sc_sensor[ACPIBAT_CHARGERATE].units = rateunit; 425 sc->sc_sensor[ACPIBAT_DISCHARGERATE].units = rateunit; 426 sc->sc_sensor[ACPIBAT_CAPACITY].units = capunit; 427 428 /* Design capacity. */ 429 val = elm[ACPIBAT_BIF_DCAPACITY].Integer.Value * 1000; 430 sc->sc_sensor[ACPIBAT_DCAPACITY].value_cur = val; 431 sc->sc_sensor[ACPIBAT_DCAPACITY].state = ACPIBAT_VAL_ISVALID(val); 432 433 /* Last full charge capacity. */ 434 val = elm[ACPIBAT_BIF_LFCCAPACITY].Integer.Value * 1000; 435 sc->sc_sensor[ACPIBAT_LFCCAPACITY].value_cur = val; 436 sc->sc_sensor[ACPIBAT_LFCCAPACITY].state = ACPIBAT_VAL_ISVALID(val); 437 438 /* Battery technology. */ 439 val = elm[ACPIBAT_BIF_TECHNOLOGY].Integer.Value; 440 sc->sc_sensor[ACPIBAT_TECHNOLOGY].value_cur = val; 441 sc->sc_sensor[ACPIBAT_TECHNOLOGY].state = ACPIBAT_VAL_ISVALID(val); 442 443 /* Design voltage. */ 444 val = elm[ACPIBAT_BIF_DVOLTAGE].Integer.Value * 1000; 445 sc->sc_sensor[ACPIBAT_DVOLTAGE].value_cur = val; 446 sc->sc_sensor[ACPIBAT_DVOLTAGE].state = ACPIBAT_VAL_ISVALID(val); 447 448 /* Design warning capacity. */ 449 val = elm[ACPIBAT_BIF_WCAPACITY].Integer.Value * 1000; 450 sc->sc_sensor[ACPIBAT_WCAPACITY].value_cur = val; 451 sc->sc_sensor[ACPIBAT_WCAPACITY].state = ACPIBAT_VAL_ISVALID(val); 452 sc->sc_sensor[ACPIBAT_WCAPACITY].flags |= 453 ENVSYS_FPERCENT | ENVSYS_FVALID_MAX; 454 455 /* Design low capacity. */ 456 val = elm[ACPIBAT_BIF_LCAPACITY].Integer.Value * 1000; 457 sc->sc_sensor[ACPIBAT_LCAPACITY].value_cur = val; 458 sc->sc_sensor[ACPIBAT_LCAPACITY].state = ACPIBAT_VAL_ISVALID(val); 459 sc->sc_sensor[ACPIBAT_LCAPACITY].flags |= 460 ENVSYS_FPERCENT | ENVSYS_FVALID_MAX; 461 462 /* 463 * Initialize the maximum of current, warning, and 464 * low capacity to the last full charge capacity. 465 */ 466 val = sc->sc_sensor[ACPIBAT_LFCCAPACITY].value_cur; 467 468 sc->sc_sensor[ACPIBAT_CAPACITY].value_max = val; 469 sc->sc_sensor[ACPIBAT_WCAPACITY].value_max = val; 470 sc->sc_sensor[ACPIBAT_LCAPACITY].value_max = val; 471 472 out: 473 if (obj != NULL) 474 ACPI_FREE(obj); 475 476 if (ACPI_FAILURE(rv)) 477 aprint_error_dev(dv, "failed to evaluate _BIF: %s\n", 478 AcpiFormatException(rv)); 479 } 480 481 /* 482 * acpibat_get_status: 483 * 484 * Get, and possibly display, the current battery line status. 485 */ 486 static void 487 acpibat_get_status(device_t dv) 488 { 489 struct acpibat_softc *sc = device_private(dv); 490 ACPI_HANDLE hdl = sc->sc_node->ad_handle; 491 int i, rate, state, val; 492 ACPI_OBJECT *elm, *obj; 493 ACPI_STATUS rv = AE_OK; 494 495 obj = acpibat_get_object(hdl, "_BST", ACPIBAT_BST_COUNT); 496 497 if (obj == NULL) { 498 rv = AE_ERROR; 499 goto out; 500 } 501 502 elm = obj->Package.Elements; 503 504 for (i = ACPIBAT_BST_STATE; i < ACPIBAT_BST_COUNT; i++) { 505 506 if (elm[i].Type != ACPI_TYPE_INTEGER) { 507 rv = AE_TYPE; 508 goto out; 509 } 510 } 511 512 state = elm[ACPIBAT_BST_STATE].Integer.Value; 513 514 if ((state & ACPIBAT_ST_CHARGING) != 0) { 515 /* XXX rate can be invalid */ 516 rate = elm[ACPIBAT_BST_RATE].Integer.Value; 517 sc->sc_sensor[ACPIBAT_CHARGERATE].state = ENVSYS_SVALID; 518 sc->sc_sensor[ACPIBAT_CHARGERATE].value_cur = rate * 1000; 519 sc->sc_sensor[ACPIBAT_DISCHARGERATE].state = ENVSYS_SINVALID; 520 sc->sc_sensor[ACPIBAT_CHARGING].state = ENVSYS_SVALID; 521 sc->sc_sensor[ACPIBAT_CHARGING].value_cur = 1; 522 } else if ((state & ACPIBAT_ST_DISCHARGING) != 0) { 523 rate = elm[ACPIBAT_BST_RATE].Integer.Value; 524 sc->sc_sensor[ACPIBAT_DISCHARGERATE].state = ENVSYS_SVALID; 525 sc->sc_sensor[ACPIBAT_DISCHARGERATE].value_cur = rate * 1000; 526 sc->sc_sensor[ACPIBAT_CHARGERATE].state = ENVSYS_SINVALID; 527 sc->sc_sensor[ACPIBAT_CHARGING].state = ENVSYS_SVALID; 528 sc->sc_sensor[ACPIBAT_CHARGING].value_cur = 0; 529 } else { 530 sc->sc_sensor[ACPIBAT_CHARGING].state = ENVSYS_SVALID; 531 sc->sc_sensor[ACPIBAT_CHARGING].value_cur = 0; 532 sc->sc_sensor[ACPIBAT_CHARGERATE].state = ENVSYS_SINVALID; 533 sc->sc_sensor[ACPIBAT_DISCHARGERATE].state = ENVSYS_SINVALID; 534 } 535 536 /* Remaining capacity. */ 537 val = elm[ACPIBAT_BST_CAPACITY].Integer.Value * 1000; 538 sc->sc_sensor[ACPIBAT_CAPACITY].value_cur = val; 539 sc->sc_sensor[ACPIBAT_CAPACITY].state = ACPIBAT_VAL_ISVALID(val); 540 sc->sc_sensor[ACPIBAT_CAPACITY].flags |= 541 ENVSYS_FPERCENT | ENVSYS_FVALID_MAX; 542 543 /* Battery voltage. */ 544 val = elm[ACPIBAT_BST_VOLTAGE].Integer.Value * 1000; 545 sc->sc_sensor[ACPIBAT_VOLTAGE].value_cur = val; 546 sc->sc_sensor[ACPIBAT_VOLTAGE].state = ACPIBAT_VAL_ISVALID(val); 547 548 sc->sc_sensor[ACPIBAT_CHARGE_STATE].state = ENVSYS_SVALID; 549 sc->sc_sensor[ACPIBAT_CHARGE_STATE].value_cur = 550 ENVSYS_BATTERY_CAPACITY_NORMAL; 551 552 if (sc->sc_sensor[ACPIBAT_CAPACITY].value_cur < 553 sc->sc_sensor[ACPIBAT_WCAPACITY].value_cur) { 554 sc->sc_sensor[ACPIBAT_CAPACITY].state = ENVSYS_SWARNUNDER; 555 sc->sc_sensor[ACPIBAT_CHARGE_STATE].value_cur = 556 ENVSYS_BATTERY_CAPACITY_WARNING; 557 } 558 559 if (sc->sc_sensor[ACPIBAT_CAPACITY].value_cur < 560 sc->sc_sensor[ACPIBAT_LCAPACITY].value_cur) { 561 sc->sc_sensor[ACPIBAT_CAPACITY].state = ENVSYS_SCRITUNDER; 562 sc->sc_sensor[ACPIBAT_CHARGE_STATE].value_cur = 563 ENVSYS_BATTERY_CAPACITY_LOW; 564 } 565 566 if ((state & ACPIBAT_ST_CRITICAL) != 0) { 567 sc->sc_sensor[ACPIBAT_CAPACITY].state = ENVSYS_SCRITICAL; 568 sc->sc_sensor[ACPIBAT_CHARGE_STATE].value_cur = 569 ENVSYS_BATTERY_CAPACITY_CRITICAL; 570 } 571 572 out: 573 if (obj != NULL) 574 ACPI_FREE(obj); 575 576 if (ACPI_FAILURE(rv)) 577 aprint_error_dev(dv, "failed to evaluate _BST: %s\n", 578 AcpiFormatException(rv)); 579 } 580 581 static void 582 acpibat_update_info(void *arg) 583 { 584 device_t dv = arg; 585 struct acpibat_softc *sc = device_private(dv); 586 int i, rv; 587 588 mutex_enter(&sc->sc_mutex); 589 590 rv = acpibat_get_sta(dv); 591 592 if (rv > 0) 593 acpibat_get_info(dv); 594 else { 595 i = (rv < 0) ? 0 : ACPIBAT_DCAPACITY; 596 597 while (i < ACPIBAT_COUNT) { 598 sc->sc_sensor[i].state = ENVSYS_SINVALID; 599 i++; 600 } 601 } 602 603 sc->sc_present = rv; 604 605 mutex_exit(&sc->sc_mutex); 606 } 607 608 static void 609 acpibat_update_status(void *arg) 610 { 611 device_t dv = arg; 612 struct acpibat_softc *sc = device_private(dv); 613 int i, rv; 614 615 mutex_enter(&sc->sc_mutex); 616 617 rv = acpibat_get_sta(dv); 618 619 if (rv > 0) { 620 621 if (sc->sc_present == 0) 622 acpibat_get_info(dv); 623 624 acpibat_get_status(dv); 625 } else { 626 i = (rv < 0) ? 0 : ACPIBAT_DCAPACITY; 627 628 while (i < ACPIBAT_COUNT) { 629 sc->sc_sensor[i].state = ENVSYS_SINVALID; 630 i++; 631 } 632 } 633 634 sc->sc_present = rv; 635 636 microtime(&sc->sc_lastupdate); 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_TECHNOLOGY, ENVSYS_INTEGER, "technology"); 689 INITDATA(ACPIBAT_DVOLTAGE, ENVSYS_SVOLTS_DC, "design voltage"); 690 INITDATA(ACPIBAT_WCAPACITY, ENVSYS_SWATTHOUR, "warn cap"); 691 INITDATA(ACPIBAT_LCAPACITY, ENVSYS_SWATTHOUR, "low cap"); 692 INITDATA(ACPIBAT_VOLTAGE, ENVSYS_SVOLTS_DC, "voltage"); 693 INITDATA(ACPIBAT_CHARGERATE, ENVSYS_SWATTS, "charge rate"); 694 INITDATA(ACPIBAT_DISCHARGERATE, ENVSYS_SWATTS, "discharge rate"); 695 INITDATA(ACPIBAT_CAPACITY, ENVSYS_SWATTHOUR, "charge"); 696 INITDATA(ACPIBAT_CHARGING, ENVSYS_BATTERY_CHARGE, "charging"); 697 INITDATA(ACPIBAT_CHARGE_STATE, ENVSYS_BATTERY_CAPACITY, "charge state"); 698 699 #undef INITDATA 700 701 /* Enable monitoring for the charge state sensor */ 702 sc->sc_sensor[ACPIBAT_CHARGE_STATE].monitor = true; 703 sc->sc_sensor[ACPIBAT_CHARGE_STATE].flags |= ENVSYS_FMONSTCHANGED; 704 705 /* Disable userland monitoring on these sensors */ 706 sc->sc_sensor[ACPIBAT_VOLTAGE].flags = ENVSYS_FMONNOTSUPP; 707 sc->sc_sensor[ACPIBAT_CHARGERATE].flags = ENVSYS_FMONNOTSUPP; 708 sc->sc_sensor[ACPIBAT_DISCHARGERATE].flags = ENVSYS_FMONNOTSUPP; 709 sc->sc_sensor[ACPIBAT_DCAPACITY].flags = ENVSYS_FMONNOTSUPP; 710 sc->sc_sensor[ACPIBAT_LFCCAPACITY].flags = ENVSYS_FMONNOTSUPP; 711 sc->sc_sensor[ACPIBAT_TECHNOLOGY].flags = ENVSYS_FMONNOTSUPP; 712 sc->sc_sensor[ACPIBAT_DVOLTAGE].flags = ENVSYS_FMONNOTSUPP; 713 sc->sc_sensor[ACPIBAT_WCAPACITY].flags = ENVSYS_FMONNOTSUPP; 714 sc->sc_sensor[ACPIBAT_LCAPACITY].flags = ENVSYS_FMONNOTSUPP; 715 716 sc->sc_sme = sysmon_envsys_create(); 717 718 for (i = 0; i < ACPIBAT_COUNT; i++) { 719 720 if (sysmon_envsys_sensor_attach(sc->sc_sme, 721 &sc->sc_sensor[i])) 722 goto fail; 723 } 724 725 sc->sc_sme->sme_name = device_xname(dv); 726 sc->sc_sme->sme_cookie = dv; 727 sc->sc_sme->sme_refresh = acpibat_refresh; 728 sc->sc_sme->sme_class = SME_CLASS_BATTERY; 729 sc->sc_sme->sme_flags = SME_POLL_ONLY; 730 731 acpibat_update_info(dv); 732 acpibat_update_status(dv); 733 734 if (sysmon_envsys_register(sc->sc_sme)) 735 goto fail; 736 737 return; 738 739 fail: 740 aprint_error_dev(dv, "failed to initialize sysmon\n"); 741 742 sysmon_envsys_destroy(sc->sc_sme); 743 kmem_free(sc->sc_sensor, ACPIBAT_COUNT * sizeof(*sc->sc_sensor)); 744 745 sc->sc_sme = NULL; 746 sc->sc_sensor = NULL; 747 } 748 749 static void 750 acpibat_refresh(struct sysmon_envsys *sme, envsys_data_t *edata) 751 { 752 device_t dv = sme->sme_cookie; 753 struct acpibat_softc *sc = device_private(dv); 754 struct timeval tv, tmp; 755 ACPI_STATUS rv; 756 757 tmp.tv_sec = 5; 758 tmp.tv_usec = 0; 759 microtime(&tv); 760 timersub(&tv, &tmp, &tv); 761 762 if (timercmp(&tv, &sc->sc_lastupdate, <)) 763 return; 764 765 if (!mutex_tryenter(&sc->sc_mutex)) 766 return; 767 768 rv = AcpiOsExecute(OSL_NOTIFY_HANDLER, acpibat_update_status, dv); 769 770 if (ACPI_SUCCESS(rv)) 771 cv_timedwait(&sc->sc_condvar, &sc->sc_mutex, hz); 772 773 mutex_exit(&sc->sc_mutex); 774 } 775 776 static bool 777 acpibat_resume(device_t dv, pmf_qual_t qual) 778 { 779 780 (void)AcpiOsExecute(OSL_NOTIFY_HANDLER, acpibat_update_info, dv); 781 (void)AcpiOsExecute(OSL_NOTIFY_HANDLER, acpibat_update_status, dv); 782 783 return true; 784 } 785