xref: /netbsd-src/sys/dev/acpi/acpi_bat.c (revision 8b0f9554ff8762542c4defc4f70e1eb76fb508fa)
1 /*	$NetBSD: acpi_bat.c,v 1.64 2007/12/09 20:27:52 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  * 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.64 2007/12/09 20:27:52 jmcneill 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_sme;
124 	envsys_data_t sc_sensor[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 void acpibat_refresh(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_DEFAULT, 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 	if (!pmf_device_register(self, NULL, NULL))
243 		aprint_error_dev(self, "couldn't establish power handler\n");
244 
245 	acpibat_init_envsys(self);
246 }
247 
248 /*
249  * clear informations
250  */
251 
252 static void
253 acpibat_clear_presence(struct acpibat_softc *sc)
254 {
255 	acpibat_clear_info(sc);
256 	sc->sc_available = ABAT_ALV_NONE;
257 	ABAT_CLEAR(sc, ABAT_F_PRESENT);
258 }
259 
260 static void
261 acpibat_clear_info(struct acpibat_softc *sc)
262 {
263 	acpibat_clear_stat(sc);
264 	if (sc->sc_available > ABAT_ALV_PRESENCE)
265 		sc->sc_available = ABAT_ALV_PRESENCE;
266 
267 	sc->sc_sensor[ACPIBAT_DCAPACITY].state = ENVSYS_SINVALID;
268 	sc->sc_sensor[ACPIBAT_LFCCAPACITY].state = ENVSYS_SINVALID;
269 	sc->sc_sensor[ACPIBAT_CAPACITY].state = ENVSYS_SINVALID;
270 	sc->sc_sensor[ACPIBAT_TECHNOLOGY].state = ENVSYS_SINVALID;
271 	sc->sc_sensor[ACPIBAT_DVOLTAGE].state = ENVSYS_SINVALID;
272 	sc->sc_sensor[ACPIBAT_WCAPACITY].state = ENVSYS_SINVALID;
273 	sc->sc_sensor[ACPIBAT_LCAPACITY].state = ENVSYS_SINVALID;
274 }
275 
276 static void
277 acpibat_clear_stat(struct acpibat_softc *sc)
278 {
279 	if (sc->sc_available > ABAT_ALV_INFO)
280 		sc->sc_available = ABAT_ALV_INFO;
281 
282 	sc->sc_sensor[ACPIBAT_CHARGERATE].state = ENVSYS_SINVALID;
283 	sc->sc_sensor[ACPIBAT_DISCHARGERATE].state = ENVSYS_SINVALID;
284 	sc->sc_sensor[ACPIBAT_CAPACITY].state = ENVSYS_SINVALID;
285 	sc->sc_sensor[ACPIBAT_VOLTAGE].state = ENVSYS_SINVALID;
286 	sc->sc_sensor[ACPIBAT_CHARGING].state = ENVSYS_SINVALID;
287 }
288 
289 
290 /*
291  * returns 0 for no battery, 1 for present, and -1 on error
292  */
293 static int
294 acpibat_battery_present(device_t dv)
295 {
296 	struct acpibat_softc *sc = device_private(dv);
297 	uint32_t sta;
298 	ACPI_INTEGER val;
299 	ACPI_STATUS rv;
300 
301 	rv = acpi_eval_integer(sc->sc_node->ad_handle, "_STA", &val);
302 	if (ACPI_FAILURE(rv)) {
303 		aprint_error_dev(dv, "failed to evaluate _STA: %s\n",
304 		    AcpiFormatException(rv));
305 		return -1;
306 	}
307 
308 	sta = (uint32_t)val;
309 
310 	mutex_enter(&sc->sc_mtx);
311 	sc->sc_available = ABAT_ALV_PRESENCE;
312 	if (sta & ACPIBAT_STA_PRESENT) {
313 		ABAT_SET(sc, ABAT_F_PRESENT);
314 		sc->sc_sensor[ACPIBAT_PRESENT].state = ENVSYS_SVALID;
315 		sc->sc_sensor[ACPIBAT_PRESENT].value_cur = 1;
316 	} else
317 		sc->sc_sensor[ACPIBAT_PRESENT].value_cur = 0;
318 
319 	mutex_exit(&sc->sc_mtx);
320 
321 	return (sta & ACPIBAT_STA_PRESENT) ? 1 : 0;
322 }
323 
324 /*
325  * acpibat_get_info
326  *
327  * 	Get, and possibly display, the battery info.
328  */
329 
330 static ACPI_STATUS
331 acpibat_get_info(device_t dv)
332 {
333 	struct acpibat_softc *sc = device_private(dv);
334 	ACPI_OBJECT *p1, *p2;
335 	ACPI_STATUS rv;
336 	ACPI_BUFFER buf;
337 	int capunit, rateunit;
338 
339 	rv = acpi_eval_struct(sc->sc_node->ad_handle, "_BIF", &buf);
340 	if (ACPI_FAILURE(rv)) {
341 		aprint_error_dev(dv, "failed to evaluate _BIF: %s\n",
342 		    AcpiFormatException(rv));
343 		return rv;
344 	}
345 	p1 = (ACPI_OBJECT *)buf.Pointer;
346 
347 	if (p1->Type != ACPI_TYPE_PACKAGE) {
348 		aprint_error_dev(dv, "expected PACKAGE, got %d\n", p1->Type);
349 		goto out;
350 	}
351 	if (p1->Package.Count < 13) {
352 		aprint_error_dev(dv, "expected 13 elements, got %d\n",
353 		    p1->Package.Count);
354 		goto out;
355 	}
356 	p2 = p1->Package.Elements;
357 
358 	mutex_enter(&sc->sc_mtx);
359 	if ((p2[0].Integer.Value & ACPIBAT_PWRUNIT_MA) != 0) {
360 		ABAT_SET(sc, ABAT_F_PWRUNIT_MA);
361 		capunit = ENVSYS_SAMPHOUR;
362 		rateunit = ENVSYS_SAMPS;
363 	} else {
364 		ABAT_CLEAR(sc, ABAT_F_PWRUNIT_MA);
365 		capunit = ENVSYS_SWATTHOUR;
366 		rateunit = ENVSYS_SWATTS;
367 	}
368 
369 	sc->sc_sensor[ACPIBAT_DCAPACITY].units = capunit;
370 	sc->sc_sensor[ACPIBAT_LFCCAPACITY].units = capunit;
371 	sc->sc_sensor[ACPIBAT_WCAPACITY].units = capunit;
372 	sc->sc_sensor[ACPIBAT_LCAPACITY].units = capunit;
373 	sc->sc_sensor[ACPIBAT_CHARGERATE].units = rateunit;
374 	sc->sc_sensor[ACPIBAT_DISCHARGERATE].units = rateunit;
375 	sc->sc_sensor[ACPIBAT_CAPACITY].units = capunit;
376 
377 	sc->sc_sensor[ACPIBAT_DCAPACITY].value_cur = p2[1].Integer.Value * 1000;
378 	sc->sc_sensor[ACPIBAT_DCAPACITY].state = ENVSYS_SVALID;
379 	sc->sc_sensor[ACPIBAT_LFCCAPACITY].value_cur = p2[2].Integer.Value * 1000;
380 	sc->sc_sensor[ACPIBAT_LFCCAPACITY].state = ENVSYS_SVALID;
381 	sc->sc_sensor[ACPIBAT_CAPACITY].value_max = p2[2].Integer.Value * 1000;
382 	sc->sc_sensor[ACPIBAT_TECHNOLOGY].value_cur = p2[3].Integer.Value;
383 	sc->sc_sensor[ACPIBAT_TECHNOLOGY].state = ENVSYS_SVALID;
384 	sc->sc_sensor[ACPIBAT_DVOLTAGE].value_cur = p2[4].Integer.Value * 1000;
385 	sc->sc_sensor[ACPIBAT_DVOLTAGE].state = ENVSYS_SVALID;
386 	sc->sc_sensor[ACPIBAT_WCAPACITY].value_cur = p2[5].Integer.Value * 1000;
387 	sc->sc_sensor[ACPIBAT_WCAPACITY].value_max = p2[2].Integer.Value * 1000;
388 	sc->sc_sensor[ACPIBAT_WCAPACITY].state = ENVSYS_SVALID;
389 	sc->sc_sensor[ACPIBAT_WCAPACITY].flags |=
390 	    (ENVSYS_FPERCENT|ENVSYS_FVALID_MAX);
391 	sc->sc_sensor[ACPIBAT_LCAPACITY].value_cur = p2[6].Integer.Value * 1000;
392 	sc->sc_sensor[ACPIBAT_LCAPACITY].value_max = p2[2].Integer.Value * 1000;
393 	sc->sc_sensor[ACPIBAT_LCAPACITY].state = ENVSYS_SVALID;
394 	sc->sc_sensor[ACPIBAT_LCAPACITY].flags |=
395 	    (ENVSYS_FPERCENT|ENVSYS_FVALID_MAX);
396 	sc->sc_available = ABAT_ALV_INFO;
397 
398 	mutex_exit(&sc->sc_mtx);
399 
400 	aprint_verbose_dev(dv, "battery info: %s, %s, %s",
401 	    p2[12].String.Pointer, p2[11].String.Pointer, p2[9].String.Pointer);
402 	if (p2[10].String.Pointer)
403 		aprint_verbose(" %s", p2[10].String.Pointer);
404 
405 	aprint_verbose("\n");
406 
407 	rv = AE_OK;
408 
409 out:
410 	AcpiOsFree(buf.Pointer);
411 	return rv;
412 }
413 
414 /*
415  * acpibat_get_status:
416  *
417  *	Get, and possibly display, the current battery line status.
418  */
419 static ACPI_STATUS
420 acpibat_get_status(device_t dv)
421 {
422 	struct acpibat_softc *sc = device_private(dv);
423 	int status, battrate;
424 	ACPI_OBJECT *p1, *p2;
425 	ACPI_STATUS rv;
426 	ACPI_BUFFER buf;
427 
428 	rv = acpi_eval_struct(sc->sc_node->ad_handle, "_BST", &buf);
429 	if (ACPI_FAILURE(rv)) {
430 		aprint_error_dev(dv, "failed to evaluate _BST: %s\n",
431 		    AcpiFormatException(rv));
432 		return rv;
433 	}
434 	p1 = (ACPI_OBJECT *)buf.Pointer;
435 
436 	if (p1->Type != ACPI_TYPE_PACKAGE) {
437 		aprint_error_dev(dv, "expected PACKAGE, got %d\n",
438 		    p1->Type);
439 		rv = AE_ERROR;
440 		goto out;
441 	}
442 	if (p1->Package.Count < 4) {
443 		aprint_error_dev(dv, "expected 4 elts, got %d\n",
444 		    p1->Package.Count);
445 		rv = AE_ERROR;
446 		goto out;
447 	}
448 	p2 = p1->Package.Elements;
449 
450 	mutex_enter(&sc->sc_mtx);
451 
452 	status = p2[0].Integer.Value;
453 	battrate = p2[1].Integer.Value;
454 
455 	if (status & ACPIBAT_ST_CHARGING) {
456 		sc->sc_sensor[ACPIBAT_CHARGERATE].state = ENVSYS_SVALID;
457 		sc->sc_sensor[ACPIBAT_CHARGERATE].value_cur = battrate * 1000;
458 		sc->sc_sensor[ACPIBAT_DISCHARGERATE].state = ENVSYS_SINVALID;
459 		sc->sc_sensor[ACPIBAT_CHARGING].state = ENVSYS_SVALID;
460 		sc->sc_sensor[ACPIBAT_CHARGING].value_cur = 1;
461 	} else if (status & ACPIBAT_ST_DISCHARGING) {
462 		sc->sc_sensor[ACPIBAT_DISCHARGERATE].state = ENVSYS_SVALID;
463 		sc->sc_sensor[ACPIBAT_DISCHARGERATE].value_cur = battrate * 1000;
464 		sc->sc_sensor[ACPIBAT_CHARGERATE].state = ENVSYS_SINVALID;
465 		sc->sc_sensor[ACPIBAT_CHARGING].state = ENVSYS_SVALID;
466 		sc->sc_sensor[ACPIBAT_CHARGING].value_cur = 0;
467 	} else if (!(status & (ACPIBAT_ST_CHARGING|ACPIBAT_ST_DISCHARGING))) {
468 		sc->sc_sensor[ACPIBAT_CHARGING].state = ENVSYS_SVALID;
469 		sc->sc_sensor[ACPIBAT_CHARGING].value_cur = 0;
470 		sc->sc_sensor[ACPIBAT_CHARGERATE].state = ENVSYS_SINVALID;
471 		sc->sc_sensor[ACPIBAT_DISCHARGERATE].state = ENVSYS_SINVALID;
472 	}
473 
474 	sc->sc_sensor[ACPIBAT_CHARGE_STATE].value_cur =
475 	    ENVSYS_BATTERY_CAPACITY_NORMAL;
476 
477 	sc->sc_sensor[ACPIBAT_CAPACITY].value_cur = p2[2].Integer.Value * 1000;
478 	sc->sc_sensor[ACPIBAT_CAPACITY].state = ENVSYS_SVALID;
479 	sc->sc_sensor[ACPIBAT_CAPACITY].flags |=
480 	    (ENVSYS_FPERCENT|ENVSYS_FVALID_MAX);
481 	sc->sc_sensor[ACPIBAT_VOLTAGE].value_cur = p2[3].Integer.Value * 1000;
482 	sc->sc_sensor[ACPIBAT_VOLTAGE].state = ENVSYS_SVALID;
483 
484 	if (sc->sc_sensor[ACPIBAT_CAPACITY].value_cur <
485 	    sc->sc_sensor[ACPIBAT_WCAPACITY].value_cur) {
486 		sc->sc_sensor[ACPIBAT_CAPACITY].state = ENVSYS_SWARNUNDER;
487 		sc->sc_sensor[ACPIBAT_CHARGE_STATE].value_cur =
488 		    ENVSYS_BATTERY_CAPACITY_WARNING;
489 	}
490 
491 	if (sc->sc_sensor[ACPIBAT_CAPACITY].value_cur <
492 	    sc->sc_sensor[ACPIBAT_LCAPACITY].value_cur) {
493 		sc->sc_sensor[ACPIBAT_CAPACITY].state = ENVSYS_SCRITUNDER;
494 		sc->sc_sensor[ACPIBAT_CHARGE_STATE].value_cur =
495 		    ENVSYS_BATTERY_CAPACITY_LOW;
496 	}
497 
498 	if (status & ACPIBAT_ST_CRITICAL) {
499 		sc->sc_sensor[ACPIBAT_CAPACITY].state = ENVSYS_SCRITICAL;
500 		sc->sc_sensor[ACPIBAT_CHARGE_STATE].value_cur =
501 		    ENVSYS_BATTERY_CAPACITY_CRITICAL;
502 	}
503 
504 	mutex_exit(&sc->sc_mtx);
505 
506 	rv = AE_OK;
507 
508 out:
509 	AcpiOsFree(buf.Pointer);
510 	return rv;
511 }
512 
513 #define SCALE(x)	((x)/1000000), (((x)%1000000)/1000)
514 #define CAPUNITS(sc)	(ABAT_ISSET((sc), ABAT_F_PWRUNIT_MA)?"Ah":"Wh")
515 #define RATEUNITS(sc)	(ABAT_ISSET((sc), ABAT_F_PWRUNIT_MA)?"A":"W")
516 static void
517 acpibat_print_info(device_t dv)
518 {
519 	struct acpibat_softc *sc = device_private(dv);
520 	const char *tech;
521 
522 	if (sc->sc_sensor[ACPIBAT_TECHNOLOGY].value_cur)
523 		tech = "secondary";
524 	else
525 		tech = "primary";
526 
527 	aprint_debug_dev(dv, "%s battery, Design %d.%03d%s "
528 	    "Last full %d.%03d%s Warn %d.%03d%s Low %d.%03d%s\n",
529 	    tech, SCALE(sc->sc_sensor[ACPIBAT_DCAPACITY].value_cur), CAPUNITS(sc),
530 	    SCALE(sc->sc_sensor[ACPIBAT_LFCCAPACITY].value_cur),CAPUNITS(sc),
531 	    SCALE(sc->sc_sensor[ACPIBAT_WCAPACITY].value_cur), CAPUNITS(sc),
532 	    SCALE(sc->sc_sensor[ACPIBAT_LCAPACITY].value_cur), CAPUNITS(sc));
533 }
534 
535 static void
536 acpibat_print_stat(device_t dv)
537 {
538 	struct acpibat_softc *sc = device_private(dv);
539 	const char *capstat, *chargestat;
540 	int percent, denom;
541 	int32_t value;
542 
543 	percent = 0;
544 
545 	if (sc->sc_sensor[ACPIBAT_CAPACITY].state == ENVSYS_SCRITUNDER)
546 		capstat = "CRITICAL UNDER ";
547 	else if (sc->sc_sensor[ACPIBAT_CAPACITY].state == ENVSYS_SCRITOVER)
548 		capstat = "CRITICAL OVER ";
549 	else
550 		capstat = "";
551 
552 	if (sc->sc_sensor[ACPIBAT_CHARGING].state != ENVSYS_SVALID) {
553 		chargestat = "idling";
554 		value = 0;
555 	} else if (sc->sc_sensor[ACPIBAT_CHARGING].value_cur == 0) {
556 		chargestat = "discharging";
557 		value = sc->sc_sensor[ACPIBAT_DISCHARGERATE].value_cur;
558 	} else {
559 		chargestat = "charging";
560 		value = sc->sc_sensor[ACPIBAT_CHARGERATE].value_cur;
561 	}
562 
563 	denom = sc->sc_sensor[ACPIBAT_LFCCAPACITY].value_cur / 100;
564 	if (denom > 0)
565 		percent = (sc->sc_sensor[ACPIBAT_CAPACITY].value_cur) / denom;
566 
567 	aprint_debug_dev(dv, "%s%s: %d.%03dV cap %d.%03d%s (%d%%) "
568 	    "rate %d.%03d%s\n", capstat, chargestat,
569 	    SCALE(sc->sc_sensor[ACPIBAT_VOLTAGE].value_cur),
570 	    SCALE(sc->sc_sensor[ACPIBAT_CAPACITY].value_cur), CAPUNITS(sc),
571 	    percent, SCALE(value), RATEUNITS(sc));
572 }
573 
574 static void
575 acpibat_update(void *arg)
576 {
577 	device_t dv = arg;
578 	struct acpibat_softc *sc = device_private(dv);
579 
580 	if (sc->sc_available < ABAT_ALV_INFO) {
581 		/* current information is invalid */
582 #if 0
583 		/*
584 		 * XXX: The driver sometimes unaware that the battery exist.
585 		 * (i.e. just after the boot or resuming)
586 		 * Thus, the driver should always check it here.
587 		 */
588 		if (sc->sc_available < ABAT_ALV_PRESENCE)
589 #endif
590 			/* presence is invalid */
591 			if (acpibat_battery_present(dv) < 0) {
592 				/* error */
593 				aprint_debug_dev(dv,
594 				    "cannot get battery presence.\n");
595 				return;
596 			}
597 
598 		if (ABAT_ISSET(sc, ABAT_F_PRESENT)) {
599 			/* the battery is present. */
600 			if (ABAT_ISSET(sc, ABAT_F_VERBOSE))
601 				aprint_debug_dev(dv,
602 				    "battery is present.\n");
603 			if (ACPI_FAILURE(acpibat_get_info(dv)))
604 				return;
605 			if (ABAT_ISSET(sc, ABAT_F_VERBOSE))
606 				acpibat_print_info(dv);
607 		} else {
608 			/* the battery is not present. */
609 			if (ABAT_ISSET(sc, ABAT_F_VERBOSE))
610 				aprint_debug_dev(dv,
611 				    "battery is not present.\n");
612 			return;
613 		}
614 	} else {
615 		/* current information is valid */
616 		if (!ABAT_ISSET(sc, ABAT_F_PRESENT)) {
617 			/* the battery is not present. */
618 			return;
619 		}
620  	}
621 
622 	if (ACPI_FAILURE(acpibat_get_status(dv)))
623 		return;
624 
625 	if (ABAT_ISSET(sc, ABAT_F_VERBOSE))
626 		acpibat_print_stat(dv);
627 }
628 
629 /*
630  * acpibat_notify_handler:
631  *
632  *	Callback from ACPI interrupt handler to notify us of an event.
633  */
634 static void
635 acpibat_notify_handler(ACPI_HANDLE handle, UINT32 notify, void *context)
636 {
637 	device_t dv = context;
638 	struct acpibat_softc *sc = device_private(dv);
639 	int rv;
640 
641 #ifdef ACPI_BAT_DEBUG
642 	aprint_debug_dev(dv, "received notify message: 0x%x\n", notify);
643 #endif
644 
645 	switch (notify) {
646 	case ACPI_NOTIFY_BusCheck:
647 		break;
648 
649 	case ACPI_NOTIFY_DeviceCheck:
650 	case ACPI_NOTIFY_BatteryInformationChanged:
651 		mutex_enter(&sc->sc_mtx);
652 		acpibat_clear_presence(sc);
653 		mutex_exit(&sc->sc_mtx);
654 		rv = AcpiOsExecute(OSL_NOTIFY_HANDLER, acpibat_update, dv);
655 		if (ACPI_FAILURE(rv))
656 			aprint_error_dev(dv,
657 			    "unable to queue status check: %s\n",
658 			    AcpiFormatException(rv));
659 		break;
660 
661 	case ACPI_NOTIFY_BatteryStatusChanged:
662 		mutex_enter(&sc->sc_mtx);
663 		acpibat_clear_stat(sc);
664 		mutex_exit(&sc->sc_mtx);
665 		rv = AcpiOsExecute(OSL_NOTIFY_HANDLER, acpibat_update, dv);
666 		if (ACPI_FAILURE(rv))
667 			aprint_error_dev(dv,
668 			    "unable to queue status check: %s\n",
669 			    AcpiFormatException(rv));
670 		break;
671 
672 	default:
673 		aprint_error_dev(dv,
674 		    "received unknown notify message: 0x%x\n", notify);
675 	}
676 }
677 
678 static void
679 acpibat_init_envsys(device_t dv)
680 {
681 	struct acpibat_softc *sc = device_private(dv);
682 	int i, capunit, rateunit;
683 
684 	if (sc->sc_flags & ABAT_F_PWRUNIT_MA) {
685 		capunit = ENVSYS_SAMPHOUR;
686 		rateunit = ENVSYS_SAMPS;
687 	} else {
688 		capunit = ENVSYS_SWATTHOUR;
689 		rateunit = ENVSYS_SWATTS;
690 	}
691 
692 #define INITDATA(index, unit, string)					\
693 	sc->sc_sensor[index].state = ENVSYS_SVALID;			\
694 	sc->sc_sensor[index].units = unit;     				\
695  	strlcpy(sc->sc_sensor[index].desc, string,			\
696  	    sizeof(sc->sc_sensor[index].desc));
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_BATTERY_CHARGE, "charging");
710 	INITDATA(ACPIBAT_CHARGE_STATE, ENVSYS_BATTERY_CAPACITY, "charge state");
711 
712 #undef INITDATA
713 
714 	/* Enable monitoring for the charge state sensor */
715 	sc->sc_sensor[ACPIBAT_CHARGE_STATE].monitor = true;
716 	sc->sc_sensor[ACPIBAT_CHARGE_STATE].flags |= ENVSYS_FMONSTCHANGED;
717 
718 	/* Disable userland monitoring on these sensors */
719 	sc->sc_sensor[ACPIBAT_VOLTAGE].flags = ENVSYS_FMONNOTSUPP;
720 	sc->sc_sensor[ACPIBAT_CHARGERATE].flags = ENVSYS_FMONNOTSUPP;
721 	sc->sc_sensor[ACPIBAT_DISCHARGERATE].flags = ENVSYS_FMONNOTSUPP;
722 	sc->sc_sensor[ACPIBAT_DCAPACITY].flags = ENVSYS_FMONNOTSUPP;
723 	sc->sc_sensor[ACPIBAT_LFCCAPACITY].flags = ENVSYS_FMONNOTSUPP;
724 	sc->sc_sensor[ACPIBAT_TECHNOLOGY].flags = ENVSYS_FMONNOTSUPP;
725 	sc->sc_sensor[ACPIBAT_DVOLTAGE].flags = ENVSYS_FMONNOTSUPP;
726 	sc->sc_sensor[ACPIBAT_WCAPACITY].flags = ENVSYS_FMONNOTSUPP;
727 	sc->sc_sensor[ACPIBAT_LCAPACITY].flags = ENVSYS_FMONNOTSUPP;
728 
729 	sc->sc_sme = sysmon_envsys_create();
730 	for (i = 0; i < ACPIBAT_NSENSORS; i++) {
731 		if (sysmon_envsys_sensor_attach(sc->sc_sme,
732 						&sc->sc_sensor[i])) {
733 			aprint_error_dev(dv, "unable to add sensor%d\n", i);
734 			sysmon_envsys_destroy(sc->sc_sme);
735 			return;
736 		}
737 	}
738 
739 	sc->sc_sme->sme_name = device_xname(dv);
740 	sc->sc_sme->sme_cookie = dv;
741 	sc->sc_sme->sme_refresh = acpibat_refresh;
742 	sc->sc_sme->sme_class = SME_CLASS_BATTERY;
743 
744 	sc->sc_updateinterval.tv_sec = 1;
745 	sc->sc_updateinterval.tv_usec = 0;
746 
747 	if (sysmon_envsys_register(sc->sc_sme)) {
748 		aprint_error_dev(dv, "unable to register with sysmon\n");
749 		sysmon_envsys_destroy(sc->sc_sme);
750 	}
751 }
752 
753 static void
754 acpibat_refresh(struct sysmon_envsys *sme, envsys_data_t *edata)
755 {
756 	device_t dv = sme->sme_cookie;
757 	struct acpibat_softc *sc = device_private(dv);
758 
759 	if (ratecheck(&sc->sc_lastupdate, &sc->sc_updateinterval))
760 		acpibat_update(dv);
761 }
762