1 1.123 christos /* $NetBSD: acpi_bat.c,v 1.123 2024/04/27 00:40:06 christos Exp $ */ 2 1.26 mycroft 3 1.26 mycroft /*- 4 1.26 mycroft * Copyright (c) 2003 The NetBSD Foundation, Inc. 5 1.26 mycroft * All rights reserved. 6 1.26 mycroft * 7 1.26 mycroft * This code is derived from software contributed to The NetBSD Foundation 8 1.26 mycroft * by Charles M. Hannum of By Noon Software, Inc. 9 1.26 mycroft * 10 1.26 mycroft * Redistribution and use in source and binary forms, with or without 11 1.26 mycroft * modification, are permitted provided that the following conditions 12 1.26 mycroft * are met: 13 1.26 mycroft * 1. Redistributions of source code must retain the above copyright 14 1.26 mycroft * notice, this list of conditions and the following disclaimer. 15 1.26 mycroft * 2. Redistributions in binary form must reproduce the above copyright 16 1.26 mycroft * notice, this list of conditions and the following disclaimer in the 17 1.26 mycroft * documentation and/or other materials provided with the distribution. 18 1.26 mycroft * 19 1.26 mycroft * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 1.26 mycroft * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.26 mycroft * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.26 mycroft * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 1.26 mycroft * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 1.26 mycroft * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.26 mycroft * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.26 mycroft * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.26 mycroft * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.26 mycroft * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.26 mycroft * POSSIBILITY OF SUCH DAMAGE. 30 1.26 mycroft */ 31 1.1 sommerfe 32 1.1 sommerfe /* 33 1.1 sommerfe * Copyright 2001 Bill Sommerfeld. 34 1.1 sommerfe * All rights reserved. 35 1.1 sommerfe * 36 1.1 sommerfe * Redistribution and use in source and binary forms, with or without 37 1.1 sommerfe * modification, are permitted provided that the following conditions 38 1.1 sommerfe * are met: 39 1.1 sommerfe * 1. Redistributions of source code must retain the above copyright 40 1.1 sommerfe * notice, this list of conditions and the following disclaimer. 41 1.1 sommerfe * 2. Redistributions in binary form must reproduce the above copyright 42 1.1 sommerfe * notice, this list of conditions and the following disclaimer in the 43 1.1 sommerfe * documentation and/or other materials provided with the distribution. 44 1.1 sommerfe * 3. All advertising materials mentioning features or use of this software 45 1.1 sommerfe * must display the following acknowledgement: 46 1.1 sommerfe * This product includes software developed for the NetBSD Project by 47 1.1 sommerfe * Wasabi Systems, Inc. 48 1.1 sommerfe * 4. The name of Wasabi Systems, Inc. may not be used to endorse 49 1.1 sommerfe * or promote products derived from this software without specific prior 50 1.1 sommerfe * written permission. 51 1.1 sommerfe * 52 1.1 sommerfe * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 53 1.1 sommerfe * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 54 1.1 sommerfe * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 55 1.1 sommerfe * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 56 1.1 sommerfe * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 57 1.1 sommerfe * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 58 1.1 sommerfe * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 59 1.1 sommerfe * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 60 1.1 sommerfe * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 61 1.1 sommerfe * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 62 1.1 sommerfe * POSSIBILITY OF SUCH DAMAGE. 63 1.1 sommerfe */ 64 1.1 sommerfe 65 1.1 sommerfe /* 66 1.1 sommerfe * ACPI Battery Driver. 67 1.1 sommerfe * 68 1.1 sommerfe * ACPI defines two different battery device interfaces: "Control 69 1.1 sommerfe * Method" batteries, in which AML methods are defined in order to get 70 1.1 sommerfe * battery status and set battery alarm thresholds, and a "Smart 71 1.1 sommerfe * Battery" device, which is an SMbus device accessed through the ACPI 72 1.1 sommerfe * Embedded Controller device. 73 1.1 sommerfe * 74 1.1 sommerfe * This driver is for the "Control Method"-style battery only. 75 1.1 sommerfe */ 76 1.1 sommerfe 77 1.1 sommerfe #include <sys/cdefs.h> 78 1.123 christos __KERNEL_RCSID(0, "$NetBSD: acpi_bat.c,v 1.123 2024/04/27 00:40:06 christos Exp $"); 79 1.1 sommerfe 80 1.1 sommerfe #include <sys/param.h> 81 1.84 jruoho #include <sys/condvar.h> 82 1.84 jruoho #include <sys/device.h> 83 1.84 jruoho #include <sys/kernel.h> 84 1.81 jruoho #include <sys/kmem.h> 85 1.83 jruoho #include <sys/module.h> 86 1.46 xtraeme #include <sys/mutex.h> 87 1.84 jruoho #include <sys/systm.h> 88 1.77 jruoho 89 1.1 sommerfe #include <dev/acpi/acpireg.h> 90 1.1 sommerfe #include <dev/acpi/acpivar.h> 91 1.1 sommerfe 92 1.77 jruoho #define _COMPONENT ACPI_BAT_COMPONENT 93 1.77 jruoho ACPI_MODULE_NAME ("acpi_bat") 94 1.73 mlelstv 95 1.102 jruoho #define ACPI_NOTIFY_BAT_STATUS 0x80 96 1.102 jruoho #define ACPI_NOTIFY_BAT_INFO 0x81 97 1.102 jruoho 98 1.76 jruoho /* 99 1.76 jruoho * Sensor indexes. 100 1.76 jruoho */ 101 1.76 jruoho enum { 102 1.76 jruoho ACPIBAT_PRESENT = 0, 103 1.90 jruoho ACPIBAT_DVOLTAGE = 1, 104 1.90 jruoho ACPIBAT_VOLTAGE = 2, 105 1.90 jruoho ACPIBAT_DCAPACITY = 3, 106 1.90 jruoho ACPIBAT_LFCCAPACITY = 4, 107 1.90 jruoho ACPIBAT_CAPACITY = 5, 108 1.90 jruoho ACPIBAT_CHARGERATE = 6, 109 1.90 jruoho ACPIBAT_DISCHARGERATE = 7, 110 1.90 jruoho ACPIBAT_CHARGING = 8, 111 1.90 jruoho ACPIBAT_CHARGE_STATE = 9, 112 1.90 jruoho ACPIBAT_COUNT = 10 113 1.76 jruoho }; 114 1.76 jruoho 115 1.76 jruoho /* 116 1.76 jruoho * Battery Information, _BIF 117 1.76 jruoho * (ACPI 3.0, sec. 10.2.2.1). 118 1.76 jruoho */ 119 1.76 jruoho enum { 120 1.76 jruoho ACPIBAT_BIF_UNIT = 0, 121 1.76 jruoho ACPIBAT_BIF_DCAPACITY = 1, 122 1.76 jruoho ACPIBAT_BIF_LFCCAPACITY = 2, 123 1.76 jruoho ACPIBAT_BIF_TECHNOLOGY = 3, 124 1.76 jruoho ACPIBAT_BIF_DVOLTAGE = 4, 125 1.76 jruoho ACPIBAT_BIF_WCAPACITY = 5, 126 1.76 jruoho ACPIBAT_BIF_LCAPACITY = 6, 127 1.76 jruoho ACPIBAT_BIF_GRANULARITY1 = 7, 128 1.76 jruoho ACPIBAT_BIF_GRANULARITY2 = 8, 129 1.76 jruoho ACPIBAT_BIF_MODEL = 9, 130 1.76 jruoho ACPIBAT_BIF_SERIAL = 10, 131 1.76 jruoho ACPIBAT_BIF_TYPE = 11, 132 1.76 jruoho ACPIBAT_BIF_OEM = 12, 133 1.76 jruoho ACPIBAT_BIF_COUNT = 13 134 1.76 jruoho }; 135 1.76 jruoho 136 1.76 jruoho /* 137 1.76 jruoho * Battery Status, _BST 138 1.76 jruoho * (ACPI 3.0, sec. 10.2.2.3). 139 1.76 jruoho */ 140 1.76 jruoho enum { 141 1.76 jruoho ACPIBAT_BST_STATE = 0, 142 1.76 jruoho ACPIBAT_BST_RATE = 1, 143 1.76 jruoho ACPIBAT_BST_CAPACITY = 2, 144 1.76 jruoho ACPIBAT_BST_VOLTAGE = 3, 145 1.76 jruoho ACPIBAT_BST_COUNT = 4 146 1.76 jruoho }; 147 1.14 explorer 148 1.1 sommerfe struct acpibat_softc { 149 1.77 jruoho struct acpi_devnode *sc_node; 150 1.77 jruoho struct sysmon_envsys *sc_sme; 151 1.108 jruoho struct timeval sc_last; 152 1.81 jruoho envsys_data_t *sc_sensor; 153 1.77 jruoho kmutex_t sc_mutex; 154 1.77 jruoho kcondvar_t sc_condvar; 155 1.111 jruoho int32_t sc_dcapacity; 156 1.111 jruoho int32_t sc_dvoltage; 157 1.87 jruoho int32_t sc_lcapacity; 158 1.87 jruoho int32_t sc_wcapacity; 159 1.78 jruoho int sc_present; 160 1.121 riastrad bool sc_dying; 161 1.1 sommerfe }; 162 1.1 sommerfe 163 1.117 thorpej static const struct device_compatible_entry compat_data[] = { 164 1.117 thorpej { .compat = "PNP0C0A" }, 165 1.117 thorpej DEVICE_COMPAT_EOL 166 1.33 kochi }; 167 1.33 kochi 168 1.11 explorer #define ACPIBAT_PWRUNIT_MA 0x00000001 /* mA not mW */ 169 1.14 explorer #define ACPIBAT_ST_DISCHARGING 0x00000001 /* battery is discharging */ 170 1.14 explorer #define ACPIBAT_ST_CHARGING 0x00000002 /* battery is charging */ 171 1.14 explorer #define ACPIBAT_ST_CRITICAL 0x00000004 /* battery is critical */ 172 1.11 explorer 173 1.11 explorer /* 174 1.88 jruoho * A value used when _BST or _BIF is temporarily unknown. 175 1.76 jruoho */ 176 1.76 jruoho #define ACPIBAT_VAL_UNKNOWN 0xFFFFFFFF 177 1.76 jruoho 178 1.76 jruoho #define ACPIBAT_VAL_ISVALID(x) \ 179 1.76 jruoho (((x) != ACPIBAT_VAL_UNKNOWN) ? ENVSYS_SVALID : ENVSYS_SINVALID) 180 1.76 jruoho 181 1.77 jruoho static int acpibat_match(device_t, cfdata_t, void *); 182 1.77 jruoho static void acpibat_attach(device_t, device_t, void *); 183 1.80 jruoho static int acpibat_detach(device_t, int); 184 1.77 jruoho static int acpibat_get_sta(device_t); 185 1.105 jruoho static ACPI_OBJECT *acpibat_get_object(ACPI_HANDLE, const char *, uint32_t); 186 1.77 jruoho static void acpibat_get_info(device_t); 187 1.90 jruoho static void acpibat_print_info(device_t, ACPI_OBJECT *); 188 1.77 jruoho static void acpibat_get_status(device_t); 189 1.77 jruoho static void acpibat_update_info(void *); 190 1.77 jruoho static void acpibat_update_status(void *); 191 1.77 jruoho static void acpibat_init_envsys(device_t); 192 1.99 jruoho static void acpibat_notify_handler(ACPI_HANDLE, uint32_t, void *); 193 1.77 jruoho static void acpibat_refresh(struct sysmon_envsys *, envsys_data_t *); 194 1.82 dyoung static bool acpibat_resume(device_t, const pmf_qual_t *); 195 1.87 jruoho static void acpibat_get_limits(struct sysmon_envsys *, envsys_data_t *, 196 1.87 jruoho sysmon_envsys_lim_t *, uint32_t *); 197 1.1 sommerfe 198 1.58 joerg CFATTACH_DECL_NEW(acpibat, sizeof(struct acpibat_softc), 199 1.80 jruoho acpibat_match, acpibat_attach, acpibat_detach, NULL); 200 1.1 sommerfe 201 1.1 sommerfe /* 202 1.1 sommerfe * acpibat_match: 203 1.1 sommerfe * 204 1.1 sommerfe * Autoconfiguration `match' routine. 205 1.1 sommerfe */ 206 1.39 kochi static int 207 1.70 cegger acpibat_match(device_t parent, cfdata_t match, void *aux) 208 1.1 sommerfe { 209 1.1 sommerfe struct acpi_attach_args *aa = aux; 210 1.1 sommerfe 211 1.117 thorpej return acpi_compatible_match(aa, compat_data); 212 1.1 sommerfe } 213 1.1 sommerfe 214 1.1 sommerfe /* 215 1.1 sommerfe * acpibat_attach: 216 1.1 sommerfe * 217 1.1 sommerfe * Autoconfiguration `attach' routine. 218 1.1 sommerfe */ 219 1.39 kochi static void 220 1.58 joerg acpibat_attach(device_t parent, device_t self, void *aux) 221 1.1 sommerfe { 222 1.58 joerg struct acpibat_softc *sc = device_private(self); 223 1.1 sommerfe struct acpi_attach_args *aa = aux; 224 1.107 jruoho ACPI_HANDLE tmp; 225 1.107 jruoho ACPI_STATUS rv; 226 1.1 sommerfe 227 1.77 jruoho aprint_naive(": ACPI Battery\n"); 228 1.77 jruoho aprint_normal(": ACPI Battery\n"); 229 1.1 sommerfe 230 1.1 sommerfe sc->sc_node = aa->aa_node; 231 1.87 jruoho 232 1.69 jmcneill mutex_init(&sc->sc_mutex, MUTEX_DEFAULT, IPL_NONE); 233 1.69 jmcneill cv_init(&sc->sc_condvar, device_xname(self)); 234 1.69 jmcneill 235 1.81 jruoho sc->sc_sensor = kmem_zalloc(ACPIBAT_COUNT * 236 1.81 jruoho sizeof(*sc->sc_sensor), KM_SLEEP); 237 1.81 jruoho 238 1.116 riastrad config_interrupts(self, acpibat_init_envsys); 239 1.107 jruoho 240 1.107 jruoho /* 241 1.107 jruoho * If this is ever seen, the driver should be extended. 242 1.107 jruoho */ 243 1.107 jruoho rv = AcpiGetHandle(sc->sc_node->ad_handle, "_BIX", &tmp); 244 1.107 jruoho if (ACPI_SUCCESS(rv)) 245 1.107 jruoho aprint_verbose_dev(self, "ACPI 4.0 functionality present\n"); 246 1.1 sommerfe } 247 1.1 sommerfe 248 1.13 explorer /* 249 1.80 jruoho * acpibat_detach: 250 1.80 jruoho * 251 1.80 jruoho * Autoconfiguration `detach' routine. 252 1.80 jruoho */ 253 1.80 jruoho static int 254 1.80 jruoho acpibat_detach(device_t self, int flags) 255 1.80 jruoho { 256 1.80 jruoho struct acpibat_softc *sc = device_private(self); 257 1.80 jruoho 258 1.121 riastrad /* Prevent further use of sc->sc_sme in acpibat_update_info. */ 259 1.121 riastrad mutex_enter(&sc->sc_mutex); 260 1.121 riastrad sc->sc_dying = true; 261 1.121 riastrad mutex_exit(&sc->sc_mutex); 262 1.121 riastrad 263 1.121 riastrad /* Prevent further calls to acpibat_resume. */ 264 1.118 riastrad pmf_device_deregister(self); 265 1.121 riastrad 266 1.121 riastrad /* Prevent further calls to acpibat_notify_handler. */ 267 1.100 jruoho acpi_deregister_notify(sc->sc_node); 268 1.80 jruoho 269 1.121 riastrad /* Detach sensors and prevent further calls to acpibat_refresh. */ 270 1.80 jruoho if (sc->sc_sme != NULL) 271 1.80 jruoho sysmon_envsys_unregister(sc->sc_sme); 272 1.80 jruoho 273 1.121 riastrad /* 274 1.121 riastrad * Wait for calls to acpibat_update_info/status in case sysmon 275 1.121 riastrad * envsys refreshed the sensors and queued them but they didn't 276 1.121 riastrad * run before sysmon_envsys_unregister. After this point, no 277 1.121 riastrad * asynchronous access to the softc is possible. 278 1.121 riastrad */ 279 1.121 riastrad AcpiOsWaitEventsComplete(); 280 1.121 riastrad 281 1.81 jruoho if (sc->sc_sensor != NULL) 282 1.81 jruoho kmem_free(sc->sc_sensor, ACPIBAT_COUNT * 283 1.81 jruoho sizeof(*sc->sc_sensor)); 284 1.81 jruoho 285 1.118 riastrad cv_destroy(&sc->sc_condvar); 286 1.118 riastrad mutex_destroy(&sc->sc_mutex); 287 1.80 jruoho 288 1.80 jruoho return 0; 289 1.80 jruoho } 290 1.80 jruoho 291 1.80 jruoho /* 292 1.77 jruoho * acpibat_get_sta: 293 1.76 jruoho * 294 1.76 jruoho * Evaluate whether the battery is present or absent. 295 1.76 jruoho * 296 1.76 jruoho * Returns: 0 for no battery, 1 for present, and -1 on error. 297 1.13 explorer */ 298 1.39 kochi static int 299 1.77 jruoho acpibat_get_sta(device_t dv) 300 1.13 explorer { 301 1.59 joerg struct acpibat_softc *sc = device_private(dv); 302 1.36 kanaoka ACPI_INTEGER val; 303 1.13 explorer ACPI_STATUS rv; 304 1.13 explorer 305 1.20 kochi rv = acpi_eval_integer(sc->sc_node->ad_handle, "_STA", &val); 306 1.35 mycroft if (ACPI_FAILURE(rv)) { 307 1.120 riastrad aprint_error_dev(dv, "failed to evaluate _STA: %s\n", 308 1.120 riastrad AcpiFormatException(rv)); 309 1.37 kochi return -1; 310 1.13 explorer } 311 1.13 explorer 312 1.76 jruoho sc->sc_sensor[ACPIBAT_PRESENT].state = ENVSYS_SVALID; 313 1.76 jruoho 314 1.85 jruoho if ((val & ACPI_STA_BATTERY_PRESENT) == 0) { 315 1.62 xtraeme sc->sc_sensor[ACPIBAT_PRESENT].value_cur = 0; 316 1.76 jruoho return 0; 317 1.76 jruoho } 318 1.46 xtraeme 319 1.76 jruoho sc->sc_sensor[ACPIBAT_PRESENT].value_cur = 1; 320 1.76 jruoho 321 1.76 jruoho return 1; 322 1.76 jruoho } 323 1.76 jruoho 324 1.76 jruoho static ACPI_OBJECT * 325 1.105 jruoho acpibat_get_object(ACPI_HANDLE hdl, const char *pth, uint32_t count) 326 1.76 jruoho { 327 1.76 jruoho ACPI_OBJECT *obj; 328 1.76 jruoho ACPI_BUFFER buf; 329 1.76 jruoho ACPI_STATUS rv; 330 1.76 jruoho 331 1.76 jruoho rv = acpi_eval_struct(hdl, pth, &buf); 332 1.76 jruoho if (ACPI_FAILURE(rv)) 333 1.76 jruoho return NULL; 334 1.76 jruoho 335 1.76 jruoho obj = buf.Pointer; 336 1.76 jruoho if (obj->Type != ACPI_TYPE_PACKAGE) { 337 1.76 jruoho ACPI_FREE(buf.Pointer); 338 1.76 jruoho return NULL; 339 1.76 jruoho } 340 1.76 jruoho if (obj->Package.Count != count) { 341 1.76 jruoho ACPI_FREE(buf.Pointer); 342 1.76 jruoho return NULL; 343 1.76 jruoho } 344 1.76 jruoho 345 1.76 jruoho return obj; 346 1.13 explorer } 347 1.1 sommerfe 348 1.1 sommerfe /* 349 1.76 jruoho * acpibat_get_info: 350 1.1 sommerfe * 351 1.90 jruoho * Get the battery info. 352 1.1 sommerfe */ 353 1.77 jruoho static void 354 1.59 joerg acpibat_get_info(device_t dv) 355 1.1 sommerfe { 356 1.59 joerg struct acpibat_softc *sc = device_private(dv); 357 1.76 jruoho ACPI_HANDLE hdl = sc->sc_node->ad_handle; 358 1.76 jruoho ACPI_OBJECT *elm, *obj; 359 1.76 jruoho ACPI_STATUS rv = AE_OK; 360 1.105 jruoho int capunit, i, rateunit; 361 1.105 jruoho uint64_t val; 362 1.76 jruoho 363 1.76 jruoho obj = acpibat_get_object(hdl, "_BIF", ACPIBAT_BIF_COUNT); 364 1.76 jruoho if (obj == NULL) { 365 1.76 jruoho rv = AE_ERROR; 366 1.76 jruoho goto out; 367 1.1 sommerfe } 368 1.32 mycroft 369 1.76 jruoho elm = obj->Package.Elements; 370 1.76 jruoho for (i = ACPIBAT_BIF_UNIT; i < ACPIBAT_BIF_MODEL; i++) { 371 1.76 jruoho if (elm[i].Type != ACPI_TYPE_INTEGER) { 372 1.76 jruoho rv = AE_TYPE; 373 1.76 jruoho goto out; 374 1.76 jruoho } 375 1.114 mlelstv if (elm[i].Integer.Value != ACPIBAT_VAL_UNKNOWN && 376 1.114 mlelstv elm[i].Integer.Value >= INT_MAX) { 377 1.113 riastrad rv = AE_LIMIT; 378 1.113 riastrad goto out; 379 1.113 riastrad } 380 1.1 sommerfe } 381 1.76 jruoho 382 1.114 mlelstv switch (elm[ACPIBAT_BIF_UNIT].Integer.Value) { 383 1.114 mlelstv case ACPIBAT_PWRUNIT_MA: 384 1.15 tshiozak capunit = ENVSYS_SAMPHOUR; 385 1.15 tshiozak rateunit = ENVSYS_SAMPS; 386 1.114 mlelstv break; 387 1.114 mlelstv default: 388 1.15 tshiozak capunit = ENVSYS_SWATTHOUR; 389 1.15 tshiozak rateunit = ENVSYS_SWATTS; 390 1.114 mlelstv break; 391 1.15 tshiozak } 392 1.32 mycroft 393 1.62 xtraeme sc->sc_sensor[ACPIBAT_DCAPACITY].units = capunit; 394 1.62 xtraeme sc->sc_sensor[ACPIBAT_LFCCAPACITY].units = capunit; 395 1.62 xtraeme sc->sc_sensor[ACPIBAT_CHARGERATE].units = rateunit; 396 1.62 xtraeme sc->sc_sensor[ACPIBAT_DISCHARGERATE].units = rateunit; 397 1.62 xtraeme sc->sc_sensor[ACPIBAT_CAPACITY].units = capunit; 398 1.62 xtraeme 399 1.76 jruoho /* Design capacity. */ 400 1.88 jruoho val = elm[ACPIBAT_BIF_DCAPACITY].Integer.Value; 401 1.88 jruoho sc->sc_sensor[ACPIBAT_DCAPACITY].value_cur = val * 1000; 402 1.76 jruoho sc->sc_sensor[ACPIBAT_DCAPACITY].state = ACPIBAT_VAL_ISVALID(val); 403 1.76 jruoho 404 1.76 jruoho /* Last full charge capacity. */ 405 1.88 jruoho val = elm[ACPIBAT_BIF_LFCCAPACITY].Integer.Value; 406 1.88 jruoho sc->sc_sensor[ACPIBAT_LFCCAPACITY].value_cur = val * 1000; 407 1.76 jruoho sc->sc_sensor[ACPIBAT_LFCCAPACITY].state = ACPIBAT_VAL_ISVALID(val); 408 1.76 jruoho 409 1.76 jruoho /* Design voltage. */ 410 1.88 jruoho val = elm[ACPIBAT_BIF_DVOLTAGE].Integer.Value; 411 1.88 jruoho sc->sc_sensor[ACPIBAT_DVOLTAGE].value_cur = val * 1000; 412 1.76 jruoho sc->sc_sensor[ACPIBAT_DVOLTAGE].state = ACPIBAT_VAL_ISVALID(val); 413 1.76 jruoho 414 1.87 jruoho /* Design low and warning capacity. */ 415 1.87 jruoho sc->sc_lcapacity = elm[ACPIBAT_BIF_LCAPACITY].Integer.Value * 1000; 416 1.87 jruoho sc->sc_wcapacity = elm[ACPIBAT_BIF_WCAPACITY].Integer.Value * 1000; 417 1.76 jruoho 418 1.76 jruoho /* 419 1.87 jruoho * Initialize the maximum of current capacity 420 1.87 jruoho * to the last known full charge capacity. 421 1.76 jruoho */ 422 1.76 jruoho val = sc->sc_sensor[ACPIBAT_LFCCAPACITY].value_cur; 423 1.76 jruoho sc->sc_sensor[ACPIBAT_CAPACITY].value_max = val; 424 1.76 jruoho 425 1.90 jruoho acpibat_print_info(dv, elm); 426 1.90 jruoho 427 1.76 jruoho out: 428 1.76 jruoho if (obj != NULL) 429 1.76 jruoho ACPI_FREE(obj); 430 1.15 tshiozak 431 1.76 jruoho if (ACPI_FAILURE(rv)) 432 1.76 jruoho aprint_error_dev(dv, "failed to evaluate _BIF: %s\n", 433 1.76 jruoho AcpiFormatException(rv)); 434 1.1 sommerfe } 435 1.1 sommerfe 436 1.1 sommerfe /* 437 1.90 jruoho * acpibat_print_info: 438 1.90 jruoho * 439 1.90 jruoho * Display the battery info. 440 1.90 jruoho */ 441 1.90 jruoho static void 442 1.90 jruoho acpibat_print_info(device_t dv, ACPI_OBJECT *elm) 443 1.90 jruoho { 444 1.103 jruoho struct acpibat_softc *sc = device_private(dv); 445 1.111 jruoho const char *tech, *unit; 446 1.111 jruoho int32_t dcap, dvol; 447 1.90 jruoho int i; 448 1.90 jruoho 449 1.90 jruoho for (i = ACPIBAT_BIF_OEM; i > ACPIBAT_BIF_GRANULARITY2; i--) { 450 1.90 jruoho if (elm[i].Type != ACPI_TYPE_STRING) 451 1.90 jruoho return; 452 1.90 jruoho if (elm[i].String.Pointer == NULL) 453 1.90 jruoho return; 454 1.103 jruoho if (elm[i].String.Pointer[0] == '\0') 455 1.103 jruoho return; 456 1.103 jruoho } 457 1.103 jruoho 458 1.111 jruoho dcap = elm[ACPIBAT_BIF_DCAPACITY].Integer.Value; 459 1.111 jruoho dvol = elm[ACPIBAT_BIF_DVOLTAGE].Integer.Value; 460 1.103 jruoho 461 1.111 jruoho /* 462 1.111 jruoho * Try to detect whether the battery was switched. 463 1.111 jruoho */ 464 1.111 jruoho if (sc->sc_dcapacity == dcap && sc->sc_dvoltage == dvol) 465 1.103 jruoho return; 466 1.103 jruoho else { 467 1.111 jruoho sc->sc_dcapacity = dcap; 468 1.111 jruoho sc->sc_dvoltage = dvol; 469 1.90 jruoho } 470 1.90 jruoho 471 1.90 jruoho tech = (elm[ACPIBAT_BIF_TECHNOLOGY].Integer.Value != 0) ? 472 1.101 christos "rechargeable" : "non-rechargeable"; 473 1.90 jruoho 474 1.101 christos aprint_normal_dev(dv, "%s %s %s battery\n", 475 1.90 jruoho elm[ACPIBAT_BIF_OEM].String.Pointer, 476 1.101 christos elm[ACPIBAT_BIF_TYPE].String.Pointer, tech); 477 1.90 jruoho 478 1.111 jruoho aprint_debug_dev(dv, "model number %s, serial number %s\n", 479 1.111 jruoho elm[ACPIBAT_BIF_MODEL].String.Pointer, 480 1.111 jruoho elm[ACPIBAT_BIF_SERIAL].String.Pointer); 481 1.91 jruoho 482 1.91 jruoho #define SCALE(x) (((int)x) / 1000000), ((((int)x) % 1000000) / 1000) 483 1.91 jruoho 484 1.91 jruoho /* 485 1.91 jruoho * These values are defined as follows (ACPI 4.0, p. 388): 486 1.91 jruoho * 487 1.91 jruoho * Granularity 1. "Battery capacity granularity between low 488 1.91 jruoho * and warning in [mAh] or [mWh]. That is, 489 1.91 jruoho * this is the smallest increment in capacity 490 1.91 jruoho * that the battery is capable of measuring." 491 1.91 jruoho * 492 1.91 jruoho * Granularity 2. "Battery capacity granularity between warning 493 1.91 jruoho * and full in [mAh] or [mWh]. [...]" 494 1.91 jruoho */ 495 1.114 mlelstv switch (elm[ACPIBAT_BIF_UNIT].Integer.Value) { 496 1.114 mlelstv case ACPIBAT_PWRUNIT_MA: 497 1.101 christos unit = "Ah"; 498 1.114 mlelstv break; 499 1.114 mlelstv default: 500 1.101 christos unit = "Wh"; 501 1.114 mlelstv break; 502 1.114 mlelstv } 503 1.103 jruoho 504 1.103 jruoho aprint_verbose_dev(dv, "granularity: " 505 1.103 jruoho "low->warn %d.%03d %s, warn->full %d.%03d %s\n", 506 1.91 jruoho SCALE(elm[ACPIBAT_BIF_GRANULARITY1].Integer.Value * 1000), unit, 507 1.91 jruoho SCALE(elm[ACPIBAT_BIF_GRANULARITY2].Integer.Value * 1000), unit); 508 1.90 jruoho } 509 1.90 jruoho 510 1.90 jruoho /* 511 1.1 sommerfe * acpibat_get_status: 512 1.1 sommerfe * 513 1.90 jruoho * Get the current battery status. 514 1.1 sommerfe */ 515 1.77 jruoho static void 516 1.59 joerg acpibat_get_status(device_t dv) 517 1.1 sommerfe { 518 1.59 joerg struct acpibat_softc *sc = device_private(dv); 519 1.76 jruoho ACPI_HANDLE hdl = sc->sc_node->ad_handle; 520 1.76 jruoho ACPI_OBJECT *elm, *obj; 521 1.76 jruoho ACPI_STATUS rv = AE_OK; 522 1.105 jruoho int i, rate, state; 523 1.105 jruoho uint64_t val; 524 1.1 sommerfe 525 1.76 jruoho obj = acpibat_get_object(hdl, "_BST", ACPIBAT_BST_COUNT); 526 1.76 jruoho if (obj == NULL) { 527 1.20 kochi rv = AE_ERROR; 528 1.20 kochi goto out; 529 1.1 sommerfe } 530 1.76 jruoho 531 1.76 jruoho elm = obj->Package.Elements; 532 1.76 jruoho for (i = ACPIBAT_BST_STATE; i < ACPIBAT_BST_COUNT; i++) { 533 1.76 jruoho if (elm[i].Type != ACPI_TYPE_INTEGER) { 534 1.76 jruoho rv = AE_TYPE; 535 1.76 jruoho goto out; 536 1.76 jruoho } 537 1.10 jmcneill } 538 1.1 sommerfe 539 1.76 jruoho state = elm[ACPIBAT_BST_STATE].Integer.Value; 540 1.76 jruoho if ((state & ACPIBAT_ST_CHARGING) != 0) { 541 1.79 drochner /* XXX rate can be invalid */ 542 1.79 drochner rate = elm[ACPIBAT_BST_RATE].Integer.Value; 543 1.62 xtraeme sc->sc_sensor[ACPIBAT_CHARGERATE].state = ENVSYS_SVALID; 544 1.76 jruoho sc->sc_sensor[ACPIBAT_CHARGERATE].value_cur = rate * 1000; 545 1.62 xtraeme sc->sc_sensor[ACPIBAT_DISCHARGERATE].state = ENVSYS_SINVALID; 546 1.62 xtraeme sc->sc_sensor[ACPIBAT_CHARGING].state = ENVSYS_SVALID; 547 1.62 xtraeme sc->sc_sensor[ACPIBAT_CHARGING].value_cur = 1; 548 1.76 jruoho } else if ((state & ACPIBAT_ST_DISCHARGING) != 0) { 549 1.79 drochner rate = elm[ACPIBAT_BST_RATE].Integer.Value; 550 1.62 xtraeme sc->sc_sensor[ACPIBAT_DISCHARGERATE].state = ENVSYS_SVALID; 551 1.76 jruoho sc->sc_sensor[ACPIBAT_DISCHARGERATE].value_cur = rate * 1000; 552 1.62 xtraeme sc->sc_sensor[ACPIBAT_CHARGERATE].state = ENVSYS_SINVALID; 553 1.62 xtraeme sc->sc_sensor[ACPIBAT_CHARGING].state = ENVSYS_SVALID; 554 1.62 xtraeme sc->sc_sensor[ACPIBAT_CHARGING].value_cur = 0; 555 1.76 jruoho } else { 556 1.62 xtraeme sc->sc_sensor[ACPIBAT_CHARGING].state = ENVSYS_SVALID; 557 1.62 xtraeme sc->sc_sensor[ACPIBAT_CHARGING].value_cur = 0; 558 1.62 xtraeme sc->sc_sensor[ACPIBAT_CHARGERATE].state = ENVSYS_SINVALID; 559 1.62 xtraeme sc->sc_sensor[ACPIBAT_DISCHARGERATE].state = ENVSYS_SINVALID; 560 1.46 xtraeme } 561 1.46 xtraeme 562 1.76 jruoho /* Remaining capacity. */ 563 1.88 jruoho val = elm[ACPIBAT_BST_CAPACITY].Integer.Value; 564 1.88 jruoho sc->sc_sensor[ACPIBAT_CAPACITY].value_cur = val * 1000; 565 1.76 jruoho sc->sc_sensor[ACPIBAT_CAPACITY].state = ACPIBAT_VAL_ISVALID(val); 566 1.76 jruoho 567 1.76 jruoho /* Battery voltage. */ 568 1.88 jruoho val = elm[ACPIBAT_BST_VOLTAGE].Integer.Value; 569 1.88 jruoho sc->sc_sensor[ACPIBAT_VOLTAGE].value_cur = val * 1000; 570 1.76 jruoho sc->sc_sensor[ACPIBAT_VOLTAGE].state = ACPIBAT_VAL_ISVALID(val); 571 1.76 jruoho 572 1.78 jruoho sc->sc_sensor[ACPIBAT_CHARGE_STATE].state = ENVSYS_SVALID; 573 1.62 xtraeme sc->sc_sensor[ACPIBAT_CHARGE_STATE].value_cur = 574 1.61 xtraeme ENVSYS_BATTERY_CAPACITY_NORMAL; 575 1.56 xtraeme 576 1.87 jruoho if (sc->sc_sensor[ACPIBAT_CAPACITY].value_cur < sc->sc_wcapacity) { 577 1.62 xtraeme sc->sc_sensor[ACPIBAT_CAPACITY].state = ENVSYS_SWARNUNDER; 578 1.62 xtraeme sc->sc_sensor[ACPIBAT_CHARGE_STATE].value_cur = 579 1.61 xtraeme ENVSYS_BATTERY_CAPACITY_WARNING; 580 1.55 xtraeme } 581 1.46 xtraeme 582 1.87 jruoho if (sc->sc_sensor[ACPIBAT_CAPACITY].value_cur < sc->sc_lcapacity) { 583 1.62 xtraeme sc->sc_sensor[ACPIBAT_CAPACITY].state = ENVSYS_SCRITUNDER; 584 1.62 xtraeme sc->sc_sensor[ACPIBAT_CHARGE_STATE].value_cur = 585 1.61 xtraeme ENVSYS_BATTERY_CAPACITY_LOW; 586 1.55 xtraeme } 587 1.46 xtraeme 588 1.76 jruoho if ((state & ACPIBAT_ST_CRITICAL) != 0) { 589 1.62 xtraeme sc->sc_sensor[ACPIBAT_CAPACITY].state = ENVSYS_SCRITICAL; 590 1.62 xtraeme sc->sc_sensor[ACPIBAT_CHARGE_STATE].value_cur = 591 1.61 xtraeme ENVSYS_BATTERY_CAPACITY_CRITICAL; 592 1.55 xtraeme } 593 1.46 xtraeme 594 1.76 jruoho out: 595 1.76 jruoho if (obj != NULL) 596 1.76 jruoho ACPI_FREE(obj); 597 1.76 jruoho 598 1.76 jruoho if (ACPI_FAILURE(rv)) 599 1.76 jruoho aprint_error_dev(dv, "failed to evaluate _BST: %s\n", 600 1.76 jruoho AcpiFormatException(rv)); 601 1.15 tshiozak } 602 1.15 tshiozak 603 1.15 tshiozak static void 604 1.77 jruoho acpibat_update_info(void *arg) 605 1.15 tshiozak { 606 1.77 jruoho device_t dv = arg; 607 1.59 joerg struct acpibat_softc *sc = device_private(dv); 608 1.77 jruoho int i, rv; 609 1.15 tshiozak 610 1.77 jruoho mutex_enter(&sc->sc_mutex); 611 1.15 tshiozak 612 1.121 riastrad /* Don't touch sc_sme if we're detaching. */ 613 1.121 riastrad if (sc->sc_dying) 614 1.121 riastrad goto out; 615 1.121 riastrad 616 1.77 jruoho rv = acpibat_get_sta(dv); 617 1.98 jruoho if (rv > 0) { 618 1.77 jruoho acpibat_get_info(dv); 619 1.98 jruoho 620 1.98 jruoho /* 621 1.98 jruoho * If the status changed, update the limits. 622 1.98 jruoho */ 623 1.98 jruoho if (sc->sc_present == 0 && 624 1.98 jruoho sc->sc_sensor[ACPIBAT_CAPACITY].value_max > 0) 625 1.98 jruoho sysmon_envsys_update_limits(sc->sc_sme, 626 1.98 jruoho &sc->sc_sensor[ACPIBAT_CAPACITY]); 627 1.98 jruoho } else { 628 1.90 jruoho i = (rv < 0) ? 0 : ACPIBAT_DVOLTAGE; 629 1.77 jruoho while (i < ACPIBAT_COUNT) { 630 1.77 jruoho sc->sc_sensor[i].state = ENVSYS_SINVALID; 631 1.77 jruoho i++; 632 1.77 jruoho } 633 1.52 cube } 634 1.46 xtraeme 635 1.78 jruoho sc->sc_present = rv; 636 1.121 riastrad out: 637 1.77 jruoho mutex_exit(&sc->sc_mutex); 638 1.15 tshiozak } 639 1.15 tshiozak 640 1.15 tshiozak static void 641 1.77 jruoho acpibat_update_status(void *arg) 642 1.15 tshiozak { 643 1.59 joerg device_t dv = arg; 644 1.59 joerg struct acpibat_softc *sc = device_private(dv); 645 1.77 jruoho int i, rv; 646 1.15 tshiozak 647 1.77 jruoho mutex_enter(&sc->sc_mutex); 648 1.15 tshiozak 649 1.77 jruoho rv = acpibat_get_sta(dv); 650 1.78 jruoho if (rv > 0) { 651 1.78 jruoho if (sc->sc_present == 0) 652 1.78 jruoho acpibat_get_info(dv); 653 1.77 jruoho acpibat_get_status(dv); 654 1.78 jruoho } else { 655 1.90 jruoho i = (rv < 0) ? 0 : ACPIBAT_DVOLTAGE; 656 1.77 jruoho while (i < ACPIBAT_COUNT) { 657 1.77 jruoho sc->sc_sensor[i].state = ENVSYS_SINVALID; 658 1.77 jruoho i++; 659 1.77 jruoho } 660 1.77 jruoho } 661 1.67 jmcneill 662 1.78 jruoho sc->sc_present = rv; 663 1.108 jruoho microtime(&sc->sc_last); 664 1.78 jruoho 665 1.69 jmcneill cv_broadcast(&sc->sc_condvar); 666 1.69 jmcneill mutex_exit(&sc->sc_mutex); 667 1.67 jmcneill } 668 1.67 jmcneill 669 1.1 sommerfe /* 670 1.1 sommerfe * acpibat_notify_handler: 671 1.1 sommerfe * 672 1.1 sommerfe * Callback from ACPI interrupt handler to notify us of an event. 673 1.1 sommerfe */ 674 1.39 kochi static void 675 1.99 jruoho acpibat_notify_handler(ACPI_HANDLE handle, uint32_t notify, void *context) 676 1.1 sommerfe { 677 1.77 jruoho static const int handler = OSL_NOTIFY_HANDLER; 678 1.59 joerg device_t dv = context; 679 1.1 sommerfe 680 1.77 jruoho switch (notify) { 681 1.102 jruoho case ACPI_NOTIFY_BUS_CHECK: 682 1.11 explorer break; 683 1.102 jruoho case ACPI_NOTIFY_BAT_INFO: 684 1.102 jruoho case ACPI_NOTIFY_DEVICE_CHECK: 685 1.77 jruoho (void)AcpiOsExecute(handler, acpibat_update_info, dv); 686 1.13 explorer break; 687 1.102 jruoho case ACPI_NOTIFY_BAT_STATUS: 688 1.77 jruoho (void)AcpiOsExecute(handler, acpibat_update_status, dv); 689 1.1 sommerfe break; 690 1.1 sommerfe default: 691 1.77 jruoho aprint_error_dev(dv, "unknown notify: 0x%02X\n", notify); 692 1.1 sommerfe } 693 1.14 explorer } 694 1.14 explorer 695 1.39 kochi static void 696 1.59 joerg acpibat_init_envsys(device_t dv) 697 1.14 explorer { 698 1.59 joerg struct acpibat_softc *sc = device_private(dv); 699 1.77 jruoho int i; 700 1.14 explorer 701 1.62 xtraeme #define INITDATA(index, unit, string) \ 702 1.77 jruoho do { \ 703 1.77 jruoho sc->sc_sensor[index].state = ENVSYS_SVALID; \ 704 1.77 jruoho sc->sc_sensor[index].units = unit; \ 705 1.77 jruoho (void)strlcpy(sc->sc_sensor[index].desc, string, \ 706 1.77 jruoho sizeof(sc->sc_sensor[index].desc)); \ 707 1.77 jruoho } while (/* CONSTCOND */ 0) 708 1.32 mycroft 709 1.15 tshiozak INITDATA(ACPIBAT_PRESENT, ENVSYS_INDICATOR, "present"); 710 1.77 jruoho INITDATA(ACPIBAT_DCAPACITY, ENVSYS_SWATTHOUR, "design cap"); 711 1.77 jruoho INITDATA(ACPIBAT_LFCCAPACITY, ENVSYS_SWATTHOUR, "last full cap"); 712 1.14 explorer INITDATA(ACPIBAT_DVOLTAGE, ENVSYS_SVOLTS_DC, "design voltage"); 713 1.14 explorer INITDATA(ACPIBAT_VOLTAGE, ENVSYS_SVOLTS_DC, "voltage"); 714 1.77 jruoho INITDATA(ACPIBAT_CHARGERATE, ENVSYS_SWATTS, "charge rate"); 715 1.77 jruoho INITDATA(ACPIBAT_DISCHARGERATE, ENVSYS_SWATTS, "discharge rate"); 716 1.77 jruoho INITDATA(ACPIBAT_CAPACITY, ENVSYS_SWATTHOUR, "charge"); 717 1.61 xtraeme INITDATA(ACPIBAT_CHARGING, ENVSYS_BATTERY_CHARGE, "charging"); 718 1.61 xtraeme INITDATA(ACPIBAT_CHARGE_STATE, ENVSYS_BATTERY_CAPACITY, "charge state"); 719 1.32 mycroft 720 1.32 mycroft #undef INITDATA 721 1.14 explorer 722 1.110 pgoyette sc->sc_sensor[ACPIBAT_CHARGE_STATE].value_cur = 723 1.110 pgoyette ENVSYS_BATTERY_CAPACITY_NORMAL; 724 1.110 pgoyette 725 1.94 jruoho sc->sc_sensor[ACPIBAT_CAPACITY].flags |= 726 1.94 jruoho ENVSYS_FPERCENT | ENVSYS_FVALID_MAX | ENVSYS_FMONLIMITS; 727 1.94 jruoho 728 1.62 xtraeme sc->sc_sensor[ACPIBAT_CHARGE_STATE].flags |= ENVSYS_FMONSTCHANGED; 729 1.53 xtraeme 730 1.87 jruoho /* Disable userland monitoring on these sensors. */ 731 1.62 xtraeme sc->sc_sensor[ACPIBAT_VOLTAGE].flags = ENVSYS_FMONNOTSUPP; 732 1.62 xtraeme sc->sc_sensor[ACPIBAT_CHARGERATE].flags = ENVSYS_FMONNOTSUPP; 733 1.62 xtraeme sc->sc_sensor[ACPIBAT_DISCHARGERATE].flags = ENVSYS_FMONNOTSUPP; 734 1.62 xtraeme sc->sc_sensor[ACPIBAT_DCAPACITY].flags = ENVSYS_FMONNOTSUPP; 735 1.62 xtraeme sc->sc_sensor[ACPIBAT_LFCCAPACITY].flags = ENVSYS_FMONNOTSUPP; 736 1.62 xtraeme sc->sc_sensor[ACPIBAT_DVOLTAGE].flags = ENVSYS_FMONNOTSUPP; 737 1.62 xtraeme 738 1.112 jruoho /* Attach rnd(9) to the (dis)charge rates. */ 739 1.112 jruoho sc->sc_sensor[ACPIBAT_CHARGERATE].flags |= ENVSYS_FHAS_ENTROPY; 740 1.112 jruoho sc->sc_sensor[ACPIBAT_DISCHARGERATE].flags |= ENVSYS_FHAS_ENTROPY; 741 1.112 jruoho 742 1.62 xtraeme sc->sc_sme = sysmon_envsys_create(); 743 1.77 jruoho 744 1.76 jruoho for (i = 0; i < ACPIBAT_COUNT; i++) { 745 1.62 xtraeme if (sysmon_envsys_sensor_attach(sc->sc_sme, 746 1.77 jruoho &sc->sc_sensor[i])) 747 1.77 jruoho goto fail; 748 1.62 xtraeme } 749 1.62 xtraeme 750 1.62 xtraeme sc->sc_sme->sme_name = device_xname(dv); 751 1.69 jmcneill sc->sc_sme->sme_cookie = dv; 752 1.69 jmcneill sc->sc_sme->sme_refresh = acpibat_refresh; 753 1.62 xtraeme sc->sc_sme->sme_class = SME_CLASS_BATTERY; 754 1.123 christos sc->sc_sme->sme_flags = SME_POLL_ONLY; 755 1.87 jruoho sc->sc_sme->sme_get_limits = acpibat_get_limits; 756 1.14 explorer 757 1.122 christos if (sysmon_envsys_register(sc->sc_sme)) 758 1.122 christos goto fail; 759 1.122 christos 760 1.118 riastrad (void)acpi_register_notify(sc->sc_node, acpibat_notify_handler); 761 1.77 jruoho acpibat_update_info(dv); 762 1.77 jruoho acpibat_update_status(dv); 763 1.77 jruoho 764 1.118 riastrad (void)pmf_device_register(dv, NULL, acpibat_resume); 765 1.118 riastrad 766 1.77 jruoho return; 767 1.77 jruoho fail: 768 1.77 jruoho aprint_error_dev(dv, "failed to initialize sysmon\n"); 769 1.81 jruoho 770 1.77 jruoho sysmon_envsys_destroy(sc->sc_sme); 771 1.81 jruoho kmem_free(sc->sc_sensor, ACPIBAT_COUNT * sizeof(*sc->sc_sensor)); 772 1.81 jruoho 773 1.80 jruoho sc->sc_sme = NULL; 774 1.81 jruoho sc->sc_sensor = NULL; 775 1.14 explorer } 776 1.69 jmcneill 777 1.69 jmcneill static void 778 1.69 jmcneill acpibat_refresh(struct sysmon_envsys *sme, envsys_data_t *edata) 779 1.69 jmcneill { 780 1.108 jruoho device_t self = sme->sme_cookie; 781 1.108 jruoho struct acpibat_softc *sc; 782 1.108 jruoho struct timeval tv, tmp; 783 1.69 jmcneill ACPI_STATUS rv; 784 1.69 jmcneill 785 1.108 jruoho sc = device_private(self); 786 1.108 jruoho 787 1.108 jruoho tmp.tv_sec = 10; 788 1.108 jruoho tmp.tv_usec = 0; 789 1.108 jruoho 790 1.108 jruoho microtime(&tv); 791 1.108 jruoho timersub(&tv, &tmp, &tv); 792 1.108 jruoho if (timercmp(&tv, &sc->sc_last, <) != 0) 793 1.108 jruoho return; 794 1.108 jruoho 795 1.89 jruoho if (mutex_tryenter(&sc->sc_mutex) == 0) 796 1.77 jruoho return; 797 1.77 jruoho 798 1.108 jruoho rv = AcpiOsExecute(OSL_NOTIFY_HANDLER, acpibat_update_status, self); 799 1.77 jruoho if (ACPI_SUCCESS(rv)) 800 1.77 jruoho cv_timedwait(&sc->sc_condvar, &sc->sc_mutex, hz); 801 1.77 jruoho 802 1.77 jruoho mutex_exit(&sc->sc_mutex); 803 1.77 jruoho } 804 1.77 jruoho 805 1.77 jruoho static bool 806 1.82 dyoung acpibat_resume(device_t dv, const pmf_qual_t *qual) 807 1.77 jruoho { 808 1.77 jruoho 809 1.106 jruoho (void)AcpiOsExecute(OSL_NOTIFY_HANDLER, acpibat_update_info, dv); 810 1.106 jruoho (void)AcpiOsExecute(OSL_NOTIFY_HANDLER, acpibat_update_status, dv); 811 1.74 jmcneill 812 1.77 jruoho return true; 813 1.69 jmcneill } 814 1.83 jruoho 815 1.87 jruoho static void 816 1.87 jruoho acpibat_get_limits(struct sysmon_envsys *sme, envsys_data_t *edata, 817 1.87 jruoho sysmon_envsys_lim_t *limits, uint32_t *props) 818 1.87 jruoho { 819 1.87 jruoho device_t dv = sme->sme_cookie; 820 1.87 jruoho struct acpibat_softc *sc = device_private(dv); 821 1.87 jruoho 822 1.87 jruoho if (edata->sensor != ACPIBAT_CAPACITY) 823 1.87 jruoho return; 824 1.87 jruoho 825 1.87 jruoho limits->sel_critmin = sc->sc_lcapacity; 826 1.87 jruoho limits->sel_warnmin = sc->sc_wcapacity; 827 1.87 jruoho 828 1.87 jruoho *props |= PROP_BATTCAP | PROP_BATTWARN | PROP_DRIVER_LIMITS; 829 1.87 jruoho } 830 1.87 jruoho 831 1.115 pgoyette MODULE(MODULE_CLASS_DRIVER, acpibat, "sysmon_envsys"); 832 1.83 jruoho 833 1.109 jruoho #ifdef _MODULE 834 1.92 pooka #include "ioconf.c" 835 1.109 jruoho #endif 836 1.83 jruoho 837 1.83 jruoho static int 838 1.109 jruoho acpibat_modcmd(modcmd_t cmd, void *aux) 839 1.83 jruoho { 840 1.109 jruoho int rv = 0; 841 1.83 jruoho 842 1.83 jruoho switch (cmd) { 843 1.83 jruoho case MODULE_CMD_INIT: 844 1.109 jruoho #ifdef _MODULE 845 1.109 jruoho rv = config_init_component(cfdriver_ioconf_acpibat, 846 1.97 pooka cfattach_ioconf_acpibat, cfdata_ioconf_acpibat); 847 1.109 jruoho #endif 848 1.109 jruoho break; 849 1.83 jruoho case MODULE_CMD_FINI: 850 1.109 jruoho #ifdef _MODULE 851 1.109 jruoho rv = config_fini_component(cfdriver_ioconf_acpibat, 852 1.97 pooka cfattach_ioconf_acpibat, cfdata_ioconf_acpibat); 853 1.109 jruoho #endif 854 1.109 jruoho break; 855 1.83 jruoho default: 856 1.109 jruoho rv = ENOTTY; 857 1.83 jruoho } 858 1.109 jruoho 859 1.109 jruoho return rv; 860 1.83 jruoho } 861