xref: /netbsd-src/sys/dev/acpi/acpi_bat.c (revision 3816d47b2c42fcd6e549e3407f842a5b1a1d23ad)
1 /*	$NetBSD: acpi_bat.c,v 1.75 2010/01/08 20:40:41 dyoung 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.75 2010/01/08 20:40:41 dyoung 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 #define _COMPONENT          ACPI_BAT_COMPONENT
96 ACPI_MODULE_NAME            ("acpi_bat")
97 
98 /* sensor indexes */
99 #define ACPIBAT_PRESENT		0
100 #define ACPIBAT_DCAPACITY	1
101 #define ACPIBAT_LFCCAPACITY	2
102 #define ACPIBAT_TECHNOLOGY	3
103 #define ACPIBAT_DVOLTAGE	4
104 #define ACPIBAT_WCAPACITY	5
105 #define ACPIBAT_LCAPACITY	6
106 #define ACPIBAT_VOLTAGE		7
107 #define ACPIBAT_CHARGERATE	8
108 #define ACPIBAT_DISCHARGERATE	9
109 #define ACPIBAT_CAPACITY	10
110 #define ACPIBAT_CHARGING	11
111 #define ACPIBAT_CHARGE_STATE	12
112 #define ACPIBAT_NSENSORS	13  /* number of sensors */
113 
114 struct acpibat_softc {
115 	struct acpi_devnode *sc_node;	/* our ACPI devnode */
116 	int sc_flags;			/* see below */
117 	int sc_available;		/* available information level */
118 
119 	struct sysmon_envsys *sc_sme;
120 	envsys_data_t sc_sensor[ACPIBAT_NSENSORS];
121 	struct timeval sc_lastupdate;
122 
123 	kmutex_t sc_mutex;
124 	kcondvar_t sc_condvar;
125 };
126 
127 static const char * const bat_hid[] = {
128 	"PNP0C0A",
129 	NULL
130 };
131 
132 /*
133  * These flags are used to examine the battery device data returned from
134  * the ACPI interface, specifically the "battery status"
135  */
136 #define ACPIBAT_PWRUNIT_MA	0x00000001  /* mA not mW */
137 
138 /*
139  * These flags are used to examine the battery charge/discharge/critical
140  * state returned from a get-status command.
141  */
142 #define ACPIBAT_ST_DISCHARGING	0x00000001  /* battery is discharging */
143 #define ACPIBAT_ST_CHARGING	0x00000002  /* battery is charging */
144 #define ACPIBAT_ST_CRITICAL	0x00000004  /* battery is critical */
145 
146 /*
147  * Flags for battery status from _STA return
148  */
149 #define ACPIBAT_STA_PRESENT	0x00000010  /* battery present */
150 
151 /*
152  * These flags are used to set internal state in our softc.
153  */
154 #define	ABAT_F_VERBOSE		0x01	/* verbose events */
155 #define ABAT_F_PWRUNIT_MA	0x02 	/* mA instead of mW */
156 #define ABAT_F_PRESENT		0x04	/* is the battery present? */
157 
158 #define ABAT_SET(sc, f)		(void)((sc)->sc_flags |= (f))
159 #define ABAT_CLEAR(sc, f)	(void)((sc)->sc_flags &= ~(f))
160 #define ABAT_ISSET(sc, f)	((sc)->sc_flags & (f))
161 
162 /*
163  * Available info level
164  */
165 
166 #define ABAT_ALV_NONE		0	/* none is available */
167 #define ABAT_ALV_PRESENCE	1	/* presence info is available */
168 #define ABAT_ALV_INFO		2	/* battery info is available */
169 #define ABAT_ALV_STAT		3	/* battery status is available */
170 
171 static int	acpibat_match(device_t, cfdata_t, void *);
172 static void	acpibat_attach(device_t, device_t, void *);
173 static bool	acpibat_resume(device_t, pmf_qual_t);
174 
175 CFATTACH_DECL_NEW(acpibat, sizeof(struct acpibat_softc),
176     acpibat_match, acpibat_attach, NULL, NULL);
177 
178 static void acpibat_clear_presence(struct acpibat_softc *);
179 static void acpibat_clear_info(struct acpibat_softc *);
180 static void acpibat_clear_stat(struct acpibat_softc *);
181 static int acpibat_battery_present(device_t);
182 static ACPI_STATUS acpibat_get_status(device_t);
183 static ACPI_STATUS acpibat_get_info(device_t);
184 static void acpibat_print_info(device_t);
185 static void acpibat_print_stat(device_t);
186 static void acpibat_update(void *);
187 static void acpibat_update_info(void *);
188 static void acpibat_update_stat(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, cfdata_t 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 static bool
211 acpibat_resume(device_t dv, pmf_qual_t qual)
212 {
213 	ACPI_STATUS rv;
214 
215 	rv = AcpiOsExecute(OSL_NOTIFY_HANDLER, acpibat_update_stat, dv);
216 	if (ACPI_FAILURE(rv))
217 		aprint_error_dev(dv, "unable to queue status check: %s\n",
218 		    AcpiFormatException(rv));
219 	rv = AcpiOsExecute(OSL_NOTIFY_HANDLER, acpibat_update_info, dv);
220 	if (ACPI_FAILURE(rv))
221 		aprint_error_dev(dv, "unable to queue info check: %s\n",
222 		    AcpiFormatException(rv));
223 
224 	return true;
225 }
226 
227 /*
228  * acpibat_attach:
229  *
230  *	Autoconfiguration `attach' routine.
231  */
232 static void
233 acpibat_attach(device_t parent, device_t self, void *aux)
234 {
235 	struct acpibat_softc *sc = device_private(self);
236 	struct acpi_attach_args *aa = aux;
237 	ACPI_STATUS rv;
238 
239 	aprint_naive(": ACPI Battery (Control Method)\n");
240 	aprint_normal(": ACPI Battery (Control Method)\n");
241 
242 	sc->sc_node = aa->aa_node;
243 
244 	mutex_init(&sc->sc_mutex, MUTEX_DEFAULT, IPL_NONE);
245 	cv_init(&sc->sc_condvar, device_xname(self));
246 
247 	rv = AcpiInstallNotifyHandler(sc->sc_node->ad_handle,
248 				      ACPI_ALL_NOTIFY,
249 				      acpibat_notify_handler, self);
250 	if (ACPI_FAILURE(rv)) {
251 		aprint_error_dev(self,
252 		    "unable to register DEVICE/SYSTEM NOTIFY handler: %s\n",
253 		    AcpiFormatException(rv));
254 		return;
255 	}
256 
257 #ifdef ACPI_BAT_DEBUG
258 	ABAT_SET(sc, ABAT_F_VERBOSE);
259 #endif
260 
261 	if (!pmf_device_register(self, NULL, acpibat_resume))
262 		aprint_error_dev(self, "couldn't establish power handler\n");
263 
264 	acpibat_init_envsys(self);
265 }
266 
267 /*
268  * clear informations
269  */
270 
271 static void
272 acpibat_clear_presence(struct acpibat_softc *sc)
273 {
274 	acpibat_clear_info(sc);
275 	sc->sc_available = ABAT_ALV_NONE;
276 	ABAT_CLEAR(sc, ABAT_F_PRESENT);
277 }
278 
279 static void
280 acpibat_clear_info(struct acpibat_softc *sc)
281 {
282 	acpibat_clear_stat(sc);
283 	if (sc->sc_available > ABAT_ALV_PRESENCE)
284 		sc->sc_available = ABAT_ALV_PRESENCE;
285 
286 	sc->sc_sensor[ACPIBAT_DCAPACITY].state = ENVSYS_SINVALID;
287 	sc->sc_sensor[ACPIBAT_LFCCAPACITY].state = ENVSYS_SINVALID;
288 	sc->sc_sensor[ACPIBAT_CAPACITY].state = ENVSYS_SINVALID;
289 	sc->sc_sensor[ACPIBAT_TECHNOLOGY].state = ENVSYS_SINVALID;
290 	sc->sc_sensor[ACPIBAT_DVOLTAGE].state = ENVSYS_SINVALID;
291 	sc->sc_sensor[ACPIBAT_WCAPACITY].state = ENVSYS_SINVALID;
292 	sc->sc_sensor[ACPIBAT_LCAPACITY].state = ENVSYS_SINVALID;
293 }
294 
295 static void
296 acpibat_clear_stat(struct acpibat_softc *sc)
297 {
298 	if (sc->sc_available > ABAT_ALV_INFO)
299 		sc->sc_available = ABAT_ALV_INFO;
300 
301 	sc->sc_sensor[ACPIBAT_CHARGERATE].state = ENVSYS_SINVALID;
302 	sc->sc_sensor[ACPIBAT_DISCHARGERATE].state = ENVSYS_SINVALID;
303 	sc->sc_sensor[ACPIBAT_CAPACITY].state = ENVSYS_SINVALID;
304 	sc->sc_sensor[ACPIBAT_VOLTAGE].state = ENVSYS_SINVALID;
305 	sc->sc_sensor[ACPIBAT_CHARGING].state = ENVSYS_SINVALID;
306 }
307 
308 
309 /*
310  * returns 0 for no battery, 1 for present, and -1 on error
311  */
312 static int
313 acpibat_battery_present(device_t dv)
314 {
315 	struct acpibat_softc *sc = device_private(dv);
316 	uint32_t sta;
317 	ACPI_INTEGER val;
318 	ACPI_STATUS rv;
319 
320 	rv = acpi_eval_integer(sc->sc_node->ad_handle, "_STA", &val);
321 	if (ACPI_FAILURE(rv)) {
322 		aprint_error_dev(dv, "failed to evaluate _STA: %s\n",
323 		    AcpiFormatException(rv));
324 		return -1;
325 	}
326 
327 	sta = (uint32_t)val;
328 
329 	sc->sc_available = ABAT_ALV_PRESENCE;
330 	if (sta & ACPIBAT_STA_PRESENT) {
331 		ABAT_SET(sc, ABAT_F_PRESENT);
332 		sc->sc_sensor[ACPIBAT_PRESENT].state = ENVSYS_SVALID;
333 		sc->sc_sensor[ACPIBAT_PRESENT].value_cur = 1;
334 	} else
335 		sc->sc_sensor[ACPIBAT_PRESENT].value_cur = 0;
336 
337 	return (sta & ACPIBAT_STA_PRESENT) ? 1 : 0;
338 }
339 
340 /*
341  * acpibat_get_info
342  *
343  * 	Get, and possibly display, the battery info.
344  */
345 
346 static ACPI_STATUS
347 acpibat_get_info(device_t dv)
348 {
349 	struct acpibat_softc *sc = device_private(dv);
350 	ACPI_OBJECT *p1, *p2;
351 	ACPI_STATUS rv;
352 	ACPI_BUFFER buf;
353 	int capunit, rateunit;
354 
355 	rv = acpi_eval_struct(sc->sc_node->ad_handle, "_BIF", &buf);
356 	if (ACPI_FAILURE(rv)) {
357 		aprint_error_dev(dv, "failed to evaluate _BIF: %s\n",
358 		    AcpiFormatException(rv));
359 		return rv;
360 	}
361 	p1 = (ACPI_OBJECT *)buf.Pointer;
362 
363 	if (p1->Type != ACPI_TYPE_PACKAGE) {
364 		aprint_error_dev(dv, "expected PACKAGE, got %d\n", p1->Type);
365 		goto out;
366 	}
367 	if (p1->Package.Count < 13) {
368 		aprint_error_dev(dv, "expected 13 elements, got %d\n",
369 		    p1->Package.Count);
370 		goto out;
371 	}
372 	p2 = p1->Package.Elements;
373 
374 	if ((p2[0].Integer.Value & ACPIBAT_PWRUNIT_MA) != 0) {
375 		ABAT_SET(sc, ABAT_F_PWRUNIT_MA);
376 		capunit = ENVSYS_SAMPHOUR;
377 		rateunit = ENVSYS_SAMPS;
378 	} else {
379 		ABAT_CLEAR(sc, ABAT_F_PWRUNIT_MA);
380 		capunit = ENVSYS_SWATTHOUR;
381 		rateunit = ENVSYS_SWATTS;
382 	}
383 
384 	sc->sc_sensor[ACPIBAT_DCAPACITY].units = capunit;
385 	sc->sc_sensor[ACPIBAT_LFCCAPACITY].units = capunit;
386 	sc->sc_sensor[ACPIBAT_WCAPACITY].units = capunit;
387 	sc->sc_sensor[ACPIBAT_LCAPACITY].units = capunit;
388 	sc->sc_sensor[ACPIBAT_CHARGERATE].units = rateunit;
389 	sc->sc_sensor[ACPIBAT_DISCHARGERATE].units = rateunit;
390 	sc->sc_sensor[ACPIBAT_CAPACITY].units = capunit;
391 
392 	sc->sc_sensor[ACPIBAT_DCAPACITY].value_cur = p2[1].Integer.Value * 1000;
393 	sc->sc_sensor[ACPIBAT_DCAPACITY].state = ENVSYS_SVALID;
394 	sc->sc_sensor[ACPIBAT_LFCCAPACITY].value_cur = p2[2].Integer.Value * 1000;
395 	sc->sc_sensor[ACPIBAT_LFCCAPACITY].state = ENVSYS_SVALID;
396 	sc->sc_sensor[ACPIBAT_CAPACITY].value_max = p2[2].Integer.Value * 1000;
397 	sc->sc_sensor[ACPIBAT_TECHNOLOGY].value_cur = p2[3].Integer.Value;
398 	sc->sc_sensor[ACPIBAT_TECHNOLOGY].state = ENVSYS_SVALID;
399 	sc->sc_sensor[ACPIBAT_DVOLTAGE].value_cur = p2[4].Integer.Value * 1000;
400 	sc->sc_sensor[ACPIBAT_DVOLTAGE].state = ENVSYS_SVALID;
401 	sc->sc_sensor[ACPIBAT_WCAPACITY].value_cur = p2[5].Integer.Value * 1000;
402 	sc->sc_sensor[ACPIBAT_WCAPACITY].value_max = p2[2].Integer.Value * 1000;
403 	sc->sc_sensor[ACPIBAT_WCAPACITY].state = ENVSYS_SVALID;
404 	sc->sc_sensor[ACPIBAT_WCAPACITY].flags |=
405 	    (ENVSYS_FPERCENT|ENVSYS_FVALID_MAX);
406 	sc->sc_sensor[ACPIBAT_LCAPACITY].value_cur = p2[6].Integer.Value * 1000;
407 	sc->sc_sensor[ACPIBAT_LCAPACITY].value_max = p2[2].Integer.Value * 1000;
408 	sc->sc_sensor[ACPIBAT_LCAPACITY].state = ENVSYS_SVALID;
409 	sc->sc_sensor[ACPIBAT_LCAPACITY].flags |=
410 	    (ENVSYS_FPERCENT|ENVSYS_FVALID_MAX);
411 	sc->sc_available = ABAT_ALV_INFO;
412 
413 	aprint_verbose_dev(dv, "battery info: %s, %s, %s",
414 	    p2[12].String.Pointer, p2[11].String.Pointer, p2[9].String.Pointer);
415 	if (p2[10].String.Pointer)
416 		aprint_verbose(" %s", p2[10].String.Pointer);
417 
418 	aprint_verbose("\n");
419 
420 	rv = AE_OK;
421 
422 out:
423 	ACPI_FREE(buf.Pointer);
424 	return rv;
425 }
426 
427 /*
428  * acpibat_get_status:
429  *
430  *	Get, and possibly display, the current battery line status.
431  */
432 static ACPI_STATUS
433 acpibat_get_status(device_t dv)
434 {
435 	struct acpibat_softc *sc = device_private(dv);
436 	int status, battrate;
437 	ACPI_OBJECT *p1, *p2;
438 	ACPI_STATUS rv;
439 	ACPI_BUFFER buf;
440 
441 	rv = acpi_eval_struct(sc->sc_node->ad_handle, "_BST", &buf);
442 	if (ACPI_FAILURE(rv)) {
443 		aprint_error_dev(dv, "failed to evaluate _BST: %s\n",
444 		    AcpiFormatException(rv));
445 		return rv;
446 	}
447 	p1 = (ACPI_OBJECT *)buf.Pointer;
448 
449 	if (p1->Type != ACPI_TYPE_PACKAGE) {
450 		aprint_error_dev(dv, "expected PACKAGE, got %d\n",
451 		    p1->Type);
452 		rv = AE_ERROR;
453 		goto out;
454 	}
455 	if (p1->Package.Count < 4) {
456 		aprint_error_dev(dv, "expected 4 elts, got %d\n",
457 		    p1->Package.Count);
458 		rv = AE_ERROR;
459 		goto out;
460 	}
461 	p2 = p1->Package.Elements;
462 
463 	status = p2[0].Integer.Value;
464 	battrate = p2[1].Integer.Value;
465 
466 	if (status & ACPIBAT_ST_CHARGING) {
467 		sc->sc_sensor[ACPIBAT_CHARGERATE].state = ENVSYS_SVALID;
468 		sc->sc_sensor[ACPIBAT_CHARGERATE].value_cur = battrate * 1000;
469 		sc->sc_sensor[ACPIBAT_DISCHARGERATE].state = ENVSYS_SINVALID;
470 		sc->sc_sensor[ACPIBAT_CHARGING].state = ENVSYS_SVALID;
471 		sc->sc_sensor[ACPIBAT_CHARGING].value_cur = 1;
472 	} else if (status & ACPIBAT_ST_DISCHARGING) {
473 		sc->sc_sensor[ACPIBAT_DISCHARGERATE].state = ENVSYS_SVALID;
474 		sc->sc_sensor[ACPIBAT_DISCHARGERATE].value_cur = battrate * 1000;
475 		sc->sc_sensor[ACPIBAT_CHARGERATE].state = ENVSYS_SINVALID;
476 		sc->sc_sensor[ACPIBAT_CHARGING].state = ENVSYS_SVALID;
477 		sc->sc_sensor[ACPIBAT_CHARGING].value_cur = 0;
478 	} else if (!(status & (ACPIBAT_ST_CHARGING|ACPIBAT_ST_DISCHARGING))) {
479 		sc->sc_sensor[ACPIBAT_CHARGING].state = ENVSYS_SVALID;
480 		sc->sc_sensor[ACPIBAT_CHARGING].value_cur = 0;
481 		sc->sc_sensor[ACPIBAT_CHARGERATE].state = ENVSYS_SINVALID;
482 		sc->sc_sensor[ACPIBAT_DISCHARGERATE].state = ENVSYS_SINVALID;
483 	}
484 
485 	sc->sc_sensor[ACPIBAT_CHARGE_STATE].value_cur =
486 	    ENVSYS_BATTERY_CAPACITY_NORMAL;
487 
488 	sc->sc_sensor[ACPIBAT_CAPACITY].value_cur = p2[2].Integer.Value * 1000;
489 	sc->sc_sensor[ACPIBAT_CAPACITY].state = ENVSYS_SVALID;
490 	sc->sc_sensor[ACPIBAT_CAPACITY].flags |=
491 	    (ENVSYS_FPERCENT|ENVSYS_FVALID_MAX);
492 	sc->sc_sensor[ACPIBAT_VOLTAGE].value_cur = p2[3].Integer.Value * 1000;
493 	sc->sc_sensor[ACPIBAT_VOLTAGE].state = ENVSYS_SVALID;
494 
495 	if (sc->sc_sensor[ACPIBAT_CAPACITY].value_cur <
496 	    sc->sc_sensor[ACPIBAT_WCAPACITY].value_cur) {
497 		sc->sc_sensor[ACPIBAT_CAPACITY].state = ENVSYS_SWARNUNDER;
498 		sc->sc_sensor[ACPIBAT_CHARGE_STATE].value_cur =
499 		    ENVSYS_BATTERY_CAPACITY_WARNING;
500 	}
501 
502 	if (sc->sc_sensor[ACPIBAT_CAPACITY].value_cur <
503 	    sc->sc_sensor[ACPIBAT_LCAPACITY].value_cur) {
504 		sc->sc_sensor[ACPIBAT_CAPACITY].state = ENVSYS_SCRITUNDER;
505 		sc->sc_sensor[ACPIBAT_CHARGE_STATE].value_cur =
506 		    ENVSYS_BATTERY_CAPACITY_LOW;
507 	}
508 
509 	if (status & ACPIBAT_ST_CRITICAL) {
510 		sc->sc_sensor[ACPIBAT_CAPACITY].state = ENVSYS_SCRITICAL;
511 		sc->sc_sensor[ACPIBAT_CHARGE_STATE].value_cur =
512 		    ENVSYS_BATTERY_CAPACITY_CRITICAL;
513 	}
514 
515 	rv = AE_OK;
516 
517 out:
518 	ACPI_FREE(buf.Pointer);
519 	return rv;
520 }
521 
522 #define SCALE(x)	((x)/1000000), (((x)%1000000)/1000)
523 #define CAPUNITS(sc)	(ABAT_ISSET((sc), ABAT_F_PWRUNIT_MA)?"Ah":"Wh")
524 #define RATEUNITS(sc)	(ABAT_ISSET((sc), ABAT_F_PWRUNIT_MA)?"A":"W")
525 static void
526 acpibat_print_info(device_t dv)
527 {
528 	struct acpibat_softc *sc = device_private(dv);
529 	const char *tech;
530 
531 	if (sc->sc_sensor[ACPIBAT_TECHNOLOGY].value_cur)
532 		tech = "secondary";
533 	else
534 		tech = "primary";
535 
536 	aprint_debug_dev(dv, "%s battery, Design %d.%03d%s "
537 	    "Last full %d.%03d%s Warn %d.%03d%s Low %d.%03d%s\n",
538 	    tech, SCALE(sc->sc_sensor[ACPIBAT_DCAPACITY].value_cur), CAPUNITS(sc),
539 	    SCALE(sc->sc_sensor[ACPIBAT_LFCCAPACITY].value_cur),CAPUNITS(sc),
540 	    SCALE(sc->sc_sensor[ACPIBAT_WCAPACITY].value_cur), CAPUNITS(sc),
541 	    SCALE(sc->sc_sensor[ACPIBAT_LCAPACITY].value_cur), CAPUNITS(sc));
542 }
543 
544 static void
545 acpibat_print_stat(device_t dv)
546 {
547 	struct acpibat_softc *sc = device_private(dv);
548 	const char *capstat, *chargestat;
549 	int percent, denom;
550 	int32_t value;
551 
552 	percent = 0;
553 
554 	if (sc->sc_sensor[ACPIBAT_CAPACITY].state == ENVSYS_SCRITUNDER)
555 		capstat = "CRITICAL UNDER ";
556 	else if (sc->sc_sensor[ACPIBAT_CAPACITY].state == ENVSYS_SCRITOVER)
557 		capstat = "CRITICAL OVER ";
558 	else
559 		capstat = "";
560 
561 	if (sc->sc_sensor[ACPIBAT_CHARGING].state != ENVSYS_SVALID) {
562 		chargestat = "idling";
563 		value = 0;
564 	} else if (sc->sc_sensor[ACPIBAT_CHARGING].value_cur == 0) {
565 		chargestat = "discharging";
566 		value = sc->sc_sensor[ACPIBAT_DISCHARGERATE].value_cur;
567 	} else {
568 		chargestat = "charging";
569 		value = sc->sc_sensor[ACPIBAT_CHARGERATE].value_cur;
570 	}
571 
572 	denom = sc->sc_sensor[ACPIBAT_LFCCAPACITY].value_cur / 100;
573 	if (denom > 0)
574 		percent = (sc->sc_sensor[ACPIBAT_CAPACITY].value_cur) / denom;
575 
576 	aprint_debug_dev(dv, "%s%s: %d.%03dV cap %d.%03d%s (%d%%) "
577 	    "rate %d.%03d%s\n", capstat, chargestat,
578 	    SCALE(sc->sc_sensor[ACPIBAT_VOLTAGE].value_cur),
579 	    SCALE(sc->sc_sensor[ACPIBAT_CAPACITY].value_cur), CAPUNITS(sc),
580 	    percent, SCALE(value), RATEUNITS(sc));
581 }
582 
583 static void
584 acpibat_update(void *arg)
585 {
586 	device_t dv = arg;
587 	struct acpibat_softc *sc = device_private(dv);
588 
589 	if (sc->sc_available < ABAT_ALV_INFO) {
590 		/* current information is invalid */
591 #if 0
592 		/*
593 		 * XXX: The driver sometimes unaware that the battery exist.
594 		 * (i.e. just after the boot or resuming)
595 		 * Thus, the driver should always check it here.
596 		 */
597 		if (sc->sc_available < ABAT_ALV_PRESENCE)
598 #endif
599 			/* presence is invalid */
600 			if (acpibat_battery_present(dv) < 0) {
601 				/* error */
602 				aprint_debug_dev(dv,
603 				    "cannot get battery presence.\n");
604 				return;
605 			}
606 
607 		if (ABAT_ISSET(sc, ABAT_F_PRESENT)) {
608 			/* the battery is present. */
609 			if (ABAT_ISSET(sc, ABAT_F_VERBOSE))
610 				aprint_debug_dev(dv,
611 				    "battery is present.\n");
612 			if (ACPI_FAILURE(acpibat_get_info(dv)))
613 				return;
614 			if (ABAT_ISSET(sc, ABAT_F_VERBOSE))
615 				acpibat_print_info(dv);
616 		} else {
617 			/* the battery is not present. */
618 			if (ABAT_ISSET(sc, ABAT_F_VERBOSE))
619 				aprint_debug_dev(dv,
620 				    "battery is not present.\n");
621 			return;
622 		}
623 	} else {
624 		/* current information is valid */
625 		if (!ABAT_ISSET(sc, ABAT_F_PRESENT)) {
626 			/* the battery is not present. */
627 			return;
628 		}
629  	}
630 
631 	if (ACPI_FAILURE(acpibat_get_status(dv)))
632 		return;
633 
634 	if (ABAT_ISSET(sc, ABAT_F_VERBOSE))
635 		acpibat_print_stat(dv);
636 }
637 
638 static void
639 acpibat_update_info(void *arg)
640 {
641 	device_t dev = arg;
642 	struct acpibat_softc *sc = device_private(dev);
643 
644 	mutex_enter(&sc->sc_mutex);
645 	acpibat_clear_presence(sc);
646 	acpibat_update(arg);
647 	mutex_exit(&sc->sc_mutex);
648 }
649 
650 static void
651 acpibat_update_stat(void *arg)
652 {
653 	device_t dev = arg;
654 	struct acpibat_softc *sc = device_private(dev);
655 
656 	mutex_enter(&sc->sc_mutex);
657 	acpibat_clear_stat(sc);
658 	acpibat_update(arg);
659 	microtime(&sc->sc_lastupdate);
660 	cv_broadcast(&sc->sc_condvar);
661 	mutex_exit(&sc->sc_mutex);
662 }
663 
664 /*
665  * acpibat_notify_handler:
666  *
667  *	Callback from ACPI interrupt handler to notify us of an event.
668  */
669 static void
670 acpibat_notify_handler(ACPI_HANDLE handle, UINT32 notify, void *context)
671 {
672 	device_t dv = context;
673 	ACPI_STATUS rv;
674 
675 #ifdef ACPI_BAT_DEBUG
676 	aprint_debug_dev(dv, "received notify message: 0x%x\n", notify);
677 #endif
678 
679 	switch (notify) {
680 	case ACPI_NOTIFY_BusCheck:
681 		break;
682 	case ACPI_NOTIFY_DeviceCheck:
683 	case ACPI_NOTIFY_BatteryInformationChanged:
684 		rv = AcpiOsExecute(OSL_NOTIFY_HANDLER, acpibat_update_info, dv);
685 		if (ACPI_FAILURE(rv))
686 			aprint_error_dev(dv,
687 			    "unable to queue info check: %s\n",
688 			    AcpiFormatException(rv));
689 		break;
690 
691 	case ACPI_NOTIFY_BatteryStatusChanged:
692 		rv = AcpiOsExecute(OSL_NOTIFY_HANDLER, acpibat_update_stat, dv);
693 		if (ACPI_FAILURE(rv))
694 			aprint_error_dev(dv,
695 			    "unable to queue status check: %s\n",
696 			    AcpiFormatException(rv));
697 		break;
698 
699 	default:
700 		aprint_error_dev(dv,
701 		    "received unknown notify message: 0x%x\n", notify);
702 	}
703 }
704 
705 static void
706 acpibat_init_envsys(device_t dv)
707 {
708 	struct acpibat_softc *sc = device_private(dv);
709 	int i, capunit, rateunit;
710 
711 	if (sc->sc_flags & ABAT_F_PWRUNIT_MA) {
712 		capunit = ENVSYS_SAMPHOUR;
713 		rateunit = ENVSYS_SAMPS;
714 	} else {
715 		capunit = ENVSYS_SWATTHOUR;
716 		rateunit = ENVSYS_SWATTS;
717 	}
718 
719 #define INITDATA(index, unit, string)					\
720 	sc->sc_sensor[index].state = ENVSYS_SVALID;			\
721 	sc->sc_sensor[index].units = unit;     				\
722  	strlcpy(sc->sc_sensor[index].desc, string,			\
723  	    sizeof(sc->sc_sensor[index].desc));
724 
725 	INITDATA(ACPIBAT_PRESENT, ENVSYS_INDICATOR, "present");
726 	INITDATA(ACPIBAT_DCAPACITY, capunit, "design cap");
727 	INITDATA(ACPIBAT_LFCCAPACITY, capunit, "last full cap");
728 	INITDATA(ACPIBAT_TECHNOLOGY, ENVSYS_INTEGER, "technology");
729 	INITDATA(ACPIBAT_DVOLTAGE, ENVSYS_SVOLTS_DC, "design voltage");
730 	INITDATA(ACPIBAT_WCAPACITY, capunit, "warn cap");
731 	INITDATA(ACPIBAT_LCAPACITY, capunit, "low cap");
732 	INITDATA(ACPIBAT_VOLTAGE, ENVSYS_SVOLTS_DC, "voltage");
733 	INITDATA(ACPIBAT_CHARGERATE, rateunit, "charge rate");
734 	INITDATA(ACPIBAT_DISCHARGERATE, rateunit, "discharge rate");
735 	INITDATA(ACPIBAT_CAPACITY, capunit, "charge");
736 	INITDATA(ACPIBAT_CHARGING, ENVSYS_BATTERY_CHARGE, "charging");
737 	INITDATA(ACPIBAT_CHARGE_STATE, ENVSYS_BATTERY_CAPACITY, "charge state");
738 
739 #undef INITDATA
740 
741 	/* Enable monitoring for the charge state sensor */
742 	sc->sc_sensor[ACPIBAT_CHARGE_STATE].monitor = true;
743 	sc->sc_sensor[ACPIBAT_CHARGE_STATE].flags |= ENVSYS_FMONSTCHANGED;
744 
745 	/* Disable userland monitoring on these sensors */
746 	sc->sc_sensor[ACPIBAT_VOLTAGE].flags = ENVSYS_FMONNOTSUPP;
747 	sc->sc_sensor[ACPIBAT_CHARGERATE].flags = ENVSYS_FMONNOTSUPP;
748 	sc->sc_sensor[ACPIBAT_DISCHARGERATE].flags = ENVSYS_FMONNOTSUPP;
749 	sc->sc_sensor[ACPIBAT_DCAPACITY].flags = ENVSYS_FMONNOTSUPP;
750 	sc->sc_sensor[ACPIBAT_LFCCAPACITY].flags = ENVSYS_FMONNOTSUPP;
751 	sc->sc_sensor[ACPIBAT_TECHNOLOGY].flags = ENVSYS_FMONNOTSUPP;
752 	sc->sc_sensor[ACPIBAT_DVOLTAGE].flags = ENVSYS_FMONNOTSUPP;
753 	sc->sc_sensor[ACPIBAT_WCAPACITY].flags = ENVSYS_FMONNOTSUPP;
754 	sc->sc_sensor[ACPIBAT_LCAPACITY].flags = ENVSYS_FMONNOTSUPP;
755 
756 	sc->sc_sme = sysmon_envsys_create();
757 	for (i = 0; i < ACPIBAT_NSENSORS; i++) {
758 		if (sysmon_envsys_sensor_attach(sc->sc_sme,
759 						&sc->sc_sensor[i])) {
760 			aprint_error_dev(dv, "unable to add sensor%d\n", i);
761 			sysmon_envsys_destroy(sc->sc_sme);
762 			return;
763 		}
764 	}
765 
766 	sc->sc_sme->sme_name = device_xname(dv);
767 	sc->sc_sme->sme_cookie = dv;
768 	sc->sc_sme->sme_refresh = acpibat_refresh;
769 	sc->sc_sme->sme_class = SME_CLASS_BATTERY;
770 	sc->sc_sme->sme_flags = SME_POLL_ONLY;
771 
772 	acpibat_update(dv);
773 
774 	if (sysmon_envsys_register(sc->sc_sme)) {
775 		aprint_error_dev(dv, "unable to register with sysmon\n");
776 		sysmon_envsys_destroy(sc->sc_sme);
777 	}
778 }
779 
780 static void
781 acpibat_refresh(struct sysmon_envsys *sme, envsys_data_t *edata)
782 {
783 	device_t dv = sme->sme_cookie;
784 	struct acpibat_softc *sc = device_private(dv);
785 	ACPI_STATUS rv;
786 	struct timeval tv, tmp;
787 
788 	if (!ABAT_ISSET(sc, ABAT_F_PRESENT))
789 		acpibat_battery_present(dv);
790 
791 	if (ABAT_ISSET(sc, ABAT_F_PRESENT)) {
792 		tmp.tv_sec = 5;
793 		tmp.tv_usec = 0;
794 		microtime(&tv);
795 		timersub(&tv, &tmp, &tv);
796 		if (timercmp(&tv, &sc->sc_lastupdate, <))
797 			return;
798 
799 		if (!mutex_tryenter(&sc->sc_mutex))
800 			return;
801 		rv = AcpiOsExecute(OSL_NOTIFY_HANDLER, acpibat_update_stat, dv);
802 		if (!ACPI_FAILURE(rv))
803 			cv_timedwait(&sc->sc_condvar, &sc->sc_mutex, hz);
804 		mutex_exit(&sc->sc_mutex);
805 	}
806 }
807