acpi_bat.c revision 1.94 1 /* $NetBSD: acpi_bat.c,v 1.94 2010/03/22 15:08:35 jruoho 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 /*
66 * ACPI Battery Driver.
67 *
68 * ACPI defines two different battery device interfaces: "Control
69 * Method" batteries, in which AML methods are defined in order to get
70 * battery status and set battery alarm thresholds, and a "Smart
71 * Battery" device, which is an SMbus device accessed through the ACPI
72 * Embedded Controller device.
73 *
74 * This driver is for the "Control Method"-style battery only.
75 */
76
77 #include <sys/cdefs.h>
78 __KERNEL_RCSID(0, "$NetBSD: acpi_bat.c,v 1.94 2010/03/22 15:08:35 jruoho Exp $");
79
80 #include <sys/param.h>
81 #include <sys/condvar.h>
82 #include <sys/device.h>
83 #include <sys/kernel.h>
84 #include <sys/kmem.h>
85 #include <sys/module.h>
86 #include <sys/mutex.h>
87 #include <sys/systm.h>
88
89 #include <dev/acpi/acpireg.h>
90 #include <dev/acpi/acpivar.h>
91
92 #define _COMPONENT ACPI_BAT_COMPONENT
93 ACPI_MODULE_NAME ("acpi_bat")
94
95 /*
96 * Sensor indexes.
97 */
98 enum {
99 ACPIBAT_PRESENT = 0,
100 ACPIBAT_DVOLTAGE = 1,
101 ACPIBAT_VOLTAGE = 2,
102 ACPIBAT_DCAPACITY = 3,
103 ACPIBAT_LFCCAPACITY = 4,
104 ACPIBAT_CAPACITY = 5,
105 ACPIBAT_CHARGERATE = 6,
106 ACPIBAT_DISCHARGERATE = 7,
107 ACPIBAT_CHARGING = 8,
108 ACPIBAT_CHARGE_STATE = 9,
109 ACPIBAT_COUNT = 10
110 };
111
112 /*
113 * Battery Information, _BIF
114 * (ACPI 3.0, sec. 10.2.2.1).
115 */
116 enum {
117 ACPIBAT_BIF_UNIT = 0,
118 ACPIBAT_BIF_DCAPACITY = 1,
119 ACPIBAT_BIF_LFCCAPACITY = 2,
120 ACPIBAT_BIF_TECHNOLOGY = 3,
121 ACPIBAT_BIF_DVOLTAGE = 4,
122 ACPIBAT_BIF_WCAPACITY = 5,
123 ACPIBAT_BIF_LCAPACITY = 6,
124 ACPIBAT_BIF_GRANULARITY1 = 7,
125 ACPIBAT_BIF_GRANULARITY2 = 8,
126 ACPIBAT_BIF_MODEL = 9,
127 ACPIBAT_BIF_SERIAL = 10,
128 ACPIBAT_BIF_TYPE = 11,
129 ACPIBAT_BIF_OEM = 12,
130 ACPIBAT_BIF_COUNT = 13
131 };
132
133 /*
134 * Battery Status, _BST
135 * (ACPI 3.0, sec. 10.2.2.3).
136 */
137 enum {
138 ACPIBAT_BST_STATE = 0,
139 ACPIBAT_BST_RATE = 1,
140 ACPIBAT_BST_CAPACITY = 2,
141 ACPIBAT_BST_VOLTAGE = 3,
142 ACPIBAT_BST_COUNT = 4
143 };
144
145 struct acpibat_softc {
146 struct acpi_devnode *sc_node;
147 struct sysmon_envsys *sc_sme;
148 envsys_data_t *sc_sensor;
149 kmutex_t sc_mutex;
150 kcondvar_t sc_condvar;
151 int32_t sc_lcapacity;
152 int32_t sc_wcapacity;
153 int sc_present;
154 };
155
156 static const char * const bat_hid[] = {
157 "PNP0C0A",
158 NULL
159 };
160
161 #define ACPIBAT_PWRUNIT_MA 0x00000001 /* mA not mW */
162 #define ACPIBAT_ST_DISCHARGING 0x00000001 /* battery is discharging */
163 #define ACPIBAT_ST_CHARGING 0x00000002 /* battery is charging */
164 #define ACPIBAT_ST_CRITICAL 0x00000004 /* battery is critical */
165
166 /*
167 * A value used when _BST or _BIF is temporarily unknown.
168 */
169 #define ACPIBAT_VAL_UNKNOWN 0xFFFFFFFF
170
171 #define ACPIBAT_VAL_ISVALID(x) \
172 (((x) != ACPIBAT_VAL_UNKNOWN) ? ENVSYS_SVALID : ENVSYS_SINVALID)
173
174 static int acpibat_match(device_t, cfdata_t, void *);
175 static void acpibat_attach(device_t, device_t, void *);
176 static int acpibat_detach(device_t, int);
177 static int acpibat_get_sta(device_t);
178 static ACPI_OBJECT *acpibat_get_object(ACPI_HANDLE, const char *, int);
179 static void acpibat_get_info(device_t);
180 static void acpibat_print_info(device_t, ACPI_OBJECT *);
181 static void acpibat_get_status(device_t);
182 static void acpibat_update_info(void *);
183 static void acpibat_update_status(void *);
184 static void acpibat_init_envsys(device_t);
185 static void acpibat_notify_handler(ACPI_HANDLE, UINT32, void *);
186 static void acpibat_refresh(struct sysmon_envsys *, envsys_data_t *);
187 static bool acpibat_resume(device_t, const pmf_qual_t *);
188 static void acpibat_get_limits(struct sysmon_envsys *, envsys_data_t *,
189 sysmon_envsys_lim_t *, uint32_t *);
190
191 CFATTACH_DECL_NEW(acpibat, sizeof(struct acpibat_softc),
192 acpibat_match, acpibat_attach, acpibat_detach, NULL);
193
194 /*
195 * acpibat_match:
196 *
197 * Autoconfiguration `match' routine.
198 */
199 static int
200 acpibat_match(device_t parent, cfdata_t match, void *aux)
201 {
202 struct acpi_attach_args *aa = aux;
203
204 if (aa->aa_node->ad_type != ACPI_TYPE_DEVICE)
205 return 0;
206
207 return acpi_match_hid(aa->aa_node->ad_devinfo, bat_hid);
208 }
209
210 /*
211 * acpibat_attach:
212 *
213 * Autoconfiguration `attach' routine.
214 */
215 static void
216 acpibat_attach(device_t parent, device_t self, void *aux)
217 {
218 struct acpibat_softc *sc = device_private(self);
219 struct acpi_attach_args *aa = aux;
220 ACPI_STATUS rv;
221
222 aprint_naive(": ACPI Battery\n");
223 aprint_normal(": ACPI Battery\n");
224
225 sc->sc_node = aa->aa_node;
226
227 sc->sc_present = 0;
228 sc->sc_lcapacity = 0;
229 sc->sc_wcapacity = 0;
230
231 sc->sc_sme = NULL;
232 sc->sc_sensor = NULL;
233
234 mutex_init(&sc->sc_mutex, MUTEX_DEFAULT, IPL_NONE);
235 cv_init(&sc->sc_condvar, device_xname(self));
236
237 if (pmf_device_register(self, NULL, acpibat_resume) != true)
238 aprint_error_dev(self, "couldn't establish power handler\n");
239
240 rv = AcpiInstallNotifyHandler(sc->sc_node->ad_handle,
241 ACPI_ALL_NOTIFY, acpibat_notify_handler, self);
242
243 if (ACPI_FAILURE(rv)) {
244 aprint_error_dev(self, "couldn't install notify handler\n");
245 return;
246 }
247
248 sc->sc_sensor = kmem_zalloc(ACPIBAT_COUNT *
249 sizeof(*sc->sc_sensor), KM_SLEEP);
250
251 if (sc->sc_sensor == NULL)
252 return;
253
254 acpibat_init_envsys(self);
255 }
256
257 /*
258 * acpibat_detach:
259 *
260 * Autoconfiguration `detach' routine.
261 */
262 static int
263 acpibat_detach(device_t self, int flags)
264 {
265 struct acpibat_softc *sc = device_private(self);
266 ACPI_STATUS rv;
267
268 rv = AcpiRemoveNotifyHandler(sc->sc_node->ad_handle,
269 ACPI_ALL_NOTIFY, acpibat_notify_handler);
270
271 if (ACPI_FAILURE(rv))
272 return EBUSY;
273
274 cv_destroy(&sc->sc_condvar);
275 mutex_destroy(&sc->sc_mutex);
276
277 if (sc->sc_sme != NULL)
278 sysmon_envsys_unregister(sc->sc_sme);
279
280 if (sc->sc_sensor != NULL)
281 kmem_free(sc->sc_sensor, ACPIBAT_COUNT *
282 sizeof(*sc->sc_sensor));
283
284 pmf_device_deregister(self);
285
286 return 0;
287 }
288
289 /*
290 * acpibat_get_sta:
291 *
292 * Evaluate whether the battery is present or absent.
293 *
294 * Returns: 0 for no battery, 1 for present, and -1 on error.
295 */
296 static int
297 acpibat_get_sta(device_t dv)
298 {
299 struct acpibat_softc *sc = device_private(dv);
300 ACPI_INTEGER val;
301 ACPI_STATUS rv;
302
303 rv = acpi_eval_integer(sc->sc_node->ad_handle, "_STA", &val);
304
305 if (ACPI_FAILURE(rv)) {
306 aprint_error_dev(dv, "failed to evaluate _STA\n");
307 return -1;
308 }
309
310 sc->sc_sensor[ACPIBAT_PRESENT].state = ENVSYS_SVALID;
311
312 if ((val & ACPI_STA_BATTERY_PRESENT) == 0) {
313 sc->sc_sensor[ACPIBAT_PRESENT].value_cur = 0;
314 return 0;
315 }
316
317 sc->sc_sensor[ACPIBAT_PRESENT].value_cur = 1;
318
319 return 1;
320 }
321
322 static ACPI_OBJECT *
323 acpibat_get_object(ACPI_HANDLE hdl, const char *pth, int count)
324 {
325 ACPI_OBJECT *obj;
326 ACPI_BUFFER buf;
327 ACPI_STATUS rv;
328
329 rv = acpi_eval_struct(hdl, pth, &buf);
330
331 if (ACPI_FAILURE(rv))
332 return NULL;
333
334 obj = buf.Pointer;
335
336 if (obj->Type != ACPI_TYPE_PACKAGE) {
337 ACPI_FREE(buf.Pointer);
338 return NULL;
339 }
340
341 if (obj->Package.Count != count) {
342 ACPI_FREE(buf.Pointer);
343 return NULL;
344 }
345
346 return obj;
347 }
348
349 /*
350 * acpibat_get_info:
351 *
352 * Get the battery info.
353 */
354 static void
355 acpibat_get_info(device_t dv)
356 {
357 struct acpibat_softc *sc = device_private(dv);
358 ACPI_HANDLE hdl = sc->sc_node->ad_handle;
359 int capunit, i, rateunit, val;
360 ACPI_OBJECT *elm, *obj;
361 ACPI_STATUS rv = AE_OK;
362
363 obj = acpibat_get_object(hdl, "_BIF", ACPIBAT_BIF_COUNT);
364
365 if (obj == NULL) {
366 rv = AE_ERROR;
367 goto out;
368 }
369
370 elm = obj->Package.Elements;
371
372 for (i = ACPIBAT_BIF_UNIT; i < ACPIBAT_BIF_MODEL; i++) {
373
374 if (elm[i].Type != ACPI_TYPE_INTEGER) {
375 rv = AE_TYPE;
376 goto out;
377 }
378
379 KDASSERT((uint64_t)elm[i].Integer.Value < INT_MAX);
380 }
381
382 if ((elm[ACPIBAT_BIF_UNIT].Integer.Value & ACPIBAT_PWRUNIT_MA) != 0) {
383 capunit = ENVSYS_SAMPHOUR;
384 rateunit = ENVSYS_SAMPS;
385 } else {
386 capunit = ENVSYS_SWATTHOUR;
387 rateunit = ENVSYS_SWATTS;
388 }
389
390 sc->sc_sensor[ACPIBAT_DCAPACITY].units = capunit;
391 sc->sc_sensor[ACPIBAT_LFCCAPACITY].units = capunit;
392 sc->sc_sensor[ACPIBAT_CHARGERATE].units = rateunit;
393 sc->sc_sensor[ACPIBAT_DISCHARGERATE].units = rateunit;
394 sc->sc_sensor[ACPIBAT_CAPACITY].units = capunit;
395
396 /* Design capacity. */
397 val = elm[ACPIBAT_BIF_DCAPACITY].Integer.Value;
398 sc->sc_sensor[ACPIBAT_DCAPACITY].value_cur = val * 1000;
399 sc->sc_sensor[ACPIBAT_DCAPACITY].state = ACPIBAT_VAL_ISVALID(val);
400
401 /* Last full charge capacity. */
402 val = elm[ACPIBAT_BIF_LFCCAPACITY].Integer.Value;
403 sc->sc_sensor[ACPIBAT_LFCCAPACITY].value_cur = val * 1000;
404 sc->sc_sensor[ACPIBAT_LFCCAPACITY].state = ACPIBAT_VAL_ISVALID(val);
405
406 /* Design voltage. */
407 val = elm[ACPIBAT_BIF_DVOLTAGE].Integer.Value;
408 sc->sc_sensor[ACPIBAT_DVOLTAGE].value_cur = val * 1000;
409 sc->sc_sensor[ACPIBAT_DVOLTAGE].state = ACPIBAT_VAL_ISVALID(val);
410
411 /* Design low and warning capacity. */
412 sc->sc_lcapacity = elm[ACPIBAT_BIF_LCAPACITY].Integer.Value * 1000;
413 sc->sc_wcapacity = elm[ACPIBAT_BIF_WCAPACITY].Integer.Value * 1000;
414
415 /*
416 * Initialize the maximum of current capacity
417 * to the last known full charge capacity.
418 */
419 val = sc->sc_sensor[ACPIBAT_LFCCAPACITY].value_cur;
420 sc->sc_sensor[ACPIBAT_CAPACITY].value_max = val;
421
422 acpibat_print_info(dv, elm);
423
424 out:
425 if (obj != NULL)
426 ACPI_FREE(obj);
427
428 if (ACPI_FAILURE(rv))
429 aprint_error_dev(dv, "failed to evaluate _BIF: %s\n",
430 AcpiFormatException(rv));
431 }
432
433 /*
434 * acpibat_print_info:
435 *
436 * Display the battery info.
437 */
438 static void
439 acpibat_print_info(device_t dv, ACPI_OBJECT *elm)
440 {
441 const char *tech, *unit = "Wh";
442 int i;
443
444 for (i = ACPIBAT_BIF_OEM; i > ACPIBAT_BIF_GRANULARITY2; i--) {
445
446 if (elm[i].Type != ACPI_TYPE_STRING)
447 return;
448
449 if (elm[i].String.Pointer == NULL)
450 return;
451 }
452
453 tech = (elm[ACPIBAT_BIF_TECHNOLOGY].Integer.Value != 0) ?
454 "secondary (rechargeable)" : "primary (non-rechargeable)";
455
456 if ((elm[ACPIBAT_BIF_UNIT].Integer.Value & ACPIBAT_PWRUNIT_MA) != 0)
457 unit = "Ah";
458
459 aprint_normal_dev(dv, "%s %s %s battery\n", tech,
460 elm[ACPIBAT_BIF_OEM].String.Pointer,
461 elm[ACPIBAT_BIF_TYPE].String.Pointer);
462
463 aprint_verbose_dev(dv, "serial number %s, model number %s\n",
464 elm[ACPIBAT_BIF_SERIAL].String.Pointer,
465 elm[ACPIBAT_BIF_MODEL].String.Pointer);
466
467 #define SCALE(x) (((int)x) / 1000000), ((((int)x) % 1000000) / 1000)
468
469 /*
470 * These values are defined as follows (ACPI 4.0, p. 388):
471 *
472 * Granularity 1. "Battery capacity granularity between low
473 * and warning in [mAh] or [mWh]. That is,
474 * this is the smallest increment in capacity
475 * that the battery is capable of measuring."
476 *
477 * Granularity 2. "Battery capacity granularity between warning
478 * and full in [mAh] or [mWh]. [...]"
479 */
480 aprint_verbose_dev(dv,
481 "granularity 1. %d.%03d %s, granularity 2. %d.%03d %s\n",
482 SCALE(elm[ACPIBAT_BIF_GRANULARITY1].Integer.Value * 1000), unit,
483 SCALE(elm[ACPIBAT_BIF_GRANULARITY2].Integer.Value * 1000), unit);
484 }
485
486 /*
487 * acpibat_get_status:
488 *
489 * Get the current battery status.
490 */
491 static void
492 acpibat_get_status(device_t dv)
493 {
494 struct acpibat_softc *sc = device_private(dv);
495 ACPI_HANDLE hdl = sc->sc_node->ad_handle;
496 int i, rate, state, val;
497 ACPI_OBJECT *elm, *obj;
498 ACPI_STATUS rv = AE_OK;
499
500 obj = acpibat_get_object(hdl, "_BST", ACPIBAT_BST_COUNT);
501
502 if (obj == NULL) {
503 rv = AE_ERROR;
504 goto out;
505 }
506
507 elm = obj->Package.Elements;
508
509 for (i = ACPIBAT_BST_STATE; i < ACPIBAT_BST_COUNT; i++) {
510
511 if (elm[i].Type != ACPI_TYPE_INTEGER) {
512 rv = AE_TYPE;
513 goto out;
514 }
515 }
516
517 state = elm[ACPIBAT_BST_STATE].Integer.Value;
518
519 if ((state & ACPIBAT_ST_CHARGING) != 0) {
520 /* XXX rate can be invalid */
521 rate = elm[ACPIBAT_BST_RATE].Integer.Value;
522 sc->sc_sensor[ACPIBAT_CHARGERATE].state = ENVSYS_SVALID;
523 sc->sc_sensor[ACPIBAT_CHARGERATE].value_cur = rate * 1000;
524 sc->sc_sensor[ACPIBAT_DISCHARGERATE].state = ENVSYS_SINVALID;
525 sc->sc_sensor[ACPIBAT_CHARGING].state = ENVSYS_SVALID;
526 sc->sc_sensor[ACPIBAT_CHARGING].value_cur = 1;
527 } else if ((state & ACPIBAT_ST_DISCHARGING) != 0) {
528 rate = elm[ACPIBAT_BST_RATE].Integer.Value;
529 sc->sc_sensor[ACPIBAT_DISCHARGERATE].state = ENVSYS_SVALID;
530 sc->sc_sensor[ACPIBAT_DISCHARGERATE].value_cur = rate * 1000;
531 sc->sc_sensor[ACPIBAT_CHARGERATE].state = ENVSYS_SINVALID;
532 sc->sc_sensor[ACPIBAT_CHARGING].state = ENVSYS_SVALID;
533 sc->sc_sensor[ACPIBAT_CHARGING].value_cur = 0;
534 } else {
535 sc->sc_sensor[ACPIBAT_CHARGING].state = ENVSYS_SVALID;
536 sc->sc_sensor[ACPIBAT_CHARGING].value_cur = 0;
537 sc->sc_sensor[ACPIBAT_CHARGERATE].state = ENVSYS_SINVALID;
538 sc->sc_sensor[ACPIBAT_DISCHARGERATE].state = ENVSYS_SINVALID;
539 }
540
541 /* Remaining capacity. */
542 val = elm[ACPIBAT_BST_CAPACITY].Integer.Value;
543 sc->sc_sensor[ACPIBAT_CAPACITY].value_cur = val * 1000;
544 sc->sc_sensor[ACPIBAT_CAPACITY].state = ACPIBAT_VAL_ISVALID(val);
545
546 /* Battery voltage. */
547 val = elm[ACPIBAT_BST_VOLTAGE].Integer.Value;
548 sc->sc_sensor[ACPIBAT_VOLTAGE].value_cur = val * 1000;
549 sc->sc_sensor[ACPIBAT_VOLTAGE].state = ACPIBAT_VAL_ISVALID(val);
550
551 sc->sc_sensor[ACPIBAT_CHARGE_STATE].state = ENVSYS_SVALID;
552 sc->sc_sensor[ACPIBAT_CHARGE_STATE].value_cur =
553 ENVSYS_BATTERY_CAPACITY_NORMAL;
554
555 if (sc->sc_sensor[ACPIBAT_CAPACITY].value_cur < sc->sc_wcapacity) {
556 sc->sc_sensor[ACPIBAT_CAPACITY].state = ENVSYS_SWARNUNDER;
557 sc->sc_sensor[ACPIBAT_CHARGE_STATE].value_cur =
558 ENVSYS_BATTERY_CAPACITY_WARNING;
559 }
560
561 if (sc->sc_sensor[ACPIBAT_CAPACITY].value_cur < sc->sc_lcapacity) {
562 sc->sc_sensor[ACPIBAT_CAPACITY].state = ENVSYS_SCRITUNDER;
563 sc->sc_sensor[ACPIBAT_CHARGE_STATE].value_cur =
564 ENVSYS_BATTERY_CAPACITY_LOW;
565 }
566
567 if ((state & ACPIBAT_ST_CRITICAL) != 0) {
568 sc->sc_sensor[ACPIBAT_CAPACITY].state = ENVSYS_SCRITICAL;
569 sc->sc_sensor[ACPIBAT_CHARGE_STATE].value_cur =
570 ENVSYS_BATTERY_CAPACITY_CRITICAL;
571 }
572
573 out:
574 if (obj != NULL)
575 ACPI_FREE(obj);
576
577 if (ACPI_FAILURE(rv))
578 aprint_error_dev(dv, "failed to evaluate _BST: %s\n",
579 AcpiFormatException(rv));
580 }
581
582 static void
583 acpibat_update_info(void *arg)
584 {
585 device_t dv = arg;
586 struct acpibat_softc *sc = device_private(dv);
587 int i, rv;
588
589 mutex_enter(&sc->sc_mutex);
590
591 rv = acpibat_get_sta(dv);
592
593 if (rv > 0)
594 acpibat_get_info(dv);
595 else {
596 i = (rv < 0) ? 0 : ACPIBAT_DVOLTAGE;
597
598 while (i < ACPIBAT_COUNT) {
599 sc->sc_sensor[i].state = ENVSYS_SINVALID;
600 i++;
601 }
602 }
603
604 sc->sc_present = rv;
605
606 mutex_exit(&sc->sc_mutex);
607 }
608
609 static void
610 acpibat_update_status(void *arg)
611 {
612 device_t dv = arg;
613 struct acpibat_softc *sc = device_private(dv);
614 int i, rv;
615
616 mutex_enter(&sc->sc_mutex);
617
618 rv = acpibat_get_sta(dv);
619
620 if (rv > 0) {
621
622 if (sc->sc_present == 0)
623 acpibat_get_info(dv);
624
625 acpibat_get_status(dv);
626 } else {
627 i = (rv < 0) ? 0 : ACPIBAT_DVOLTAGE;
628
629 while (i < ACPIBAT_COUNT) {
630 sc->sc_sensor[i].state = ENVSYS_SINVALID;
631 i++;
632 }
633 }
634
635 sc->sc_present = rv;
636
637 cv_broadcast(&sc->sc_condvar);
638 mutex_exit(&sc->sc_mutex);
639 }
640
641 /*
642 * acpibat_notify_handler:
643 *
644 * Callback from ACPI interrupt handler to notify us of an event.
645 */
646 static void
647 acpibat_notify_handler(ACPI_HANDLE handle, UINT32 notify, void *context)
648 {
649 static const int handler = OSL_NOTIFY_HANDLER;
650 device_t dv = context;
651
652 switch (notify) {
653
654 case ACPI_NOTIFY_BusCheck:
655 break;
656
657 case ACPI_NOTIFY_DeviceCheck:
658 case ACPI_NOTIFY_BatteryInformationChanged:
659 (void)AcpiOsExecute(handler, acpibat_update_info, dv);
660 break;
661
662 case ACPI_NOTIFY_BatteryStatusChanged:
663 (void)AcpiOsExecute(handler, acpibat_update_status, dv);
664 break;
665
666 default:
667 aprint_error_dev(dv, "unknown notify: 0x%02X\n", notify);
668 }
669 }
670
671 static void
672 acpibat_init_envsys(device_t dv)
673 {
674 struct acpibat_softc *sc = device_private(dv);
675 int i;
676
677 #define INITDATA(index, unit, string) \
678 do { \
679 sc->sc_sensor[index].state = ENVSYS_SVALID; \
680 sc->sc_sensor[index].units = unit; \
681 (void)strlcpy(sc->sc_sensor[index].desc, string, \
682 sizeof(sc->sc_sensor[index].desc)); \
683 } while (/* CONSTCOND */ 0)
684
685 INITDATA(ACPIBAT_PRESENT, ENVSYS_INDICATOR, "present");
686 INITDATA(ACPIBAT_DCAPACITY, ENVSYS_SWATTHOUR, "design cap");
687 INITDATA(ACPIBAT_LFCCAPACITY, ENVSYS_SWATTHOUR, "last full cap");
688 INITDATA(ACPIBAT_DVOLTAGE, ENVSYS_SVOLTS_DC, "design voltage");
689 INITDATA(ACPIBAT_VOLTAGE, ENVSYS_SVOLTS_DC, "voltage");
690 INITDATA(ACPIBAT_CHARGERATE, ENVSYS_SWATTS, "charge rate");
691 INITDATA(ACPIBAT_DISCHARGERATE, ENVSYS_SWATTS, "discharge rate");
692 INITDATA(ACPIBAT_CAPACITY, ENVSYS_SWATTHOUR, "charge");
693 INITDATA(ACPIBAT_CHARGING, ENVSYS_BATTERY_CHARGE, "charging");
694 INITDATA(ACPIBAT_CHARGE_STATE, ENVSYS_BATTERY_CAPACITY, "charge state");
695
696 #undef INITDATA
697
698 sc->sc_sensor[ACPIBAT_CAPACITY].flags |=
699 ENVSYS_FPERCENT | ENVSYS_FVALID_MAX | ENVSYS_FMONLIMITS;
700
701 sc->sc_sensor[ACPIBAT_CHARGE_STATE].flags |= ENVSYS_FMONSTCHANGED;
702
703 /* Disable userland monitoring on these sensors. */
704 sc->sc_sensor[ACPIBAT_VOLTAGE].flags = ENVSYS_FMONNOTSUPP;
705 sc->sc_sensor[ACPIBAT_CHARGERATE].flags = ENVSYS_FMONNOTSUPP;
706 sc->sc_sensor[ACPIBAT_DISCHARGERATE].flags = ENVSYS_FMONNOTSUPP;
707 sc->sc_sensor[ACPIBAT_DCAPACITY].flags = ENVSYS_FMONNOTSUPP;
708 sc->sc_sensor[ACPIBAT_LFCCAPACITY].flags = ENVSYS_FMONNOTSUPP;
709 sc->sc_sensor[ACPIBAT_DVOLTAGE].flags = ENVSYS_FMONNOTSUPP;
710
711 sc->sc_sme = sysmon_envsys_create();
712
713 for (i = 0; i < ACPIBAT_COUNT; i++) {
714
715 if (sysmon_envsys_sensor_attach(sc->sc_sme,
716 &sc->sc_sensor[i]))
717 goto fail;
718 }
719
720 sc->sc_sme->sme_name = device_xname(dv);
721 sc->sc_sme->sme_cookie = dv;
722 sc->sc_sme->sme_refresh = acpibat_refresh;
723 sc->sc_sme->sme_class = SME_CLASS_BATTERY;
724 sc->sc_sme->sme_flags = SME_POLL_ONLY;
725 sc->sc_sme->sme_get_limits = acpibat_get_limits;
726
727 acpibat_update_info(dv);
728 acpibat_update_status(dv);
729
730 if (sysmon_envsys_register(sc->sc_sme))
731 goto fail;
732
733 return;
734
735 fail:
736 aprint_error_dev(dv, "failed to initialize sysmon\n");
737
738 sysmon_envsys_destroy(sc->sc_sme);
739 kmem_free(sc->sc_sensor, ACPIBAT_COUNT * sizeof(*sc->sc_sensor));
740
741 sc->sc_sme = NULL;
742 sc->sc_sensor = NULL;
743 }
744
745 static void
746 acpibat_refresh(struct sysmon_envsys *sme, envsys_data_t *edata)
747 {
748 device_t dv = sme->sme_cookie;
749 struct acpibat_softc *sc = device_private(dv);
750 ACPI_STATUS rv;
751
752 if (mutex_tryenter(&sc->sc_mutex) == 0)
753 return;
754
755 rv = AcpiOsExecute(OSL_NOTIFY_HANDLER, acpibat_update_status, dv);
756
757 if (ACPI_SUCCESS(rv))
758 cv_timedwait(&sc->sc_condvar, &sc->sc_mutex, hz);
759
760 mutex_exit(&sc->sc_mutex);
761 }
762
763 static bool
764 acpibat_resume(device_t dv, const pmf_qual_t *qual)
765 {
766
767 (void)AcpiOsExecute(OSL_NOTIFY_HANDLER, acpibat_update_info, dv);
768 (void)AcpiOsExecute(OSL_NOTIFY_HANDLER, acpibat_update_status, dv);
769
770 return true;
771 }
772
773 static void
774 acpibat_get_limits(struct sysmon_envsys *sme, envsys_data_t *edata,
775 sysmon_envsys_lim_t *limits, uint32_t *props)
776 {
777 device_t dv = sme->sme_cookie;
778 struct acpibat_softc *sc = device_private(dv);
779
780 if (edata->sensor != ACPIBAT_CAPACITY)
781 return;
782
783 limits->sel_critmin = sc->sc_lcapacity;
784 limits->sel_warnmin = sc->sc_wcapacity;
785
786 *props |= PROP_BATTCAP | PROP_BATTWARN | PROP_DRIVER_LIMITS;
787 }
788
789 #ifdef _MODULE
790
791 MODULE(MODULE_CLASS_DRIVER, acpibat, NULL);
792
793 #include "ioconf.c"
794
795 static int
796 acpibat_modcmd(modcmd_t cmd, void *context)
797 {
798 int err;
799
800 switch (cmd) {
801
802 case MODULE_CMD_INIT:
803
804 err = config_cfdriver_attach(&acpibat_cd);
805
806 if (err != 0)
807 return err;
808
809 err = config_cfattach_attach("acpibat", &acpibat_ca);
810
811 if (err != 0) {
812 config_cfdriver_detach(&acpibat_cd);
813 return err;
814 }
815
816 err = config_cfdata_attach(cfdata_acpibat, 1);
817
818 if (err != 0) {
819 config_cfattach_detach("acpibat", &acpibat_ca);
820 config_cfdriver_detach(&acpibat_cd);
821 return err;
822 }
823
824 return 0;
825
826 case MODULE_CMD_FINI:
827
828 err = config_cfdata_detach(cfdata_acpibat);
829
830 if (err != 0)
831 return err;
832
833 config_cfattach_detach("acpibat", &acpibat_ca);
834 config_cfdriver_detach(&acpibat_cd);
835
836 return 0;
837
838 default:
839 return ENOTTY;
840 }
841 }
842
843 #endif /* _MODULE */
844