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;
 };
 

Reply via email to