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