1 /* $NetBSD: acpi_bat.c,v 1.74 2009/09/29 21:41:38 jmcneill Exp $ */
4 * Copyright (c) 2003 The NetBSD Foundation, Inc.
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
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
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
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.
66 #define ACPI_BAT_DEBUG
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")
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
;
124 kcondvar_t sc_condvar
;
127 static const char * const bat_hid
[] = {
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
*);
197 * Autoconfiguration `match' routine.
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
)
207 return acpi_match_hid(aa
->aa_node
->ad_devinfo
, bat_hid
);
211 acpibat_resume(device_t dv
, pmf_qual_t qual
)
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
));
230 * Autoconfiguration `attach' routine.
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
;
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
,
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
));
257 #ifdef ACPI_BAT_DEBUG
258 ABAT_SET(sc
, ABAT_F_VERBOSE
);
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
);
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
);
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
;
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
313 acpibat_battery_present(device_t dv
)
315 struct acpibat_softc
*sc
= device_private(dv
);
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
));
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;
335 sc
->sc_sensor
[ACPIBAT_PRESENT
].value_cur
= 0;
337 return (sta
& ACPIBAT_STA_PRESENT
) ? 1 : 0;
343 * Get, and possibly display, the battery info.
347 acpibat_get_info(device_t dv
)
349 struct acpibat_softc
*sc
= device_private(dv
);
350 ACPI_OBJECT
*p1
, *p2
;
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
));
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
);
367 if (p1
->Package
.Count
< 13) {
368 aprint_error_dev(dv
, "expected 13 elements, got %d\n",
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
;
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");
423 ACPI_FREE(buf
.Pointer
);
428 * acpibat_get_status:
430 * Get, and possibly display, the current battery line 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
;
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
));
447 p1
= (ACPI_OBJECT
*)buf
.Pointer
;
449 if (p1
->Type
!= ACPI_TYPE_PACKAGE
) {
450 aprint_error_dev(dv
, "expected PACKAGE, got %d\n",
455 if (p1
->Package
.Count
< 4) {
456 aprint_error_dev(dv
, "expected 4 elts, got %d\n",
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
;
518 ACPI_FREE(buf
.Pointer
);
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")
526 acpibat_print_info(device_t dv
)
528 struct acpibat_softc
*sc
= device_private(dv
);
531 if (sc
->sc_sensor
[ACPIBAT_TECHNOLOGY
].value_cur
)
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
));
545 acpibat_print_stat(device_t dv
)
547 struct acpibat_softc
*sc
= device_private(dv
);
548 const char *capstat
, *chargestat
;
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 ";
561 if (sc
->sc_sensor
[ACPIBAT_CHARGING
].state
!= ENVSYS_SVALID
) {
562 chargestat
= "idling";
564 } else if (sc
->sc_sensor
[ACPIBAT_CHARGING
].value_cur
== 0) {
565 chargestat
= "discharging";
566 value
= sc
->sc_sensor
[ACPIBAT_DISCHARGERATE
].value_cur
;
568 chargestat
= "charging";
569 value
= sc
->sc_sensor
[ACPIBAT_CHARGERATE
].value_cur
;
572 denom
= sc
->sc_sensor
[ACPIBAT_LFCCAPACITY
].value_cur
/ 100;
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
));
584 acpibat_update(void *arg
)
587 struct acpibat_softc
*sc
= device_private(dv
);
589 if (sc
->sc_available
< ABAT_ALV_INFO
) {
590 /* current information is invalid */
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
)
599 /* presence is invalid */
600 if (acpibat_battery_present(dv
) < 0) {
603 "cannot get battery presence.\n");
607 if (ABAT_ISSET(sc
, ABAT_F_PRESENT
)) {
608 /* the battery is present. */
609 if (ABAT_ISSET(sc
, ABAT_F_VERBOSE
))
611 "battery is present.\n");
612 if (ACPI_FAILURE(acpibat_get_info(dv
)))
614 if (ABAT_ISSET(sc
, ABAT_F_VERBOSE
))
615 acpibat_print_info(dv
);
617 /* the battery is not present. */
618 if (ABAT_ISSET(sc
, ABAT_F_VERBOSE
))
620 "battery is not present.\n");
624 /* current information is valid */
625 if (!ABAT_ISSET(sc
, ABAT_F_PRESENT
)) {
626 /* the battery is not present. */
631 if (ACPI_FAILURE(acpibat_get_status(dv
)))
634 if (ABAT_ISSET(sc
, ABAT_F_VERBOSE
))
635 acpibat_print_stat(dv
);
639 acpibat_update_info(void *arg
)
642 struct acpibat_softc
*sc
= device_private(dev
);
644 mutex_enter(&sc
->sc_mutex
);
645 acpibat_clear_presence(sc
);
647 mutex_exit(&sc
->sc_mutex
);
651 acpibat_update_stat(void *arg
)
654 struct acpibat_softc
*sc
= device_private(dev
);
656 mutex_enter(&sc
->sc_mutex
);
657 acpibat_clear_stat(sc
);
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.
670 acpibat_notify_handler(ACPI_HANDLE handle
, UINT32 notify
, void *context
)
672 device_t dv
= context
;
675 #ifdef ACPI_BAT_DEBUG
676 aprint_debug_dev(dv
, "received notify message: 0x%x\n", notify
);
680 case ACPI_NOTIFY_BusCheck
:
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
))
687 "unable to queue info check: %s\n",
688 AcpiFormatException(rv
));
691 case ACPI_NOTIFY_BatteryStatusChanged
:
692 rv
= AcpiOsExecute(OSL_NOTIFY_HANDLER
, acpibat_update_stat
, dv
);
693 if (ACPI_FAILURE(rv
))
695 "unable to queue status check: %s\n",
696 AcpiFormatException(rv
));
701 "received unknown notify message: 0x%x\n", notify
);
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
;
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");
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
);
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
;
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
);
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
);
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
)) {
795 timersub(&tv
, &tmp
, &tv
);
796 if (timercmp(&tv
, &sc
->sc_lastupdate
, <))
799 if (!mutex_tryenter(&sc
->sc_mutex
))
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
);