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