1 /* $NetBSD: acpi_bat.c,v 1.21 2003/05/29 02:47:49 gson Exp $ */ 2 3 /* 4 * Copyright 2001 Bill Sommerfeld. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed for the NetBSD Project by 18 * Wasabi Systems, Inc. 19 * 4. The name of Wasabi Systems, Inc. may not be used to endorse 20 * or promote products derived from this software without specific prior 21 * written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 25 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 26 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 27 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 28 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 29 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 30 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 31 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 32 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33 * POSSIBILITY OF SUCH DAMAGE. 34 */ 35 36 #if 0 37 #define ACPI_BAT_DEBUG 38 #endif 39 40 /* 41 * ACPI Battery Driver. 42 * 43 * ACPI defines two different battery device interfaces: "Control 44 * Method" batteries, in which AML methods are defined in order to get 45 * battery status and set battery alarm thresholds, and a "Smart 46 * Battery" device, which is an SMbus device accessed through the ACPI 47 * Embedded Controller device. 48 * 49 * This driver is for the "Control Method"-style battery only. 50 */ 51 52 #include <sys/cdefs.h> 53 __KERNEL_RCSID(0, "$NetBSD: acpi_bat.c,v 1.21 2003/05/29 02:47:49 gson Exp $"); 54 55 #include <sys/param.h> 56 #include <sys/systm.h> 57 #include <sys/kernel.h> /* for hz */ 58 #include <sys/device.h> 59 #include <dev/sysmon/sysmonvar.h> 60 61 #include <dev/acpi/acpica.h> 62 #include <dev/acpi/acpireg.h> 63 #include <dev/acpi/acpivar.h> 64 65 /* sensor indexes */ 66 #define ACPIBAT_PRESENT 0 67 #define ACPIBAT_DCAPACITY 1 68 #define ACPIBAT_LFCCAPACITY 2 69 #define ACPIBAT_TECHNOLOGY 3 70 #define ACPIBAT_DVOLTAGE 4 71 #define ACPIBAT_WCAPACITY 5 72 #define ACPIBAT_LCAPACITY 6 73 #define ACPIBAT_VOLTAGE 7 74 #define ACPIBAT_LOAD 8 75 #define ACPIBAT_CAPACITY 9 76 #define ACPIBAT_CHARGING 10 77 #define ACPIBAT_DISCHARGING 11 78 #define ACPIBAT_NSENSORS 12 /* number of sensors */ 79 80 const struct envsys_range acpibat_range_amp[] = { 81 { 0, 1, ENVSYS_SVOLTS_DC }, 82 { 1, 2, ENVSYS_SAMPS }, 83 { 2, 3, ENVSYS_SAMPHOUR }, 84 { 1, 0, -1 }, 85 }; 86 87 const struct envsys_range acpibat_range_watt[] = { 88 { 0, 1, ENVSYS_SVOLTS_DC }, 89 { 1, 2, ENVSYS_SWATTS }, 90 { 2, 3, ENVSYS_SWATTHOUR }, 91 { 1, 0, -1 }, 92 }; 93 94 struct acpibat_softc { 95 struct device sc_dev; /* base device glue */ 96 struct acpi_devnode *sc_node; /* our ACPI devnode */ 97 int sc_flags; /* see below */ 98 int sc_available; /* available information level */ 99 100 struct sysmon_envsys sc_sysmon; 101 struct envsys_basic_info sc_info[ACPIBAT_NSENSORS]; 102 struct envsys_tre_data sc_data[ACPIBAT_NSENSORS]; 103 104 struct simplelock sc_lock; 105 }; 106 107 /* 108 * These flags are used to examine the battery device data returned from 109 * the ACPI interface, specifically the "battery status" 110 */ 111 #define ACPIBAT_PWRUNIT_MA 0x00000001 /* mA not mW */ 112 113 /* 114 * These flags are used to examine the battery charge/discharge/critical 115 * state returned from a get-status command. 116 */ 117 #define ACPIBAT_ST_DISCHARGING 0x00000001 /* battery is discharging */ 118 #define ACPIBAT_ST_CHARGING 0x00000002 /* battery is charging */ 119 #define ACPIBAT_ST_CRITICAL 0x00000004 /* battery is critical */ 120 121 /* 122 * Flags for battery status from _STA return 123 */ 124 #define ACPIBAT_STA_PRESENT 0x00000010 /* battery present */ 125 126 /* 127 * These flags are used to set internal state in our softc. 128 */ 129 #define ABAT_F_VERBOSE 0x01 /* verbose events */ 130 #define ABAT_F_PWRUNIT_MA 0x02 /* mA instead of mW */ 131 #define ABAT_F_PRESENT 0x04 /* is the battery present? */ 132 #define ABAT_F_LOCKED 0x08 /* is locked? */ 133 #define ABAT_F_DISCHARGING 0x10 /* discharging */ 134 #define ABAT_F_CHARGING 0x20 /* charging */ 135 #define ABAT_F_CRITICAL 0x40 /* charging */ 136 137 #define ABAT_SET(sc, f) (void)((sc)->sc_flags |= (f)) 138 #define ABAT_CLEAR(sc, f) (void)((sc)->sc_flags &= ~(f)) 139 #define ABAT_ISSET(sc, f) ((sc)->sc_flags & (f)) 140 141 /* 142 * Available info level 143 */ 144 145 #define ABAT_ALV_NONE 0 /* none is available */ 146 #define ABAT_ALV_PRESENCE 1 /* presence info is available */ 147 #define ABAT_ALV_INFO 2 /* battery info is available */ 148 #define ABAT_ALV_STAT 3 /* battery status is available */ 149 150 #define ABAT_ASSERT_LOCKED(sc) \ 151 do { \ 152 if (!((sc)->sc_flags & ABAT_F_LOCKED)) \ 153 panic("acpi_bat (expected to be locked)"); \ 154 } while(/*CONSTCOND*/0) 155 #define ABAT_ASSERT_UNLOCKED(sc) \ 156 do { \ 157 if (((sc)->sc_flags & ABAT_F_LOCKED)) \ 158 panic("acpi_bat (expected to be unlocked)"); \ 159 } while(/*CONSTCOND*/0) 160 #define ABAT_LOCK(sc, s) \ 161 do { \ 162 ABAT_ASSERT_UNLOCKED(sc); \ 163 (s) = splhigh(); \ 164 simple_lock(&(sc)->sc_lock); \ 165 ABAT_SET((sc), ABAT_F_LOCKED); \ 166 } while(/*CONSTCOND*/0) 167 #define ABAT_UNLOCK(sc, s) \ 168 do { \ 169 ABAT_ASSERT_LOCKED(sc); \ 170 ABAT_CLEAR((sc), ABAT_F_LOCKED); \ 171 simple_unlock(&(sc)->sc_lock); \ 172 splx((s)); \ 173 } while(/*CONSTCOND*/0) 174 175 int acpibat_match(struct device *, struct cfdata *, void *); 176 void acpibat_attach(struct device *, struct device *, void *); 177 178 CFATTACH_DECL(acpibat, sizeof(struct acpibat_softc), 179 acpibat_match, acpibat_attach, NULL, NULL); 180 181 static void acpibat_clear_presence(struct acpibat_softc *); 182 static void acpibat_clear_info(struct acpibat_softc *); 183 static void acpibat_clear_stat(struct acpibat_softc *); 184 static int acpibat_battery_present(struct acpibat_softc *); 185 static ACPI_STATUS acpibat_get_status(struct acpibat_softc *); 186 static ACPI_STATUS acpibat_get_info(struct acpibat_softc *); 187 static void acpibat_print_info(struct acpibat_softc *); 188 static void acpibat_print_stat(struct acpibat_softc *); 189 static void acpibat_update(void *); 190 191 static void acpibat_init_envsys(struct acpibat_softc *); 192 static void acpibat_notify_handler(ACPI_HANDLE, UINT32, void *context); 193 static int acpibat_gtredata(struct sysmon_envsys *, struct envsys_tre_data *); 194 static int acpibat_streinfo(struct sysmon_envsys *, struct envsys_basic_info *); 195 196 /* 197 * acpibat_match: 198 * 199 * Autoconfiguration `match' routine. 200 */ 201 int 202 acpibat_match(struct device *parent, struct cfdata *match, void *aux) 203 { 204 struct acpi_attach_args *aa = aux; 205 206 if (aa->aa_node->ad_type != ACPI_TYPE_DEVICE) 207 return (0); 208 209 if (strcmp(aa->aa_node->ad_devinfo.HardwareId, "PNP0C0A") == 0) 210 return (1); 211 212 return (0); 213 } 214 215 /* 216 * acpibat_attach: 217 * 218 * Autoconfiguration `attach' routine. 219 */ 220 void 221 acpibat_attach(struct device *parent, struct device *self, void *aux) 222 { 223 struct acpibat_softc *sc = (void *) self; 224 struct acpi_attach_args *aa = aux; 225 ACPI_STATUS rv; 226 227 printf(": ACPI Battery (Control Method)\n"); 228 229 sc->sc_node = aa->aa_node; 230 simple_lock_init(&sc->sc_lock); 231 232 rv = AcpiInstallNotifyHandler(sc->sc_node->ad_handle, 233 ACPI_DEVICE_NOTIFY, 234 acpibat_notify_handler, sc); 235 if (rv != AE_OK) { 236 printf("%s: unable to register DEVICE NOTIFY handler: %d\n", 237 sc->sc_dev.dv_xname, rv); 238 return; 239 } 240 241 /* XXX See acpibat_notify_handler() */ 242 rv = AcpiInstallNotifyHandler(sc->sc_node->ad_handle, 243 ACPI_SYSTEM_NOTIFY, 244 acpibat_notify_handler, sc); 245 if (rv != AE_OK) { 246 printf("%s: unable to register SYSTEM NOTIFY handler: %d\n", 247 sc->sc_dev.dv_xname, rv); 248 return; 249 } 250 251 #ifdef ACPI_BAT_DEBUG 252 ABAT_SET(sc, ABAT_F_VERBOSE); 253 #endif 254 255 acpibat_init_envsys(sc); 256 } 257 258 /* 259 * clear informations 260 */ 261 262 void 263 acpibat_clear_presence(struct acpibat_softc *sc) 264 { 265 266 ABAT_ASSERT_LOCKED(sc); 267 268 acpibat_clear_info(sc); 269 sc->sc_available = ABAT_ALV_NONE; 270 ABAT_CLEAR(sc, ABAT_F_PRESENT); 271 } 272 273 void 274 acpibat_clear_info(struct acpibat_softc *sc) 275 { 276 277 ABAT_ASSERT_LOCKED(sc); 278 279 acpibat_clear_stat(sc); 280 if (sc->sc_available>ABAT_ALV_PRESENCE) 281 sc->sc_available = ABAT_ALV_PRESENCE; 282 sc->sc_data[ACPIBAT_DCAPACITY].cur.data_s = 0; 283 sc->sc_data[ACPIBAT_LFCCAPACITY].cur.data_s = 0; 284 sc->sc_data[ACPIBAT_LFCCAPACITY].max.data_s = 0; 285 sc->sc_data[ACPIBAT_CAPACITY].max.data_s = 0; 286 sc->sc_data[ACPIBAT_TECHNOLOGY].cur.data_s = 0; 287 sc->sc_data[ACPIBAT_DVOLTAGE].cur.data_s = 0; 288 sc->sc_data[ACPIBAT_WCAPACITY].cur.data_s = 0; 289 sc->sc_data[ACPIBAT_LCAPACITY].cur.data_s = 0; 290 } 291 292 void 293 acpibat_clear_stat(struct acpibat_softc *sc) 294 { 295 296 ABAT_ASSERT_LOCKED(sc); 297 298 if (sc->sc_available>ABAT_ALV_INFO) 299 sc->sc_available = ABAT_ALV_INFO; 300 sc->sc_data[ACPIBAT_LOAD].cur.data_s = 0; 301 sc->sc_data[ACPIBAT_CAPACITY].cur.data_s = 0; 302 sc->sc_data[ACPIBAT_VOLTAGE].cur.data_s = 0; 303 sc->sc_data[ACPIBAT_CAPACITY].warnflags = 0; 304 sc->sc_data[ACPIBAT_DISCHARGING].cur.data_s = 0; 305 sc->sc_data[ACPIBAT_CHARGING].cur.data_s = 0; 306 } 307 308 309 /* 310 * returns 0 for no battery, 1 for present, and -1 on error 311 */ 312 int 313 acpibat_battery_present(struct acpibat_softc *sc) 314 { 315 u_int32_t sta; 316 int s, val; 317 ACPI_STATUS rv; 318 319 rv = acpi_eval_integer(sc->sc_node->ad_handle, "_STA", &val); 320 if (rv != AE_OK) { 321 printf("%s: failed to evaluate _STA: %x\n", 322 sc->sc_dev.dv_xname, rv); 323 return (-1); 324 } 325 326 sta = (u_int32_t)val; 327 328 ABAT_LOCK(sc, s); 329 sc->sc_available = ABAT_ALV_PRESENCE; 330 if (sta & ACPIBAT_STA_PRESENT) { 331 ABAT_SET(sc, ABAT_F_PRESENT); 332 sc->sc_data[ACPIBAT_PRESENT].cur.data_s = 1; 333 } else 334 sc->sc_data[ACPIBAT_PRESENT].cur.data_s = 0; 335 ABAT_UNLOCK(sc, s); 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 ACPI_STATUS 347 acpibat_get_info(struct acpibat_softc *sc) 348 { 349 ACPI_OBJECT *p1, *p2; 350 ACPI_STATUS rv; 351 ACPI_BUFFER buf; 352 int capunit, rateunit, s; 353 const char *capstring, *ratestring; 354 355 rv = acpi_eval_struct(sc->sc_node->ad_handle, "_BIF", &buf); 356 if (rv != AE_OK) { 357 printf("%s: failed to evaluate _BIF: 0x%x\n", 358 sc->sc_dev.dv_xname, rv); 359 return (rv); 360 } 361 p1 = (ACPI_OBJECT *)buf.Pointer; 362 if (p1->Type != ACPI_TYPE_PACKAGE) { 363 printf("%s: expected PACKAGE, got %d\n", sc->sc_dev.dv_xname, 364 p1->Type); 365 goto out; 366 } 367 if (p1->Package.Count < 13) { 368 printf("%s: expected 13 elts, got %d\n", 369 sc->sc_dev.dv_xname, p1->Package.Count); 370 goto out; 371 } 372 373 #define INITDATA(index, unit, string) \ 374 sc->sc_data[index].units = unit; \ 375 sc->sc_info[index].units = unit; \ 376 snprintf(sc->sc_info[index].desc, sizeof(sc->sc_info->desc), \ 377 "%s %s", sc->sc_dev.dv_xname, string); \ 378 379 ABAT_LOCK(sc, s); 380 p2 = p1->Package.Elements; 381 /* 382 * XXX: It seems that the below attributes should not be overriden 383 * in such manner... we should unregister them for a while, maybe. 384 */ 385 if ((p2[0].Integer.Value & ACPIBAT_PWRUNIT_MA) != 0) { 386 ABAT_SET(sc, ABAT_F_PWRUNIT_MA); 387 sc->sc_sysmon.sme_ranges = acpibat_range_amp; 388 capunit = ENVSYS_SAMPHOUR; 389 capstring = "charge"; 390 rateunit = ENVSYS_SAMPS; 391 ratestring = "current"; 392 } else { 393 ABAT_CLEAR(sc, ABAT_F_PWRUNIT_MA); 394 sc->sc_sysmon.sme_ranges = acpibat_range_watt; 395 capunit = ENVSYS_SWATTHOUR; 396 capstring = "energy"; 397 rateunit = ENVSYS_SWATTS; 398 ratestring = "power"; 399 } 400 INITDATA(ACPIBAT_DCAPACITY, capunit, "design cap"); 401 INITDATA(ACPIBAT_LFCCAPACITY, capunit, "lfc cap"); 402 INITDATA(ACPIBAT_WCAPACITY, capunit, "warn cap"); 403 INITDATA(ACPIBAT_LCAPACITY, capunit, "low cap"); 404 INITDATA(ACPIBAT_LOAD, rateunit, ratestring); 405 INITDATA(ACPIBAT_CAPACITY, capunit, capstring); 406 407 sc->sc_data[ACPIBAT_DCAPACITY].cur.data_s = p2[1].Integer.Value * 1000; 408 sc->sc_data[ACPIBAT_LFCCAPACITY].cur.data_s = p2[2].Integer.Value * 1000; 409 sc->sc_data[ACPIBAT_LFCCAPACITY].max.data_s = p2[1].Integer.Value * 1000; 410 sc->sc_data[ACPIBAT_CAPACITY].max.data_s = p2[1].Integer.Value * 1000; 411 sc->sc_data[ACPIBAT_TECHNOLOGY].cur.data_s = p2[3].Integer.Value; 412 sc->sc_data[ACPIBAT_DVOLTAGE].cur.data_s = p2[4].Integer.Value * 1000; 413 sc->sc_data[ACPIBAT_WCAPACITY].cur.data_s = p2[5].Integer.Value * 1000; 414 sc->sc_data[ACPIBAT_LCAPACITY].cur.data_s = p2[6].Integer.Value * 1000; 415 sc->sc_available = ABAT_ALV_INFO; 416 ABAT_UNLOCK(sc, s); 417 418 if ((sc->sc_flags & ABAT_F_VERBOSE)) 419 printf("%s: %s %s %s %s\n", 420 sc->sc_dev.dv_xname, 421 p2[12].String.Pointer, p2[11].String.Pointer, 422 p2[9].String.Pointer, p2[10].String.Pointer); 423 424 rv = AE_OK; 425 426 out: 427 AcpiOsFree(buf.Pointer); 428 return (rv); 429 } 430 431 /* 432 * acpibat_get_status: 433 * 434 * Get, and possibly display, the current battery line status. 435 */ 436 ACPI_STATUS 437 acpibat_get_status(struct acpibat_softc *sc) 438 { 439 int flags, status, s; 440 ACPI_OBJECT *p1, *p2; 441 ACPI_STATUS rv; 442 ACPI_BUFFER buf; 443 444 rv = acpi_eval_struct(sc->sc_node->ad_handle, "_BST", &buf); 445 if (rv != AE_OK) { 446 printf("bat: failed to evaluate _BST: 0x%x\n", rv); 447 return (rv); 448 } 449 p1 = (ACPI_OBJECT *)buf.Pointer; 450 451 if (p1->Type != ACPI_TYPE_PACKAGE) { 452 printf("bat: expected PACKAGE, got %d\n", p1->Type); 453 rv = AE_ERROR; 454 goto out; 455 } 456 if (p1->Package.Count < 4) { 457 printf("bat: expected 4 elts, got %d\n", p1->Package.Count); 458 rv = AE_ERROR; 459 goto out; 460 } 461 p2 = p1->Package.Elements; 462 463 ABAT_LOCK(sc, s); 464 status = p2[0].Integer.Value; 465 sc->sc_data[ACPIBAT_LOAD].cur.data_s = p2[1].Integer.Value * 1000; 466 sc->sc_data[ACPIBAT_CAPACITY].cur.data_s = p2[2].Integer.Value * 1000; 467 sc->sc_data[ACPIBAT_VOLTAGE].cur.data_s = p2[3].Integer.Value * 1000; 468 469 flags = 0; 470 if (sc->sc_data[ACPIBAT_CAPACITY].cur.data_s < 471 sc->sc_data[ACPIBAT_WCAPACITY].cur.data_s) 472 flags |= ENVSYS_WARN_UNDER; 473 if (status & ACPIBAT_ST_CRITICAL) 474 flags |= ENVSYS_WARN_CRITUNDER; 475 sc->sc_data[ACPIBAT_CAPACITY].warnflags = flags; 476 sc->sc_data[ACPIBAT_DISCHARGING].cur.data_s = 477 ((status & ACPIBAT_ST_DISCHARGING) != 0); 478 sc->sc_data[ACPIBAT_CHARGING].cur.data_s = 479 ((status & ACPIBAT_ST_CHARGING) != 0); 480 sc->sc_available = ABAT_ALV_STAT; 481 ABAT_UNLOCK(sc, s); 482 483 rv = AE_OK; 484 out: 485 AcpiOsFree(buf.Pointer); 486 return (rv); 487 } 488 489 #define SCALE(x) ((x)/1000000), (((x)%1000000)/1000) 490 #define CAPUNITS(sc) (ABAT_ISSET((sc), ABAT_F_PWRUNIT_MA)?"mAh":"mWh") 491 #define RATEUNITS(sc) (ABAT_ISSET((sc), ABAT_F_PWRUNIT_MA)?"mA":"mW") 492 static void 493 acpibat_print_info(struct acpibat_softc *sc) 494 { 495 const char *tech; 496 497 if (sc->sc_data[ACPIBAT_TECHNOLOGY].cur.data_s) 498 tech = "secondary"; 499 else 500 tech = "primary"; 501 502 printf("%s: %s battery, Design %d.%03d%s, Predicted %d.%03d%s" 503 "Warn %d.%03d%s Low %d.%03d%s\n", 504 sc->sc_dev.dv_xname, tech, 505 SCALE(sc->sc_data[ACPIBAT_DCAPACITY].cur.data_s), CAPUNITS(sc), 506 SCALE(sc->sc_data[ACPIBAT_LFCCAPACITY].cur.data_s),CAPUNITS(sc), 507 SCALE(sc->sc_data[ACPIBAT_WCAPACITY].cur.data_s), CAPUNITS(sc), 508 SCALE(sc->sc_data[ACPIBAT_LCAPACITY].cur.data_s), CAPUNITS(sc)); 509 } 510 511 static void 512 acpibat_print_stat(struct acpibat_softc *sc) 513 { 514 const char *capstat, *chargestat; 515 int percent, denom; 516 517 percent = 0; 518 519 if (sc->sc_data[ACPIBAT_CAPACITY].warnflags&ENVSYS_WARN_CRITUNDER) 520 capstat = "CRITICAL "; 521 else if (sc->sc_data[ACPIBAT_CAPACITY].warnflags&ENVSYS_WARN_UNDER) 522 capstat = "UNDER "; 523 else 524 capstat = ""; 525 if (sc->sc_data[ACPIBAT_CHARGING].cur.data_s) 526 chargestat = "charging"; 527 else if (sc->sc_data[ACPIBAT_DISCHARGING].cur.data_s) 528 chargestat = "discharging"; 529 else 530 chargestat = "idling"; 531 denom = sc->sc_data[ACPIBAT_DCAPACITY].cur.data_s / 100; 532 if (denom > 0) 533 percent = (sc->sc_data[ACPIBAT_CAPACITY].cur.data_s) / denom; 534 printf("%s: %s%s: %d.%03dV cap %d.%03d%s (%d%%) rate %d.%03d%s\n", 535 sc->sc_dev.dv_xname, 536 capstat, chargestat, 537 SCALE(sc->sc_data[ACPIBAT_VOLTAGE].cur.data_s), 538 SCALE(sc->sc_data[ACPIBAT_CAPACITY].cur.data_s), CAPUNITS(sc), 539 percent, 540 SCALE(sc->sc_data[ACPIBAT_LOAD].cur.data_s), RATEUNITS(sc)); 541 } 542 543 static void 544 acpibat_update(void *arg) 545 { 546 struct acpibat_softc *sc = arg; 547 548 if (sc->sc_available < ABAT_ALV_INFO) { 549 /* current information is invalid */ 550 #if 0 551 /* 552 * XXX: The driver sometimes unaware that the battery exist. 553 * (i.e. just after the boot or resuming) 554 * Thus, the driver should always check it here. 555 */ 556 if (sc->sc_available < ABAT_ALV_PRESENCE) 557 #endif 558 /* presence is invalid */ 559 if (acpibat_battery_present(sc)<0) { 560 /* error */ 561 printf("%s: cannot get battery presence.\n", 562 sc->sc_dev.dv_xname); 563 return; 564 } 565 if (ABAT_ISSET(sc, ABAT_F_PRESENT)) { 566 /* the battery is present. */ 567 if (ABAT_ISSET(sc, ABAT_F_VERBOSE)) 568 printf("%s: battery is present.\n", 569 sc->sc_dev.dv_xname); 570 if (ACPI_FAILURE(acpibat_get_info(sc))) 571 return; 572 if (ABAT_ISSET(sc, ABAT_F_VERBOSE)) 573 acpibat_print_info(sc); 574 } else { 575 /* the battery is not present. */ 576 if (ABAT_ISSET(sc, ABAT_F_VERBOSE)) 577 printf("%s: battery is not present.\n", 578 sc->sc_dev.dv_xname); 579 return; 580 } 581 } else { 582 /* current information is valid */ 583 if (!ABAT_ISSET(sc, ABAT_F_PRESENT)) { 584 /* the battery is not present. */ 585 return; 586 } 587 } 588 589 if (ACPI_FAILURE(acpibat_get_status(sc))) 590 return; 591 592 if (ABAT_ISSET(sc, ABAT_F_VERBOSE)) 593 acpibat_print_stat(sc); 594 } 595 596 /* 597 * acpibat_notify_handler: 598 * 599 * Callback from ACPI interrupt handler to notify us of an event. 600 */ 601 void 602 acpibat_notify_handler(ACPI_HANDLE handle, UINT32 notify, void *context) 603 { 604 struct acpibat_softc *sc = context; 605 int rv, s; 606 607 #ifdef ACPI_BAT_DEBUG 608 printf("%s: received notify message: 0x%x\n", 609 sc->sc_dev.dv_xname, notify); 610 #endif 611 612 switch (notify) { 613 case ACPI_NOTIFY_BusCheck: 614 break; 615 616 case ACPI_NOTIFY_BatteryInformationChanged: 617 ABAT_LOCK(sc, s); 618 acpibat_clear_presence(sc); 619 ABAT_UNLOCK(sc, s); 620 rv = AcpiOsQueueForExecution(OSD_PRIORITY_LO, 621 acpibat_update, sc); 622 if (rv != AE_OK) 623 printf("%s: unable to queue status check: %d\n", 624 sc->sc_dev.dv_xname, rv); 625 break; 626 627 case ACPI_NOTIFY_BatteryStatusChanged: 628 ABAT_LOCK(sc, s); 629 acpibat_clear_stat(sc); 630 ABAT_UNLOCK(sc, s); 631 rv = AcpiOsQueueForExecution(OSD_PRIORITY_LO, 632 acpibat_update, sc); 633 if (rv != AE_OK) 634 printf("%s: unable to queue status check: %d\n", 635 sc->sc_dev.dv_xname, rv); 636 break; 637 638 default: 639 printf("%s: received unknown notify message: 0x%x\n", 640 sc->sc_dev.dv_xname, notify); 641 } 642 } 643 644 void 645 acpibat_init_envsys(struct acpibat_softc *sc) 646 { 647 int capunit, rateunit, i; 648 const char *capstring, *ratestring; 649 650 #if 0 651 if (sc->sc_flags & ABAT_F_PWRUNIT_MA) { 652 #endif 653 /* XXX */ 654 sc->sc_sysmon.sme_ranges = acpibat_range_amp; 655 capunit = ENVSYS_SAMPHOUR; 656 capstring = "charge"; 657 rateunit = ENVSYS_SAMPS; 658 ratestring = "current"; 659 #if 0 660 } else { 661 sc->sc_sysmon.sme_ranges = acpibat_range_watt; 662 capunit = ENVSYS_SWATTHOUR; 663 capstring = "energy"; 664 rateunit = ENVSYS_SWATTS; 665 ratestring = "power"; 666 } 667 #endif 668 669 for (i = 0 ; i < ACPIBAT_NSENSORS; i++) { 670 sc->sc_data[i].sensor = sc->sc_info[i].sensor = i; 671 sc->sc_data[i].validflags |= (ENVSYS_FVALID | ENVSYS_FCURVALID); 672 sc->sc_info[i].validflags = ENVSYS_FVALID; 673 sc->sc_data[i].warnflags = 0; 674 } 675 INITDATA(ACPIBAT_PRESENT, ENVSYS_INDICATOR, "present"); 676 INITDATA(ACPIBAT_DCAPACITY, capunit, "design cap"); 677 INITDATA(ACPIBAT_LFCCAPACITY, capunit, "lfc cap"); 678 INITDATA(ACPIBAT_TECHNOLOGY, ENVSYS_INTEGER, "technology"); 679 INITDATA(ACPIBAT_DVOLTAGE, ENVSYS_SVOLTS_DC, "design voltage"); 680 INITDATA(ACPIBAT_WCAPACITY, capunit, "warn cap"); 681 INITDATA(ACPIBAT_LCAPACITY, capunit, "low cap"); 682 INITDATA(ACPIBAT_VOLTAGE, ENVSYS_SVOLTS_DC, "voltage"); 683 INITDATA(ACPIBAT_LOAD, rateunit, ratestring); 684 INITDATA(ACPIBAT_CAPACITY, capunit, capstring); 685 INITDATA(ACPIBAT_CHARGING, ENVSYS_INDICATOR, "charging"); 686 INITDATA(ACPIBAT_DISCHARGING, ENVSYS_INDICATOR, "discharging"); 687 688 /* 689 * ACPIBAT_CAPACITY is the "gas gauge". 690 * ACPIBAT_LFCCAPACITY is the "wear gauge". 691 */ 692 sc->sc_data[ACPIBAT_CAPACITY].validflags |= 693 ENVSYS_FMAXVALID | ENVSYS_FFRACVALID; 694 sc->sc_data[ACPIBAT_LFCCAPACITY].validflags |= 695 ENVSYS_FMAXVALID | ENVSYS_FFRACVALID; 696 697 sc->sc_sysmon.sme_sensor_info = sc->sc_info; 698 sc->sc_sysmon.sme_sensor_data = sc->sc_data; 699 sc->sc_sysmon.sme_cookie = sc; 700 sc->sc_sysmon.sme_gtredata = acpibat_gtredata; 701 sc->sc_sysmon.sme_streinfo = acpibat_streinfo; 702 sc->sc_sysmon.sme_nsensors = ACPIBAT_NSENSORS; 703 sc->sc_sysmon.sme_envsys_version = 1000; 704 705 if (sysmon_envsys_register(&sc->sc_sysmon)) 706 printf("%s: unable to register with sysmon\n", 707 sc->sc_dev.dv_xname); 708 } 709 710 int 711 acpibat_gtredata(struct sysmon_envsys *sme, struct envsys_tre_data *tred) 712 { 713 struct acpibat_softc *sc = sme->sme_cookie; 714 715 acpibat_update(sc); 716 717 /* XXX locking */ 718 /* XXX it should be checked whether info/stat is valid. */ 719 *tred = sc->sc_data[tred->sensor]; 720 /* XXX locking */ 721 722 return (0); 723 } 724 725 int 726 acpibat_streinfo(struct sysmon_envsys *sme, struct envsys_basic_info *binfo) 727 { 728 729 /* XXX Not implemented */ 730 binfo->validflags = 0; 731 732 return (0); 733 } 734