> Date: Fri, 21 Jul 2017 23:31:28 -0500
> From: joshua stein <[email protected]>
> 
> 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.

Why not just switch to acpibat_bix and have acpibat_getbif() populate
that struct?  That would make the diff much simpler.

I had some code that did it the other way around (have
acpibat_getbix() populate the fields in struct acpibat_bif).  That
would be acceptable too and result in an even simplet diff, but you'd
lost the extra sensor that you're adding.  Don't know where I left
that diff though.  It didn't work because the battery was behind smbus
or something.

> 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