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
32int	acpibat_match(struct device *, void *, void *);
33void	acpibat_attach(struct device *, struct device *, void *);
34int	acpibat_activate(struct device *, int);
35
36const struct cfattach acpibat_ca = {
37	sizeof(struct acpibat_softc),
38	acpibat_match,
39	acpibat_attach,
40	NULL,
41	acpibat_activate,
42};
43
44struct cfdriver acpibat_cd = {
45	NULL, "acpibat", DV_DULL
46};
47
48const char *acpibat_hids[] = {
49	ACPI_DEV_CMB,
50	"MSHW0146",
51	NULL
52};
53
54void	acpibat_monitor(struct acpibat_softc *);
55void	acpibat_refresh(void *);
56int	acpibat_getbix(struct acpibat_softc *);
57int	acpibat_getbst(struct acpibat_softc *);
58int	acpibat_notify(struct aml_node *, int, void *);
59
60int
61acpibat_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
73void
74acpibat_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
119int
120acpibat_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
144void
145acpibat_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
219void
220acpibat_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
351int
352acpibat_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;
453out:
454	aml_freevalue(&res);
455	return (rv);
456}
457
458int
459acpibat_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;
492out:
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
507int
508acpibat_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