ACPI 4.0 deprecated _BIF for battery status, so some newer machines
have _BIX instead which provides the same info plus some extra
fields.
I used some macro magic to make the diff less painful, and added a
sensor for the new cycle count exported by _BIX which can be useful
to see.
Index: dev/acpi/acpi.c
===================================================================
RCS file: /cvs/src/sys/dev/acpi/acpi.c,v
retrieving revision 1.329
diff -u -p -u -p -r1.329 acpi.c
--- dev/acpi/acpi.c 20 Jul 2017 18:34:24 -0000 1.329
+++ dev/acpi/acpi.c 22 Jul 2017 04:25:07 -0000
@@ -3093,15 +3093,19 @@ acpiioctl(dev_t dev, u_long cmd, caddr_t
minutes = 0;
rate = 0;
SLIST_FOREACH(bat, &sc->sc_bat, aba_link) {
+ u_int32_t last_capacity = (bat->aba_softc->sc_use_bix ?
+ bat->aba_softc->sc_bix.bix_last_capacity :
+ bat->aba_softc->sc_bif.bif_last_capacity);
+
if (bat->aba_softc->sc_bat_present == 0)
continue;
- if (bat->aba_softc->sc_bif.bif_last_capacity == 0)
+ if (last_capacity == 0)
continue;
bats++;
rem = (bat->aba_softc->sc_bst.bst_capacity * 100) /
- bat->aba_softc->sc_bif.bif_last_capacity;
+ last_capacity;
if (rem > 100)
rem = 100;
remaining += rem;
Index: dev/acpi/acpibat.c
===================================================================
RCS file: /cvs/src/sys/dev/acpi/acpibat.c,v
retrieving revision 1.63
diff -u -p -u -p -r1.63 acpibat.c
--- dev/acpi/acpibat.c 12 Mar 2017 21:30:44 -0000 1.63
+++ dev/acpi/acpibat.c 22 Jul 2017 04:25:07 -0000
@@ -29,6 +29,9 @@
#include <dev/acpi/amltypes.h>
#include <dev/acpi/dsdt.h>
+#define sc_bix_bif(var) (sc->sc_use_bix ? sc->sc_bix.bix_##var :
sc->sc_bif.bif_##var)
+#define BIX_BIF(var) (sc->sc_use_bix ? BIX_##var : BIF_##var)
+
int acpibat_match(struct device *, void *, void *);
void acpibat_attach(struct device *, struct device *, void *);
@@ -45,6 +48,7 @@ const char *acpibat_hids[] = { ACPI_DEV_
void acpibat_monitor(struct acpibat_softc *);
void acpibat_refresh(void *);
int acpibat_getbif(struct acpibat_softc *);
+int acpibat_getbix(struct acpibat_softc *);
int acpibat_getbst(struct acpibat_softc *);
int acpibat_notify(struct aml_node *, int, void *);
@@ -78,18 +82,25 @@ acpibat_attach(struct device *parent, st
if ((sta & STA_BATTERY) != 0) {
sc->sc_bat_present = 1;
- acpibat_getbif(sc);
- acpibat_getbst(sc);
printf(": %s", sc->sc_devnode->name);
- if (sc->sc_bif.bif_model[0])
- printf(" model \"%s\"", sc->sc_bif.bif_model);
- if (sc->sc_bif.bif_serial[0])
- printf(" serial %s", sc->sc_bif.bif_serial);
- if (sc->sc_bif.bif_type[0])
- printf(" type %s", sc->sc_bif.bif_type);
- if (sc->sc_bif.bif_oem[0])
- printf(" oem \"%s\"", sc->sc_bif.bif_oem);
+
+ if (acpibat_getbix(sc) == 0)
+ sc->sc_use_bix = 1;
+ else
+ acpibat_getbif(sc);
+
+ acpibat_getbst(sc);
+
+ if (sc_bix_bif(model)[0])
+ printf(" model \"%s\"", sc_bix_bif(model));
+ if (sc_bix_bif(serial)[0])
+ printf(" serial %s", sc_bix_bif(serial));
+ if (sc_bix_bif(type)[0])
+ printf(" type %s", sc_bix_bif(type));
+ if (sc_bix_bif(oem)[0])
+ printf(" oem \"%s\"", sc_bix_bif(oem));
+
printf("\n");
} else {
sc->sc_bat_present = 0;
@@ -111,34 +122,34 @@ acpibat_monitor(struct acpibat_softc *sc
{
int type;
- /* assume _BIF and _BST have been called */
+ /* assume _BIF/_BIX and _BST have been called */
strlcpy(sc->sc_sensdev.xname, DEVNAME(sc),
sizeof(sc->sc_sensdev.xname));
- type = sc->sc_bif.bif_power_unit ? SENSOR_AMPHOUR : SENSOR_WATTHOUR;
+ type = sc_bix_bif(power_unit) ? SENSOR_AMPHOUR : SENSOR_WATTHOUR;
strlcpy(sc->sc_sens[0].desc, "last full capacity",
sizeof(sc->sc_sens[0].desc));
sc->sc_sens[0].type = type;
sensor_attach(&sc->sc_sensdev, &sc->sc_sens[0]);
- sc->sc_sens[0].value = sc->sc_bif.bif_last_capacity * 1000;
+ sc->sc_sens[0].value = sc_bix_bif(last_capacity) * 1000;
strlcpy(sc->sc_sens[1].desc, "warning capacity",
sizeof(sc->sc_sens[1].desc));
sc->sc_sens[1].type = type;
sensor_attach(&sc->sc_sensdev, &sc->sc_sens[1]);
- sc->sc_sens[1].value = sc->sc_bif.bif_warning * 1000;
+ sc->sc_sens[1].value = sc_bix_bif(warning) * 1000;
strlcpy(sc->sc_sens[2].desc, "low capacity",
sizeof(sc->sc_sens[2].desc));
sc->sc_sens[2].type = type;
sensor_attach(&sc->sc_sensdev, &sc->sc_sens[2]);
- sc->sc_sens[2].value = sc->sc_bif.bif_low * 1000;
+ sc->sc_sens[2].value = sc_bix_bif(low) * 1000;
strlcpy(sc->sc_sens[3].desc, "voltage", sizeof(sc->sc_sens[3].desc));
sc->sc_sens[3].type = SENSOR_VOLTS_DC;
sensor_attach(&sc->sc_sensdev, &sc->sc_sens[3]);
- sc->sc_sens[3].value = sc->sc_bif.bif_voltage * 1000;
+ sc->sc_sens[3].value = sc_bix_bif(voltage) * 1000;
strlcpy(sc->sc_sens[4].desc, "battery unknown",
sizeof(sc->sc_sens[4].desc));
@@ -147,8 +158,7 @@ acpibat_monitor(struct acpibat_softc *sc
sc->sc_sens[4].value = sc->sc_bst.bst_state;
strlcpy(sc->sc_sens[5].desc, "rate", sizeof(sc->sc_sens[5].desc));
- sc->sc_sens[5].type =
- sc->sc_bif.bif_power_unit ? SENSOR_AMPS : SENSOR_WATTS;
+ sc->sc_sens[5].type = sc_bix_bif(power_unit) ? SENSOR_AMPS :
SENSOR_WATTS;
sensor_attach(&sc->sc_sensdev, &sc->sc_sens[5]);
sc->sc_sens[5].value = sc->sc_bst.bst_rate * 1000;
@@ -156,19 +166,27 @@ acpibat_monitor(struct acpibat_softc *sc
sizeof(sc->sc_sens[6].desc));
sc->sc_sens[6].type = type;
sensor_attach(&sc->sc_sensdev, &sc->sc_sens[6]);
- sc->sc_sens[6].value = sc->sc_bst.bst_capacity * 1000;
+ sc->sc_sens[6].value = sc_bix_bif(capacity) * 1000;
strlcpy(sc->sc_sens[7].desc, "current voltage",
sizeof(sc->sc_sens[7].desc));
sc->sc_sens[7].type = SENSOR_VOLTS_DC;
sensor_attach(&sc->sc_sensdev, &sc->sc_sens[7]);
- sc->sc_sens[7].value = sc->sc_bst.bst_voltage * 1000;
+ sc->sc_sens[7].value = sc_bix_bif(voltage) * 1000;
strlcpy(sc->sc_sens[8].desc, "design capacity",
sizeof(sc->sc_sens[8].desc));
sc->sc_sens[8].type = type;
sensor_attach(&sc->sc_sensdev, &sc->sc_sens[8]);
- sc->sc_sens[8].value = sc->sc_bif.bif_capacity * 1000;
+ sc->sc_sens[8].value = sc_bix_bif(capacity) * 1000;
+
+ if (sc->sc_use_bix) {
+ strlcpy(sc->sc_sens[9].desc, "discharge cycles",
+ sizeof(sc->sc_sens[9].desc));
+ sc->sc_sens[9].type = SENSOR_INTEGER;
+ sensor_attach(&sc->sc_sensdev, &sc->sc_sens[9]);
+ sc->sc_sens[9].value = sc->sc_bix.bix_cycle_count;
+ }
sensordev_install(&sc->sc_sensdev);
}
@@ -183,7 +201,7 @@ acpibat_refresh(void *arg)
sc->sc_devnode->name);
if (!sc->sc_bat_present) {
- for (i = 0; i < 9; i++) {
+ for (i = 0; i <= 9; i++) {
sc->sc_sens[i].value = 0;
sc->sc_sens[i].status = SENSOR_S_UNSPEC;
sc->sc_sens[i].flags = SENSOR_FINVALID;
@@ -194,26 +212,26 @@ acpibat_refresh(void *arg)
return;
}
- /* _BIF values are static, sensor 0..3 */
- if (sc->sc_bif.bif_last_capacity == BIF_UNKNOWN) {
+ /* _BIF/_BIX values are static, sensor 0..3 */
+ if (sc_bix_bif(last_capacity) == BIX_BIF(UNKNOWN)) {
sc->sc_sens[0].value = 0;
sc->sc_sens[0].status = SENSOR_S_UNKNOWN;
sc->sc_sens[0].flags = SENSOR_FUNKNOWN;
} else {
- sc->sc_sens[0].value = sc->sc_bif.bif_last_capacity * 1000;
+ sc->sc_sens[0].value = sc_bix_bif(last_capacity) * 1000;
sc->sc_sens[0].status = SENSOR_S_UNSPEC;
sc->sc_sens[0].flags = 0;
}
- sc->sc_sens[1].value = sc->sc_bif.bif_warning * 1000;
+ sc->sc_sens[1].value = sc_bix_bif(warning) * 1000;
sc->sc_sens[1].flags = 0;
- sc->sc_sens[2].value = sc->sc_bif.bif_low * 1000;
+ sc->sc_sens[2].value = sc_bix_bif(low) * 1000;
sc->sc_sens[2].flags = 0;
- if (sc->sc_bif.bif_voltage == BIF_UNKNOWN) {
+ if (sc_bix_bif(voltage) == BIX_BIF(UNKNOWN)) {
sc->sc_sens[3].value = 0;
sc->sc_sens[3].status = SENSOR_S_UNKNOWN;
sc->sc_sens[3].flags = SENSOR_FUNKNOWN;
} else {
- sc->sc_sens[3].value = sc->sc_bif.bif_voltage * 1000;
+ sc->sc_sens[3].value = sc_bix_bif(voltage) * 1000;
sc->sc_sens[3].status = SENSOR_S_UNSPEC;
sc->sc_sens[3].flags = 0;
}
@@ -221,13 +239,13 @@ acpibat_refresh(void *arg)
/* _BST values are dynamic, sensor 4..7 */
sc->sc_sens[4].status = SENSOR_S_OK;
sc->sc_sens[4].flags = 0;
- if (sc->sc_bif.bif_last_capacity == BIF_UNKNOWN ||
+ if (sc_bix_bif(last_capacity) == BIX_BIF(UNKNOWN) ||
sc->sc_bst.bst_capacity == BST_UNKNOWN) {
sc->sc_sens[4].status = SENSOR_S_UNKNOWN;
sc->sc_sens[4].flags = SENSOR_FUNKNOWN;
strlcpy(sc->sc_sens[4].desc, "battery unknown",
sizeof(sc->sc_sens[4].desc));
- } else if (sc->sc_bst.bst_capacity >= sc->sc_bif.bif_last_capacity)
+ } else if (sc->sc_bst.bst_capacity >= sc_bix_bif(last_capacity))
strlcpy(sc->sc_sens[4].desc, "battery full",
sizeof(sc->sc_sens[4].desc));
else if (sc->sc_bst.bst_state & BST_DISCHARGE)
@@ -263,10 +281,10 @@ acpibat_refresh(void *arg)
sc->sc_sens[6].value = sc->sc_bst.bst_capacity * 1000;
sc->sc_sens[6].flags = 0;
- if (sc->sc_bst.bst_capacity < sc->sc_bif.bif_low)
+ if (sc->sc_bst.bst_capacity < sc_bix_bif(low))
/* XXX we should shutdown the system */
sc->sc_sens[6].status = SENSOR_S_CRIT;
- else if (sc->sc_bst.bst_capacity < sc->sc_bif.bif_warning)
+ else if (sc->sc_bst.bst_capacity < sc_bix_bif(warning))
sc->sc_sens[6].status = SENSOR_S_WARN;
else
sc->sc_sens[6].status = SENSOR_S_OK;
@@ -282,15 +300,28 @@ acpibat_refresh(void *arg)
sc->sc_sens[7].flags = 0;
}
- if (sc->sc_bif.bif_capacity == BIF_UNKNOWN) {
+ if (sc_bix_bif(capacity) == BIX_BIF(UNKNOWN)) {
sc->sc_sens[8].value = 0;
sc->sc_sens[8].status = SENSOR_S_UNKNOWN;
sc->sc_sens[8].flags = SENSOR_FUNKNOWN;
} else {
- sc->sc_sens[8].value = sc->sc_bif.bif_capacity * 1000;
+ sc->sc_sens[8].value = sc_bix_bif(capacity) * 1000;
sc->sc_sens[8].status = SENSOR_S_UNSPEC;
sc->sc_sens[8].flags = 0;
}
+
+ if (sc->sc_use_bix) {
+ if (sc_bix_bif(capacity) == BIX_BIF(UNKNOWN)) {
+ sc->sc_sens[9].value = 0;
+ sc->sc_sens[9].status = SENSOR_S_UNKNOWN;
+ sc->sc_sens[9].flags = SENSOR_FUNKNOWN;
+ } else {
+ sc->sc_sens[9].value = sc->sc_bix.bix_cycle_count;
+ sc->sc_sens[9].status = SENSOR_S_UNSPEC;
+ sc->sc_sens[9].flags = 0;
+ }
+ }
+
acpi_record_event(sc->sc_acpi, APM_POWER_CHANGE);
}
@@ -359,6 +390,85 @@ out:
}
int
+acpibat_getbix(struct acpibat_softc *sc)
+{
+ struct aml_value res;
+ int rv = EINVAL;
+
+ if (!sc->sc_bat_present) {
+ memset(&sc->sc_bix, 0, sizeof(sc->sc_bix));
+ return (0);
+ }
+
+ if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_BIX", 0, NULL, &res)) {
+ dnprintf(10, "%s: no _BIX\n", DEVNAME(sc));
+ goto out;
+ }
+
+ if (res.length != 20) {
+ dnprintf(10, "%s: invalid _BIX (%d != 20)\n", DEVNAME(sc),
+ res.length);
+ goto out;
+ }
+
+ sc->sc_bix.bix_revision = aml_val2int(res.v_package[0]);
+ sc->sc_bix.bix_power_unit = aml_val2int(res.v_package[1]);
+ sc->sc_bix.bix_capacity = aml_val2int(res.v_package[2]);
+ sc->sc_bix.bix_last_capacity = aml_val2int(res.v_package[3]);
+ sc->sc_bix.bix_technology = aml_val2int(res.v_package[4]);
+ sc->sc_bix.bix_voltage = aml_val2int(res.v_package[5]);
+ sc->sc_bix.bix_warning = aml_val2int(res.v_package[6]);
+ sc->sc_bix.bix_low = aml_val2int(res.v_package[7]);
+ sc->sc_bix.bix_cycle_count = aml_val2int(res.v_package[8]);
+ sc->sc_bix.bix_accuracy = aml_val2int(res.v_package[9]);
+ sc->sc_bix.bix_max_sample = aml_val2int(res.v_package[10]);
+ sc->sc_bix.bix_min_sample = aml_val2int(res.v_package[11]);
+ sc->sc_bix.bix_max_avg = aml_val2int(res.v_package[12]);
+ sc->sc_bix.bix_min_avg = aml_val2int(res.v_package[13]);
+ sc->sc_bix.bix_cap_granu1 = aml_val2int(res.v_package[14]);
+ sc->sc_bix.bix_cap_granu2 = aml_val2int(res.v_package[15]);
+
+ strlcpy(sc->sc_bix.bix_model, aml_val_to_string(res.v_package[16]),
+ sizeof(sc->sc_bix.bix_model));
+ strlcpy(sc->sc_bix.bix_serial, aml_val_to_string(res.v_package[17]),
+ sizeof(sc->sc_bix.bix_serial));
+ strlcpy(sc->sc_bix.bix_type, aml_val_to_string(res.v_package[18]),
+ sizeof(sc->sc_bix.bix_type));
+ strlcpy(sc->sc_bix.bix_oem, aml_val_to_string(res.v_package[19]),
+ sizeof(sc->sc_bix.bix_oem));
+
+ dnprintf(60, "revision: %u power_unit: %u capacity: %u last_cap: %u "
+ "tech: %u volt: %u warn: %u low: %u cycles: %u accuracy: %u "
+ "max_sample: %u min_sample: %u max_avg: %u min_avg: %u gran1: %u "
+ "gran2: %d model: %s serial: %s type: %s oem: %s\n",
+ sc->sc_bix.bix_revision,
+ sc->sc_bix.bix_power_unit,
+ sc->sc_bix.bix_capacity,
+ sc->sc_bix.bix_last_capacity,
+ sc->sc_bix.bix_technology,
+ sc->sc_bix.bix_voltage,
+ sc->sc_bix.bix_warning,
+ sc->sc_bix.bix_low,
+ sc->sc_bix.bix_cycle_count,
+ sc->sc_bix.bix_accuracy,
+ sc->sc_bix.bix_max_sample,
+ sc->sc_bix.bix_min_sample,
+ sc->sc_bix.bix_max_avg,
+ sc->sc_bix.bix_min_avg,
+ sc->sc_bix.bix_cap_granu1,
+ sc->sc_bix.bix_cap_granu2,
+ sc->sc_bix.bix_model,
+ sc->sc_bix.bix_serial,
+ sc->sc_bix.bix_type,
+ sc->sc_bix.bix_oem);
+
+ rv = 0;
+out:
+ aml_freevalue(&res);
+ return (rv);
+}
+
+int
acpibat_getbst(struct acpibat_softc *sc)
{
struct aml_value res;
@@ -430,7 +540,10 @@ acpibat_notify(struct aml_node *node, in
acpibat_getbst(sc);
break;
case 0x81: /* _BIF changed */
- acpibat_getbif(sc);
+ if (sc->sc_use_bix)
+ acpibat_getbix(sc);
+ else
+ acpibat_getbif(sc);
break;
default:
break;
Index: dev/acpi/acpidev.h
===================================================================
RCS file: /cvs/src/sys/dev/acpi/acpidev.h,v
retrieving revision 1.40
diff -u -p -u -p -r1.40 acpidev.h
--- dev/acpi/acpidev.h 22 Feb 2017 16:39:56 -0000 1.40
+++ dev/acpi/acpidev.h 22 Jul 2017 04:25:07 -0000
@@ -72,6 +72,62 @@ struct acpibat_bif {
};
/*
+ * _BIX (Battery InFormation Extended)
+ * Arguments: none
+ * Results : package _BIX (Battery InFormation Extended)
+ * Package {
+ * // ASCIIZ is ASCII character string terminated with a 0x00.
+ * Revision //Integer
+ * Power Unit //DWORD
+ * Design Capacity //DWORD
+ * Last Full Charge Capacity //DWORD
+ * Battery Technology //DWORD
+ * Design Voltage //DWORD
+ * Design Capacity of Warning //DWORD
+ * Design Capacity of Low //DWORD
+ * Cycle Count //DWORD
+ * Measurement Accuracy //DWORD
+ * Max Sampling Time //DWORD
+ * Min Sampling Time //DWORD
+ * Max Averaging Interval //DWORD
+ * Min Averaging Interval //DWORD
+ * Battery Capacity Granularity 1 //DWORD
+ * Battery Capacity Granularity 2 //DWORD
+ * Model Number //ASCIIZ
+ * Serial Number //ASCIIZ
+ * Battery Type //ASCIIZ
+ * OEM Information //ASCIIZ
+ * }
+ */
+struct acpibat_bix {
+ u_int8_t bix_revision;
+ u_int32_t bix_power_unit;
+#define BIX_POWER_MW 0x00
+#define BIX_POWER_MA 0x01
+ u_int32_t bix_capacity;
+#define BIX_UNKNOWN 0xffffffff
+ u_int32_t bix_last_capacity;
+ u_int32_t bix_technology;
+#define BIX_TECH_PRIMARY 0x00
+#define BIX_TECH_SECONDARY 0x01
+ u_int32_t bix_voltage;
+ u_int32_t bix_warning;
+ u_int32_t bix_low;
+ u_int32_t bix_cycle_count;
+ u_int32_t bix_accuracy;
+ u_int32_t bix_max_sample;
+ u_int32_t bix_min_sample;
+ u_int32_t bix_max_avg;
+ u_int32_t bix_min_avg;
+ u_int32_t bix_cap_granu1;
+ u_int32_t bix_cap_granu2;
+ char bix_model[20];
+ char bix_serial[20];
+ char bix_type[20];
+ char bix_oem[20];
+};
+
+/*
* _OSC Definition for Control Method Battery
* Arguments: none
* Results : DWORD flags
@@ -279,10 +335,12 @@ struct acpibat_softc {
struct aml_node *sc_devnode;
struct acpibat_bif sc_bif;
+ struct acpibat_bix sc_bix;
+ int sc_use_bix;
struct acpibat_bst sc_bst;
volatile int sc_bat_present;
- struct ksensor sc_sens[9];
+ struct ksensor sc_sens[10];
struct ksensordev sc_sensdev;
};