No empty .Rs/.Re
[netbsd-mini2440.git] / sys / dev / acpi / acpi_bat.c
blob95185975d0a762f081c0e8acb81b3ad8c4b95342
1 /* $NetBSD: acpi_bat.c,v 1.74 2009/09/29 21:41:38 jmcneill Exp $ */
3 /*-
4 * Copyright (c) 2003 The NetBSD Foundation, Inc.
5 * All rights reserved.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Charles M. Hannum of By Noon Software, Inc.
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.
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.
33 * Copyright 2001 Bill Sommerfeld.
34 * All rights reserved.
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.
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.
65 #if 0
66 #define ACPI_BAT_DEBUG
67 #endif
70 * ACPI Battery Driver.
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.
78 * This driver is for the "Control Method"-style battery only.
81 #include <sys/cdefs.h>
82 __KERNEL_RCSID(0, "$NetBSD: acpi_bat.c,v 1.74 2009/09/29 21:41:38 jmcneill Exp $");
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>
91 #include <dev/acpi/acpica.h>
92 #include <dev/acpi/acpireg.h>
93 #include <dev/acpi/acpivar.h>
95 #define _COMPONENT ACPI_BAT_COMPONENT
96 ACPI_MODULE_NAME ("acpi_bat")
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 */
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 */
119 struct sysmon_envsys *sc_sme;
120 envsys_data_t sc_sensor[ACPIBAT_NSENSORS];
121 struct timeval sc_lastupdate;
123 kmutex_t sc_mutex;
124 kcondvar_t sc_condvar;
127 static const char * const bat_hid[] = {
128 "PNP0C0A",
129 NULL
133 * These flags are used to examine the battery device data returned from
134 * the ACPI interface, specifically the "battery status"
136 #define ACPIBAT_PWRUNIT_MA 0x00000001 /* mA not mW */
139 * These flags are used to examine the battery charge/discharge/critical
140 * state returned from a get-status command.
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 */
147 * Flags for battery status from _STA return
149 #define ACPIBAT_STA_PRESENT 0x00000010 /* battery present */
152 * These flags are used to set internal state in our softc.
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? */
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))
163 * Available info level
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 */
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);
175 CFATTACH_DECL_NEW(acpibat, sizeof(struct acpibat_softc),
176 acpibat_match, acpibat_attach, NULL, NULL);
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 *);
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 *);
195 * acpibat_match:
197 * Autoconfiguration `match' routine.
199 static int
200 acpibat_match(device_t parent, cfdata_t match, void *aux)
202 struct acpi_attach_args *aa = aux;
204 if (aa->aa_node->ad_type != ACPI_TYPE_DEVICE)
205 return 0;
207 return acpi_match_hid(aa->aa_node->ad_devinfo, bat_hid);
210 static bool
211 acpibat_resume(device_t dv, pmf_qual_t qual)
213 ACPI_STATUS rv;
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));
224 return true;
228 * acpibat_attach:
230 * Autoconfiguration `attach' routine.
232 static void
233 acpibat_attach(device_t parent, device_t self, void *aux)
235 struct acpibat_softc *sc = device_private(self);
236 struct acpi_attach_args *aa = aux;
237 ACPI_STATUS rv;
239 aprint_naive(": ACPI Battery (Control Method)\n");
240 aprint_normal(": ACPI Battery (Control Method)\n");
242 sc->sc_node = aa->aa_node;
244 mutex_init(&sc->sc_mutex, MUTEX_DEFAULT, IPL_NONE);
245 cv_init(&sc->sc_condvar, device_xname(self));
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;
257 #ifdef ACPI_BAT_DEBUG
258 ABAT_SET(sc, ABAT_F_VERBOSE);
259 #endif
261 if (!pmf_device_register(self, NULL, acpibat_resume))
262 aprint_error_dev(self, "couldn't establish power handler\n");
264 acpibat_init_envsys(self);
268 * clear informations
271 static void
272 acpibat_clear_presence(struct acpibat_softc *sc)
274 acpibat_clear_info(sc);
275 sc->sc_available = ABAT_ALV_NONE;
276 ABAT_CLEAR(sc, ABAT_F_PRESENT);
279 static void
280 acpibat_clear_info(struct acpibat_softc *sc)
282 acpibat_clear_stat(sc);
283 if (sc->sc_available > ABAT_ALV_PRESENCE)
284 sc->sc_available = ABAT_ALV_PRESENCE;
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;
295 static void
296 acpibat_clear_stat(struct acpibat_softc *sc)
298 if (sc->sc_available > ABAT_ALV_INFO)
299 sc->sc_available = ABAT_ALV_INFO;
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;
310 * returns 0 for no battery, 1 for present, and -1 on error
312 static int
313 acpibat_battery_present(device_t dv)
315 struct acpibat_softc *sc = device_private(dv);
316 uint32_t sta;
317 ACPI_INTEGER val;
318 ACPI_STATUS rv;
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;
327 sta = (uint32_t)val;
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;
337 return (sta & ACPIBAT_STA_PRESENT) ? 1 : 0;
341 * acpibat_get_info
343 * Get, and possibly display, the battery info.
346 static ACPI_STATUS
347 acpibat_get_info(device_t dv)
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;
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;
361 p1 = (ACPI_OBJECT *)buf.Pointer;
363 if (p1->Type != ACPI_TYPE_PACKAGE) {
364 aprint_error_dev(dv, "expected PACKAGE, got %d\n", p1->Type);
365 goto out;
367 if (p1->Package.Count < 13) {
368 aprint_error_dev(dv, "expected 13 elements, got %d\n",
369 p1->Package.Count);
370 goto out;
372 p2 = p1->Package.Elements;
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;
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;
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;
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);
418 aprint_verbose("\n");
420 rv = AE_OK;
422 out:
423 ACPI_FREE(buf.Pointer);
424 return rv;
428 * acpibat_get_status:
430 * Get, and possibly display, the current battery line status.
432 static ACPI_STATUS
433 acpibat_get_status(device_t dv)
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;
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;
447 p1 = (ACPI_OBJECT *)buf.Pointer;
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;
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;
461 p2 = p1->Package.Elements;
463 status = p2[0].Integer.Value;
464 battrate = p2[1].Integer.Value;
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;
485 sc->sc_sensor[ACPIBAT_CHARGE_STATE].value_cur =
486 ENVSYS_BATTERY_CAPACITY_NORMAL;
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;
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;
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;
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;
515 rv = AE_OK;
517 out:
518 ACPI_FREE(buf.Pointer);
519 return rv;
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)
528 struct acpibat_softc *sc = device_private(dv);
529 const char *tech;
531 if (sc->sc_sensor[ACPIBAT_TECHNOLOGY].value_cur)
532 tech = "secondary";
533 else
534 tech = "primary";
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));
544 static void
545 acpibat_print_stat(device_t dv)
547 struct acpibat_softc *sc = device_private(dv);
548 const char *capstat, *chargestat;
549 int percent, denom;
550 int32_t value;
552 percent = 0;
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 = "";
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;
572 denom = sc->sc_sensor[ACPIBAT_LFCCAPACITY].value_cur / 100;
573 if (denom > 0)
574 percent = (sc->sc_sensor[ACPIBAT_CAPACITY].value_cur) / denom;
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));
583 static void
584 acpibat_update(void *arg)
586 device_t dv = arg;
587 struct acpibat_softc *sc = device_private(dv);
589 if (sc->sc_available < ABAT_ALV_INFO) {
590 /* current information is invalid */
591 #if 0
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.
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;
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;
623 } else {
624 /* current information is valid */
625 if (!ABAT_ISSET(sc, ABAT_F_PRESENT)) {
626 /* the battery is not present. */
627 return;
631 if (ACPI_FAILURE(acpibat_get_status(dv)))
632 return;
634 if (ABAT_ISSET(sc, ABAT_F_VERBOSE))
635 acpibat_print_stat(dv);
638 static void
639 acpibat_update_info(void *arg)
641 device_t dev = arg;
642 struct acpibat_softc *sc = device_private(dev);
644 mutex_enter(&sc->sc_mutex);
645 acpibat_clear_presence(sc);
646 acpibat_update(arg);
647 mutex_exit(&sc->sc_mutex);
650 static void
651 acpibat_update_stat(void *arg)
653 device_t dev = arg;
654 struct acpibat_softc *sc = device_private(dev);
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);
665 * acpibat_notify_handler:
667 * Callback from ACPI interrupt handler to notify us of an event.
669 static void
670 acpibat_notify_handler(ACPI_HANDLE handle, UINT32 notify, void *context)
672 device_t dv = context;
673 ACPI_STATUS rv;
675 #ifdef ACPI_BAT_DEBUG
676 aprint_debug_dev(dv, "received notify message: 0x%x\n", notify);
677 #endif
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;
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;
699 default:
700 aprint_error_dev(dv,
701 "received unknown notify message: 0x%x\n", notify);
705 static void
706 acpibat_init_envsys(device_t dv)
708 struct acpibat_softc *sc = device_private(dv);
709 int i, capunit, rateunit;
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;
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));
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");
739 #undef INITDATA
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;
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;
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;
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;
772 acpibat_update(dv);
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);
780 static void
781 acpibat_refresh(struct sysmon_envsys *sme, envsys_data_t *edata)
783 device_t dv = sme->sme_cookie;
784 struct acpibat_softc *sc = device_private(dv);
785 ACPI_STATUS rv;
786 struct timeval tv, tmp;
788 if (!ABAT_ISSET(sc, ABAT_F_PRESENT))
789 acpibat_battery_present(dv);
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;
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);