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