1 /* $NetBSD: acpi_bat.c,v 1.69 2008/06/03 15:02:31 jmcneill 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 #if 0 66 #define ACPI_BAT_DEBUG 67 #endif 68 69 /* 70 * ACPI Battery Driver. 71 * 72 * ACPI defines two different battery device interfaces: "Control 73 * Method" batteries, in which AML methods are defined in order to get 74 * battery status and set battery alarm thresholds, and a "Smart 75 * Battery" device, which is an SMbus device accessed through the ACPI 76 * Embedded Controller device. 77 * 78 * This driver is for the "Control Method"-style battery only. 79 */ 80 81 #include <sys/cdefs.h> 82 __KERNEL_RCSID(0, "$NetBSD: acpi_bat.c,v 1.69 2008/06/03 15:02:31 jmcneill Exp $"); 83 84 #include <sys/param.h> 85 #include <sys/systm.h> 86 #include <sys/kernel.h> /* for hz */ 87 #include <sys/device.h> 88 #include <sys/mutex.h> 89 #include <dev/sysmon/sysmonvar.h> 90 91 #include <dev/acpi/acpica.h> 92 #include <dev/acpi/acpireg.h> 93 #include <dev/acpi/acpivar.h> 94 95 /* sensor indexes */ 96 #define ACPIBAT_PRESENT 0 97 #define ACPIBAT_DCAPACITY 1 98 #define ACPIBAT_LFCCAPACITY 2 99 #define ACPIBAT_TECHNOLOGY 3 100 #define ACPIBAT_DVOLTAGE 4 101 #define ACPIBAT_WCAPACITY 5 102 #define ACPIBAT_LCAPACITY 6 103 #define ACPIBAT_VOLTAGE 7 104 #define ACPIBAT_CHARGERATE 8 105 #define ACPIBAT_DISCHARGERATE 9 106 #define ACPIBAT_CAPACITY 10 107 #define ACPIBAT_CHARGING 11 108 #define ACPIBAT_CHARGE_STATE 12 109 #define ACPIBAT_NSENSORS 13 /* number of sensors */ 110 111 struct acpibat_softc { 112 struct acpi_devnode *sc_node; /* our ACPI devnode */ 113 int sc_flags; /* see below */ 114 int sc_available; /* available information level */ 115 116 struct sysmon_envsys *sc_sme; 117 envsys_data_t sc_sensor[ACPIBAT_NSENSORS]; 118 struct timeval sc_lastupdate; 119 120 kmutex_t sc_mutex; 121 kcondvar_t sc_condvar; 122 }; 123 124 static const char * const bat_hid[] = { 125 "PNP0C0A", 126 NULL 127 }; 128 129 /* 130 * These flags are used to examine the battery device data returned from 131 * the ACPI interface, specifically the "battery status" 132 */ 133 #define ACPIBAT_PWRUNIT_MA 0x00000001 /* mA not mW */ 134 135 /* 136 * These flags are used to examine the battery charge/discharge/critical 137 * state returned from a get-status command. 138 */ 139 #define ACPIBAT_ST_DISCHARGING 0x00000001 /* battery is discharging */ 140 #define ACPIBAT_ST_CHARGING 0x00000002 /* battery is charging */ 141 #define ACPIBAT_ST_CRITICAL 0x00000004 /* battery is critical */ 142 143 /* 144 * Flags for battery status from _STA return 145 */ 146 #define ACPIBAT_STA_PRESENT 0x00000010 /* battery present */ 147 148 /* 149 * These flags are used to set internal state in our softc. 150 */ 151 #define ABAT_F_VERBOSE 0x01 /* verbose events */ 152 #define ABAT_F_PWRUNIT_MA 0x02 /* mA instead of mW */ 153 #define ABAT_F_PRESENT 0x04 /* is the battery present? */ 154 155 #define ABAT_SET(sc, f) (void)((sc)->sc_flags |= (f)) 156 #define ABAT_CLEAR(sc, f) (void)((sc)->sc_flags &= ~(f)) 157 #define ABAT_ISSET(sc, f) ((sc)->sc_flags & (f)) 158 159 /* 160 * Available info level 161 */ 162 163 #define ABAT_ALV_NONE 0 /* none is available */ 164 #define ABAT_ALV_PRESENCE 1 /* presence info is available */ 165 #define ABAT_ALV_INFO 2 /* battery info is available */ 166 #define ABAT_ALV_STAT 3 /* battery status is available */ 167 168 static int acpibat_match(device_t, struct cfdata *, void *); 169 static void acpibat_attach(device_t, struct device *, void *); 170 static bool acpibat_resume(device_t PMF_FN_PROTO); 171 172 CFATTACH_DECL_NEW(acpibat, sizeof(struct acpibat_softc), 173 acpibat_match, acpibat_attach, NULL, NULL); 174 175 static void acpibat_clear_presence(struct acpibat_softc *); 176 static void acpibat_clear_info(struct acpibat_softc *); 177 static void acpibat_clear_stat(struct acpibat_softc *); 178 static int acpibat_battery_present(device_t); 179 static ACPI_STATUS acpibat_get_status(device_t); 180 static ACPI_STATUS acpibat_get_info(device_t); 181 static void acpibat_print_info(device_t); 182 static void acpibat_print_stat(device_t); 183 static void acpibat_update(void *); 184 static void acpibat_update_info(void *); 185 static void acpibat_update_stat(void *); 186 187 static void acpibat_init_envsys(device_t); 188 static void acpibat_notify_handler(ACPI_HANDLE, UINT32, void *); 189 static void acpibat_refresh(struct sysmon_envsys *, envsys_data_t *); 190 191 /* 192 * acpibat_match: 193 * 194 * Autoconfiguration `match' routine. 195 */ 196 static int 197 acpibat_match(device_t parent, struct cfdata *match, void *aux) 198 { 199 struct acpi_attach_args *aa = aux; 200 201 if (aa->aa_node->ad_type != ACPI_TYPE_DEVICE) 202 return 0; 203 204 return acpi_match_hid(aa->aa_node->ad_devinfo, bat_hid); 205 } 206 207 static bool 208 acpibat_resume(device_t dv PMF_FN_ARGS) 209 { 210 ACPI_STATUS rv; 211 212 rv = AcpiOsExecute(OSL_NOTIFY_HANDLER, acpibat_update_stat, dv); 213 if (ACPI_FAILURE(rv)) 214 aprint_error_dev(dv, "unable to queue status check: %s\n", 215 AcpiFormatException(rv)); 216 rv = AcpiOsExecute(OSL_NOTIFY_HANDLER, acpibat_update_info, dv); 217 if (ACPI_FAILURE(rv)) 218 aprint_error_dev(dv, "unable to queue info check: %s\n", 219 AcpiFormatException(rv)); 220 221 return true; 222 } 223 224 /* 225 * acpibat_attach: 226 * 227 * Autoconfiguration `attach' routine. 228 */ 229 static void 230 acpibat_attach(device_t parent, device_t self, void *aux) 231 { 232 struct acpibat_softc *sc = device_private(self); 233 struct acpi_attach_args *aa = aux; 234 ACPI_STATUS rv; 235 236 aprint_naive(": ACPI Battery (Control Method)\n"); 237 aprint_normal(": ACPI Battery (Control Method)\n"); 238 239 sc->sc_node = aa->aa_node; 240 241 mutex_init(&sc->sc_mutex, MUTEX_DEFAULT, IPL_NONE); 242 cv_init(&sc->sc_condvar, device_xname(self)); 243 244 rv = AcpiInstallNotifyHandler(sc->sc_node->ad_handle, 245 ACPI_ALL_NOTIFY, 246 acpibat_notify_handler, self); 247 if (ACPI_FAILURE(rv)) { 248 aprint_error_dev(self, 249 "unable to register DEVICE/SYSTEM NOTIFY handler: %s\n", 250 AcpiFormatException(rv)); 251 return; 252 } 253 254 #ifdef ACPI_BAT_DEBUG 255 ABAT_SET(sc, ABAT_F_VERBOSE); 256 #endif 257 258 if (!pmf_device_register(self, NULL, acpibat_resume)) 259 aprint_error_dev(self, "couldn't establish power handler\n"); 260 261 acpibat_init_envsys(self); 262 } 263 264 /* 265 * clear informations 266 */ 267 268 static void 269 acpibat_clear_presence(struct acpibat_softc *sc) 270 { 271 acpibat_clear_info(sc); 272 sc->sc_available = ABAT_ALV_NONE; 273 ABAT_CLEAR(sc, ABAT_F_PRESENT); 274 } 275 276 static void 277 acpibat_clear_info(struct acpibat_softc *sc) 278 { 279 acpibat_clear_stat(sc); 280 if (sc->sc_available > ABAT_ALV_PRESENCE) 281 sc->sc_available = ABAT_ALV_PRESENCE; 282 283 sc->sc_sensor[ACPIBAT_DCAPACITY].state = ENVSYS_SINVALID; 284 sc->sc_sensor[ACPIBAT_LFCCAPACITY].state = ENVSYS_SINVALID; 285 sc->sc_sensor[ACPIBAT_CAPACITY].state = ENVSYS_SINVALID; 286 sc->sc_sensor[ACPIBAT_TECHNOLOGY].state = ENVSYS_SINVALID; 287 sc->sc_sensor[ACPIBAT_DVOLTAGE].state = ENVSYS_SINVALID; 288 sc->sc_sensor[ACPIBAT_WCAPACITY].state = ENVSYS_SINVALID; 289 sc->sc_sensor[ACPIBAT_LCAPACITY].state = ENVSYS_SINVALID; 290 } 291 292 static void 293 acpibat_clear_stat(struct acpibat_softc *sc) 294 { 295 if (sc->sc_available > ABAT_ALV_INFO) 296 sc->sc_available = ABAT_ALV_INFO; 297 298 sc->sc_sensor[ACPIBAT_CHARGERATE].state = ENVSYS_SINVALID; 299 sc->sc_sensor[ACPIBAT_DISCHARGERATE].state = ENVSYS_SINVALID; 300 sc->sc_sensor[ACPIBAT_CAPACITY].state = ENVSYS_SINVALID; 301 sc->sc_sensor[ACPIBAT_VOLTAGE].state = ENVSYS_SINVALID; 302 sc->sc_sensor[ACPIBAT_CHARGING].state = ENVSYS_SINVALID; 303 } 304 305 306 /* 307 * returns 0 for no battery, 1 for present, and -1 on error 308 */ 309 static int 310 acpibat_battery_present(device_t dv) 311 { 312 struct acpibat_softc *sc = device_private(dv); 313 uint32_t sta; 314 ACPI_INTEGER val; 315 ACPI_STATUS rv; 316 317 rv = acpi_eval_integer(sc->sc_node->ad_handle, "_STA", &val); 318 if (ACPI_FAILURE(rv)) { 319 aprint_error_dev(dv, "failed to evaluate _STA: %s\n", 320 AcpiFormatException(rv)); 321 return -1; 322 } 323 324 sta = (uint32_t)val; 325 326 sc->sc_available = ABAT_ALV_PRESENCE; 327 if (sta & ACPIBAT_STA_PRESENT) { 328 ABAT_SET(sc, ABAT_F_PRESENT); 329 sc->sc_sensor[ACPIBAT_PRESENT].state = ENVSYS_SVALID; 330 sc->sc_sensor[ACPIBAT_PRESENT].value_cur = 1; 331 } else 332 sc->sc_sensor[ACPIBAT_PRESENT].value_cur = 0; 333 334 return (sta & ACPIBAT_STA_PRESENT) ? 1 : 0; 335 } 336 337 /* 338 * acpibat_get_info 339 * 340 * Get, and possibly display, the battery info. 341 */ 342 343 static ACPI_STATUS 344 acpibat_get_info(device_t dv) 345 { 346 struct acpibat_softc *sc = device_private(dv); 347 ACPI_OBJECT *p1, *p2; 348 ACPI_STATUS rv; 349 ACPI_BUFFER buf; 350 int capunit, rateunit; 351 352 rv = acpi_eval_struct(sc->sc_node->ad_handle, "_BIF", &buf); 353 if (ACPI_FAILURE(rv)) { 354 aprint_error_dev(dv, "failed to evaluate _BIF: %s\n", 355 AcpiFormatException(rv)); 356 return rv; 357 } 358 p1 = (ACPI_OBJECT *)buf.Pointer; 359 360 if (p1->Type != ACPI_TYPE_PACKAGE) { 361 aprint_error_dev(dv, "expected PACKAGE, got %d\n", p1->Type); 362 goto out; 363 } 364 if (p1->Package.Count < 13) { 365 aprint_error_dev(dv, "expected 13 elements, got %d\n", 366 p1->Package.Count); 367 goto out; 368 } 369 p2 = p1->Package.Elements; 370 371 if ((p2[0].Integer.Value & ACPIBAT_PWRUNIT_MA) != 0) { 372 ABAT_SET(sc, ABAT_F_PWRUNIT_MA); 373 capunit = ENVSYS_SAMPHOUR; 374 rateunit = ENVSYS_SAMPS; 375 } else { 376 ABAT_CLEAR(sc, ABAT_F_PWRUNIT_MA); 377 capunit = ENVSYS_SWATTHOUR; 378 rateunit = ENVSYS_SWATTS; 379 } 380 381 sc->sc_sensor[ACPIBAT_DCAPACITY].units = capunit; 382 sc->sc_sensor[ACPIBAT_LFCCAPACITY].units = capunit; 383 sc->sc_sensor[ACPIBAT_WCAPACITY].units = capunit; 384 sc->sc_sensor[ACPIBAT_LCAPACITY].units = capunit; 385 sc->sc_sensor[ACPIBAT_CHARGERATE].units = rateunit; 386 sc->sc_sensor[ACPIBAT_DISCHARGERATE].units = rateunit; 387 sc->sc_sensor[ACPIBAT_CAPACITY].units = capunit; 388 389 sc->sc_sensor[ACPIBAT_DCAPACITY].value_cur = p2[1].Integer.Value * 1000; 390 sc->sc_sensor[ACPIBAT_DCAPACITY].state = ENVSYS_SVALID; 391 sc->sc_sensor[ACPIBAT_LFCCAPACITY].value_cur = p2[2].Integer.Value * 1000; 392 sc->sc_sensor[ACPIBAT_LFCCAPACITY].state = ENVSYS_SVALID; 393 sc->sc_sensor[ACPIBAT_CAPACITY].value_max = p2[2].Integer.Value * 1000; 394 sc->sc_sensor[ACPIBAT_TECHNOLOGY].value_cur = p2[3].Integer.Value; 395 sc->sc_sensor[ACPIBAT_TECHNOLOGY].state = ENVSYS_SVALID; 396 sc->sc_sensor[ACPIBAT_DVOLTAGE].value_cur = p2[4].Integer.Value * 1000; 397 sc->sc_sensor[ACPIBAT_DVOLTAGE].state = ENVSYS_SVALID; 398 sc->sc_sensor[ACPIBAT_WCAPACITY].value_cur = p2[5].Integer.Value * 1000; 399 sc->sc_sensor[ACPIBAT_WCAPACITY].value_max = p2[2].Integer.Value * 1000; 400 sc->sc_sensor[ACPIBAT_WCAPACITY].state = ENVSYS_SVALID; 401 sc->sc_sensor[ACPIBAT_WCAPACITY].flags |= 402 (ENVSYS_FPERCENT|ENVSYS_FVALID_MAX); 403 sc->sc_sensor[ACPIBAT_LCAPACITY].value_cur = p2[6].Integer.Value * 1000; 404 sc->sc_sensor[ACPIBAT_LCAPACITY].value_max = p2[2].Integer.Value * 1000; 405 sc->sc_sensor[ACPIBAT_LCAPACITY].state = ENVSYS_SVALID; 406 sc->sc_sensor[ACPIBAT_LCAPACITY].flags |= 407 (ENVSYS_FPERCENT|ENVSYS_FVALID_MAX); 408 sc->sc_available = ABAT_ALV_INFO; 409 410 aprint_verbose_dev(dv, "battery info: %s, %s, %s", 411 p2[12].String.Pointer, p2[11].String.Pointer, p2[9].String.Pointer); 412 if (p2[10].String.Pointer) 413 aprint_verbose(" %s", p2[10].String.Pointer); 414 415 aprint_verbose("\n"); 416 417 rv = AE_OK; 418 419 out: 420 AcpiOsFree(buf.Pointer); 421 return rv; 422 } 423 424 /* 425 * acpibat_get_status: 426 * 427 * Get, and possibly display, the current battery line status. 428 */ 429 static ACPI_STATUS 430 acpibat_get_status(device_t dv) 431 { 432 struct acpibat_softc *sc = device_private(dv); 433 int status, battrate; 434 ACPI_OBJECT *p1, *p2; 435 ACPI_STATUS rv; 436 ACPI_BUFFER buf; 437 438 rv = acpi_eval_struct(sc->sc_node->ad_handle, "_BST", &buf); 439 if (ACPI_FAILURE(rv)) { 440 aprint_error_dev(dv, "failed to evaluate _BST: %s\n", 441 AcpiFormatException(rv)); 442 return rv; 443 } 444 p1 = (ACPI_OBJECT *)buf.Pointer; 445 446 if (p1->Type != ACPI_TYPE_PACKAGE) { 447 aprint_error_dev(dv, "expected PACKAGE, got %d\n", 448 p1->Type); 449 rv = AE_ERROR; 450 goto out; 451 } 452 if (p1->Package.Count < 4) { 453 aprint_error_dev(dv, "expected 4 elts, got %d\n", 454 p1->Package.Count); 455 rv = AE_ERROR; 456 goto out; 457 } 458 p2 = p1->Package.Elements; 459 460 status = p2[0].Integer.Value; 461 battrate = p2[1].Integer.Value; 462 463 if (status & ACPIBAT_ST_CHARGING) { 464 sc->sc_sensor[ACPIBAT_CHARGERATE].state = ENVSYS_SVALID; 465 sc->sc_sensor[ACPIBAT_CHARGERATE].value_cur = battrate * 1000; 466 sc->sc_sensor[ACPIBAT_DISCHARGERATE].state = ENVSYS_SINVALID; 467 sc->sc_sensor[ACPIBAT_CHARGING].state = ENVSYS_SVALID; 468 sc->sc_sensor[ACPIBAT_CHARGING].value_cur = 1; 469 } else if (status & ACPIBAT_ST_DISCHARGING) { 470 sc->sc_sensor[ACPIBAT_DISCHARGERATE].state = ENVSYS_SVALID; 471 sc->sc_sensor[ACPIBAT_DISCHARGERATE].value_cur = battrate * 1000; 472 sc->sc_sensor[ACPIBAT_CHARGERATE].state = ENVSYS_SINVALID; 473 sc->sc_sensor[ACPIBAT_CHARGING].state = ENVSYS_SVALID; 474 sc->sc_sensor[ACPIBAT_CHARGING].value_cur = 0; 475 } else if (!(status & (ACPIBAT_ST_CHARGING|ACPIBAT_ST_DISCHARGING))) { 476 sc->sc_sensor[ACPIBAT_CHARGING].state = ENVSYS_SVALID; 477 sc->sc_sensor[ACPIBAT_CHARGING].value_cur = 0; 478 sc->sc_sensor[ACPIBAT_CHARGERATE].state = ENVSYS_SINVALID; 479 sc->sc_sensor[ACPIBAT_DISCHARGERATE].state = ENVSYS_SINVALID; 480 } 481 482 sc->sc_sensor[ACPIBAT_CHARGE_STATE].value_cur = 483 ENVSYS_BATTERY_CAPACITY_NORMAL; 484 485 sc->sc_sensor[ACPIBAT_CAPACITY].value_cur = p2[2].Integer.Value * 1000; 486 sc->sc_sensor[ACPIBAT_CAPACITY].state = ENVSYS_SVALID; 487 sc->sc_sensor[ACPIBAT_CAPACITY].flags |= 488 (ENVSYS_FPERCENT|ENVSYS_FVALID_MAX); 489 sc->sc_sensor[ACPIBAT_VOLTAGE].value_cur = p2[3].Integer.Value * 1000; 490 sc->sc_sensor[ACPIBAT_VOLTAGE].state = ENVSYS_SVALID; 491 492 if (sc->sc_sensor[ACPIBAT_CAPACITY].value_cur < 493 sc->sc_sensor[ACPIBAT_WCAPACITY].value_cur) { 494 sc->sc_sensor[ACPIBAT_CAPACITY].state = ENVSYS_SWARNUNDER; 495 sc->sc_sensor[ACPIBAT_CHARGE_STATE].value_cur = 496 ENVSYS_BATTERY_CAPACITY_WARNING; 497 } 498 499 if (sc->sc_sensor[ACPIBAT_CAPACITY].value_cur < 500 sc->sc_sensor[ACPIBAT_LCAPACITY].value_cur) { 501 sc->sc_sensor[ACPIBAT_CAPACITY].state = ENVSYS_SCRITUNDER; 502 sc->sc_sensor[ACPIBAT_CHARGE_STATE].value_cur = 503 ENVSYS_BATTERY_CAPACITY_LOW; 504 } 505 506 if (status & ACPIBAT_ST_CRITICAL) { 507 sc->sc_sensor[ACPIBAT_CAPACITY].state = ENVSYS_SCRITICAL; 508 sc->sc_sensor[ACPIBAT_CHARGE_STATE].value_cur = 509 ENVSYS_BATTERY_CAPACITY_CRITICAL; 510 } 511 512 rv = AE_OK; 513 514 out: 515 AcpiOsFree(buf.Pointer); 516 return rv; 517 } 518 519 #define SCALE(x) ((x)/1000000), (((x)%1000000)/1000) 520 #define CAPUNITS(sc) (ABAT_ISSET((sc), ABAT_F_PWRUNIT_MA)?"Ah":"Wh") 521 #define RATEUNITS(sc) (ABAT_ISSET((sc), ABAT_F_PWRUNIT_MA)?"A":"W") 522 static void 523 acpibat_print_info(device_t dv) 524 { 525 struct acpibat_softc *sc = device_private(dv); 526 const char *tech; 527 528 if (sc->sc_sensor[ACPIBAT_TECHNOLOGY].value_cur) 529 tech = "secondary"; 530 else 531 tech = "primary"; 532 533 aprint_debug_dev(dv, "%s battery, Design %d.%03d%s " 534 "Last full %d.%03d%s Warn %d.%03d%s Low %d.%03d%s\n", 535 tech, SCALE(sc->sc_sensor[ACPIBAT_DCAPACITY].value_cur), CAPUNITS(sc), 536 SCALE(sc->sc_sensor[ACPIBAT_LFCCAPACITY].value_cur),CAPUNITS(sc), 537 SCALE(sc->sc_sensor[ACPIBAT_WCAPACITY].value_cur), CAPUNITS(sc), 538 SCALE(sc->sc_sensor[ACPIBAT_LCAPACITY].value_cur), CAPUNITS(sc)); 539 } 540 541 static void 542 acpibat_print_stat(device_t dv) 543 { 544 struct acpibat_softc *sc = device_private(dv); 545 const char *capstat, *chargestat; 546 int percent, denom; 547 int32_t value; 548 549 percent = 0; 550 551 if (sc->sc_sensor[ACPIBAT_CAPACITY].state == ENVSYS_SCRITUNDER) 552 capstat = "CRITICAL UNDER "; 553 else if (sc->sc_sensor[ACPIBAT_CAPACITY].state == ENVSYS_SCRITOVER) 554 capstat = "CRITICAL OVER "; 555 else 556 capstat = ""; 557 558 if (sc->sc_sensor[ACPIBAT_CHARGING].state != ENVSYS_SVALID) { 559 chargestat = "idling"; 560 value = 0; 561 } else if (sc->sc_sensor[ACPIBAT_CHARGING].value_cur == 0) { 562 chargestat = "discharging"; 563 value = sc->sc_sensor[ACPIBAT_DISCHARGERATE].value_cur; 564 } else { 565 chargestat = "charging"; 566 value = sc->sc_sensor[ACPIBAT_CHARGERATE].value_cur; 567 } 568 569 denom = sc->sc_sensor[ACPIBAT_LFCCAPACITY].value_cur / 100; 570 if (denom > 0) 571 percent = (sc->sc_sensor[ACPIBAT_CAPACITY].value_cur) / denom; 572 573 aprint_debug_dev(dv, "%s%s: %d.%03dV cap %d.%03d%s (%d%%) " 574 "rate %d.%03d%s\n", capstat, chargestat, 575 SCALE(sc->sc_sensor[ACPIBAT_VOLTAGE].value_cur), 576 SCALE(sc->sc_sensor[ACPIBAT_CAPACITY].value_cur), CAPUNITS(sc), 577 percent, SCALE(value), RATEUNITS(sc)); 578 } 579 580 static void 581 acpibat_update(void *arg) 582 { 583 device_t dv = arg; 584 struct acpibat_softc *sc = device_private(dv); 585 586 if (sc->sc_available < ABAT_ALV_INFO) { 587 /* current information is invalid */ 588 #if 0 589 /* 590 * XXX: The driver sometimes unaware that the battery exist. 591 * (i.e. just after the boot or resuming) 592 * Thus, the driver should always check it here. 593 */ 594 if (sc->sc_available < ABAT_ALV_PRESENCE) 595 #endif 596 /* presence is invalid */ 597 if (acpibat_battery_present(dv) < 0) { 598 /* error */ 599 aprint_debug_dev(dv, 600 "cannot get battery presence.\n"); 601 return; 602 } 603 604 if (ABAT_ISSET(sc, ABAT_F_PRESENT)) { 605 /* the battery is present. */ 606 if (ABAT_ISSET(sc, ABAT_F_VERBOSE)) 607 aprint_debug_dev(dv, 608 "battery is present.\n"); 609 if (ACPI_FAILURE(acpibat_get_info(dv))) 610 return; 611 if (ABAT_ISSET(sc, ABAT_F_VERBOSE)) 612 acpibat_print_info(dv); 613 } else { 614 /* the battery is not present. */ 615 if (ABAT_ISSET(sc, ABAT_F_VERBOSE)) 616 aprint_debug_dev(dv, 617 "battery is not present.\n"); 618 return; 619 } 620 } else { 621 /* current information is valid */ 622 if (!ABAT_ISSET(sc, ABAT_F_PRESENT)) { 623 /* the battery is not present. */ 624 return; 625 } 626 } 627 628 if (ACPI_FAILURE(acpibat_get_status(dv))) 629 return; 630 631 if (ABAT_ISSET(sc, ABAT_F_VERBOSE)) 632 acpibat_print_stat(dv); 633 } 634 635 static void 636 acpibat_update_info(void *arg) 637 { 638 device_t dev = arg; 639 struct acpibat_softc *sc = device_private(dev); 640 641 mutex_enter(&sc->sc_mutex); 642 acpibat_clear_presence(sc); 643 acpibat_update(arg); 644 mutex_exit(&sc->sc_mutex); 645 } 646 647 static void 648 acpibat_update_stat(void *arg) 649 { 650 device_t dev = arg; 651 struct acpibat_softc *sc = device_private(dev); 652 653 mutex_enter(&sc->sc_mutex); 654 acpibat_clear_stat(sc); 655 acpibat_update(arg); 656 microtime(&sc->sc_lastupdate); 657 cv_broadcast(&sc->sc_condvar); 658 mutex_exit(&sc->sc_mutex); 659 } 660 661 /* 662 * acpibat_notify_handler: 663 * 664 * Callback from ACPI interrupt handler to notify us of an event. 665 */ 666 static void 667 acpibat_notify_handler(ACPI_HANDLE handle, UINT32 notify, void *context) 668 { 669 device_t dv = context; 670 int rv; 671 672 #ifdef ACPI_BAT_DEBUG 673 aprint_debug_dev(dv, "received notify message: 0x%x\n", notify); 674 #endif 675 676 switch (notify) { 677 case ACPI_NOTIFY_BusCheck: 678 break; 679 case ACPI_NOTIFY_DeviceCheck: 680 case ACPI_NOTIFY_BatteryInformationChanged: 681 rv = AcpiOsExecute(OSL_NOTIFY_HANDLER, acpibat_update_info, dv); 682 if (ACPI_FAILURE(rv)) 683 aprint_error_dev(dv, 684 "unable to queue info check: %s\n", 685 AcpiFormatException(rv)); 686 break; 687 688 case ACPI_NOTIFY_BatteryStatusChanged: 689 rv = AcpiOsExecute(OSL_NOTIFY_HANDLER, acpibat_update_stat, dv); 690 if (ACPI_FAILURE(rv)) 691 aprint_error_dev(dv, 692 "unable to queue status check: %s\n", 693 AcpiFormatException(rv)); 694 break; 695 696 default: 697 aprint_error_dev(dv, 698 "received unknown notify message: 0x%x\n", notify); 699 } 700 } 701 702 static void 703 acpibat_init_envsys(device_t dv) 704 { 705 struct acpibat_softc *sc = device_private(dv); 706 int i, capunit, rateunit; 707 708 if (sc->sc_flags & ABAT_F_PWRUNIT_MA) { 709 capunit = ENVSYS_SAMPHOUR; 710 rateunit = ENVSYS_SAMPS; 711 } else { 712 capunit = ENVSYS_SWATTHOUR; 713 rateunit = ENVSYS_SWATTS; 714 } 715 716 #define INITDATA(index, unit, string) \ 717 sc->sc_sensor[index].state = ENVSYS_SVALID; \ 718 sc->sc_sensor[index].units = unit; \ 719 strlcpy(sc->sc_sensor[index].desc, string, \ 720 sizeof(sc->sc_sensor[index].desc)); 721 722 INITDATA(ACPIBAT_PRESENT, ENVSYS_INDICATOR, "present"); 723 INITDATA(ACPIBAT_DCAPACITY, capunit, "design cap"); 724 INITDATA(ACPIBAT_LFCCAPACITY, capunit, "last full cap"); 725 INITDATA(ACPIBAT_TECHNOLOGY, ENVSYS_INTEGER, "technology"); 726 INITDATA(ACPIBAT_DVOLTAGE, ENVSYS_SVOLTS_DC, "design voltage"); 727 INITDATA(ACPIBAT_WCAPACITY, capunit, "warn cap"); 728 INITDATA(ACPIBAT_LCAPACITY, capunit, "low cap"); 729 INITDATA(ACPIBAT_VOLTAGE, ENVSYS_SVOLTS_DC, "voltage"); 730 INITDATA(ACPIBAT_CHARGERATE, rateunit, "charge rate"); 731 INITDATA(ACPIBAT_DISCHARGERATE, rateunit, "discharge rate"); 732 INITDATA(ACPIBAT_CAPACITY, capunit, "charge"); 733 INITDATA(ACPIBAT_CHARGING, ENVSYS_BATTERY_CHARGE, "charging"); 734 INITDATA(ACPIBAT_CHARGE_STATE, ENVSYS_BATTERY_CAPACITY, "charge state"); 735 736 #undef INITDATA 737 738 /* Enable monitoring for the charge state sensor */ 739 sc->sc_sensor[ACPIBAT_CHARGE_STATE].monitor = true; 740 sc->sc_sensor[ACPIBAT_CHARGE_STATE].flags |= ENVSYS_FMONSTCHANGED; 741 742 /* Disable userland monitoring on these sensors */ 743 sc->sc_sensor[ACPIBAT_VOLTAGE].flags = ENVSYS_FMONNOTSUPP; 744 sc->sc_sensor[ACPIBAT_CHARGERATE].flags = ENVSYS_FMONNOTSUPP; 745 sc->sc_sensor[ACPIBAT_DISCHARGERATE].flags = ENVSYS_FMONNOTSUPP; 746 sc->sc_sensor[ACPIBAT_DCAPACITY].flags = ENVSYS_FMONNOTSUPP; 747 sc->sc_sensor[ACPIBAT_LFCCAPACITY].flags = ENVSYS_FMONNOTSUPP; 748 sc->sc_sensor[ACPIBAT_TECHNOLOGY].flags = ENVSYS_FMONNOTSUPP; 749 sc->sc_sensor[ACPIBAT_DVOLTAGE].flags = ENVSYS_FMONNOTSUPP; 750 sc->sc_sensor[ACPIBAT_WCAPACITY].flags = ENVSYS_FMONNOTSUPP; 751 sc->sc_sensor[ACPIBAT_LCAPACITY].flags = ENVSYS_FMONNOTSUPP; 752 753 sc->sc_sme = sysmon_envsys_create(); 754 for (i = 0; i < ACPIBAT_NSENSORS; i++) { 755 if (sysmon_envsys_sensor_attach(sc->sc_sme, 756 &sc->sc_sensor[i])) { 757 aprint_error_dev(dv, "unable to add sensor%d\n", i); 758 sysmon_envsys_destroy(sc->sc_sme); 759 return; 760 } 761 } 762 763 sc->sc_sme->sme_name = device_xname(dv); 764 sc->sc_sme->sme_cookie = dv; 765 sc->sc_sme->sme_refresh = acpibat_refresh; 766 sc->sc_sme->sme_class = SME_CLASS_BATTERY; 767 sc->sc_sme->sme_flags = SME_POLL_ONLY; 768 769 acpibat_update(dv); 770 771 if (sysmon_envsys_register(sc->sc_sme)) { 772 aprint_error_dev(dv, "unable to register with sysmon\n"); 773 sysmon_envsys_destroy(sc->sc_sme); 774 } 775 } 776 777 static void 778 acpibat_refresh(struct sysmon_envsys *sme, envsys_data_t *edata) 779 { 780 device_t dv = sme->sme_cookie; 781 struct acpibat_softc *sc = device_private(dv); 782 ACPI_STATUS rv; 783 struct timeval tv, tmp; 784 785 if (ABAT_ISSET(sc, ABAT_F_PRESENT)) { 786 tmp.tv_sec = 5; 787 tmp.tv_usec = 0; 788 microtime(&tv); 789 timersub(&tv, &tmp, &tv); 790 if (timercmp(&tv, &sc->sc_lastupdate, <)) 791 return; 792 793 if (!mutex_tryenter(&sc->sc_mutex)) 794 return; 795 rv = AcpiOsExecute(OSL_NOTIFY_HANDLER, acpibat_update_stat, dv); 796 if (!ACPI_FAILURE(rv)) 797 cv_timedwait(&sc->sc_condvar, &sc->sc_mutex, hz); 798 mutex_exit(&sc->sc_mutex); 799 } 800 } 801