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