xref: /openbsd-src/sys/dev/acpi/acpibat.c (revision 5a38ef86d0b61900239c7913d24a05e7b88a58f0)
1 /* $OpenBSD: acpibat.c,v 1.68 2020/06/10 22:26:40 jca Exp $ */
2 /*
3  * Copyright (c) 2005 Marco Peereboom <marco@openbsd.org>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include <sys/param.h>
19 #include <sys/systm.h>
20 #include <sys/device.h>
21 #include <sys/malloc.h>
22 #include <sys/sensors.h>
23 
24 #include <machine/apmvar.h>
25 
26 #include <dev/acpi/acpireg.h>
27 #include <dev/acpi/acpivar.h>
28 #include <dev/acpi/acpidev.h>
29 #include <dev/acpi/amltypes.h>
30 #include <dev/acpi/dsdt.h>
31 
32 int	acpibat_match(struct device *, void *, void *);
33 void	acpibat_attach(struct device *, struct device *, void *);
34 int	acpibat_activate(struct device *, int);
35 
36 struct cfattach acpibat_ca = {
37 	sizeof(struct acpibat_softc),
38 	acpibat_match,
39 	acpibat_attach,
40 	NULL,
41 	acpibat_activate,
42 };
43 
44 struct cfdriver acpibat_cd = {
45 	NULL, "acpibat", DV_DULL
46 };
47 
48 const char *acpibat_hids[] = {
49 	ACPI_DEV_CMB,
50 	NULL
51 };
52 
53 void	acpibat_monitor(struct acpibat_softc *);
54 void	acpibat_refresh(void *);
55 int	acpibat_getbix(struct acpibat_softc *);
56 int	acpibat_getbst(struct acpibat_softc *);
57 int	acpibat_notify(struct aml_node *, int, void *);
58 
59 int
60 acpibat_match(struct device *parent, void *match, void *aux)
61 {
62 	struct acpi_attach_args	*aa = aux;
63 	struct cfdata		*cf = match;
64 
65 	if (((struct acpi_softc *)parent)->sc_havesbs)
66 		return (0);
67 
68 	/* sanity */
69 	return (acpi_matchhids(aa, acpibat_hids, cf->cf_driver->cd_name));
70 }
71 
72 void
73 acpibat_attach(struct device *parent, struct device *self, void *aux)
74 {
75 	struct acpibat_softc	*sc = (struct acpibat_softc *)self;
76 	struct acpi_attach_args	*aa = aux;
77 	int64_t			sta;
78 
79 	sc->sc_acpi = (struct acpi_softc *)parent;
80 	sc->sc_devnode = aa->aaa_node;
81 
82 	if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "_STA", 0, NULL, &sta)) {
83 		dnprintf(10, "%s: no _STA\n", DEVNAME(sc));
84 		return;
85 	}
86 
87 	if ((sta & STA_BATTERY) != 0) {
88 		sc->sc_bat_present = 1;
89 		acpibat_getbix(sc);
90 		acpibat_getbst(sc);
91 
92 		printf(": %s", sc->sc_devnode->name);
93 		if (sc->sc_bix.bix_model[0])
94 			printf(" model \"%s\"", sc->sc_bix.bix_model);
95 		if (sc->sc_bix.bix_serial[0])
96 			printf(" serial %s", sc->sc_bix.bix_serial);
97 		if (sc->sc_bix.bix_type[0])
98 			printf(" type %s", sc->sc_bix.bix_type);
99 		if (sc->sc_bix.bix_oem[0])
100 			printf(" oem \"%s\"", sc->sc_bix.bix_oem);
101 
102 		printf("\n");
103 	} else {
104 		sc->sc_bat_present = 0;
105 		printf(": %s not present\n", sc->sc_devnode->name);
106 	}
107 
108 	/* create sensors */
109 	acpibat_monitor(sc);
110 
111 	/* populate sensors */
112 	acpibat_refresh(sc);
113 
114 	aml_register_notify(sc->sc_devnode, aa->aaa_dev,
115 	    acpibat_notify, sc, ACPIDEV_POLL);
116 }
117 
118 int
119 acpibat_activate(struct device *self, int act)
120 {
121 	struct acpibat_softc *sc = (struct acpibat_softc *)self;
122 	int64_t sta;
123 
124 	switch (act) {
125 	case DVACT_WAKEUP:
126 		/* Check if installed state of battery has changed */
127 		if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "_STA", 0,
128 		    NULL, &sta) == 0) {
129 			if (sta & STA_BATTERY)
130 				sc->sc_bat_present = 1;
131 			else
132 				sc->sc_bat_present = 0;
133 		}
134 		acpibat_getbix(sc);
135 		acpibat_getbst(sc);
136 		acpibat_refresh(sc);
137 		break;
138 	}
139 
140 	return (0);
141 }
142 
143 void
144 acpibat_monitor(struct acpibat_softc *sc)
145 {
146 	int			type;
147 
148 	/* assume _BIF/_BIX and _BST have been called */
149 	strlcpy(sc->sc_sensdev.xname, DEVNAME(sc),
150 	    sizeof(sc->sc_sensdev.xname));
151 
152 	type = sc->sc_bix.bix_power_unit ? SENSOR_AMPHOUR : SENSOR_WATTHOUR;
153 
154 	strlcpy(sc->sc_sens[0].desc, "last full capacity",
155 	    sizeof(sc->sc_sens[0].desc));
156 	sc->sc_sens[0].type = type;
157 	sensor_attach(&sc->sc_sensdev, &sc->sc_sens[0]);
158 	sc->sc_sens[0].value = sc->sc_bix.bix_last_capacity * 1000;
159 
160 	strlcpy(sc->sc_sens[1].desc, "warning capacity",
161 	    sizeof(sc->sc_sens[1].desc));
162 	sc->sc_sens[1].type = type;
163 	sensor_attach(&sc->sc_sensdev, &sc->sc_sens[1]);
164 	sc->sc_sens[1].value = sc->sc_bix.bix_warning * 1000;
165 
166 	strlcpy(sc->sc_sens[2].desc, "low capacity",
167 	    sizeof(sc->sc_sens[2].desc));
168 	sc->sc_sens[2].type = type;
169 	sensor_attach(&sc->sc_sensdev, &sc->sc_sens[2]);
170 	sc->sc_sens[2].value = sc->sc_bix.bix_low * 1000;
171 
172 	strlcpy(sc->sc_sens[3].desc, "voltage", sizeof(sc->sc_sens[3].desc));
173 	sc->sc_sens[3].type = SENSOR_VOLTS_DC;
174 	sensor_attach(&sc->sc_sensdev, &sc->sc_sens[3]);
175 	sc->sc_sens[3].value = sc->sc_bix.bix_voltage * 1000;
176 
177 	strlcpy(sc->sc_sens[4].desc, "battery unknown",
178 	    sizeof(sc->sc_sens[4].desc));
179 	sc->sc_sens[4].type = SENSOR_INTEGER;
180 	sensor_attach(&sc->sc_sensdev, &sc->sc_sens[4]);
181 	sc->sc_sens[4].value = sc->sc_bst.bst_state;
182 
183 	strlcpy(sc->sc_sens[5].desc, "rate", sizeof(sc->sc_sens[5].desc));
184 	sc->sc_sens[5].type =
185 		sc->sc_bix.bix_power_unit ? SENSOR_AMPS : SENSOR_WATTS;
186 	sensor_attach(&sc->sc_sensdev, &sc->sc_sens[5]);
187 	sc->sc_sens[5].value = sc->sc_bst.bst_rate * 1000;
188 
189 	strlcpy(sc->sc_sens[6].desc, "remaining capacity",
190 	    sizeof(sc->sc_sens[6].desc));
191 	sc->sc_sens[6].type = type;
192 	sensor_attach(&sc->sc_sensdev, &sc->sc_sens[6]);
193 	sc->sc_sens[6].value = sc->sc_bix.bix_capacity * 1000;
194 
195 	strlcpy(sc->sc_sens[7].desc, "current voltage",
196 	    sizeof(sc->sc_sens[7].desc));
197 	sc->sc_sens[7].type = SENSOR_VOLTS_DC;
198 	sensor_attach(&sc->sc_sensdev, &sc->sc_sens[7]);
199 	sc->sc_sens[7].value = sc->sc_bix.bix_voltage * 1000;
200 
201 	strlcpy(sc->sc_sens[8].desc, "design capacity",
202 	    sizeof(sc->sc_sens[8].desc));
203 	sc->sc_sens[8].type = type;
204 	sensor_attach(&sc->sc_sensdev, &sc->sc_sens[8]);
205 	sc->sc_sens[8].value = sc->sc_bix.bix_capacity * 1000;
206 
207 	if (!sc->sc_use_bif) {
208 		strlcpy(sc->sc_sens[9].desc, "discharge cycles",
209 		    sizeof(sc->sc_sens[9].desc));
210 		sc->sc_sens[9].type = SENSOR_INTEGER;
211 		sensor_attach(&sc->sc_sensdev, &sc->sc_sens[9]);
212 		sc->sc_sens[9].value = sc->sc_bix.bix_cycle_count;
213 	}
214 
215 	sensordev_install(&sc->sc_sensdev);
216 }
217 
218 void
219 acpibat_refresh(void *arg)
220 {
221 	struct acpibat_softc	*sc = arg;
222 	int			i;
223 
224 	dnprintf(30, "%s: %s: refresh\n", DEVNAME(sc),
225 	    sc->sc_devnode->name);
226 
227 	if (!sc->sc_bat_present) {
228 		for (i = 0; i < nitems(sc->sc_sens); i++) {
229 			sc->sc_sens[i].value = 0;
230 			sc->sc_sens[i].status = SENSOR_S_UNSPEC;
231 			sc->sc_sens[i].flags = SENSOR_FINVALID;
232 		}
233 		/* override state */
234 		strlcpy(sc->sc_sens[4].desc, "battery removed",
235 		    sizeof(sc->sc_sens[4].desc));
236 		return;
237 	}
238 
239 	/* _BIF/_BIX values are static, sensor 0..3 */
240 	if (sc->sc_bix.bix_last_capacity == BIX_UNKNOWN) {
241 		sc->sc_sens[0].value = 0;
242 		sc->sc_sens[0].status = SENSOR_S_UNKNOWN;
243 		sc->sc_sens[0].flags = SENSOR_FUNKNOWN;
244 	} else {
245 		sc->sc_sens[0].value = sc->sc_bix.bix_last_capacity * 1000;
246 		sc->sc_sens[0].status = SENSOR_S_UNSPEC;
247 		sc->sc_sens[0].flags = 0;
248 	}
249 	sc->sc_sens[1].value = sc->sc_bix.bix_warning * 1000;
250 	sc->sc_sens[1].flags = 0;
251 	sc->sc_sens[2].value = sc->sc_bix.bix_low * 1000;
252 	sc->sc_sens[2].flags = 0;
253 	if (sc->sc_bix.bix_voltage == BIX_UNKNOWN) {
254 		sc->sc_sens[3].value = 0;
255 		sc->sc_sens[3].status = SENSOR_S_UNKNOWN;
256 		sc->sc_sens[3].flags = SENSOR_FUNKNOWN;
257 	} else {
258 		sc->sc_sens[3].value = sc->sc_bix.bix_voltage * 1000;
259 		sc->sc_sens[3].status = SENSOR_S_UNSPEC;
260 		sc->sc_sens[3].flags = 0;
261 	}
262 
263 	/* _BST values are dynamic, sensor 4..7 */
264 	sc->sc_sens[4].status = SENSOR_S_OK;
265 	sc->sc_sens[4].flags = 0;
266 	if (sc->sc_bix.bix_last_capacity == BIX_UNKNOWN ||
267 	    sc->sc_bst.bst_capacity == BST_UNKNOWN) {
268 		sc->sc_sens[4].status = SENSOR_S_UNKNOWN;
269 		sc->sc_sens[4].flags = SENSOR_FUNKNOWN;
270 		strlcpy(sc->sc_sens[4].desc, "battery unknown",
271 		    sizeof(sc->sc_sens[4].desc));
272 	} else if (sc->sc_bst.bst_capacity >= sc->sc_bix.bix_last_capacity)
273 		strlcpy(sc->sc_sens[4].desc, "battery full",
274 		    sizeof(sc->sc_sens[4].desc));
275 	else if (sc->sc_bst.bst_state & BST_DISCHARGE)
276 		strlcpy(sc->sc_sens[4].desc, "battery discharging",
277 		    sizeof(sc->sc_sens[4].desc));
278 	else if (sc->sc_bst.bst_state & BST_CHARGE)
279 		strlcpy(sc->sc_sens[4].desc, "battery charging",
280 		    sizeof(sc->sc_sens[4].desc));
281 	else if (sc->sc_bst.bst_state & BST_CRITICAL) {
282 		strlcpy(sc->sc_sens[4].desc, "battery critical",
283 		    sizeof(sc->sc_sens[4].desc));
284 		sc->sc_sens[4].status = SENSOR_S_CRIT;
285 	} else
286 		strlcpy(sc->sc_sens[4].desc, "battery idle",
287 		    sizeof(sc->sc_sens[4].desc));
288 	sc->sc_sens[4].value = sc->sc_bst.bst_state;
289 
290 	if (sc->sc_bst.bst_rate == BST_UNKNOWN) {
291 		sc->sc_sens[5].value = 0;
292 		sc->sc_sens[5].status = SENSOR_S_UNKNOWN;
293 		sc->sc_sens[5].flags = SENSOR_FUNKNOWN;
294 	} else {
295 		sc->sc_sens[5].value = sc->sc_bst.bst_rate * 1000;
296 		sc->sc_sens[5].status = SENSOR_S_UNSPEC;
297 		sc->sc_sens[5].flags = 0;
298 	}
299 
300 	if (sc->sc_bst.bst_capacity == BST_UNKNOWN) {
301 		sc->sc_sens[6].value = 0;
302 		sc->sc_sens[6].status = SENSOR_S_UNKNOWN;
303 		sc->sc_sens[6].flags = SENSOR_FUNKNOWN;
304 	} else {
305 		sc->sc_sens[6].value = sc->sc_bst.bst_capacity * 1000;
306 		sc->sc_sens[6].flags = 0;
307 
308 		if (sc->sc_bst.bst_capacity < sc->sc_bix.bix_low)
309 			/* XXX we should shutdown the system */
310 			sc->sc_sens[6].status = SENSOR_S_CRIT;
311 		else if (sc->sc_bst.bst_capacity < sc->sc_bix.bix_warning)
312 			sc->sc_sens[6].status = SENSOR_S_WARN;
313 		else
314 			sc->sc_sens[6].status = SENSOR_S_OK;
315 	}
316 
317 	if (sc->sc_bst.bst_voltage == BST_UNKNOWN) {
318 		sc->sc_sens[7].value = 0;
319 		sc->sc_sens[7].status = SENSOR_S_UNKNOWN;
320 		sc->sc_sens[7].flags = SENSOR_FUNKNOWN;
321 	} else {
322 		sc->sc_sens[7].value = sc->sc_bst.bst_voltage * 1000;
323 		sc->sc_sens[7].status = SENSOR_S_UNSPEC;
324 		sc->sc_sens[7].flags = 0;
325 	}
326 
327 	if (sc->sc_bix.bix_capacity == BIX_UNKNOWN) {
328 		sc->sc_sens[8].value = 0;
329 		sc->sc_sens[8].status = SENSOR_S_UNKNOWN;
330 		sc->sc_sens[8].flags = SENSOR_FUNKNOWN;
331 	} else {
332 		sc->sc_sens[8].value = sc->sc_bix.bix_capacity * 1000;
333 		sc->sc_sens[8].status = SENSOR_S_UNSPEC;
334 		sc->sc_sens[8].flags = 0;
335 	}
336 
337 	if (!sc->sc_use_bif) {
338 		if (sc->sc_bix.bix_capacity == BIX_UNKNOWN) {
339 			sc->sc_sens[9].value = 0;
340 			sc->sc_sens[9].status = SENSOR_S_UNKNOWN;
341 			sc->sc_sens[9].flags = SENSOR_FUNKNOWN;
342 		} else {
343 			sc->sc_sens[9].value = sc->sc_bix.bix_cycle_count;
344 			sc->sc_sens[9].status = SENSOR_S_UNSPEC;
345 			sc->sc_sens[9].flags = 0;
346 		}
347 	}
348 }
349 
350 int
351 acpibat_getbix(struct acpibat_softc *sc)
352 {
353 	struct aml_value	res;
354 	int			rv = EINVAL;
355 	int			n = 0;
356 
357 	if (!sc->sc_bat_present) {
358 		memset(&sc->sc_bix, 0, sizeof(sc->sc_bix));
359 		return (0);
360 	}
361 
362 	sc->sc_use_bif = 1;
363 
364 	if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_BIX", 0, NULL,
365 	    &res) == 0) {
366 		if (res.length >= 20)
367 			sc->sc_use_bif = 0;
368 		else
369 			dnprintf(10, "%s: invalid _BIX (%d < 20)\n",
370 			    DEVNAME(sc), res.length);
371 	}
372 
373 	if (sc->sc_use_bif) {
374 		if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_BIF", 0, NULL,
375 		    &res)) {
376 			dnprintf(10, "%s: no _BIX or _BIF\n", DEVNAME(sc));
377 			goto out;
378 		}
379 
380 		if (res.length != 13) {
381 			dnprintf(10, "%s: invalid _BIF (%d != 13)\n",
382 			    DEVNAME(sc), res.length);
383 			goto out;
384 		}
385 	}
386 
387 	if (!sc->sc_use_bif)
388 		sc->sc_bix.bix_revision = aml_val2int(res.v_package[n++]);
389 
390 	sc->sc_bix.bix_power_unit = aml_val2int(res.v_package[n++]);
391 	sc->sc_bix.bix_capacity = aml_val2int(res.v_package[n++]);
392 	sc->sc_bix.bix_last_capacity = aml_val2int(res.v_package[n++]);
393 	sc->sc_bix.bix_technology = aml_val2int(res.v_package[n++]);
394 	sc->sc_bix.bix_voltage = aml_val2int(res.v_package[n++]);
395 	sc->sc_bix.bix_warning = aml_val2int(res.v_package[n++]);
396 	sc->sc_bix.bix_low = aml_val2int(res.v_package[n++]);
397 
398 	if (!sc->sc_use_bif) {
399 		sc->sc_bix.bix_cycle_count = aml_val2int(res.v_package[n++]);
400 		sc->sc_bix.bix_accuracy = aml_val2int(res.v_package[n++]);
401 		sc->sc_bix.bix_max_sample = aml_val2int(res.v_package[n++]);
402 		sc->sc_bix.bix_min_sample = aml_val2int(res.v_package[n++]);
403 		sc->sc_bix.bix_max_avg = aml_val2int(res.v_package[n++]);
404 		sc->sc_bix.bix_min_avg = aml_val2int(res.v_package[n++]);
405 	}
406 
407 	sc->sc_bix.bix_cap_granu1 = aml_val2int(res.v_package[n++]);
408 	sc->sc_bix.bix_cap_granu2 = aml_val2int(res.v_package[n++]);
409 
410 	strlcpy(sc->sc_bix.bix_model, aml_val_to_string(res.v_package[n++]),
411 		sizeof(sc->sc_bix.bix_model));
412 	strlcpy(sc->sc_bix.bix_serial, aml_val_to_string(res.v_package[n++]),
413 		sizeof(sc->sc_bix.bix_serial));
414 	strlcpy(sc->sc_bix.bix_type, aml_val_to_string(res.v_package[n++]),
415 		sizeof(sc->sc_bix.bix_type));
416 	strlcpy(sc->sc_bix.bix_oem, aml_val_to_string(res.v_package[n++]),
417 		sizeof(sc->sc_bix.bix_oem));
418 
419 	if (!sc->sc_use_bif)
420 		dnprintf(60, "revision: %u ", sc->sc_bix.bix_revision);
421 
422 	dnprintf(60, "power_unit: %u capacity: %u last_cap: %u "
423 	    "tech: %u volt: %u warn: %u low: %u ",
424 	    sc->sc_bix.bix_power_unit,
425 	    sc->sc_bix.bix_capacity,
426 	    sc->sc_bix.bix_last_capacity,
427 	    sc->sc_bix.bix_technology,
428 	    sc->sc_bix.bix_voltage,
429 	    sc->sc_bix.bix_warning,
430 	    sc->sc_bix.bix_low);
431 
432 	if (!sc->sc_use_bif)
433 		dnprintf(60, "cycles: %u accuracy: %u max_sample: %u "
434 		    "min_sample: %u max_avg: %u min_avg: %u ",
435 		    sc->sc_bix.bix_cycle_count,
436 		    sc->sc_bix.bix_accuracy,
437 		    sc->sc_bix.bix_max_sample,
438 		    sc->sc_bix.bix_min_sample,
439 		    sc->sc_bix.bix_max_avg,
440 		    sc->sc_bix.bix_min_avg);
441 
442 	dnprintf(60, "gran1: %u gran2: %d model: %s serial: %s type: %s "
443 	    "oem: %s\n",
444 	    sc->sc_bix.bix_cap_granu1,
445 	    sc->sc_bix.bix_cap_granu2,
446 	    sc->sc_bix.bix_model,
447 	    sc->sc_bix.bix_serial,
448 	    sc->sc_bix.bix_type,
449 	    sc->sc_bix.bix_oem);
450 
451 	rv = 0;
452 out:
453 	aml_freevalue(&res);
454 	return (rv);
455 }
456 
457 int
458 acpibat_getbst(struct acpibat_softc *sc)
459 {
460 	struct aml_value	res;
461 	int			rv = EINVAL;
462 
463 	if (!sc->sc_bat_present) {
464 		memset(&sc->sc_bst, 0, sizeof(sc->sc_bst));
465 		return (0);
466 	}
467 
468 	if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_BST", 0, NULL, &res)) {
469 		dnprintf(10, "%s: no _BST\n", DEVNAME(sc));
470 		goto out;
471 	}
472 
473 	if (res.length != 4) {
474 		dnprintf(10, "%s: invalid _BST, battery status not saved\n",
475 		    DEVNAME(sc));
476 		goto out;
477 	}
478 
479 	sc->sc_bst.bst_state = aml_val2int(res.v_package[0]);
480 	sc->sc_bst.bst_rate = aml_val2int(res.v_package[1]);
481 	sc->sc_bst.bst_capacity = aml_val2int(res.v_package[2]);
482 	sc->sc_bst.bst_voltage = aml_val2int(res.v_package[3]);
483 
484 	dnprintf(60, "state: %u rate: %u cap: %u volt: %u ",
485 	    sc->sc_bst.bst_state,
486 	    sc->sc_bst.bst_rate,
487 	    sc->sc_bst.bst_capacity,
488 	    sc->sc_bst.bst_voltage);
489 
490 	rv = 0;
491 out:
492 	aml_freevalue(&res);
493 	return (rv);
494 }
495 
496 /*
497  * XXX it has been observed that some systems do not propagate battery
498  * insertion events up to the driver.  What seems to happen is that DSDT
499  * does receive an interrupt however the originator bit is not set.
500  * This seems to happen when one inserts a 100% full battery.  Removal
501  * of the power cord or insertion of a not 100% full battery breaks this
502  * behavior and all events will then be sent upwards.  Currently there
503  * is no known work-around for it.
504  */
505 
506 int
507 acpibat_notify(struct aml_node *node, int notify_type, void *arg)
508 {
509 	struct acpibat_softc	*sc = arg;
510 	int64_t			sta;
511 
512 	dnprintf(10, "acpibat_notify: %.2x %s\n", notify_type,
513 	    sc->sc_devnode->name);
514 
515 	/* Check if installed state of battery has changed */
516 	if (aml_evalinteger(sc->sc_acpi, node, "_STA", 0, NULL, &sta) == 0) {
517 		if (sta & STA_BATTERY)
518 			sc->sc_bat_present = 1;
519 		else
520 			sc->sc_bat_present = 0;
521 	}
522 
523 	switch (notify_type) {
524 	case 0x00:	/* Poll sensors */
525 	case 0x80:	/* _BST changed */
526 		acpibat_getbst(sc);
527 		break;
528 	case 0x81:	/* _BIF/_BIX changed */
529 		acpibat_getbix(sc);
530 		break;
531 	default:
532 		break;
533 	}
534 
535 	acpibat_refresh(sc);
536 	acpi_record_event(sc->sc_acpi, APM_POWER_CHANGE);
537 
538 	return (0);
539 }
540