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