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