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