xref: /openbsd-src/sys/dev/acpi/acpibat.c (revision f2da64fbbbf1b03f09f390ab01267c93dfd77c4c)
1 /* $OpenBSD: acpibat.c,v 1.62 2015/03/14 03:38:46 jsg 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 
35 struct cfattach acpibat_ca = {
36 	sizeof(struct acpibat_softc), acpibat_match, acpibat_attach
37 };
38 
39 struct cfdriver acpibat_cd = {
40 	NULL, "acpibat", DV_DULL
41 };
42 
43 const char *acpibat_hids[] = { ACPI_DEV_CMB, 0 };
44 
45 void	acpibat_monitor(struct acpibat_softc *);
46 void	acpibat_refresh(void *);
47 int	acpibat_getbif(struct acpibat_softc *);
48 int	acpibat_getbst(struct acpibat_softc *);
49 int	acpibat_notify(struct aml_node *, int, void *);
50 
51 int
52 acpibat_match(struct device *parent, void *match, void *aux)
53 {
54 	struct acpi_attach_args	*aa = aux;
55 	struct cfdata		*cf = match;
56 
57 	/* sanity */
58 	return (acpi_matchhids(aa, acpibat_hids, cf->cf_driver->cd_name));
59 }
60 
61 void
62 acpibat_attach(struct device *parent, struct device *self, void *aux)
63 {
64 	struct acpibat_softc	*sc = (struct acpibat_softc *)self;
65 	struct acpi_attach_args	*aa = aux;
66 	int64_t			sta;
67 
68 	sc->sc_acpi = (struct acpi_softc *)parent;
69 	sc->sc_devnode = aa->aaa_node;
70 
71 	if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "_STA", 0, NULL, &sta)) {
72 		dnprintf(10, "%s: no _STA\n", DEVNAME(sc));
73 		return;
74 	}
75 
76 	if ((sta & STA_BATTERY) != 0) {
77 		sc->sc_bat_present = 1;
78 		acpibat_getbif(sc);
79 		acpibat_getbst(sc);
80 
81 		printf(": %s", sc->sc_devnode->name);
82 		if (sc->sc_bif.bif_model[0])
83 			printf(" model \"%s\"", sc->sc_bif.bif_model);
84 		if (sc->sc_bif.bif_serial[0])
85 			printf(" serial %s", sc->sc_bif.bif_serial);
86 		if (sc->sc_bif.bif_type[0])
87 			printf(" type %s", sc->sc_bif.bif_type);
88 		if (sc->sc_bif.bif_oem[0])
89 			printf(" oem \"%s\"", sc->sc_bif.bif_oem);
90 		printf("\n");
91 	} else {
92 		sc->sc_bat_present = 0;
93 		printf(": %s not present\n", sc->sc_devnode->name);
94 	}
95 
96 	/* create sensors */
97 	acpibat_monitor(sc);
98 
99 	/* populate sensors */
100 	acpibat_refresh(sc);
101 
102 	aml_register_notify(sc->sc_devnode, aa->aaa_dev,
103 	    acpibat_notify, sc, ACPIDEV_POLL);
104 }
105 
106 void
107 acpibat_monitor(struct acpibat_softc *sc)
108 {
109 	int			type;
110 
111 	/* assume _BIF and _BST have been called */
112 	strlcpy(sc->sc_sensdev.xname, DEVNAME(sc),
113 	    sizeof(sc->sc_sensdev.xname));
114 
115 	type = sc->sc_bif.bif_power_unit ? SENSOR_AMPHOUR : SENSOR_WATTHOUR;
116 
117 	strlcpy(sc->sc_sens[0].desc, "last full capacity",
118 	    sizeof(sc->sc_sens[0].desc));
119 	sc->sc_sens[0].type = type;
120 	sensor_attach(&sc->sc_sensdev, &sc->sc_sens[0]);
121 	sc->sc_sens[0].value = sc->sc_bif.bif_last_capacity * 1000;
122 
123 	strlcpy(sc->sc_sens[1].desc, "warning capacity",
124 	    sizeof(sc->sc_sens[1].desc));
125 	sc->sc_sens[1].type = type;
126 	sensor_attach(&sc->sc_sensdev, &sc->sc_sens[1]);
127 	sc->sc_sens[1].value = sc->sc_bif.bif_warning * 1000;
128 
129 	strlcpy(sc->sc_sens[2].desc, "low capacity",
130 	    sizeof(sc->sc_sens[2].desc));
131 	sc->sc_sens[2].type = type;
132 	sensor_attach(&sc->sc_sensdev, &sc->sc_sens[2]);
133 	sc->sc_sens[2].value = sc->sc_bif.bif_low * 1000;
134 
135 	strlcpy(sc->sc_sens[3].desc, "voltage", sizeof(sc->sc_sens[3].desc));
136 	sc->sc_sens[3].type = SENSOR_VOLTS_DC;
137 	sensor_attach(&sc->sc_sensdev, &sc->sc_sens[3]);
138 	sc->sc_sens[3].value = sc->sc_bif.bif_voltage * 1000;
139 
140 	strlcpy(sc->sc_sens[4].desc, "battery unknown",
141 	    sizeof(sc->sc_sens[4].desc));
142 	sc->sc_sens[4].type = SENSOR_INTEGER;
143 	sensor_attach(&sc->sc_sensdev, &sc->sc_sens[4]);
144 	sc->sc_sens[4].value = sc->sc_bst.bst_state;
145 
146 	strlcpy(sc->sc_sens[5].desc, "rate", sizeof(sc->sc_sens[5].desc));
147 	sc->sc_sens[5].type =
148 		sc->sc_bif.bif_power_unit ? SENSOR_AMPS : SENSOR_WATTS;
149 	sensor_attach(&sc->sc_sensdev, &sc->sc_sens[5]);
150 	sc->sc_sens[5].value = sc->sc_bst.bst_rate * 1000;
151 
152 	strlcpy(sc->sc_sens[6].desc, "remaining capacity",
153 	    sizeof(sc->sc_sens[6].desc));
154 	sc->sc_sens[6].type = type;
155 	sensor_attach(&sc->sc_sensdev, &sc->sc_sens[6]);
156 	sc->sc_sens[6].value = sc->sc_bst.bst_capacity * 1000;
157 
158 	strlcpy(sc->sc_sens[7].desc, "current voltage",
159 	    sizeof(sc->sc_sens[7].desc));
160 	sc->sc_sens[7].type = SENSOR_VOLTS_DC;
161 	sensor_attach(&sc->sc_sensdev, &sc->sc_sens[7]);
162 	sc->sc_sens[7].value = sc->sc_bst.bst_voltage * 1000;
163 
164 	strlcpy(sc->sc_sens[8].desc, "design capacity",
165 	    sizeof(sc->sc_sens[8].desc));
166 	sc->sc_sens[8].type = type;
167 	sensor_attach(&sc->sc_sensdev, &sc->sc_sens[8]);
168 	sc->sc_sens[8].value = sc->sc_bif.bif_capacity * 1000;
169 
170 	sensordev_install(&sc->sc_sensdev);
171 }
172 
173 void
174 acpibat_refresh(void *arg)
175 {
176 	struct acpibat_softc	*sc = arg;
177 	int			i;
178 
179 	dnprintf(30, "%s: %s: refresh\n", DEVNAME(sc),
180 	    sc->sc_devnode->name);
181 
182 	if (!sc->sc_bat_present) {
183 		for (i = 0; i < 9; i++) {
184 			sc->sc_sens[i].value = 0;
185 			sc->sc_sens[i].status = SENSOR_S_UNSPEC;
186 			sc->sc_sens[i].flags = SENSOR_FINVALID;
187 		}
188 		/* override state */
189 		strlcpy(sc->sc_sens[4].desc, "battery removed",
190 		    sizeof(sc->sc_sens[4].desc));
191 		return;
192 	}
193 
194 	/* _BIF values are static, sensor 0..3 */
195 	if (sc->sc_bif.bif_last_capacity == BIF_UNKNOWN) {
196 		sc->sc_sens[0].value = 0;
197 		sc->sc_sens[0].status = SENSOR_S_UNKNOWN;
198 		sc->sc_sens[0].flags = SENSOR_FUNKNOWN;
199 	} else {
200 		sc->sc_sens[0].value = sc->sc_bif.bif_last_capacity * 1000;
201 		sc->sc_sens[0].status = SENSOR_S_UNSPEC;
202 		sc->sc_sens[0].flags = 0;
203 	}
204 	sc->sc_sens[1].value = sc->sc_bif.bif_warning * 1000;
205 	sc->sc_sens[1].flags = 0;
206 	sc->sc_sens[2].value = sc->sc_bif.bif_low * 1000;
207 	sc->sc_sens[2].flags = 0;
208 	if (sc->sc_bif.bif_voltage == BIF_UNKNOWN) {
209 		sc->sc_sens[3].value = 0;
210 		sc->sc_sens[3].status = SENSOR_S_UNKNOWN;
211 		sc->sc_sens[3].flags = SENSOR_FUNKNOWN;
212 	} else {
213 		sc->sc_sens[3].value = sc->sc_bif.bif_voltage * 1000;
214 		sc->sc_sens[3].status = SENSOR_S_UNSPEC;
215 		sc->sc_sens[3].flags = 0;
216 	}
217 
218 	/* _BST values are dynamic, sensor 4..7 */
219 	sc->sc_sens[4].status = SENSOR_S_OK;
220 	sc->sc_sens[4].flags = 0;
221 	if (sc->sc_bif.bif_last_capacity == BIF_UNKNOWN ||
222 	    sc->sc_bst.bst_capacity == BST_UNKNOWN) {
223 		sc->sc_sens[4].status = SENSOR_S_UNKNOWN;
224 		sc->sc_sens[4].flags = SENSOR_FUNKNOWN;
225 		strlcpy(sc->sc_sens[4].desc, "battery unknown",
226 		    sizeof(sc->sc_sens[4].desc));
227 	} else if (sc->sc_bst.bst_capacity >= sc->sc_bif.bif_last_capacity)
228 		strlcpy(sc->sc_sens[4].desc, "battery full",
229 		    sizeof(sc->sc_sens[4].desc));
230 	else if (sc->sc_bst.bst_state & BST_DISCHARGE)
231 		strlcpy(sc->sc_sens[4].desc, "battery discharging",
232 		    sizeof(sc->sc_sens[4].desc));
233 	else if (sc->sc_bst.bst_state & BST_CHARGE)
234 		strlcpy(sc->sc_sens[4].desc, "battery charging",
235 		    sizeof(sc->sc_sens[4].desc));
236 	else if (sc->sc_bst.bst_state & BST_CRITICAL) {
237 		strlcpy(sc->sc_sens[4].desc, "battery critical",
238 		    sizeof(sc->sc_sens[4].desc));
239 		sc->sc_sens[4].status = SENSOR_S_CRIT;
240 	} else
241 		strlcpy(sc->sc_sens[4].desc, "battery idle",
242 		    sizeof(sc->sc_sens[4].desc));
243 	sc->sc_sens[4].value = sc->sc_bst.bst_state;
244 
245 	if (sc->sc_bst.bst_rate == BST_UNKNOWN) {
246 		sc->sc_sens[5].value = 0;
247 		sc->sc_sens[5].status = SENSOR_S_UNKNOWN;
248 		sc->sc_sens[5].flags = SENSOR_FUNKNOWN;
249 	} else {
250 		sc->sc_sens[5].value = sc->sc_bst.bst_rate * 1000;
251 		sc->sc_sens[5].status = SENSOR_S_UNSPEC;
252 		sc->sc_sens[5].flags = 0;
253 	}
254 
255 	if (sc->sc_bst.bst_capacity == BST_UNKNOWN) {
256 		sc->sc_sens[6].value = 0;
257 		sc->sc_sens[6].status = SENSOR_S_UNKNOWN;
258 		sc->sc_sens[6].flags = SENSOR_FUNKNOWN;
259 	} else {
260 		sc->sc_sens[6].value = sc->sc_bst.bst_capacity * 1000;
261 		sc->sc_sens[6].flags = 0;
262 
263 		if (sc->sc_bst.bst_capacity < sc->sc_bif.bif_low)
264 			/* XXX we should shutdown the system */
265 			sc->sc_sens[6].status = SENSOR_S_CRIT;
266 		else if (sc->sc_bst.bst_capacity < sc->sc_bif.bif_warning)
267 			sc->sc_sens[6].status = SENSOR_S_WARN;
268 		else
269 			sc->sc_sens[6].status = SENSOR_S_OK;
270 	}
271 
272 	if (sc->sc_bst.bst_voltage == BST_UNKNOWN) {
273 		sc->sc_sens[7].value = 0;
274 		sc->sc_sens[7].status = SENSOR_S_UNKNOWN;
275 		sc->sc_sens[7].flags = SENSOR_FUNKNOWN;
276 	} else {
277 		sc->sc_sens[7].value = sc->sc_bst.bst_voltage * 1000;
278 		sc->sc_sens[7].status = SENSOR_S_UNSPEC;
279 		sc->sc_sens[7].flags = 0;
280 	}
281 
282 	if (sc->sc_bif.bif_capacity == BIF_UNKNOWN) {
283 		sc->sc_sens[8].value = 0;
284 		sc->sc_sens[8].status = SENSOR_S_UNKNOWN;
285 		sc->sc_sens[8].flags = SENSOR_FUNKNOWN;
286 	} else {
287 		sc->sc_sens[8].value = sc->sc_bif.bif_capacity * 1000;
288 		sc->sc_sens[8].status = SENSOR_S_UNSPEC;
289 		sc->sc_sens[8].flags = 0;
290 	}
291 	acpi_record_event(sc->sc_acpi, APM_POWER_CHANGE);
292 }
293 
294 int
295 acpibat_getbif(struct acpibat_softc *sc)
296 {
297 	struct aml_value	res;
298 	int			rv = EINVAL;
299 
300 	if (!sc->sc_bat_present) {
301 		memset(&sc->sc_bif, 0, sizeof(sc->sc_bif));
302 		return (0);
303 	}
304 
305 	if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_BIF", 0, NULL, &res)) {
306 		dnprintf(10, "%s: no _BIF\n", DEVNAME(sc));
307 		goto out;
308 	}
309 
310 	if (res.length != 13) {
311 		dnprintf(10, "%s: invalid _BIF, battery info not saved\n",
312 		    DEVNAME(sc));
313 		goto out;
314 	}
315 
316 	sc->sc_bif.bif_power_unit = aml_val2int(res.v_package[0]);
317 	sc->sc_bif.bif_capacity = aml_val2int(res.v_package[1]);
318 	sc->sc_bif.bif_last_capacity = aml_val2int(res.v_package[2]);
319 	sc->sc_bif.bif_technology = aml_val2int(res.v_package[3]);
320 	sc->sc_bif.bif_voltage = aml_val2int(res.v_package[4]);
321 	sc->sc_bif.bif_warning = aml_val2int(res.v_package[5]);
322 	sc->sc_bif.bif_low = aml_val2int(res.v_package[6]);
323 	sc->sc_bif.bif_cap_granu1 = aml_val2int(res.v_package[7]);
324 	sc->sc_bif.bif_cap_granu2 = aml_val2int(res.v_package[8]);
325 
326 	strlcpy(sc->sc_bif.bif_model, aml_val_to_string(res.v_package[9]),
327 		sizeof(sc->sc_bif.bif_model));
328 	strlcpy(sc->sc_bif.bif_serial, aml_val_to_string(res.v_package[10]),
329 		sizeof(sc->sc_bif.bif_serial));
330 	strlcpy(sc->sc_bif.bif_type, aml_val_to_string(res.v_package[11]),
331 		sizeof(sc->sc_bif.bif_type));
332 	strlcpy(sc->sc_bif.bif_oem, aml_val_to_string(res.v_package[12]),
333 		sizeof(sc->sc_bif.bif_oem));
334 
335 	dnprintf(60, "power_unit: %u capacity: %u last_cap: %u tech: %u "
336 	    "volt: %u warn: %u low: %u gran1: %u gran2: %d model: %s "
337 	    "serial: %s type: %s oem: %s\n",
338 	    sc->sc_bif.bif_power_unit,
339 	    sc->sc_bif.bif_capacity,
340 	    sc->sc_bif.bif_last_capacity,
341 	    sc->sc_bif.bif_technology,
342 	    sc->sc_bif.bif_voltage,
343 	    sc->sc_bif.bif_warning,
344 	    sc->sc_bif.bif_low,
345 	    sc->sc_bif.bif_cap_granu1,
346 	    sc->sc_bif.bif_cap_granu2,
347 	    sc->sc_bif.bif_model,
348 	    sc->sc_bif.bif_serial,
349 	    sc->sc_bif.bif_type,
350 	    sc->sc_bif.bif_oem);
351 
352 	rv = 0;
353 out:
354 	aml_freevalue(&res);
355 	return (rv);
356 }
357 
358 int
359 acpibat_getbst(struct acpibat_softc *sc)
360 {
361 	struct aml_value	res;
362 	int			rv = EINVAL;
363 
364 	if (!sc->sc_bat_present) {
365 		memset(&sc->sc_bst, 0, sizeof(sc->sc_bst));
366 		return (0);
367 	}
368 
369 	if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_BST", 0, NULL, &res)) {
370 		dnprintf(10, "%s: no _BST\n", DEVNAME(sc));
371 		goto out;
372 	}
373 
374 	if (res.length != 4) {
375 		dnprintf(10, "%s: invalid _BST, battery status not saved\n",
376 		    DEVNAME(sc));
377 		goto out;
378 	}
379 
380 	sc->sc_bst.bst_state = aml_val2int(res.v_package[0]);
381 	sc->sc_bst.bst_rate = aml_val2int(res.v_package[1]);
382 	sc->sc_bst.bst_capacity = aml_val2int(res.v_package[2]);
383 	sc->sc_bst.bst_voltage = aml_val2int(res.v_package[3]);
384 
385 	dnprintf(60, "state: %u rate: %u cap: %u volt: %u ",
386 	    sc->sc_bst.bst_state,
387 	    sc->sc_bst.bst_rate,
388 	    sc->sc_bst.bst_capacity,
389 	    sc->sc_bst.bst_voltage);
390 
391 	rv = 0;
392 out:
393 	aml_freevalue(&res);
394 	return (rv);
395 }
396 
397 /*
398  * XXX it has been observed that some systems do not propagate battery
399  * insertion events up to the driver.  What seems to happen is that DSDT
400  * does receive an interrupt however the originator bit is not set.
401  * This seems to happen when one inserts a 100% full battery.  Removal
402  * of the power cord or insertion of a not 100% full battery breaks this
403  * behavior and all events will then be sent upwards.  Currently there
404  * is no known work-around for it.
405  */
406 
407 int
408 acpibat_notify(struct aml_node *node, int notify_type, void *arg)
409 {
410 	struct acpibat_softc	*sc = arg;
411 	int64_t			sta;
412 
413 	dnprintf(10, "acpibat_notify: %.2x %s\n", notify_type,
414 	    sc->sc_devnode->name);
415 
416 	/* Check if installed state of battery has changed */
417 	if (aml_evalinteger(sc->sc_acpi, node, "_STA", 0, NULL, &sta) == 0) {
418 		if (sta & STA_BATTERY)
419 			sc->sc_bat_present = 1;
420 		else
421 			sc->sc_bat_present = 0;
422 	}
423 
424 	switch (notify_type) {
425 	case 0x00:	/* Poll sensors */
426 	case 0x80:	/* _BST changed */
427 		acpibat_getbst(sc);
428 		break;
429 	case 0x81:	/* _BIF changed */
430 		acpibat_getbif(sc);
431 		break;
432 	default:
433 		break;
434 	}
435 
436 	acpibat_refresh(sc);
437 
438 	return (0);
439 }
440