acpi_bat.c revision 1.69 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