1 /* $NetBSD: pbbat.c,v 1.2 2025/04/09 00:10:02 nat Exp $ */ 2 3 /*- 4 * Copyright (c) 2025 Nathanial Sloss <nathanialsloss (at) yahoo.com.au> 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 * 16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 /* Based on acpibat(4). */ 30 31 /*- 32 * Copyright (c) 2003 The NetBSD Foundation, Inc. 33 * All rights reserved. 34 * 35 * This code is derived from software contributed to The NetBSD Foundation 36 * by Charles M. Hannum of By Noon Software, Inc. 37 * 38 * Redistribution and use in source and binary forms, with or without 39 * modification, are permitted provided that the following conditions 40 * are met: 41 * 1. Redistributions of source code must retain the above copyright 42 * notice, this list of conditions and the following disclaimer. 43 * 2. Redistributions in binary form must reproduce the above copyright 44 * notice, this list of conditions and the following disclaimer in the 45 * documentation and/or other materials provided with the distribution. 46 * 47 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 48 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 49 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 50 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 51 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 52 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 53 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 54 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 55 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 56 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 57 * POSSIBILITY OF SUCH DAMAGE. 58 */ 59 60 /* 61 * Copyright 2001 Bill Sommerfeld. 62 * All rights reserved. 63 * 64 * Redistribution and use in source and binary forms, with or without 65 * modification, are permitted provided that the following conditions 66 * are met: 67 * 1. Redistributions of source code must retain the above copyright 68 * notice, this list of conditions and the following disclaimer. 69 * 2. Redistributions in binary form must reproduce the above copyright 70 * notice, this list of conditions and the following disclaimer in the 71 * documentation and/or other materials provided with the distribution. 72 * 3. All advertising materials mentioning features or use of this software 73 * must display the following acknowledgement: 74 * This product includes software developed for the NetBSD Project by 75 * Wasabi Systems, Inc. 76 * 4. The name of Wasabi Systems, Inc. may not be used to endorse 77 * or promote products derived from this software without specific prior 78 * written permission. 79 * 80 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 81 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 82 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 83 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 84 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 85 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 86 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 87 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 88 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 89 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 90 * POSSIBILITY OF SUCH DAMAGE. 91 */ 92 93 /* AC Adaptor attachment and logic based on macppc/smartbat(4). */ 94 95 /*- 96 * Copyright (c) 2007 Michael Lorenz 97 * 2008 Magnus Henoch 98 * All rights reserved. 99 * 100 * Redistribution and use in source and binary forms, with or without 101 * modification, are permitted provided that the following conditions 102 * are met: 103 * 1. Redistributions of source code must retain the above copyright 104 * notice, this list of conditions and the following disclaimer. 105 * 2. Redistributions in binary form must reproduce the above copyright 106 * notice, this list of conditions and the following disclaimer in the 107 * documentation and/or other materials provided with the distribution. 108 * 109 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 110 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 111 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 112 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 113 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 114 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 115 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 116 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 117 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 118 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 119 * POSSIBILITY OF SUCH DAMAGE. 120 */ 121 122 #include <sys/cdefs.h> 123 __KERNEL_RCSID(0, "$NetBSD: pbbat.c,v 1.2 2025/04/09 00:10:02 nat Exp $"); 124 125 #include <sys/param.h> 126 #include <sys/device.h> 127 #include <sys/kmem.h> 128 #include <sys/types.h> 129 #include <sys/systm.h> 130 131 #include <dev/sysmon/sysmonvar.h> 132 133 #include <machine/param.h> 134 #include <machine/cpu.h> 135 136 #include <mac68k/dev/pm_direct.h> 137 138 static int pbbatmatch(device_t, cfdata_t, void *); 139 static void pbbatattach(device_t, device_t, void *); 140 141 static void bat_get_pm_limits(device_t); 142 static uint16_t bat_get_status(device_t); 143 static void bat_init_envsys(device_t); 144 static void bat_update_status(void *); 145 146 extern int pm_pmgrop_pm1(PMData *); 147 148 struct pbatt_softc { 149 device_t sc_dev; 150 struct sysmon_envsys *sc_ac_sme; 151 envsys_data_t sc_ac_sensor[1]; 152 struct sysmon_pswitch sc_sm_acpower; 153 int8_t sc_ac_state; 154 struct sysmon_envsys *sc_bat_sme; 155 envsys_data_t *sc_bat_sensor; 156 struct timeval sc_last; 157 kmutex_t sc_mutex; 158 int32_t sc_dcapacity; 159 int32_t sc_dvoltage; 160 int32_t sc_disrate; 161 int32_t sc_chargerate; 162 int32_t sc_empty; 163 int32_t sc_lcapacity; 164 int32_t sc_wcapacity; 165 int sc_present; 166 }; 167 168 #define PBBAT_AC_PRESENT 0 169 170 /* AC Adaptor states */ 171 #define PBBAT_AC_UNKNOWN -1 172 #define PBBAT_AC_DISCONNECTED 0 173 #define PBBAT_AC_CONNECTED 1 174 175 enum { 176 PBBAT_PRESENT = 0, 177 PBBAT_DVOLTAGE = 1, 178 PBBAT_VOLTAGE = 2, 179 PBBAT_DCAPACITY = 3, 180 PBBAT_LFCCAPACITY = 4, 181 PBBAT_CAPACITY = 5, 182 PBBAT_CHARGERATE = 6, 183 PBBAT_DISCHARGERATE = 7, 184 PBBAT_CHARGING = 8, 185 PBBAT_CHARGE_STATE = 9, 186 PBBAT_COUNT = 10 187 }; 188 189 /* Driver definition */ 190 CFATTACH_DECL_NEW(pbbat, sizeof(struct pbatt_softc), 191 pbbatmatch, pbbatattach, NULL, NULL); 192 193 /* Battery voltage definitions (mV) */ 194 #define VOLTS_DESIGN 6000 195 #define WATTS_DESIGN 60000 /* mW */ 196 #define VOLTS_CHARGING 6600 197 #define VOLTS_NOBATT 7700 198 199 #define VOLTS_MULTI 35 /* PM value multiplier. */ 200 #define LIMIT_SCALE (100 * 100 / (VOLTS_DESIGN / 1000)) 201 202 #define PM_BATT_VOLTS 0x68 /* 0x69 is a duplicate. */ 203 #define PM_BATT_LIMITS 0x6a 204 205 static int 206 pbbatmatch(device_t parent, cfdata_t cf, void *aux) 207 { 208 switch (mac68k_machine.machineid) { 209 case MACH_MACPB140: 210 case MACH_MACPB145: 211 case MACH_MACPB160: 212 case MACH_MACPB165: 213 case MACH_MACPB165C: 214 case MACH_MACPB170: 215 case MACH_MACPB180: 216 case MACH_MACPB180C: 217 return 1; 218 break; 219 default: 220 return 0; 221 } 222 223 return 0; 224 } 225 226 static void 227 pbbatattach(device_t parent, device_t self, void *aux) 228 { 229 struct pbatt_softc *sc = device_private(self); 230 231 aprint_naive(": PowerBook Battery\n"); 232 aprint_normal(": PowerBook Battery\n"); 233 234 mutex_init(&sc->sc_mutex, MUTEX_DEFAULT, IPL_NONE); 235 sc->sc_bat_sensor = kmem_zalloc(PBBAT_COUNT * 236 sizeof(*sc->sc_bat_sensor), KM_SLEEP); 237 238 memset(&sc->sc_sm_acpower, 0, sizeof(struct sysmon_pswitch)); 239 sc->sc_ac_state = PBBAT_AC_UNKNOWN; 240 sc->sc_sm_acpower.smpsw_name = "AC Power"; 241 sc->sc_sm_acpower.smpsw_type = PSWITCH_TYPE_ACADAPTER; 242 if (sysmon_pswitch_register(&sc->sc_sm_acpower) != 0) 243 printf("%s: unable to register AC power status with sysmon\n", 244 device_xname(sc->sc_dev)); 245 246 config_interrupts(self, bat_init_envsys); 247 } 248 249 static void 250 bat_get_pm_limits(device_t self) 251 { 252 int s; 253 int rval; 254 PMData pmdata; 255 struct pbatt_softc *sc = device_private(self); 256 257 s = splhigh(); 258 259 pmdata.command = PM_BATT_LIMITS; 260 pmdata.num_data = 0; 261 pmdata.data[0] = pmdata.data[1] = 0; 262 pmdata.s_buf = pmdata.data; 263 pmdata.r_buf = pmdata.data; 264 rval = pm_pmgrop_pm1(&pmdata); 265 if (rval != 0) { 266 #ifdef ADB_DEBUG 267 if (adb_debug) 268 printf("pm: PM is not ready. error code=%08x\n", rval); 269 #endif 270 splx(s); 271 return; 272 } 273 274 splx(s); 275 276 sc->sc_empty = (pmdata.data[1] & 0xff) * VOLTS_MULTI; 277 sc->sc_lcapacity = (pmdata.data[0] & 0xff) * VOLTS_MULTI; 278 sc->sc_wcapacity = sc->sc_lcapacity * 12 / 10; 279 280 return; 281 } 282 283 static uint16_t 284 bat_get_voltage(void) 285 { 286 int s; 287 int rval; 288 PMData pmdata; 289 290 s = splhigh(); 291 292 pmdata.command = PM_BATT_VOLTS; 293 pmdata.num_data = 0; 294 pmdata.data[0] = pmdata.data[1] = 0; 295 pmdata.s_buf = pmdata.data; 296 pmdata.r_buf = pmdata.data; 297 rval = pm_pmgrop_pm1(&pmdata); 298 if (rval != 0) { 299 #ifdef ADB_DEBUG 300 if (adb_debug) 301 printf("pm: PM is not ready. error code=%08x\n", rval); 302 #endif 303 splx(s); 304 return 0; 305 } 306 307 splx(s); 308 309 return (pmdata.data[1] & 0xff) * VOLTS_MULTI; 310 } 311 312 static void 313 bat_refresh(struct sysmon_envsys *sme, envsys_data_t *edata) 314 { 315 device_t self = sme->sme_cookie; 316 struct pbatt_softc *sc = device_private(self); 317 struct timeval tv, tmp; 318 319 tmp.tv_sec = 10; 320 tmp.tv_usec = 0; 321 322 microuptime(&tv); 323 timersub(&tv, &tmp, &tv); 324 if (timercmp(&tv, &sc->sc_last, <) != 0) 325 return; 326 327 bat_update_status(self); 328 } 329 330 static void 331 bat_refresh_ac(struct sysmon_envsys *sme, envsys_data_t *edata) 332 { 333 struct pbatt_softc *sc = sme->sme_cookie; 334 int which = edata->sensor; 335 336 mutex_enter(&sc->sc_mutex); 337 switch (which) { 338 case PBBAT_AC_PRESENT: 339 edata->value_cur = 340 (sc->sc_ac_state == PBBAT_AC_CONNECTED ? 1 : 0); 341 edata->state = ENVSYS_SVALID; 342 break; 343 default: 344 edata->value_cur = 0; 345 edata->state = ENVSYS_SINVALID; 346 } 347 mutex_exit(&sc->sc_mutex); 348 } 349 350 static void 351 bat_get_info(device_t dv) 352 { 353 struct pbatt_softc *sc = device_private(dv); 354 int capunit; 355 356 capunit = ENVSYS_SWATTHOUR; 357 358 sc->sc_bat_sensor[PBBAT_DCAPACITY].units = capunit; 359 sc->sc_bat_sensor[PBBAT_CHARGERATE].units = capunit; 360 sc->sc_bat_sensor[PBBAT_DISCHARGERATE].units = capunit; 361 sc->sc_bat_sensor[PBBAT_LFCCAPACITY].units = capunit; 362 sc->sc_bat_sensor[PBBAT_CAPACITY].units = capunit; 363 364 /* Design capacity. */ 365 366 /* 367 * This is a guesstimate - repacked battery runs at 10 Watts/h for an 368 * 1 hour. 369 */ 370 371 sc->sc_bat_sensor[PBBAT_DCAPACITY].value_cur = WATTS_DESIGN * 1000; 372 sc->sc_bat_sensor[PBBAT_DCAPACITY].state = ENVSYS_SVALID; 373 374 /* Design voltage. */ 375 sc->sc_bat_sensor[PBBAT_DVOLTAGE].value_cur = VOLTS_DESIGN * 1000; 376 sc->sc_bat_sensor[PBBAT_DVOLTAGE].state = ENVSYS_SVALID; 377 378 sc->sc_bat_sensor[PBBAT_LFCCAPACITY].state = ENVSYS_SINVALID; 379 380 bat_get_pm_limits(dv); 381 382 sc->sc_bat_sensor[PBBAT_CAPACITY].value_max = 100 * 1000 * 1000; 383 } 384 385 static void 386 bat_get_limits(struct sysmon_envsys *sme, envsys_data_t *edata, 387 sysmon_envsys_lim_t *limits, uint32_t *props) 388 { 389 device_t self = sme->sme_cookie; 390 struct pbatt_softc *sc = device_private(self); 391 392 if (edata->sensor != PBBAT_CAPACITY) 393 return; 394 395 limits->sel_critmin = sc->sc_lcapacity * LIMIT_SCALE; 396 limits->sel_warnmin = sc->sc_wcapacity * LIMIT_SCALE; 397 398 *props |= PROP_BATTCAP | PROP_BATTWARN | PROP_DRIVER_LIMITS; 399 } 400 401 static void 402 bat_update_status(void *arg) 403 { 404 device_t dv = arg; 405 struct pbatt_softc *sc = device_private(dv); 406 int i; 407 uint16_t val; 408 409 mutex_enter(&sc->sc_mutex); 410 411 val = bat_get_status(dv); 412 if (val != 0) { 413 if (sc->sc_present == 0) 414 bat_get_info(dv); 415 } else { 416 i = PBBAT_DVOLTAGE; 417 while (i < PBBAT_COUNT) { 418 sc->sc_bat_sensor[i].state = ENVSYS_SINVALID; 419 i++; 420 } 421 } 422 423 sc->sc_present = (val >= VOLTS_NOBATT ? 0 : 1); 424 425 microuptime(&sc->sc_last); 426 427 mutex_exit(&sc->sc_mutex); 428 } 429 430 static void 431 bat_init_envsys(device_t dv) 432 { 433 struct pbatt_softc *sc = device_private(dv); 434 int i; 435 436 #define INITDATA(index, unit, string) \ 437 sc->sc_ac_sensor[index].units = unit; \ 438 sc->sc_ac_sensor[index].state = ENVSYS_SINVALID; \ 439 snprintf(sc->sc_ac_sensor[index].desc, \ 440 sizeof(sc->sc_ac_sensor[index].desc), "%s", string); 441 442 INITDATA(PBBAT_AC_PRESENT, ENVSYS_INDICATOR, "connected"); 443 #undef INITDATA 444 445 sc->sc_ac_sme = sysmon_envsys_create(); 446 447 if (sysmon_envsys_sensor_attach(sc->sc_ac_sme, &sc->sc_ac_sensor[0])) { 448 sysmon_envsys_destroy(sc->sc_ac_sme); 449 return; 450 } 451 452 sc->sc_ac_sme->sme_name = "AC Adaptor"; 453 sc->sc_ac_sme->sme_cookie = sc; 454 sc->sc_ac_sme->sme_refresh = bat_refresh_ac; 455 sc->sc_ac_sme->sme_class = SME_CLASS_ACADAPTER; 456 457 if (sysmon_envsys_register(sc->sc_ac_sme)) { 458 aprint_error("%s: unable to register AC with sysmon\n", 459 device_xname(sc->sc_dev)); 460 sysmon_envsys_destroy(sc->sc_ac_sme); 461 } 462 463 #define INITDATA(index, unit, string) \ 464 do { \ 465 sc->sc_bat_sensor[index].state = ENVSYS_SVALID; \ 466 sc->sc_bat_sensor[index].units = unit; \ 467 (void)strlcpy(sc->sc_bat_sensor[index].desc, string, \ 468 sizeof(sc->sc_bat_sensor[index].desc)); \ 469 } while (/* CONSTCOND */ 0) 470 471 INITDATA(PBBAT_PRESENT, ENVSYS_INDICATOR, "present"); 472 INITDATA(PBBAT_DCAPACITY, ENVSYS_SWATTHOUR, "design cap"); 473 INITDATA(PBBAT_LFCCAPACITY, ENVSYS_SWATTHOUR, "last full cap"); 474 INITDATA(PBBAT_DVOLTAGE, ENVSYS_SVOLTS_DC, "design voltage"); 475 INITDATA(PBBAT_VOLTAGE, ENVSYS_SVOLTS_DC, "voltage"); 476 INITDATA(PBBAT_CAPACITY, ENVSYS_SWATTHOUR, "charge"); 477 INITDATA(PBBAT_CHARGERATE, ENVSYS_SWATTS, "charge rate"); 478 INITDATA(PBBAT_DISCHARGERATE, ENVSYS_SWATTS, "discharge rate"); 479 INITDATA(PBBAT_CHARGING, ENVSYS_BATTERY_CHARGE, "charging"); 480 INITDATA(PBBAT_CHARGE_STATE, ENVSYS_BATTERY_CAPACITY, "charge state"); 481 482 #undef INITDATA 483 484 sc->sc_bat_sensor[PBBAT_CHARGE_STATE].value_cur = 485 ENVSYS_BATTERY_CAPACITY_NORMAL; 486 487 sc->sc_bat_sensor[PBBAT_CAPACITY].flags |= 488 ENVSYS_FPERCENT | ENVSYS_FVALID_MAX | ENVSYS_FMONLIMITS; 489 490 sc->sc_bat_sensor[PBBAT_CHARGE_STATE].flags |= ENVSYS_FMONSTCHANGED; 491 492 /* Disable userland monitoring on these sensors. */ 493 sc->sc_bat_sensor[PBBAT_VOLTAGE].flags = ENVSYS_FMONNOTSUPP; 494 sc->sc_bat_sensor[PBBAT_CHARGERATE].flags = ENVSYS_FMONNOTSUPP; 495 sc->sc_bat_sensor[PBBAT_DISCHARGERATE].flags = ENVSYS_FMONNOTSUPP; 496 sc->sc_bat_sensor[PBBAT_DCAPACITY].flags = ENVSYS_FMONNOTSUPP; 497 sc->sc_bat_sensor[PBBAT_LFCCAPACITY].flags = ENVSYS_FMONNOTSUPP; 498 sc->sc_bat_sensor[PBBAT_DVOLTAGE].flags = ENVSYS_FMONNOTSUPP; 499 500 sc->sc_bat_sensor[PBBAT_CHARGERATE].flags |= ENVSYS_FHAS_ENTROPY; 501 sc->sc_bat_sensor[PBBAT_DISCHARGERATE].flags |= ENVSYS_FHAS_ENTROPY; 502 503 sc->sc_bat_sme = sysmon_envsys_create(); 504 505 for (i = 0; i < PBBAT_COUNT; i++) { 506 if (sysmon_envsys_sensor_attach(sc->sc_bat_sme, 507 &sc->sc_bat_sensor[i])) 508 goto fail; 509 } 510 511 sc->sc_bat_sme->sme_name = device_xname(dv); 512 sc->sc_bat_sme->sme_cookie = dv; 513 sc->sc_bat_sme->sme_refresh = bat_refresh; 514 sc->sc_bat_sme->sme_class = SME_CLASS_BATTERY; 515 sc->sc_bat_sme->sme_flags = SME_POLL_ONLY; 516 sc->sc_bat_sme->sme_get_limits = bat_get_limits; 517 518 if (sysmon_envsys_register(sc->sc_bat_sme)) 519 goto fail; 520 521 bat_get_pm_limits(dv); 522 bat_update_status(dv); 523 524 return; 525 fail: 526 aprint_error("failed to initialize sysmon\n"); 527 528 sysmon_envsys_destroy(sc->sc_bat_sme); 529 kmem_free(sc->sc_bat_sensor, PBBAT_COUNT * sizeof(*sc->sc_bat_sensor)); 530 531 sc->sc_bat_sme = NULL; 532 sc->sc_bat_sensor = NULL; 533 } 534 535 static uint16_t 536 bat_get_status(device_t dv) 537 { 538 struct pbatt_softc *sc = device_private(dv); 539 uint16_t val; 540 541 val = bat_get_voltage(); 542 543 sc->sc_bat_sensor[PBBAT_PRESENT].state = ENVSYS_SVALID; 544 sc->sc_bat_sensor[PBBAT_PRESENT].value_cur = 1; 545 546 if (val > VOLTS_NOBATT) { 547 sc->sc_bat_sensor[PBBAT_PRESENT].value_cur = 0; 548 sc->sc_bat_sensor[PBBAT_CHARGING].state = ENVSYS_SVALID; 549 sc->sc_bat_sensor[PBBAT_CHARGING].value_cur = 0; 550 sc->sc_bat_sensor[PBBAT_CHARGERATE].state = ENVSYS_SINVALID; 551 sc->sc_bat_sensor[PBBAT_DISCHARGERATE].state = ENVSYS_SINVALID; 552 if (sc->sc_ac_state != PBBAT_AC_CONNECTED) { 553 sysmon_pswitch_event(&sc->sc_sm_acpower, 554 PSWITCH_EVENT_PRESSED); 555 } 556 sc->sc_ac_state = PBBAT_AC_CONNECTED; 557 } else if (val > VOLTS_CHARGING) { 558 sc->sc_bat_sensor[PBBAT_CHARGING].state = ENVSYS_SVALID; 559 if (sc->sc_chargerate) 560 sc->sc_bat_sensor[PBBAT_CHARGING].value_cur = 1; 561 else 562 sc->sc_bat_sensor[PBBAT_CHARGING].value_cur = 0; 563 sc->sc_bat_sensor[PBBAT_CHARGERATE].state = ENVSYS_SVALID; 564 sc->sc_bat_sensor[PBBAT_CHARGERATE].value_cur = 565 sc->sc_chargerate; 566 sc->sc_bat_sensor[PBBAT_DISCHARGERATE].state = ENVSYS_SINVALID; 567 if (sc->sc_ac_state != PBBAT_AC_CONNECTED) { 568 sysmon_pswitch_event(&sc->sc_sm_acpower, 569 PSWITCH_EVENT_PRESSED); 570 } 571 sc->sc_ac_state = PBBAT_AC_CONNECTED; 572 } else { 573 sc->sc_bat_sensor[PBBAT_CHARGING].value_cur = 0; 574 sc->sc_bat_sensor[PBBAT_CHARGING].state = ENVSYS_SVALID; 575 sc->sc_bat_sensor[PBBAT_CHARGERATE].state = ENVSYS_SINVALID; 576 sc->sc_bat_sensor[PBBAT_DISCHARGERATE].state = ENVSYS_SVALID; 577 sc->sc_bat_sensor[PBBAT_DISCHARGERATE].value_cur = 578 sc->sc_disrate; 579 if (sc->sc_ac_state != PBBAT_AC_DISCONNECTED) { 580 sysmon_pswitch_event(&sc->sc_sm_acpower, 581 PSWITCH_EVENT_RELEASED); 582 } 583 sc->sc_ac_state = PBBAT_AC_DISCONNECTED; 584 } 585 586 /* Remaining capacity. */ 587 sc->sc_chargerate = sc->sc_bat_sensor[PBBAT_CAPACITY].value_cur; 588 sc->sc_disrate = sc->sc_bat_sensor[PBBAT_CAPACITY].value_cur; 589 590 sc->sc_bat_sensor[PBBAT_CAPACITY].value_cur = 591 (val - sc->sc_empty) * 10 * LIMIT_SCALE; 592 593 sc->sc_chargerate = 594 (sc->sc_bat_sensor[PBBAT_CAPACITY].value_cur - sc->sc_chargerate) * 10; 595 sc->sc_disrate = 596 (sc->sc_disrate - sc->sc_bat_sensor[PBBAT_CAPACITY].value_cur) * 10; 597 598 /* Battery voltage. */ 599 sc->sc_bat_sensor[PBBAT_VOLTAGE].value_cur = val * 1000; 600 sc->sc_bat_sensor[PBBAT_VOLTAGE].state = 601 (val >= VOLTS_NOBATT ? ENVSYS_SINVALID : ENVSYS_SVALID); 602 603 if (val < sc->sc_lcapacity) { 604 sc->sc_bat_sensor[PBBAT_CAPACITY].state = ENVSYS_SCRITUNDER; 605 sc->sc_bat_sensor[PBBAT_CHARGE_STATE].value_cur = 606 ENVSYS_BATTERY_CAPACITY_CRITICAL; 607 } else if (val < sc->sc_wcapacity) { 608 sc->sc_bat_sensor[PBBAT_CAPACITY].state = ENVSYS_SWARNUNDER; 609 sc->sc_bat_sensor[PBBAT_CHARGE_STATE].value_cur = 610 ENVSYS_BATTERY_CAPACITY_WARNING; 611 } else { 612 sc->sc_bat_sensor[PBBAT_CHARGE_STATE].value_cur = 613 ENVSYS_BATTERY_CAPACITY_NORMAL; 614 } 615 616 sc->sc_bat_sensor[PBBAT_CHARGE_STATE].state = ENVSYS_SVALID; 617 618 return val; 619 } 620