xref: /netbsd-src/sys/dev/acpi/acpi_bat.c (revision 4e6df137e8e14049b5a701d249962c480449c141)
1 /*	$NetBSD: acpi_bat.c,v 1.84 2010/03/05 14:00:16 jruoho 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 /*
66  * ACPI Battery Driver.
67  *
68  * ACPI defines two different battery device interfaces: "Control
69  * Method" batteries, in which AML methods are defined in order to get
70  * battery status and set battery alarm thresholds, and a "Smart
71  * Battery" device, which is an SMbus device accessed through the ACPI
72  * Embedded Controller device.
73  *
74  * This driver is for the "Control Method"-style battery only.
75  */
76 
77 #include <sys/cdefs.h>
78 __KERNEL_RCSID(0, "$NetBSD: acpi_bat.c,v 1.84 2010/03/05 14:00:16 jruoho Exp $");
79 
80 #include <sys/param.h>
81 #include <sys/condvar.h>
82 #include <sys/device.h>
83 #include <sys/kernel.h>
84 #include <sys/kmem.h>
85 #include <sys/module.h>
86 #include <sys/mutex.h>
87 #include <sys/systm.h>
88 
89 #include <dev/acpi/acpireg.h>
90 #include <dev/acpi/acpivar.h>
91 
92 #define _COMPONENT		 ACPI_BAT_COMPONENT
93 ACPI_MODULE_NAME		 ("acpi_bat")
94 
95 /*
96  * Sensor indexes.
97  */
98 enum {
99 	ACPIBAT_PRESENT		 = 0,
100 	ACPIBAT_DCAPACITY	 = 1,
101 	ACPIBAT_LFCCAPACITY	 = 2,
102 	ACPIBAT_TECHNOLOGY	 = 3,
103 	ACPIBAT_DVOLTAGE	 = 4,
104 	ACPIBAT_WCAPACITY	 = 5,
105 	ACPIBAT_LCAPACITY	 = 6,
106 	ACPIBAT_VOLTAGE		 = 7,
107 	ACPIBAT_CHARGERATE	 = 8,
108 	ACPIBAT_DISCHARGERATE	 = 9,
109 	ACPIBAT_CAPACITY	 = 10,
110 	ACPIBAT_CHARGING	 = 11,
111 	ACPIBAT_CHARGE_STATE	 = 12,
112 	ACPIBAT_COUNT		 = 13
113 };
114 
115 /*
116  * Battery Information, _BIF
117  * (ACPI 3.0, sec. 10.2.2.1).
118  */
119 enum {
120 	ACPIBAT_BIF_UNIT	 = 0,
121 	ACPIBAT_BIF_DCAPACITY	 = 1,
122 	ACPIBAT_BIF_LFCCAPACITY	 = 2,
123 	ACPIBAT_BIF_TECHNOLOGY	 = 3,
124 	ACPIBAT_BIF_DVOLTAGE	 = 4,
125 	ACPIBAT_BIF_WCAPACITY	 = 5,
126 	ACPIBAT_BIF_LCAPACITY	 = 6,
127 	ACPIBAT_BIF_GRANULARITY1 = 7,
128 	ACPIBAT_BIF_GRANULARITY2 = 8,
129 	ACPIBAT_BIF_MODEL	 = 9,
130 	ACPIBAT_BIF_SERIAL	 = 10,
131 	ACPIBAT_BIF_TYPE	 = 11,
132 	ACPIBAT_BIF_OEM		 = 12,
133 	ACPIBAT_BIF_COUNT	 = 13
134 };
135 
136 /*
137  * Battery Status, _BST
138  * (ACPI 3.0, sec. 10.2.2.3).
139  */
140 enum {
141 	ACPIBAT_BST_STATE	 = 0,
142 	ACPIBAT_BST_RATE	 = 1,
143 	ACPIBAT_BST_CAPACITY	 = 2,
144 	ACPIBAT_BST_VOLTAGE	 = 3,
145 	ACPIBAT_BST_COUNT	 = 4
146 };
147 
148 struct acpibat_softc {
149 	struct acpi_devnode	*sc_node;
150 	struct sysmon_envsys	*sc_sme;
151 	struct timeval		 sc_lastupdate;
152 	envsys_data_t		*sc_sensor;
153 	kmutex_t		 sc_mutex;
154 	kcondvar_t		 sc_condvar;
155 	int                      sc_present;
156 };
157 
158 static const char * const bat_hid[] = {
159 	"PNP0C0A",
160 	NULL
161 };
162 
163 #define ACPIBAT_PWRUNIT_MA	0x00000001  /* mA not mW */
164 #define ACPIBAT_ST_DISCHARGING	0x00000001  /* battery is discharging */
165 #define ACPIBAT_ST_CHARGING	0x00000002  /* battery is charging */
166 #define ACPIBAT_ST_CRITICAL	0x00000004  /* battery is critical */
167 
168 /*
169  * Flags for battery status from _STA return. Note that
170  * this differs from the conventional evaluation of _STA:
171  *
172  *	"Unlike most other devices, when a battery is inserted or
173  *	 removed from the system, the device itself (the battery bay)
174  *	 is still considered to be present in the system. For most
175  *	 systems, the _STA for this device will always return a value
176  *	 with bits 0-3 set and will toggle bit 4 to indicate the actual
177  *	 presence of a battery. (ACPI 3.0, sec. 10.2.1, p. 320.)"
178  */
179 #define ACPIBAT_STA_PRESENT	0x00000010  /* battery present */
180 
181 /*
182  * A value used when _BST or _BIF is teporarily unknown (see ibid.).
183  */
184 #define ACPIBAT_VAL_UNKNOWN	0xFFFFFFFF
185 
186 #define ACPIBAT_VAL_ISVALID(x)						      \
187 	(((x) != ACPIBAT_VAL_UNKNOWN) ? ENVSYS_SVALID : ENVSYS_SINVALID)
188 
189 static int	    acpibat_match(device_t, cfdata_t, void *);
190 static void	    acpibat_attach(device_t, device_t, void *);
191 static int	    acpibat_detach(device_t, int);
192 static int          acpibat_get_sta(device_t);
193 static ACPI_OBJECT *acpibat_get_object(ACPI_HANDLE, const char *, int);
194 static void         acpibat_get_info(device_t);
195 static void         acpibat_get_status(device_t);
196 static void         acpibat_update_info(void *);
197 static void         acpibat_update_status(void *);
198 static void         acpibat_init_envsys(device_t);
199 static void         acpibat_notify_handler(ACPI_HANDLE, UINT32, void *);
200 static void         acpibat_refresh(struct sysmon_envsys *, envsys_data_t *);
201 static bool	    acpibat_resume(device_t, const pmf_qual_t *);
202 
203 CFATTACH_DECL_NEW(acpibat, sizeof(struct acpibat_softc),
204     acpibat_match, acpibat_attach, acpibat_detach, NULL);
205 
206 /*
207  * acpibat_match:
208  *
209  *	Autoconfiguration `match' routine.
210  */
211 static int
212 acpibat_match(device_t parent, cfdata_t match, void *aux)
213 {
214 	struct acpi_attach_args *aa = aux;
215 
216 	if (aa->aa_node->ad_type != ACPI_TYPE_DEVICE)
217 		return 0;
218 
219 	return acpi_match_hid(aa->aa_node->ad_devinfo, bat_hid);
220 }
221 
222 /*
223  * acpibat_attach:
224  *
225  *	Autoconfiguration `attach' routine.
226  */
227 static void
228 acpibat_attach(device_t parent, device_t self, void *aux)
229 {
230 	struct acpibat_softc *sc = device_private(self);
231 	struct acpi_attach_args *aa = aux;
232 	ACPI_STATUS rv;
233 
234 	aprint_naive(": ACPI Battery\n");
235 	aprint_normal(": ACPI Battery\n");
236 
237 	sc->sc_node = aa->aa_node;
238 	sc->sc_present = 0;
239 
240 	sc->sc_sme = NULL;
241 	sc->sc_sensor = NULL;
242 
243 	mutex_init(&sc->sc_mutex, MUTEX_DEFAULT, IPL_NONE);
244 	cv_init(&sc->sc_condvar, device_xname(self));
245 
246 	if (pmf_device_register(self, NULL, acpibat_resume) != true)
247 		aprint_error_dev(self, "couldn't establish power handler\n");
248 
249 	rv = AcpiInstallNotifyHandler(sc->sc_node->ad_handle,
250 	    ACPI_ALL_NOTIFY, acpibat_notify_handler, self);
251 
252 	if (ACPI_FAILURE(rv)) {
253 		aprint_error_dev(self, "couldn't install notify handler\n");
254 		return;
255 	}
256 
257 	sc->sc_sensor = kmem_zalloc(ACPIBAT_COUNT *
258 	    sizeof(*sc->sc_sensor), KM_SLEEP);
259 
260 	if (sc->sc_sensor == NULL)
261 		return;
262 
263 	acpibat_init_envsys(self);
264 }
265 
266 /*
267  * acpibat_detach:
268  *
269  *	Autoconfiguration `detach' routine.
270  */
271 static int
272 acpibat_detach(device_t self, int flags)
273 {
274 	struct acpibat_softc *sc = device_private(self);
275 	ACPI_STATUS rv;
276 
277 	rv = AcpiRemoveNotifyHandler(sc->sc_node->ad_handle,
278 	    ACPI_ALL_NOTIFY, acpibat_notify_handler);
279 
280 	if (ACPI_FAILURE(rv))
281 		return EBUSY;
282 
283 	cv_destroy(&sc->sc_condvar);
284 	mutex_destroy(&sc->sc_mutex);
285 
286 	if (sc->sc_sme != NULL)
287 		sysmon_envsys_unregister(sc->sc_sme);
288 
289 	if (sc->sc_sensor != NULL)
290 		kmem_free(sc->sc_sensor, ACPIBAT_COUNT *
291 		    sizeof(*sc->sc_sensor));
292 
293 	pmf_device_deregister(self);
294 
295 	return 0;
296 }
297 
298 /*
299  * acpibat_get_sta:
300  *
301  *	Evaluate whether the battery is present or absent.
302  *
303  *	Returns: 0 for no battery, 1 for present, and -1 on error.
304  */
305 static int
306 acpibat_get_sta(device_t dv)
307 {
308 	struct acpibat_softc *sc = device_private(dv);
309 	ACPI_INTEGER val;
310 	ACPI_STATUS rv;
311 
312 	rv = acpi_eval_integer(sc->sc_node->ad_handle, "_STA", &val);
313 
314 	if (ACPI_FAILURE(rv)) {
315 		aprint_error_dev(dv, "failed to evaluate _STA\n");
316 		return -1;
317 	}
318 
319 	sc->sc_sensor[ACPIBAT_PRESENT].state = ENVSYS_SVALID;
320 
321 	if ((val & ACPIBAT_STA_PRESENT) == 0) {
322 		sc->sc_sensor[ACPIBAT_PRESENT].value_cur = 0;
323 		return 0;
324 	}
325 
326 	sc->sc_sensor[ACPIBAT_PRESENT].value_cur = 1;
327 
328 	return 1;
329 }
330 
331 static ACPI_OBJECT *
332 acpibat_get_object(ACPI_HANDLE hdl, const char *pth, int count)
333 {
334 	ACPI_OBJECT *obj;
335 	ACPI_BUFFER buf;
336 	ACPI_STATUS rv;
337 
338 	rv = acpi_eval_struct(hdl, pth, &buf);
339 
340 	if (ACPI_FAILURE(rv))
341 		return NULL;
342 
343 	obj = buf.Pointer;
344 
345 	if (obj->Type != ACPI_TYPE_PACKAGE) {
346 		ACPI_FREE(buf.Pointer);
347 		return NULL;
348 	}
349 
350 	if (obj->Package.Count != count) {
351 		ACPI_FREE(buf.Pointer);
352 		return NULL;
353 	}
354 
355 	return obj;
356 }
357 
358 /*
359  * acpibat_get_info:
360  *
361  * 	Get, and possibly display, the battery info.
362  */
363 static void
364 acpibat_get_info(device_t dv)
365 {
366 	struct acpibat_softc *sc = device_private(dv);
367 	ACPI_HANDLE hdl = sc->sc_node->ad_handle;
368 	int capunit, i, j, rateunit, val;
369 	ACPI_OBJECT *elm, *obj;
370 	ACPI_STATUS rv = AE_OK;
371 
372 	obj = acpibat_get_object(hdl, "_BIF", ACPIBAT_BIF_COUNT);
373 
374 	if (obj == NULL) {
375 		rv = AE_ERROR;
376 		goto out;
377 	}
378 
379 	elm = obj->Package.Elements;
380 
381 	for (i = ACPIBAT_BIF_UNIT; i < ACPIBAT_BIF_MODEL; i++) {
382 
383 		if (elm[i].Type != ACPI_TYPE_INTEGER) {
384 			rv = AE_TYPE;
385 			goto out;
386 		}
387 
388 		KDASSERT((uint64_t)elm[i].Integer.Value < INT_MAX);
389 	}
390 
391 	aprint_verbose_dev(dv, "battery info: ");
392 
393 	for (i = j = ACPIBAT_BIF_OEM; i > ACPIBAT_BIF_GRANULARITY2; i--) {
394 
395 		if (elm[i].Type != ACPI_TYPE_STRING)
396 			continue;
397 
398 		if (elm[i].String.Pointer == NULL)
399 			continue;
400 
401 		aprint_verbose("%s ", elm[i].String.Pointer);
402 
403 		j = 0;
404 	}
405 
406 	if (j != 0)
407 		aprint_verbose("not available");
408 
409 	aprint_verbose("\n");
410 
411 	if ((elm[ACPIBAT_BIF_UNIT].Integer.Value & ACPIBAT_PWRUNIT_MA) != 0) {
412 		capunit = ENVSYS_SAMPHOUR;
413 		rateunit = ENVSYS_SAMPS;
414 	} else {
415 		capunit = ENVSYS_SWATTHOUR;
416 		rateunit = ENVSYS_SWATTS;
417 	}
418 
419 	sc->sc_sensor[ACPIBAT_DCAPACITY].units = capunit;
420 	sc->sc_sensor[ACPIBAT_LFCCAPACITY].units = capunit;
421 	sc->sc_sensor[ACPIBAT_WCAPACITY].units = capunit;
422 	sc->sc_sensor[ACPIBAT_LCAPACITY].units = capunit;
423 	sc->sc_sensor[ACPIBAT_CHARGERATE].units = rateunit;
424 	sc->sc_sensor[ACPIBAT_DISCHARGERATE].units = rateunit;
425 	sc->sc_sensor[ACPIBAT_CAPACITY].units = capunit;
426 
427 	/* Design capacity. */
428 	val = elm[ACPIBAT_BIF_DCAPACITY].Integer.Value * 1000;
429 	sc->sc_sensor[ACPIBAT_DCAPACITY].value_cur = val;
430 	sc->sc_sensor[ACPIBAT_DCAPACITY].state = ACPIBAT_VAL_ISVALID(val);
431 
432 	/* Last full charge capacity. */
433 	val = elm[ACPIBAT_BIF_LFCCAPACITY].Integer.Value * 1000;
434 	sc->sc_sensor[ACPIBAT_LFCCAPACITY].value_cur = val;
435 	sc->sc_sensor[ACPIBAT_LFCCAPACITY].state = ACPIBAT_VAL_ISVALID(val);
436 
437 	/* Battery technology. */
438 	val = elm[ACPIBAT_BIF_TECHNOLOGY].Integer.Value;
439 	sc->sc_sensor[ACPIBAT_TECHNOLOGY].value_cur = val;
440 	sc->sc_sensor[ACPIBAT_TECHNOLOGY].state = ACPIBAT_VAL_ISVALID(val);
441 
442 	/* Design voltage. */
443 	val = elm[ACPIBAT_BIF_DVOLTAGE].Integer.Value * 1000;
444 	sc->sc_sensor[ACPIBAT_DVOLTAGE].value_cur = val;
445 	sc->sc_sensor[ACPIBAT_DVOLTAGE].state = ACPIBAT_VAL_ISVALID(val);
446 
447 	/* Design warning capacity. */
448 	val = elm[ACPIBAT_BIF_WCAPACITY].Integer.Value * 1000;
449 	sc->sc_sensor[ACPIBAT_WCAPACITY].value_cur = val;
450 	sc->sc_sensor[ACPIBAT_WCAPACITY].state = ACPIBAT_VAL_ISVALID(val);
451 	sc->sc_sensor[ACPIBAT_WCAPACITY].flags |=
452 	    ENVSYS_FPERCENT | ENVSYS_FVALID_MAX;
453 
454 	/* Design low capacity. */
455 	val = elm[ACPIBAT_BIF_LCAPACITY].Integer.Value * 1000;
456 	sc->sc_sensor[ACPIBAT_LCAPACITY].value_cur = val;
457 	sc->sc_sensor[ACPIBAT_LCAPACITY].state = ACPIBAT_VAL_ISVALID(val);
458 	sc->sc_sensor[ACPIBAT_LCAPACITY].flags |=
459 	    ENVSYS_FPERCENT | ENVSYS_FVALID_MAX;
460 
461 	/*
462 	 * Initialize the maximum of current, warning, and
463 	 * low capacity to the last full charge capacity.
464 	 */
465 	val = sc->sc_sensor[ACPIBAT_LFCCAPACITY].value_cur;
466 
467 	sc->sc_sensor[ACPIBAT_CAPACITY].value_max = val;
468 	sc->sc_sensor[ACPIBAT_WCAPACITY].value_max = val;
469 	sc->sc_sensor[ACPIBAT_LCAPACITY].value_max = val;
470 
471 out:
472 	if (obj != NULL)
473 		ACPI_FREE(obj);
474 
475 	if (ACPI_FAILURE(rv))
476 		aprint_error_dev(dv, "failed to evaluate _BIF: %s\n",
477 		    AcpiFormatException(rv));
478 }
479 
480 /*
481  * acpibat_get_status:
482  *
483  *	Get, and possibly display, the current battery line status.
484  */
485 static void
486 acpibat_get_status(device_t dv)
487 {
488 	struct acpibat_softc *sc = device_private(dv);
489 	ACPI_HANDLE hdl = sc->sc_node->ad_handle;
490 	int i, rate, state, val;
491 	ACPI_OBJECT *elm, *obj;
492 	ACPI_STATUS rv = AE_OK;
493 
494 	obj = acpibat_get_object(hdl, "_BST", ACPIBAT_BST_COUNT);
495 
496 	if (obj == NULL) {
497 		rv = AE_ERROR;
498 		goto out;
499 	}
500 
501 	elm = obj->Package.Elements;
502 
503 	for (i = ACPIBAT_BST_STATE; i < ACPIBAT_BST_COUNT; i++) {
504 
505 		if (elm[i].Type != ACPI_TYPE_INTEGER) {
506 			rv = AE_TYPE;
507 			goto out;
508 		}
509 	}
510 
511 	state = elm[ACPIBAT_BST_STATE].Integer.Value;
512 
513 	if ((state & ACPIBAT_ST_CHARGING) != 0) {
514 		/* XXX rate can be invalid */
515 		rate = elm[ACPIBAT_BST_RATE].Integer.Value;
516 		sc->sc_sensor[ACPIBAT_CHARGERATE].state = ENVSYS_SVALID;
517 		sc->sc_sensor[ACPIBAT_CHARGERATE].value_cur = rate * 1000;
518 		sc->sc_sensor[ACPIBAT_DISCHARGERATE].state = ENVSYS_SINVALID;
519 		sc->sc_sensor[ACPIBAT_CHARGING].state = ENVSYS_SVALID;
520 		sc->sc_sensor[ACPIBAT_CHARGING].value_cur = 1;
521 	} else if ((state & ACPIBAT_ST_DISCHARGING) != 0) {
522 		rate = elm[ACPIBAT_BST_RATE].Integer.Value;
523 		sc->sc_sensor[ACPIBAT_DISCHARGERATE].state = ENVSYS_SVALID;
524 		sc->sc_sensor[ACPIBAT_DISCHARGERATE].value_cur = rate * 1000;
525 		sc->sc_sensor[ACPIBAT_CHARGERATE].state = ENVSYS_SINVALID;
526 		sc->sc_sensor[ACPIBAT_CHARGING].state = ENVSYS_SVALID;
527 		sc->sc_sensor[ACPIBAT_CHARGING].value_cur = 0;
528 	} else {
529 		sc->sc_sensor[ACPIBAT_CHARGING].state = ENVSYS_SVALID;
530 		sc->sc_sensor[ACPIBAT_CHARGING].value_cur = 0;
531 		sc->sc_sensor[ACPIBAT_CHARGERATE].state = ENVSYS_SINVALID;
532 		sc->sc_sensor[ACPIBAT_DISCHARGERATE].state = ENVSYS_SINVALID;
533 	}
534 
535 	/* Remaining capacity. */
536 	val = elm[ACPIBAT_BST_CAPACITY].Integer.Value * 1000;
537 	sc->sc_sensor[ACPIBAT_CAPACITY].value_cur = val;
538 	sc->sc_sensor[ACPIBAT_CAPACITY].state = ACPIBAT_VAL_ISVALID(val);
539 	sc->sc_sensor[ACPIBAT_CAPACITY].flags |=
540 	    ENVSYS_FPERCENT | ENVSYS_FVALID_MAX;
541 
542 	/* Battery voltage. */
543 	val = elm[ACPIBAT_BST_VOLTAGE].Integer.Value * 1000;
544 	sc->sc_sensor[ACPIBAT_VOLTAGE].value_cur = val;
545 	sc->sc_sensor[ACPIBAT_VOLTAGE].state = ACPIBAT_VAL_ISVALID(val);
546 
547 	sc->sc_sensor[ACPIBAT_CHARGE_STATE].state = ENVSYS_SVALID;
548 	sc->sc_sensor[ACPIBAT_CHARGE_STATE].value_cur =
549 	    ENVSYS_BATTERY_CAPACITY_NORMAL;
550 
551 	if (sc->sc_sensor[ACPIBAT_CAPACITY].value_cur <
552 	    sc->sc_sensor[ACPIBAT_WCAPACITY].value_cur) {
553 		sc->sc_sensor[ACPIBAT_CAPACITY].state = ENVSYS_SWARNUNDER;
554 		sc->sc_sensor[ACPIBAT_CHARGE_STATE].value_cur =
555 		    ENVSYS_BATTERY_CAPACITY_WARNING;
556 	}
557 
558 	if (sc->sc_sensor[ACPIBAT_CAPACITY].value_cur <
559 	    sc->sc_sensor[ACPIBAT_LCAPACITY].value_cur) {
560 		sc->sc_sensor[ACPIBAT_CAPACITY].state = ENVSYS_SCRITUNDER;
561 		sc->sc_sensor[ACPIBAT_CHARGE_STATE].value_cur =
562 		    ENVSYS_BATTERY_CAPACITY_LOW;
563 	}
564 
565 	if ((state & ACPIBAT_ST_CRITICAL) != 0) {
566 		sc->sc_sensor[ACPIBAT_CAPACITY].state = ENVSYS_SCRITICAL;
567 		sc->sc_sensor[ACPIBAT_CHARGE_STATE].value_cur =
568 		    ENVSYS_BATTERY_CAPACITY_CRITICAL;
569 	}
570 
571 out:
572 	if (obj != NULL)
573 		ACPI_FREE(obj);
574 
575 	if (ACPI_FAILURE(rv))
576 		aprint_error_dev(dv, "failed to evaluate _BST: %s\n",
577 		    AcpiFormatException(rv));
578 }
579 
580 static void
581 acpibat_update_info(void *arg)
582 {
583 	device_t dv = arg;
584 	struct acpibat_softc *sc = device_private(dv);
585 	int i, rv;
586 
587 	mutex_enter(&sc->sc_mutex);
588 
589 	rv = acpibat_get_sta(dv);
590 
591 	if (rv > 0)
592 		acpibat_get_info(dv);
593 	else {
594 		i = (rv < 0) ? 0 : ACPIBAT_DCAPACITY;
595 
596 		while (i < ACPIBAT_COUNT) {
597 			sc->sc_sensor[i].state = ENVSYS_SINVALID;
598 			i++;
599 		}
600 	}
601 
602 	sc->sc_present = rv;
603 
604 	mutex_exit(&sc->sc_mutex);
605 }
606 
607 static void
608 acpibat_update_status(void *arg)
609 {
610 	device_t dv = arg;
611 	struct acpibat_softc *sc = device_private(dv);
612 	int i, rv;
613 
614 	mutex_enter(&sc->sc_mutex);
615 
616 	rv = acpibat_get_sta(dv);
617 
618 	if (rv > 0) {
619 
620 		if (sc->sc_present == 0)
621 			acpibat_get_info(dv);
622 
623 		acpibat_get_status(dv);
624 	} else {
625 		i = (rv < 0) ? 0 : ACPIBAT_DCAPACITY;
626 
627 		while (i < ACPIBAT_COUNT) {
628 			sc->sc_sensor[i].state = ENVSYS_SINVALID;
629 			i++;
630 		}
631 	}
632 
633 	sc->sc_present = rv;
634 
635 	microtime(&sc->sc_lastupdate);
636 	cv_broadcast(&sc->sc_condvar);
637 	mutex_exit(&sc->sc_mutex);
638 }
639 
640 /*
641  * acpibat_notify_handler:
642  *
643  *	Callback from ACPI interrupt handler to notify us of an event.
644  */
645 static void
646 acpibat_notify_handler(ACPI_HANDLE handle, UINT32 notify, void *context)
647 {
648 	static const int handler = OSL_NOTIFY_HANDLER;
649 	device_t dv = context;
650 
651 	switch (notify) {
652 
653 	case ACPI_NOTIFY_BusCheck:
654 		break;
655 
656 	case ACPI_NOTIFY_DeviceCheck:
657 	case ACPI_NOTIFY_BatteryInformationChanged:
658 		(void)AcpiOsExecute(handler, acpibat_update_info, dv);
659 		break;
660 
661 	case ACPI_NOTIFY_BatteryStatusChanged:
662 		(void)AcpiOsExecute(handler, acpibat_update_status, dv);
663 		break;
664 
665 	default:
666 		aprint_error_dev(dv, "unknown notify: 0x%02X\n", notify);
667 	}
668 }
669 
670 static void
671 acpibat_init_envsys(device_t dv)
672 {
673 	struct acpibat_softc *sc = device_private(dv);
674 	int i;
675 
676 #define INITDATA(index, unit, string)					\
677 	do {								\
678 		sc->sc_sensor[index].state = ENVSYS_SVALID;		\
679 		sc->sc_sensor[index].units = unit;			\
680 		(void)strlcpy(sc->sc_sensor[index].desc, string,	\
681 		    sizeof(sc->sc_sensor[index].desc));			\
682 	} while (/* CONSTCOND */ 0)
683 
684 	INITDATA(ACPIBAT_PRESENT, ENVSYS_INDICATOR, "present");
685 	INITDATA(ACPIBAT_DCAPACITY, ENVSYS_SWATTHOUR, "design cap");
686 	INITDATA(ACPIBAT_LFCCAPACITY, ENVSYS_SWATTHOUR, "last full cap");
687 	INITDATA(ACPIBAT_TECHNOLOGY, ENVSYS_INTEGER, "technology");
688 	INITDATA(ACPIBAT_DVOLTAGE, ENVSYS_SVOLTS_DC, "design voltage");
689 	INITDATA(ACPIBAT_WCAPACITY, ENVSYS_SWATTHOUR, "warn cap");
690 	INITDATA(ACPIBAT_LCAPACITY, ENVSYS_SWATTHOUR, "low cap");
691 	INITDATA(ACPIBAT_VOLTAGE, ENVSYS_SVOLTS_DC, "voltage");
692 	INITDATA(ACPIBAT_CHARGERATE, ENVSYS_SWATTS, "charge rate");
693 	INITDATA(ACPIBAT_DISCHARGERATE, ENVSYS_SWATTS, "discharge rate");
694 	INITDATA(ACPIBAT_CAPACITY, ENVSYS_SWATTHOUR, "charge");
695 	INITDATA(ACPIBAT_CHARGING, ENVSYS_BATTERY_CHARGE, "charging");
696 	INITDATA(ACPIBAT_CHARGE_STATE, ENVSYS_BATTERY_CAPACITY, "charge state");
697 
698 #undef INITDATA
699 
700 	/* Enable monitoring for the charge state sensor */
701 	sc->sc_sensor[ACPIBAT_CHARGE_STATE].monitor = true;
702 	sc->sc_sensor[ACPIBAT_CHARGE_STATE].flags |= ENVSYS_FMONSTCHANGED;
703 
704 	/* Disable userland monitoring on these sensors */
705 	sc->sc_sensor[ACPIBAT_VOLTAGE].flags = ENVSYS_FMONNOTSUPP;
706 	sc->sc_sensor[ACPIBAT_CHARGERATE].flags = ENVSYS_FMONNOTSUPP;
707 	sc->sc_sensor[ACPIBAT_DISCHARGERATE].flags = ENVSYS_FMONNOTSUPP;
708 	sc->sc_sensor[ACPIBAT_DCAPACITY].flags = ENVSYS_FMONNOTSUPP;
709 	sc->sc_sensor[ACPIBAT_LFCCAPACITY].flags = ENVSYS_FMONNOTSUPP;
710 	sc->sc_sensor[ACPIBAT_TECHNOLOGY].flags = ENVSYS_FMONNOTSUPP;
711 	sc->sc_sensor[ACPIBAT_DVOLTAGE].flags = ENVSYS_FMONNOTSUPP;
712 	sc->sc_sensor[ACPIBAT_WCAPACITY].flags = ENVSYS_FMONNOTSUPP;
713 	sc->sc_sensor[ACPIBAT_LCAPACITY].flags = ENVSYS_FMONNOTSUPP;
714 
715 	sc->sc_sme = sysmon_envsys_create();
716 
717 	for (i = 0; i < ACPIBAT_COUNT; i++) {
718 
719 		if (sysmon_envsys_sensor_attach(sc->sc_sme,
720 			&sc->sc_sensor[i]))
721 			goto fail;
722 	}
723 
724 	sc->sc_sme->sme_name = device_xname(dv);
725 	sc->sc_sme->sme_cookie = dv;
726 	sc->sc_sme->sme_refresh = acpibat_refresh;
727 	sc->sc_sme->sme_class = SME_CLASS_BATTERY;
728 	sc->sc_sme->sme_flags = SME_POLL_ONLY;
729 
730 	acpibat_update_info(dv);
731 	acpibat_update_status(dv);
732 
733 	if (sysmon_envsys_register(sc->sc_sme))
734 		goto fail;
735 
736 	return;
737 
738 fail:
739 	aprint_error_dev(dv, "failed to initialize sysmon\n");
740 
741 	sysmon_envsys_destroy(sc->sc_sme);
742 	kmem_free(sc->sc_sensor, ACPIBAT_COUNT * sizeof(*sc->sc_sensor));
743 
744 	sc->sc_sme = NULL;
745 	sc->sc_sensor = NULL;
746 }
747 
748 static void
749 acpibat_refresh(struct sysmon_envsys *sme, envsys_data_t *edata)
750 {
751 	device_t dv = sme->sme_cookie;
752 	struct acpibat_softc *sc = device_private(dv);
753 	struct timeval tv, tmp;
754 	ACPI_STATUS rv;
755 
756 	tmp.tv_sec = 5;
757 	tmp.tv_usec = 0;
758 	microtime(&tv);
759 	timersub(&tv, &tmp, &tv);
760 
761 	if (timercmp(&tv, &sc->sc_lastupdate, <))
762 		return;
763 
764 	if (!mutex_tryenter(&sc->sc_mutex))
765 		return;
766 
767 	rv = AcpiOsExecute(OSL_NOTIFY_HANDLER, acpibat_update_status, dv);
768 
769 	if (ACPI_SUCCESS(rv))
770 		cv_timedwait(&sc->sc_condvar, &sc->sc_mutex, hz);
771 
772 	mutex_exit(&sc->sc_mutex);
773 }
774 
775 static bool
776 acpibat_resume(device_t dv, const pmf_qual_t *qual)
777 {
778 
779 	(void)AcpiOsExecute(OSL_NOTIFY_HANDLER, acpibat_update_info, dv);
780 	(void)AcpiOsExecute(OSL_NOTIFY_HANDLER, acpibat_update_status, dv);
781 
782 	return true;
783 }
784 
785 #ifdef _MODULE
786 
787 MODULE(MODULE_CLASS_DRIVER, acpibat, NULL);
788 CFDRIVER_DECL(acpibat, DV_DULL, NULL);
789 
790 static int acpibatloc[] = { -1 };
791 extern struct cfattach acpibat_ca;
792 
793 static struct cfparent acpiparent = {
794 	"acpinodebus", NULL, DVUNIT_ANY
795 };
796 
797 static struct cfdata acpibat_cfdata[] = {
798 	{
799 		.cf_name = "acpibat",
800 		.cf_atname = "acpibat",
801 		.cf_unit = 0,
802 		.cf_fstate = FSTATE_STAR,
803 		.cf_loc = acpibatloc,
804 		.cf_flags = 0,
805 		.cf_pspec = &acpiparent,
806 	},
807 
808 	{ NULL }
809 };
810 
811 static int
812 acpibat_modcmd(modcmd_t cmd, void *context)
813 {
814 	int err;
815 
816 	switch (cmd) {
817 
818 	case MODULE_CMD_INIT:
819 
820 		err = config_cfdriver_attach(&acpibat_cd);
821 
822 		if (err != 0)
823 			return err;
824 
825 		err = config_cfattach_attach("acpibat", &acpibat_ca);
826 
827 		if (err != 0) {
828 			config_cfdriver_detach(&acpibat_cd);
829 			return err;
830 		}
831 
832 		err = config_cfdata_attach(acpibat_cfdata, 1);
833 
834 		if (err != 0) {
835 			config_cfattach_detach("acpibat", &acpibat_ca);
836 			config_cfdriver_detach(&acpibat_cd);
837 			return err;
838 		}
839 
840 		return 0;
841 
842 	case MODULE_CMD_FINI:
843 
844 		err = config_cfdata_detach(acpibat_cfdata);
845 
846 		if (err != 0)
847 			return err;
848 
849 		config_cfattach_detach("acpibat", &acpibat_ca);
850 		config_cfdriver_detach(&acpibat_cd);
851 
852 		return 0;
853 
854 	default:
855 		return ENOTTY;
856 	}
857 }
858 
859 #endif	/* _MODULE */
860