Home | History | Annotate | Line # | Download | only in acpi
acpi_bat.c revision 1.69
      1 /*	$NetBSD: acpi_bat.c,v 1.69 2008/06/03 15:02:31 jmcneill Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2003 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Charles M. Hannum of By Noon Software, Inc.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29  * POSSIBILITY OF SUCH DAMAGE.
     30  */
     31 
     32 /*
     33  * Copyright 2001 Bill Sommerfeld.
     34  * All rights reserved.
     35  *
     36  * Redistribution and use in source and binary forms, with or without
     37  * modification, are permitted provided that the following conditions
     38  * are met:
     39  * 1. Redistributions of source code must retain the above copyright
     40  *    notice, this list of conditions and the following disclaimer.
     41  * 2. Redistributions in binary form must reproduce the above copyright
     42  *    notice, this list of conditions and the following disclaimer in the
     43  *    documentation and/or other materials provided with the distribution.
     44  * 3. All advertising materials mentioning features or use of this software
     45  *    must display the following acknowledgement:
     46  *	This product includes software developed for the NetBSD Project by
     47  *	Wasabi Systems, Inc.
     48  * 4. The name of Wasabi Systems, Inc. may not be used to endorse
     49  *    or promote products derived from this software without specific prior
     50  *    written permission.
     51  *
     52  * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
     53  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     54  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     55  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
     56  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     57  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     58  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     59  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     60  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     61  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     62  * POSSIBILITY OF SUCH DAMAGE.
     63  */
     64 
     65 #if 0
     66 #define ACPI_BAT_DEBUG
     67 #endif
     68 
     69 /*
     70  * ACPI Battery Driver.
     71  *
     72  * ACPI defines two different battery device interfaces: "Control
     73  * Method" batteries, in which AML methods are defined in order to get
     74  * battery status and set battery alarm thresholds, and a "Smart
     75  * Battery" device, which is an SMbus device accessed through the ACPI
     76  * Embedded Controller device.
     77  *
     78  * This driver is for the "Control Method"-style battery only.
     79  */
     80 
     81 #include <sys/cdefs.h>
     82 __KERNEL_RCSID(0, "$NetBSD: acpi_bat.c,v 1.69 2008/06/03 15:02:31 jmcneill Exp $");
     83 
     84 #include <sys/param.h>
     85 #include <sys/systm.h>
     86 #include <sys/kernel.h>		/* for hz */
     87 #include <sys/device.h>
     88 #include <sys/mutex.h>
     89 #include <dev/sysmon/sysmonvar.h>
     90 
     91 #include <dev/acpi/acpica.h>
     92 #include <dev/acpi/acpireg.h>
     93 #include <dev/acpi/acpivar.h>
     94 
     95 /* sensor indexes */
     96 #define ACPIBAT_PRESENT		0
     97 #define ACPIBAT_DCAPACITY	1
     98 #define ACPIBAT_LFCCAPACITY	2
     99 #define ACPIBAT_TECHNOLOGY	3
    100 #define ACPIBAT_DVOLTAGE	4
    101 #define ACPIBAT_WCAPACITY	5
    102 #define ACPIBAT_LCAPACITY	6
    103 #define ACPIBAT_VOLTAGE		7
    104 #define ACPIBAT_CHARGERATE	8
    105 #define ACPIBAT_DISCHARGERATE	9
    106 #define ACPIBAT_CAPACITY	10
    107 #define ACPIBAT_CHARGING	11
    108 #define ACPIBAT_CHARGE_STATE	12
    109 #define ACPIBAT_NSENSORS	13  /* number of sensors */
    110 
    111 struct acpibat_softc {
    112 	struct acpi_devnode *sc_node;	/* our ACPI devnode */
    113 	int sc_flags;			/* see below */
    114 	int sc_available;		/* available information level */
    115 
    116 	struct sysmon_envsys *sc_sme;
    117 	envsys_data_t sc_sensor[ACPIBAT_NSENSORS];
    118 	struct timeval sc_lastupdate;
    119 
    120 	kmutex_t sc_mutex;
    121 	kcondvar_t sc_condvar;
    122 };
    123 
    124 static const char * const bat_hid[] = {
    125 	"PNP0C0A",
    126 	NULL
    127 };
    128 
    129 /*
    130  * These flags are used to examine the battery device data returned from
    131  * the ACPI interface, specifically the "battery status"
    132  */
    133 #define ACPIBAT_PWRUNIT_MA	0x00000001  /* mA not mW */
    134 
    135 /*
    136  * These flags are used to examine the battery charge/discharge/critical
    137  * state returned from a get-status command.
    138  */
    139 #define ACPIBAT_ST_DISCHARGING	0x00000001  /* battery is discharging */
    140 #define ACPIBAT_ST_CHARGING	0x00000002  /* battery is charging */
    141 #define ACPIBAT_ST_CRITICAL	0x00000004  /* battery is critical */
    142 
    143 /*
    144  * Flags for battery status from _STA return
    145  */
    146 #define ACPIBAT_STA_PRESENT	0x00000010  /* battery present */
    147 
    148 /*
    149  * These flags are used to set internal state in our softc.
    150  */
    151 #define	ABAT_F_VERBOSE		0x01	/* verbose events */
    152 #define ABAT_F_PWRUNIT_MA	0x02 	/* mA instead of mW */
    153 #define ABAT_F_PRESENT		0x04	/* is the battery present? */
    154 
    155 #define ABAT_SET(sc, f)		(void)((sc)->sc_flags |= (f))
    156 #define ABAT_CLEAR(sc, f)	(void)((sc)->sc_flags &= ~(f))
    157 #define ABAT_ISSET(sc, f)	((sc)->sc_flags & (f))
    158 
    159 /*
    160  * Available info level
    161  */
    162 
    163 #define ABAT_ALV_NONE		0	/* none is available */
    164 #define ABAT_ALV_PRESENCE	1	/* presence info is available */
    165 #define ABAT_ALV_INFO		2	/* battery info is available */
    166 #define ABAT_ALV_STAT		3	/* battery status is available */
    167 
    168 static int	acpibat_match(device_t, struct cfdata *, void *);
    169 static void	acpibat_attach(device_t, struct device *, void *);
    170 static bool	acpibat_resume(device_t PMF_FN_PROTO);
    171 
    172 CFATTACH_DECL_NEW(acpibat, sizeof(struct acpibat_softc),
    173     acpibat_match, acpibat_attach, NULL, NULL);
    174 
    175 static void acpibat_clear_presence(struct acpibat_softc *);
    176 static void acpibat_clear_info(struct acpibat_softc *);
    177 static void acpibat_clear_stat(struct acpibat_softc *);
    178 static int acpibat_battery_present(device_t);
    179 static ACPI_STATUS acpibat_get_status(device_t);
    180 static ACPI_STATUS acpibat_get_info(device_t);
    181 static void acpibat_print_info(device_t);
    182 static void acpibat_print_stat(device_t);
    183 static void acpibat_update(void *);
    184 static void acpibat_update_info(void *);
    185 static void acpibat_update_stat(void *);
    186 
    187 static void acpibat_init_envsys(device_t);
    188 static void acpibat_notify_handler(ACPI_HANDLE, UINT32, void *);
    189 static void acpibat_refresh(struct sysmon_envsys *, envsys_data_t *);
    190 
    191 /*
    192  * acpibat_match:
    193  *
    194  *	Autoconfiguration `match' routine.
    195  */
    196 static int
    197 acpibat_match(device_t parent, struct cfdata *match, void *aux)
    198 {
    199 	struct acpi_attach_args *aa = aux;
    200 
    201 	if (aa->aa_node->ad_type != ACPI_TYPE_DEVICE)
    202 		return 0;
    203 
    204 	return acpi_match_hid(aa->aa_node->ad_devinfo, bat_hid);
    205 }
    206 
    207 static bool
    208 acpibat_resume(device_t dv PMF_FN_ARGS)
    209 {
    210 	ACPI_STATUS rv;
    211 
    212 	rv = AcpiOsExecute(OSL_NOTIFY_HANDLER, acpibat_update_stat, dv);
    213 	if (ACPI_FAILURE(rv))
    214 		aprint_error_dev(dv, "unable to queue status check: %s\n",
    215 		    AcpiFormatException(rv));
    216 	rv = AcpiOsExecute(OSL_NOTIFY_HANDLER, acpibat_update_info, dv);
    217 	if (ACPI_FAILURE(rv))
    218 		aprint_error_dev(dv, "unable to queue info check: %s\n",
    219 		    AcpiFormatException(rv));
    220 
    221 	return true;
    222 }
    223 
    224 /*
    225  * acpibat_attach:
    226  *
    227  *	Autoconfiguration `attach' routine.
    228  */
    229 static void
    230 acpibat_attach(device_t parent, device_t self, void *aux)
    231 {
    232 	struct acpibat_softc *sc = device_private(self);
    233 	struct acpi_attach_args *aa = aux;
    234 	ACPI_STATUS rv;
    235 
    236 	aprint_naive(": ACPI Battery (Control Method)\n");
    237 	aprint_normal(": ACPI Battery (Control Method)\n");
    238 
    239 	sc->sc_node = aa->aa_node;
    240 
    241 	mutex_init(&sc->sc_mutex, MUTEX_DEFAULT, IPL_NONE);
    242 	cv_init(&sc->sc_condvar, device_xname(self));
    243 
    244 	rv = AcpiInstallNotifyHandler(sc->sc_node->ad_handle,
    245 				      ACPI_ALL_NOTIFY,
    246 				      acpibat_notify_handler, self);
    247 	if (ACPI_FAILURE(rv)) {
    248 		aprint_error_dev(self,
    249 		    "unable to register DEVICE/SYSTEM NOTIFY handler: %s\n",
    250 		    AcpiFormatException(rv));
    251 		return;
    252 	}
    253 
    254 #ifdef ACPI_BAT_DEBUG
    255 	ABAT_SET(sc, ABAT_F_VERBOSE);
    256 #endif
    257 
    258 	if (!pmf_device_register(self, NULL, acpibat_resume))
    259 		aprint_error_dev(self, "couldn't establish power handler\n");
    260 
    261 	acpibat_init_envsys(self);
    262 }
    263 
    264 /*
    265  * clear informations
    266  */
    267 
    268 static void
    269 acpibat_clear_presence(struct acpibat_softc *sc)
    270 {
    271 	acpibat_clear_info(sc);
    272 	sc->sc_available = ABAT_ALV_NONE;
    273 	ABAT_CLEAR(sc, ABAT_F_PRESENT);
    274 }
    275 
    276 static void
    277 acpibat_clear_info(struct acpibat_softc *sc)
    278 {
    279 	acpibat_clear_stat(sc);
    280 	if (sc->sc_available > ABAT_ALV_PRESENCE)
    281 		sc->sc_available = ABAT_ALV_PRESENCE;
    282 
    283 	sc->sc_sensor[ACPIBAT_DCAPACITY].state = ENVSYS_SINVALID;
    284 	sc->sc_sensor[ACPIBAT_LFCCAPACITY].state = ENVSYS_SINVALID;
    285 	sc->sc_sensor[ACPIBAT_CAPACITY].state = ENVSYS_SINVALID;
    286 	sc->sc_sensor[ACPIBAT_TECHNOLOGY].state = ENVSYS_SINVALID;
    287 	sc->sc_sensor[ACPIBAT_DVOLTAGE].state = ENVSYS_SINVALID;
    288 	sc->sc_sensor[ACPIBAT_WCAPACITY].state = ENVSYS_SINVALID;
    289 	sc->sc_sensor[ACPIBAT_LCAPACITY].state = ENVSYS_SINVALID;
    290 }
    291 
    292 static void
    293 acpibat_clear_stat(struct acpibat_softc *sc)
    294 {
    295 	if (sc->sc_available > ABAT_ALV_INFO)
    296 		sc->sc_available = ABAT_ALV_INFO;
    297 
    298 	sc->sc_sensor[ACPIBAT_CHARGERATE].state = ENVSYS_SINVALID;
    299 	sc->sc_sensor[ACPIBAT_DISCHARGERATE].state = ENVSYS_SINVALID;
    300 	sc->sc_sensor[ACPIBAT_CAPACITY].state = ENVSYS_SINVALID;
    301 	sc->sc_sensor[ACPIBAT_VOLTAGE].state = ENVSYS_SINVALID;
    302 	sc->sc_sensor[ACPIBAT_CHARGING].state = ENVSYS_SINVALID;
    303 }
    304 
    305 
    306 /*
    307  * returns 0 for no battery, 1 for present, and -1 on error
    308  */
    309 static int
    310 acpibat_battery_present(device_t dv)
    311 {
    312 	struct acpibat_softc *sc = device_private(dv);
    313 	uint32_t sta;
    314 	ACPI_INTEGER val;
    315 	ACPI_STATUS rv;
    316 
    317 	rv = acpi_eval_integer(sc->sc_node->ad_handle, "_STA", &val);
    318 	if (ACPI_FAILURE(rv)) {
    319 		aprint_error_dev(dv, "failed to evaluate _STA: %s\n",
    320 		    AcpiFormatException(rv));
    321 		return -1;
    322 	}
    323 
    324 	sta = (uint32_t)val;
    325 
    326 	sc->sc_available = ABAT_ALV_PRESENCE;
    327 	if (sta & ACPIBAT_STA_PRESENT) {
    328 		ABAT_SET(sc, ABAT_F_PRESENT);
    329 		sc->sc_sensor[ACPIBAT_PRESENT].state = ENVSYS_SVALID;
    330 		sc->sc_sensor[ACPIBAT_PRESENT].value_cur = 1;
    331 	} else
    332 		sc->sc_sensor[ACPIBAT_PRESENT].value_cur = 0;
    333 
    334 	return (sta & ACPIBAT_STA_PRESENT) ? 1 : 0;
    335 }
    336 
    337 /*
    338  * acpibat_get_info
    339  *
    340  * 	Get, and possibly display, the battery info.
    341  */
    342 
    343 static ACPI_STATUS
    344 acpibat_get_info(device_t dv)
    345 {
    346 	struct acpibat_softc *sc = device_private(dv);
    347 	ACPI_OBJECT *p1, *p2;
    348 	ACPI_STATUS rv;
    349 	ACPI_BUFFER buf;
    350 	int capunit, rateunit;
    351 
    352 	rv = acpi_eval_struct(sc->sc_node->ad_handle, "_BIF", &buf);
    353 	if (ACPI_FAILURE(rv)) {
    354 		aprint_error_dev(dv, "failed to evaluate _BIF: %s\n",
    355 		    AcpiFormatException(rv));
    356 		return rv;
    357 	}
    358 	p1 = (ACPI_OBJECT *)buf.Pointer;
    359 
    360 	if (p1->Type != ACPI_TYPE_PACKAGE) {
    361 		aprint_error_dev(dv, "expected PACKAGE, got %d\n", p1->Type);
    362 		goto out;
    363 	}
    364 	if (p1->Package.Count < 13) {
    365 		aprint_error_dev(dv, "expected 13 elements, got %d\n",
    366 		    p1->Package.Count);
    367 		goto out;
    368 	}
    369 	p2 = p1->Package.Elements;
    370 
    371 	if ((p2[0].Integer.Value & ACPIBAT_PWRUNIT_MA) != 0) {
    372 		ABAT_SET(sc, ABAT_F_PWRUNIT_MA);
    373 		capunit = ENVSYS_SAMPHOUR;
    374 		rateunit = ENVSYS_SAMPS;
    375 	} else {
    376 		ABAT_CLEAR(sc, ABAT_F_PWRUNIT_MA);
    377 		capunit = ENVSYS_SWATTHOUR;
    378 		rateunit = ENVSYS_SWATTS;
    379 	}
    380 
    381 	sc->sc_sensor[ACPIBAT_DCAPACITY].units = capunit;
    382 	sc->sc_sensor[ACPIBAT_LFCCAPACITY].units = capunit;
    383 	sc->sc_sensor[ACPIBAT_WCAPACITY].units = capunit;
    384 	sc->sc_sensor[ACPIBAT_LCAPACITY].units = capunit;
    385 	sc->sc_sensor[ACPIBAT_CHARGERATE].units = rateunit;
    386 	sc->sc_sensor[ACPIBAT_DISCHARGERATE].units = rateunit;
    387 	sc->sc_sensor[ACPIBAT_CAPACITY].units = capunit;
    388 
    389 	sc->sc_sensor[ACPIBAT_DCAPACITY].value_cur = p2[1].Integer.Value * 1000;
    390 	sc->sc_sensor[ACPIBAT_DCAPACITY].state = ENVSYS_SVALID;
    391 	sc->sc_sensor[ACPIBAT_LFCCAPACITY].value_cur = p2[2].Integer.Value * 1000;
    392 	sc->sc_sensor[ACPIBAT_LFCCAPACITY].state = ENVSYS_SVALID;
    393 	sc->sc_sensor[ACPIBAT_CAPACITY].value_max = p2[2].Integer.Value * 1000;
    394 	sc->sc_sensor[ACPIBAT_TECHNOLOGY].value_cur = p2[3].Integer.Value;
    395 	sc->sc_sensor[ACPIBAT_TECHNOLOGY].state = ENVSYS_SVALID;
    396 	sc->sc_sensor[ACPIBAT_DVOLTAGE].value_cur = p2[4].Integer.Value * 1000;
    397 	sc->sc_sensor[ACPIBAT_DVOLTAGE].state = ENVSYS_SVALID;
    398 	sc->sc_sensor[ACPIBAT_WCAPACITY].value_cur = p2[5].Integer.Value * 1000;
    399 	sc->sc_sensor[ACPIBAT_WCAPACITY].value_max = p2[2].Integer.Value * 1000;
    400 	sc->sc_sensor[ACPIBAT_WCAPACITY].state = ENVSYS_SVALID;
    401 	sc->sc_sensor[ACPIBAT_WCAPACITY].flags |=
    402 	    (ENVSYS_FPERCENT|ENVSYS_FVALID_MAX);
    403 	sc->sc_sensor[ACPIBAT_LCAPACITY].value_cur = p2[6].Integer.Value * 1000;
    404 	sc->sc_sensor[ACPIBAT_LCAPACITY].value_max = p2[2].Integer.Value * 1000;
    405 	sc->sc_sensor[ACPIBAT_LCAPACITY].state = ENVSYS_SVALID;
    406 	sc->sc_sensor[ACPIBAT_LCAPACITY].flags |=
    407 	    (ENVSYS_FPERCENT|ENVSYS_FVALID_MAX);
    408 	sc->sc_available = ABAT_ALV_INFO;
    409 
    410 	aprint_verbose_dev(dv, "battery info: %s, %s, %s",
    411 	    p2[12].String.Pointer, p2[11].String.Pointer, p2[9].String.Pointer);
    412 	if (p2[10].String.Pointer)
    413 		aprint_verbose(" %s", p2[10].String.Pointer);
    414 
    415 	aprint_verbose("\n");
    416 
    417 	rv = AE_OK;
    418 
    419 out:
    420 	AcpiOsFree(buf.Pointer);
    421 	return rv;
    422 }
    423 
    424 /*
    425  * acpibat_get_status:
    426  *
    427  *	Get, and possibly display, the current battery line status.
    428  */
    429 static ACPI_STATUS
    430 acpibat_get_status(device_t dv)
    431 {
    432 	struct acpibat_softc *sc = device_private(dv);
    433 	int status, battrate;
    434 	ACPI_OBJECT *p1, *p2;
    435 	ACPI_STATUS rv;
    436 	ACPI_BUFFER buf;
    437 
    438 	rv = acpi_eval_struct(sc->sc_node->ad_handle, "_BST", &buf);
    439 	if (ACPI_FAILURE(rv)) {
    440 		aprint_error_dev(dv, "failed to evaluate _BST: %s\n",
    441 		    AcpiFormatException(rv));
    442 		return rv;
    443 	}
    444 	p1 = (ACPI_OBJECT *)buf.Pointer;
    445 
    446 	if (p1->Type != ACPI_TYPE_PACKAGE) {
    447 		aprint_error_dev(dv, "expected PACKAGE, got %d\n",
    448 		    p1->Type);
    449 		rv = AE_ERROR;
    450 		goto out;
    451 	}
    452 	if (p1->Package.Count < 4) {
    453 		aprint_error_dev(dv, "expected 4 elts, got %d\n",
    454 		    p1->Package.Count);
    455 		rv = AE_ERROR;
    456 		goto out;
    457 	}
    458 	p2 = p1->Package.Elements;
    459 
    460 	status = p2[0].Integer.Value;
    461 	battrate = p2[1].Integer.Value;
    462 
    463 	if (status & ACPIBAT_ST_CHARGING) {
    464 		sc->sc_sensor[ACPIBAT_CHARGERATE].state = ENVSYS_SVALID;
    465 		sc->sc_sensor[ACPIBAT_CHARGERATE].value_cur = battrate * 1000;
    466 		sc->sc_sensor[ACPIBAT_DISCHARGERATE].state = ENVSYS_SINVALID;
    467 		sc->sc_sensor[ACPIBAT_CHARGING].state = ENVSYS_SVALID;
    468 		sc->sc_sensor[ACPIBAT_CHARGING].value_cur = 1;
    469 	} else if (status & ACPIBAT_ST_DISCHARGING) {
    470 		sc->sc_sensor[ACPIBAT_DISCHARGERATE].state = ENVSYS_SVALID;
    471 		sc->sc_sensor[ACPIBAT_DISCHARGERATE].value_cur = battrate * 1000;
    472 		sc->sc_sensor[ACPIBAT_CHARGERATE].state = ENVSYS_SINVALID;
    473 		sc->sc_sensor[ACPIBAT_CHARGING].state = ENVSYS_SVALID;
    474 		sc->sc_sensor[ACPIBAT_CHARGING].value_cur = 0;
    475 	} else if (!(status & (ACPIBAT_ST_CHARGING|ACPIBAT_ST_DISCHARGING))) {
    476 		sc->sc_sensor[ACPIBAT_CHARGING].state = ENVSYS_SVALID;
    477 		sc->sc_sensor[ACPIBAT_CHARGING].value_cur = 0;
    478 		sc->sc_sensor[ACPIBAT_CHARGERATE].state = ENVSYS_SINVALID;
    479 		sc->sc_sensor[ACPIBAT_DISCHARGERATE].state = ENVSYS_SINVALID;
    480 	}
    481 
    482 	sc->sc_sensor[ACPIBAT_CHARGE_STATE].value_cur =
    483 	    ENVSYS_BATTERY_CAPACITY_NORMAL;
    484 
    485 	sc->sc_sensor[ACPIBAT_CAPACITY].value_cur = p2[2].Integer.Value * 1000;
    486 	sc->sc_sensor[ACPIBAT_CAPACITY].state = ENVSYS_SVALID;
    487 	sc->sc_sensor[ACPIBAT_CAPACITY].flags |=
    488 	    (ENVSYS_FPERCENT|ENVSYS_FVALID_MAX);
    489 	sc->sc_sensor[ACPIBAT_VOLTAGE].value_cur = p2[3].Integer.Value * 1000;
    490 	sc->sc_sensor[ACPIBAT_VOLTAGE].state = ENVSYS_SVALID;
    491 
    492 	if (sc->sc_sensor[ACPIBAT_CAPACITY].value_cur <
    493 	    sc->sc_sensor[ACPIBAT_WCAPACITY].value_cur) {
    494 		sc->sc_sensor[ACPIBAT_CAPACITY].state = ENVSYS_SWARNUNDER;
    495 		sc->sc_sensor[ACPIBAT_CHARGE_STATE].value_cur =
    496 		    ENVSYS_BATTERY_CAPACITY_WARNING;
    497 	}
    498 
    499 	if (sc->sc_sensor[ACPIBAT_CAPACITY].value_cur <
    500 	    sc->sc_sensor[ACPIBAT_LCAPACITY].value_cur) {
    501 		sc->sc_sensor[ACPIBAT_CAPACITY].state = ENVSYS_SCRITUNDER;
    502 		sc->sc_sensor[ACPIBAT_CHARGE_STATE].value_cur =
    503 		    ENVSYS_BATTERY_CAPACITY_LOW;
    504 	}
    505 
    506 	if (status & ACPIBAT_ST_CRITICAL) {
    507 		sc->sc_sensor[ACPIBAT_CAPACITY].state = ENVSYS_SCRITICAL;
    508 		sc->sc_sensor[ACPIBAT_CHARGE_STATE].value_cur =
    509 		    ENVSYS_BATTERY_CAPACITY_CRITICAL;
    510 	}
    511 
    512 	rv = AE_OK;
    513 
    514 out:
    515 	AcpiOsFree(buf.Pointer);
    516 	return rv;
    517 }
    518 
    519 #define SCALE(x)	((x)/1000000), (((x)%1000000)/1000)
    520 #define CAPUNITS(sc)	(ABAT_ISSET((sc), ABAT_F_PWRUNIT_MA)?"Ah":"Wh")
    521 #define RATEUNITS(sc)	(ABAT_ISSET((sc), ABAT_F_PWRUNIT_MA)?"A":"W")
    522 static void
    523 acpibat_print_info(device_t dv)
    524 {
    525 	struct acpibat_softc *sc = device_private(dv);
    526 	const char *tech;
    527 
    528 	if (sc->sc_sensor[ACPIBAT_TECHNOLOGY].value_cur)
    529 		tech = "secondary";
    530 	else
    531 		tech = "primary";
    532 
    533 	aprint_debug_dev(dv, "%s battery, Design %d.%03d%s "
    534 	    "Last full %d.%03d%s Warn %d.%03d%s Low %d.%03d%s\n",
    535 	    tech, SCALE(sc->sc_sensor[ACPIBAT_DCAPACITY].value_cur), CAPUNITS(sc),
    536 	    SCALE(sc->sc_sensor[ACPIBAT_LFCCAPACITY].value_cur),CAPUNITS(sc),
    537 	    SCALE(sc->sc_sensor[ACPIBAT_WCAPACITY].value_cur), CAPUNITS(sc),
    538 	    SCALE(sc->sc_sensor[ACPIBAT_LCAPACITY].value_cur), CAPUNITS(sc));
    539 }
    540 
    541 static void
    542 acpibat_print_stat(device_t dv)
    543 {
    544 	struct acpibat_softc *sc = device_private(dv);
    545 	const char *capstat, *chargestat;
    546 	int percent, denom;
    547 	int32_t value;
    548 
    549 	percent = 0;
    550 
    551 	if (sc->sc_sensor[ACPIBAT_CAPACITY].state == ENVSYS_SCRITUNDER)
    552 		capstat = "CRITICAL UNDER ";
    553 	else if (sc->sc_sensor[ACPIBAT_CAPACITY].state == ENVSYS_SCRITOVER)
    554 		capstat = "CRITICAL OVER ";
    555 	else
    556 		capstat = "";
    557 
    558 	if (sc->sc_sensor[ACPIBAT_CHARGING].state != ENVSYS_SVALID) {
    559 		chargestat = "idling";
    560 		value = 0;
    561 	} else if (sc->sc_sensor[ACPIBAT_CHARGING].value_cur == 0) {
    562 		chargestat = "discharging";
    563 		value = sc->sc_sensor[ACPIBAT_DISCHARGERATE].value_cur;
    564 	} else {
    565 		chargestat = "charging";
    566 		value = sc->sc_sensor[ACPIBAT_CHARGERATE].value_cur;
    567 	}
    568 
    569 	denom = sc->sc_sensor[ACPIBAT_LFCCAPACITY].value_cur / 100;
    570 	if (denom > 0)
    571 		percent = (sc->sc_sensor[ACPIBAT_CAPACITY].value_cur) / denom;
    572 
    573 	aprint_debug_dev(dv, "%s%s: %d.%03dV cap %d.%03d%s (%d%%) "
    574 	    "rate %d.%03d%s\n", capstat, chargestat,
    575 	    SCALE(sc->sc_sensor[ACPIBAT_VOLTAGE].value_cur),
    576 	    SCALE(sc->sc_sensor[ACPIBAT_CAPACITY].value_cur), CAPUNITS(sc),
    577 	    percent, SCALE(value), RATEUNITS(sc));
    578 }
    579 
    580 static void
    581 acpibat_update(void *arg)
    582 {
    583 	device_t dv = arg;
    584 	struct acpibat_softc *sc = device_private(dv);
    585 
    586 	if (sc->sc_available < ABAT_ALV_INFO) {
    587 		/* current information is invalid */
    588 #if 0
    589 		/*
    590 		 * XXX: The driver sometimes unaware that the battery exist.
    591 		 * (i.e. just after the boot or resuming)
    592 		 * Thus, the driver should always check it here.
    593 		 */
    594 		if (sc->sc_available < ABAT_ALV_PRESENCE)
    595 #endif
    596 			/* presence is invalid */
    597 			if (acpibat_battery_present(dv) < 0) {
    598 				/* error */
    599 				aprint_debug_dev(dv,
    600 				    "cannot get battery presence.\n");
    601 				return;
    602 			}
    603 
    604 		if (ABAT_ISSET(sc, ABAT_F_PRESENT)) {
    605 			/* the battery is present. */
    606 			if (ABAT_ISSET(sc, ABAT_F_VERBOSE))
    607 				aprint_debug_dev(dv,
    608 				    "battery is present.\n");
    609 			if (ACPI_FAILURE(acpibat_get_info(dv)))
    610 				return;
    611 			if (ABAT_ISSET(sc, ABAT_F_VERBOSE))
    612 				acpibat_print_info(dv);
    613 		} else {
    614 			/* the battery is not present. */
    615 			if (ABAT_ISSET(sc, ABAT_F_VERBOSE))
    616 				aprint_debug_dev(dv,
    617 				    "battery is not present.\n");
    618 			return;
    619 		}
    620 	} else {
    621 		/* current information is valid */
    622 		if (!ABAT_ISSET(sc, ABAT_F_PRESENT)) {
    623 			/* the battery is not present. */
    624 			return;
    625 		}
    626  	}
    627 
    628 	if (ACPI_FAILURE(acpibat_get_status(dv)))
    629 		return;
    630 
    631 	if (ABAT_ISSET(sc, ABAT_F_VERBOSE))
    632 		acpibat_print_stat(dv);
    633 }
    634 
    635 static void
    636 acpibat_update_info(void *arg)
    637 {
    638 	device_t dev = arg;
    639 	struct acpibat_softc *sc = device_private(dev);
    640 
    641 	mutex_enter(&sc->sc_mutex);
    642 	acpibat_clear_presence(sc);
    643 	acpibat_update(arg);
    644 	mutex_exit(&sc->sc_mutex);
    645 }
    646 
    647 static void
    648 acpibat_update_stat(void *arg)
    649 {
    650 	device_t dev = arg;
    651 	struct acpibat_softc *sc = device_private(dev);
    652 
    653 	mutex_enter(&sc->sc_mutex);
    654 	acpibat_clear_stat(sc);
    655 	acpibat_update(arg);
    656 	microtime(&sc->sc_lastupdate);
    657 	cv_broadcast(&sc->sc_condvar);
    658 	mutex_exit(&sc->sc_mutex);
    659 }
    660 
    661 /*
    662  * acpibat_notify_handler:
    663  *
    664  *	Callback from ACPI interrupt handler to notify us of an event.
    665  */
    666 static void
    667 acpibat_notify_handler(ACPI_HANDLE handle, UINT32 notify, void *context)
    668 {
    669 	device_t dv = context;
    670 	int rv;
    671 
    672 #ifdef ACPI_BAT_DEBUG
    673 	aprint_debug_dev(dv, "received notify message: 0x%x\n", notify);
    674 #endif
    675 
    676 	switch (notify) {
    677 	case ACPI_NOTIFY_BusCheck:
    678 		break;
    679 	case ACPI_NOTIFY_DeviceCheck:
    680 	case ACPI_NOTIFY_BatteryInformationChanged:
    681 		rv = AcpiOsExecute(OSL_NOTIFY_HANDLER, acpibat_update_info, dv);
    682 		if (ACPI_FAILURE(rv))
    683 			aprint_error_dev(dv,
    684 			    "unable to queue info check: %s\n",
    685 			    AcpiFormatException(rv));
    686 		break;
    687 
    688 	case ACPI_NOTIFY_BatteryStatusChanged:
    689 		rv = AcpiOsExecute(OSL_NOTIFY_HANDLER, acpibat_update_stat, dv);
    690 		if (ACPI_FAILURE(rv))
    691 			aprint_error_dev(dv,
    692 			    "unable to queue status check: %s\n",
    693 			    AcpiFormatException(rv));
    694 		break;
    695 
    696 	default:
    697 		aprint_error_dev(dv,
    698 		    "received unknown notify message: 0x%x\n", notify);
    699 	}
    700 }
    701 
    702 static void
    703 acpibat_init_envsys(device_t dv)
    704 {
    705 	struct acpibat_softc *sc = device_private(dv);
    706 	int i, capunit, rateunit;
    707 
    708 	if (sc->sc_flags & ABAT_F_PWRUNIT_MA) {
    709 		capunit = ENVSYS_SAMPHOUR;
    710 		rateunit = ENVSYS_SAMPS;
    711 	} else {
    712 		capunit = ENVSYS_SWATTHOUR;
    713 		rateunit = ENVSYS_SWATTS;
    714 	}
    715 
    716 #define INITDATA(index, unit, string)					\
    717 	sc->sc_sensor[index].state = ENVSYS_SVALID;			\
    718 	sc->sc_sensor[index].units = unit;     				\
    719  	strlcpy(sc->sc_sensor[index].desc, string,			\
    720  	    sizeof(sc->sc_sensor[index].desc));
    721 
    722 	INITDATA(ACPIBAT_PRESENT, ENVSYS_INDICATOR, "present");
    723 	INITDATA(ACPIBAT_DCAPACITY, capunit, "design cap");
    724 	INITDATA(ACPIBAT_LFCCAPACITY, capunit, "last full cap");
    725 	INITDATA(ACPIBAT_TECHNOLOGY, ENVSYS_INTEGER, "technology");
    726 	INITDATA(ACPIBAT_DVOLTAGE, ENVSYS_SVOLTS_DC, "design voltage");
    727 	INITDATA(ACPIBAT_WCAPACITY, capunit, "warn cap");
    728 	INITDATA(ACPIBAT_LCAPACITY, capunit, "low cap");
    729 	INITDATA(ACPIBAT_VOLTAGE, ENVSYS_SVOLTS_DC, "voltage");
    730 	INITDATA(ACPIBAT_CHARGERATE, rateunit, "charge rate");
    731 	INITDATA(ACPIBAT_DISCHARGERATE, rateunit, "discharge rate");
    732 	INITDATA(ACPIBAT_CAPACITY, capunit, "charge");
    733 	INITDATA(ACPIBAT_CHARGING, ENVSYS_BATTERY_CHARGE, "charging");
    734 	INITDATA(ACPIBAT_CHARGE_STATE, ENVSYS_BATTERY_CAPACITY, "charge state");
    735 
    736 #undef INITDATA
    737 
    738 	/* Enable monitoring for the charge state sensor */
    739 	sc->sc_sensor[ACPIBAT_CHARGE_STATE].monitor = true;
    740 	sc->sc_sensor[ACPIBAT_CHARGE_STATE].flags |= ENVSYS_FMONSTCHANGED;
    741 
    742 	/* Disable userland monitoring on these sensors */
    743 	sc->sc_sensor[ACPIBAT_VOLTAGE].flags = ENVSYS_FMONNOTSUPP;
    744 	sc->sc_sensor[ACPIBAT_CHARGERATE].flags = ENVSYS_FMONNOTSUPP;
    745 	sc->sc_sensor[ACPIBAT_DISCHARGERATE].flags = ENVSYS_FMONNOTSUPP;
    746 	sc->sc_sensor[ACPIBAT_DCAPACITY].flags = ENVSYS_FMONNOTSUPP;
    747 	sc->sc_sensor[ACPIBAT_LFCCAPACITY].flags = ENVSYS_FMONNOTSUPP;
    748 	sc->sc_sensor[ACPIBAT_TECHNOLOGY].flags = ENVSYS_FMONNOTSUPP;
    749 	sc->sc_sensor[ACPIBAT_DVOLTAGE].flags = ENVSYS_FMONNOTSUPP;
    750 	sc->sc_sensor[ACPIBAT_WCAPACITY].flags = ENVSYS_FMONNOTSUPP;
    751 	sc->sc_sensor[ACPIBAT_LCAPACITY].flags = ENVSYS_FMONNOTSUPP;
    752 
    753 	sc->sc_sme = sysmon_envsys_create();
    754 	for (i = 0; i < ACPIBAT_NSENSORS; i++) {
    755 		if (sysmon_envsys_sensor_attach(sc->sc_sme,
    756 						&sc->sc_sensor[i])) {
    757 			aprint_error_dev(dv, "unable to add sensor%d\n", i);
    758 			sysmon_envsys_destroy(sc->sc_sme);
    759 			return;
    760 		}
    761 	}
    762 
    763 	sc->sc_sme->sme_name = device_xname(dv);
    764 	sc->sc_sme->sme_cookie = dv;
    765 	sc->sc_sme->sme_refresh = acpibat_refresh;
    766 	sc->sc_sme->sme_class = SME_CLASS_BATTERY;
    767 	sc->sc_sme->sme_flags = SME_POLL_ONLY;
    768 
    769 	acpibat_update(dv);
    770 
    771 	if (sysmon_envsys_register(sc->sc_sme)) {
    772 		aprint_error_dev(dv, "unable to register with sysmon\n");
    773 		sysmon_envsys_destroy(sc->sc_sme);
    774 	}
    775 }
    776 
    777 static void
    778 acpibat_refresh(struct sysmon_envsys *sme, envsys_data_t *edata)
    779 {
    780 	device_t dv = sme->sme_cookie;
    781 	struct acpibat_softc *sc = device_private(dv);
    782 	ACPI_STATUS rv;
    783 	struct timeval tv, tmp;
    784 
    785 	if (ABAT_ISSET(sc, ABAT_F_PRESENT)) {
    786 		tmp.tv_sec = 5;
    787 		tmp.tv_usec = 0;
    788 		microtime(&tv);
    789 		timersub(&tv, &tmp, &tv);
    790 		if (timercmp(&tv, &sc->sc_lastupdate, <))
    791 			return;
    792 
    793 		if (!mutex_tryenter(&sc->sc_mutex))
    794 			return;
    795 		rv = AcpiOsExecute(OSL_NOTIFY_HANDLER, acpibat_update_stat, dv);
    796 		if (!ACPI_FAILURE(rv))
    797 			cv_timedwait(&sc->sc_condvar, &sc->sc_mutex, hz);
    798 		mutex_exit(&sc->sc_mutex);
    799 	}
    800 }
    801