Author: hrs
Date: Wed Mar 18 18:02:33 2020
New Revision: 359076
URL: https://svnweb.freebsd.org/changeset/base/359076

Log:
  MFC of r355574, r358095, and r358395:
  
  Add ACPI battery subsystem man page.
  
  Add _BIX (Battery Information Extended) object support.
  
  ACPI Control Method Batteries have a _BIF and/or _BIX object which
  provide static properties of the battery.  FreeBSD acpi_cmbat module
  supported _BIF object only, which was deprecated as of ACPI 4.0.
  _BIX is an extended version of _BIF defined in ACPI 4.0 or later.
  
  As of writing, _BIX has two revisions.  One is in ACPI 4.0 (rev.0) and
  another is in ACPI 6.0 (rev.1).  It seems that hardware vendors still
  stick to _BIF only or _BIX rev.0 + _BIF for the maximum compatibility.
  Microsoft requires _BIX rev.0 for Windows machines, so there are some
  laptop machines with _BIX rev.0 only. In this case, FreeBSD does not
  recognize the battery information.
  
  After this change, the acpi_cmbat module gets battery information from
  _BIX or _BIF object and internally uses _BIX rev.1 data structure as
  the primary information store in the kernel.  ACPIIO_BATT_GET_BI[FX]
  returns an acpi_bi[fx] structure built by using information obtained
  from a _BIF or a _BIX object found on the system.  The revision number
  field can be used to check which field is available.  The acpiconf(8)
  utility will show additional information if _BIX is available.
  
  Although ABIs of ACPIIO_BATT_* were changed, the existing APIs for
  userland utilities are not changed and the backward-compatible ABIs
  are provided.  This means that older versions of acpiconf(8) can also
  work with the new kernel. The (union acpi_battery_ioctl_arg) was
  padded to 256 byte long to avoid another ABI change in the future.
  A _BIX object with its revision number >1 will be treated as
  compatible with the rev.1 _BIX format.
  
  Add workaround for models which do not follow the ACPI specification strictly.
  Extra objects are now simply ignored instead of rejecting everything.
  
  Differential Revision:        https://reviews.freebsd.org/D22556
  Differential Revision:        https://reviews.freebsd.org/D23728

Added:
  stable/11/share/man/man4/acpi_battery.4
     - copied, changed from r355574, head/share/man/man4/acpi_battery.4
Modified:
  stable/11/share/man/man4/Makefile
  stable/11/sys/dev/acpica/acpi_battery.c
  stable/11/sys/dev/acpica/acpi_cmbat.c
  stable/11/sys/dev/acpica/acpi_if.m
  stable/11/sys/dev/acpica/acpi_package.c
  stable/11/sys/dev/acpica/acpi_smbat.c
  stable/11/sys/dev/acpica/acpiio.h
  stable/11/sys/dev/acpica/acpivar.h
  stable/11/usr.sbin/acpi/acpiconf/acpiconf.c
Directory Properties:
  stable/11/   (props changed)

Changes in other areas also in this revision:
Added:
  stable/12/share/man/man4/acpi_battery.4
     - copied, changed from r355574, head/share/man/man4/acpi_battery.4
Modified:
  stable/12/share/man/man4/Makefile
  stable/12/sys/dev/acpica/acpi_battery.c
  stable/12/sys/dev/acpica/acpi_cmbat.c
  stable/12/sys/dev/acpica/acpi_if.m
  stable/12/sys/dev/acpica/acpi_package.c
  stable/12/sys/dev/acpica/acpi_smbat.c
  stable/12/sys/dev/acpica/acpiio.h
  stable/12/sys/dev/acpica/acpivar.h
  stable/12/usr.sbin/acpi/acpiconf/acpiconf.c
Directory Properties:
  stable/12/   (props changed)

Modified: stable/11/share/man/man4/Makefile
==============================================================================
--- stable/11/share/man/man4/Makefile   Wed Mar 18 17:42:18 2020        
(r359075)
+++ stable/11/share/man/man4/Makefile   Wed Mar 18 18:02:33 2020        
(r359076)
@@ -18,6 +18,7 @@ MAN=  aac.4 \
        ${_acpi_rapidstart.4} \
        ${_acpi_sony.4} \
        acpi_thermal.4 \
+       acpi_battery.4 \
        ${_acpi_toshiba.4} \
        acpi_video.4 \
        ${_acpi_wmi.4} \

Copied and modified: stable/11/share/man/man4/acpi_battery.4 (from r355574, 
head/share/man/man4/acpi_battery.4)
==============================================================================
--- head/share/man/man4/acpi_battery.4  Tue Dec 10 02:19:07 2019        
(r355574, copy source)
+++ stable/11/share/man/man4/acpi_battery.4     Wed Mar 18 18:02:33 2020        
(r359076)
@@ -25,7 +25,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd November 26, 2019
+.Dd February 16, 2020
 .Dt ACPI_BATTERY 4
 .Os
 .Sh NAME
@@ -37,6 +37,7 @@
 The
 .Nm
 is a driver for battery management features of the ACPI module.
+.Pp
 An ACPI-compatible battery device supports either a Control
 Method Battery interface or a Smart Battery subsystem interface.
 The former is accessed by the AML
@@ -45,7 +46,8 @@ code control methods,
 and the latter is controlled directly through the ACPI EC
 .Pq Embedded Controller
 typically via an SMBus interface.
-This driver supports the 
+.Pp
+This driver supports the
 .Xr sysctl 8
 and
 .Xr ioctl 2
@@ -59,60 +61,86 @@ driver takes a single integer value for the battery un
 number as an argument,
 and returns a specific structure for each request.
 A special unit number
-.Li ACPI_BATTERY_ALL_UNITS
+.Dv ACPI_BATTERY_ALL_UNITS
 specifies all of the attached units
 and reports accumulated information.
 .Bl -tag -width indent
-.It ACPIIO_BATT_GET_UNITS Vt int
+.It Dv ACPIIO_BATT_GET_UNITS Vt int
 Returns the number of battery units in the system.
 The unit number argument will be ignored.
-.It ACPIIO_BATT_GET_BATTINFO Vt struct acpi_battinfo
+.It Dv ACPIIO_BATT_GET_BATTINFO Vt struct acpi_battinfo
 Returns the following:
 .Bl -tag -width indent
-.It cap
+.It Va cap
 Battery capacity in percent,
-.It min
+.It Va min
 Remaining battery life in minutes,
-.It state
+.It Va state
 Current status of the battery encoded in the following:
 .Bl -tag -width indent
-.It ACPI_BATT_STAT_DISCHARG Pq 0x0001
+.It Dv ACPI_BATT_STAT_DISCHARG Pq 0x0001
 Battery is discharging,
-.It ACPI_BATT_STAT_CHARGING Pq 0x0002
+.It Dv ACPI_BATT_STAT_CHARGING Pq 0x0002
 Battery is being charged, or
-.It ACPI_BATT_STAT_CRITICAL Pq 0x0004
+.It Dv ACPI_BATT_STAT_CRITICAL Pq 0x0004
 Remaining battery life is critically low.
 .El
 .Pp
 Note that the status bits of each battery will be
 consolidated when
-.Li ACPI_BATTERY_ALL_UNITS
+.Dv ACPI_BATTERY_ALL_UNITS
 is specified.
-.It rate
+.It Va rate
 Current battery discharging rate in mW.
 .Li -1
 means not discharging right now.
 .El
-.It ACPIIO_BATT_GET_BIF Vt struct acpi_bif
+.It Dv ACPIIO_BATT_GET_BIX Vt struct acpi_bix
 Returns battery information given by the ACPI
-.Li _BIF Pq Battery Information
+.Li _BIX Pq Battery Information
 object,
 which is the static portion of the Control Method
 Battery information.
-In the case of a Smart Battery attached to SMBus,
+In the case of a Smart Battery attached to
+SMBus or a Control Method Battery with a
+.Li _BIF
+object,
 this ioctl will build a
-.Vt struct acpi_bif
+.Vt struct acpi_bix
 structure based on the obtained information
 and return it.
 .Bl -tag -width indent
-.It units
+.It Va rev
+Revision number of the object.
+There are the following well-known values:
+.Bl -tag -width indent
+.It Dv ACPI_BIX_REV_0 Pq 0x0000
+A
+.Li _BIX
+object in ACPI 4.0.
+.It Dv ACPI_BIX_REV_1 Pq 0x0001
+A
+.Li _BIX
+object in ACPI 6.0.
+.It Dv ACPI_BIX_REV_BIF Pq 0xffff
+A
+.Li _BIX
+object built from the
+.Li _BIF
+object found on the system.
+.El
+.Pp
+Note that this field should be checked by using
+.Fn ACPI_BIX_REV_MIN_CHECK var rev
+macro when checking the minimum revision number.
+.It Va units
 Indicates the units used by the battery to report its
 capacity and charge rate encoded in the following:
 .Bl -tag -width indent
-.It ACPI_BIF_UNITS_MW Pq 0x00000000
+.It ACPI_BIX_UNITS_MW Pq 0x00000000
 in mW
 .Pq power
-.It ACPI_BIF_UNITS_MA Pq 0x00000001
+.It ACPI_BIX_UNITS_MA Pq 0x00000001
 in mA
 .Pq current
 .El
@@ -120,31 +148,69 @@ in mA
 Note that capacity is expressed in mWh or mAh,
 and rate is expressed in mW or mA,
 respectively.
-.It dcap
+.It Va dcap
 The Battery's design capacity,
 which is the nominal capacity of a new battery.
 This is expressed as power or current depending on
 the value of
 .Va units .
-.It lfcap
+.It Va lfcap
 Predicted battery capacity when fully charged.
 Typically this will decrease every charging cycle.
 .It btech
 Battery technology:
 .Bl -tag -width indent
 .It 0x00000000 Primary cell Pq non-rechargable
-.It 0x00000001 Secondery cell Pq rechargable
+.It 0x00000001 Secondary cell Pq rechargable
 .El
-.It dvol
+.It Va dvol
 Design voltage in mV,
 which is the nominal voltage of a new battery.
-.It wcap
+.It Va wcap
 Design capacity of warning.
 When a discharging battery device reaches this capacity,
 notification is sent to the system.
-.It lcap
+.It Va lcap
 Design capacity of low.
-.It gra1
+.It Va cycles
+.Pq rev 0 or newer
+The number of cycles the battery has experienced.
+A cycle means an amount of discharge occurred which was
+approximately equal to the value of Design Capacity.
+.It Va accuracy
+.Pq rev 0 or newer
+The accuracy of the battery capacity measurement,
+in thousandth of a percent.
+.It Va stmax
+.Pq rev 0 or newer
+The Maximum Sampling Time of the battery in
+milliseconds.
+This is the maximum duration between two consecutive
+measurements of the battery's capacities specified in
+.Li _BST .
+If two succeeding readings of
+.Li _BST
+beyond this duration occur,
+two different results can be returned.
+.It Va stmin
+.Pq rev 0 or newer
+The Minimum Sampling Time of the battery in
+milliseconds.
+.It Va aimax
+.Pq rev 0 or newer
+The Maximum Average Interval of the battery in
+milliseconds.
+This is the length of time within which the battery
+averages the capacity measurements specified in
+.Li _BST .
+The Sampling Time specifies the frequency of measurements,
+and the Average Interval specifies the width of the time
+window of every measurement.
+.It Va aimin
+.Pq rev 0 or newer
+The Minimum Average Interval of the battery in
+milliseconds.
+.It Va gra1
 Battery capacity granularity between
 .Va low
 and
@@ -152,7 +218,7 @@ and
 This is expressed as power or current depending on
 the value of
 .Va units .
-.It gra2
+.It Va gra2
 Battery capacity granularity between
 .Va warning
 and
@@ -160,15 +226,41 @@ and
 This is expressed as power or current depending on
 the value of
 .Va units .
-.It model
+.It Va model
 Model number of the battery as a string.
-.It serial
+.It Va serial
 Serial number of the battery as a string.
-.It type
+.It Va type
 Type identifier of the battery as a string.
-.It oeminfo
+.It Va oeminfo
 OEM-specific information of the battery as a string.
+.It Va scap
+.Pq rev 1 or newer
+Battery swapping capability encoded in the following:
+.Bl -tag -width indent
+.It ACPI_BIX_SCAP_NO Pq 0x00000000
+Non-swappable
+.It ACPI_BIX_SCAP_COLD Pq 0x00000001
+Cold-swappable
+.It ACPI_BIX_SCAP_HOT Pq 0x00000010
+Hot-swappable
 .El
+.El
+.It Dv ACPIIO_BATT_GET_BIF Vt struct acpi_bif
+.Pq deprecated
+Returns battery information given by the ACPI
+.Li _BIF Pq Battery Information
+object,
+which was deprecated in ACPI 4.0 specification.
+The data structure is a subset of
+.Vt struct acpi_bix .
+.Pp
+Note that this ioctl will built a
+.Vt struct acpi_bif
+structure based on the obtained information
+even if this object is not available and a
+.Li _BIX
+object is found.
 .It ACPIIO_BATT_GET_BST Vt struct acpi_bst
 Returns battery information given by the ACPI
 .Li _BST Pq Battery Status
@@ -180,25 +272,25 @@ this ioctl will build a
 structure based on the obtained information
 and return it.
 .Bl -tag -width indent
-.It state
+.It Va state
 Battery state.
 The value is encoded in the same way as
 .Va state
 of
 .Vt struct acpi_battinfo .
-.It rate
+.It Va rate
 Battery present rate of charging or discharging.
 The unit of the value depends on
 .Va unit
 of
 .Vt struct acpi_bif .
-.It cap
+.It Va cap
 Battery remaining capacity.
 The unit of this value depends on
 .Va unit
 of
 .Vt struct acpi_bif .
-.It volt
+.It Va volt
 Battery present voltage.
 .El
 .El
@@ -212,6 +304,8 @@ connected batteries:
 .It Va hw.acpi.battery.info_expire
 Information cache expiration time in seconds.
 The battery information obtained by
+.Li _BIX
+or
 .Li _BIF
 object will be stored and reused for successive
 read access to this MIB within the specified period.
@@ -276,8 +370,11 @@ Battery information was changed.
 .An Munehiro Matsuda ,
 .An Takanori Watanabe Aq Mt takaw...@freebsd.org ,
 .An Mitsuru IWASAKI Aq Mt iwas...@freebsd.org ,
+.An Hans Petter Selasky Aq Mt hsela...@freebsd.org ,
 and
-.An Hans Petter Selasky Aq Mt hsela...@freebsd.org .
+.An Hiroki Sato Aq Mt h...@freebsd.org .
 .Pp
 This manual page was written by
-.An Takanori Watanabe Aq Mt takaw...@freebsd.org .
+.An Takanori Watanabe Aq Mt takaw...@freebsd.org
+and
+.An Hiroki Sato Aq Mt h...@freebsd.org .

Modified: stable/11/sys/dev/acpica/acpi_battery.c
==============================================================================
--- stable/11/sys/dev/acpica/acpi_battery.c     Wed Mar 18 17:42:18 2020        
(r359075)
+++ stable/11/sys/dev/acpica/acpi_battery.c     Wed Mar 18 18:02:33 2020        
(r359076)
@@ -44,7 +44,7 @@ __FBSDID("$FreeBSD$");
 /* Default seconds before re-sampling the battery state. */
 #define        ACPI_BATTERY_INFO_EXPIRE        5
 
-static int     acpi_batteries_initted;
+static int     acpi_batteries_initialized;
 static int     acpi_battery_info_expire = ACPI_BATTERY_INFO_EXPIRE;
 static struct  acpi_battinfo   acpi_battery_battinfo;
 static struct  sysctl_ctx_list acpi_battery_sysctl_ctx;
@@ -65,11 +65,10 @@ acpi_battery_register(device_t dev)
 {
     int error;
 
-    error = 0;
     ACPI_SERIAL_BEGIN(battery);
-    if (!acpi_batteries_initted)
-       error = acpi_battery_init();
+    error = acpi_battery_init();
     ACPI_SERIAL_END(battery);
+
     return (error);
 }
 
@@ -107,11 +106,12 @@ acpi_battery_bst_valid(struct acpi_bst *bst)
        bst->cap != ACPI_BATT_UNKNOWN && bst->volt != ACPI_BATT_UNKNOWN);
 }
 
-/* Check _BIF results for validity. */
+/* Check _BI[FX] results for validity. */
 int
-acpi_battery_bif_valid(struct acpi_bif *bif)
+acpi_battery_bix_valid(struct acpi_bix *bix)
 {
-    return (bif->lfcap != 0);
+
+    return (bix->lfcap != 0);
 }
 
 /* Get info about one or all batteries. */
@@ -123,7 +123,7 @@ acpi_battery_get_battinfo(device_t dev, struct acpi_ba
     devclass_t batt_dc;
     device_t batt_dev;
     struct acpi_bst *bst;
-    struct acpi_bif *bif;
+    struct acpi_bix *bix;
     struct acpi_battinfo *bi;
 
     /*
@@ -139,11 +139,11 @@ acpi_battery_get_battinfo(device_t dev, struct acpi_ba
 
     /*
      * Allocate storage for all _BST data, their derived battinfo data,
-     * and the current battery's _BIF data.
+     * and the current battery's _BIX (or _BIF) data.
      */
     bst = malloc(devcount * sizeof(*bst), M_TEMP, M_WAITOK | M_ZERO);
     bi = malloc(devcount * sizeof(*bi), M_TEMP, M_WAITOK | M_ZERO);
-    bif = malloc(sizeof(*bif), M_TEMP, M_WAITOK | M_ZERO);
+    bix = malloc(sizeof(*bix), M_TEMP, M_WAITOK | M_ZERO);
 
     /*
      * Pass 1:  for each battery that is present and valid, get its status,
@@ -176,12 +176,12 @@ acpi_battery_get_battinfo(device_t dev, struct acpi_ba
         */
        if (!acpi_BatteryIsPresent(batt_dev) ||
            ACPI_BATT_GET_STATUS(batt_dev, &bst[i]) != 0 ||
-           ACPI_BATT_GET_INFO(batt_dev, bif) != 0)
+           ACPI_BATT_GET_INFO(batt_dev, bix, sizeof(*bix)) != 0)
            continue;
 
        /* If a battery is not installed, we sometimes get strange values. */
        if (!acpi_battery_bst_valid(&bst[i]) ||
-           !acpi_battery_bif_valid(bif))
+           !acpi_battery_bix_valid(bix))
            continue;
 
        /*
@@ -200,18 +200,18 @@ acpi_battery_get_battinfo(device_t dev, struct acpi_ba
         * is 0 (due to some error reading the battery), skip this
         * conversion.
         */
-       if (bif->units == ACPI_BIF_UNITS_MA && bif->dvol != 0 && dev == NULL) {
-           bst[i].rate = (bst[i].rate * bif->dvol) / 1000;
-           bst[i].cap = (bst[i].cap * bif->dvol) / 1000;
-           bif->lfcap = (bif->lfcap * bif->dvol) / 1000;
+       if (bix->units == ACPI_BIX_UNITS_MA && bix->dvol != 0 && dev == NULL) {
+           bst[i].rate = (bst[i].rate * bix->dvol) / 1000;
+           bst[i].cap = (bst[i].cap * bix->dvol) / 1000;
+           bix->lfcap = (bix->lfcap * bix->dvol) / 1000;
        }
 
        /*
-        * The calculation above may set bif->lfcap to zero. This was
+        * The calculation above may set bix->lfcap to zero. This was
         * seen on a laptop with a broken battery. The result of the
         * division was rounded to zero.
         */
-       if (!acpi_battery_bif_valid(bif))
+       if (!acpi_battery_bix_valid(bix))
            continue;
 
        /*
@@ -219,16 +219,16 @@ acpi_battery_get_battinfo(device_t dev, struct acpi_ba
         * "real-capacity" when the battery is fully charged.  That breaks
         * the above arithmetic as it needs to be 100% maximum.
         */
-       if (bst[i].cap > bif->lfcap)
-           bst[i].cap = bif->lfcap;
+       if (bst[i].cap > bix->lfcap)
+           bst[i].cap = bix->lfcap;
 
        /* Calculate percent capacity remaining. */
-       bi[i].cap = (100 * bst[i].cap) / bif->lfcap;
+       bi[i].cap = (100 * bst[i].cap) / bix->lfcap;
 
        /* If this battery is not present, don't use its capacity. */
        if (bi[i].cap != -1) {
            total_cap += bst[i].cap;
-           total_lfcap += bif->lfcap;
+           total_lfcap += bix->lfcap;
        }
 
        /*
@@ -294,12 +294,9 @@ acpi_battery_get_battinfo(device_t dev, struct acpi_ba
     error = 0;
 
 out:
-    if (bi)
-       free(bi, M_TEMP);
-    if (bif)
-       free(bif, M_TEMP);
-    if (bst)
-       free(bst, M_TEMP);
+    free(bi, M_TEMP);
+    free(bix, M_TEMP);
+    free(bst, M_TEMP);
     return (error);
 }
 
@@ -368,7 +365,8 @@ acpi_battery_ioctl(u_long cmd, caddr_t addr, void *arg
     unit = 0;
     dev = NULL;
     ioctl_arg = NULL;
-    if (IOCPARM_LEN(cmd) == sizeof(*ioctl_arg)) {
+    if (IOCPARM_LEN(cmd) == sizeof(union acpi_battery_ioctl_arg) ||
+        IOCPARM_LEN(cmd) == sizeof(union acpi_battery_ioctl_arg_v1)) {
        ioctl_arg = (union acpi_battery_ioctl_arg *)addr;
        unit = ioctl_arg->unit;
        if (unit != ACPI_BATTERY_ALL_UNITS)
@@ -379,12 +377,14 @@ acpi_battery_ioctl(u_long cmd, caddr_t addr, void *arg
      * No security check required: information retrieval only.  If
      * new functions are added here, a check might be required.
      */
+    /* Unit check */
     switch (cmd) {
     case ACPIIO_BATT_GET_UNITS:
        *(int *)addr = acpi_battery_get_units();
        error = 0;
        break;
     case ACPIIO_BATT_GET_BATTINFO:
+    case ACPIIO_BATT_GET_BATTINFO_V1:
        if (dev != NULL || unit == ACPI_BATTERY_ALL_UNITS) {
            bzero(&ioctl_arg->battinfo, sizeof(ioctl_arg->battinfo));
            error = acpi_battery_get_battinfo(dev, &ioctl_arg->battinfo);
@@ -393,24 +393,19 @@ acpi_battery_ioctl(u_long cmd, caddr_t addr, void *arg
     case ACPIIO_BATT_GET_BIF:
        if (dev != NULL) {
            bzero(&ioctl_arg->bif, sizeof(ioctl_arg->bif));
-           error = ACPI_BATT_GET_INFO(dev, &ioctl_arg->bif);
-
-           /*
-            * Remove invalid characters.  Perhaps this should be done
-            * within a convenience function so all callers get the
-            * benefit.
-            */
-           acpi_battery_clean_str(ioctl_arg->bif.model,
-               sizeof(ioctl_arg->bif.model));
-           acpi_battery_clean_str(ioctl_arg->bif.serial,
-               sizeof(ioctl_arg->bif.serial));
-           acpi_battery_clean_str(ioctl_arg->bif.type,
-               sizeof(ioctl_arg->bif.type));
-           acpi_battery_clean_str(ioctl_arg->bif.oeminfo,
-               sizeof(ioctl_arg->bif.oeminfo));
+           error = ACPI_BATT_GET_INFO(dev, &ioctl_arg->bif,
+               sizeof(ioctl_arg->bif));
        }
        break;
+    case ACPIIO_BATT_GET_BIX:
+       if (dev != NULL) {
+           bzero(&ioctl_arg->bix, sizeof(ioctl_arg->bix));
+           error = ACPI_BATT_GET_INFO(dev, &ioctl_arg->bix,
+               sizeof(ioctl_arg->bix));
+       }
+       break;
     case ACPIIO_BATT_GET_BST:
+    case ACPIIO_BATT_GET_BST_V1:
        if (dev != NULL) {
            bzero(&ioctl_arg->bst, sizeof(ioctl_arg->bst));
            error = ACPI_BATT_GET_STATUS(dev, &ioctl_arg->bst);
@@ -420,6 +415,25 @@ acpi_battery_ioctl(u_long cmd, caddr_t addr, void *arg
        error = EINVAL;
     }
 
+    /* Sanitize the string members. */
+    switch (cmd) {
+    case ACPIIO_BATT_GET_BIX:
+    case ACPIIO_BATT_GET_BIF:
+           /*
+            * Remove invalid characters.  Perhaps this should be done
+            * within a convenience function so all callers get the
+            * benefit.
+            */
+           acpi_battery_clean_str(ioctl_arg->bix.model,
+               sizeof(ioctl_arg->bix.model));
+           acpi_battery_clean_str(ioctl_arg->bix.serial,
+               sizeof(ioctl_arg->bix.serial));
+           acpi_battery_clean_str(ioctl_arg->bix.type,
+               sizeof(ioctl_arg->bix.type));
+           acpi_battery_clean_str(ioctl_arg->bix.oeminfo,
+               sizeof(ioctl_arg->bix.oeminfo));
+    };
+
     return (error);
 }
 
@@ -453,27 +467,30 @@ acpi_battery_init(void)
 
     ACPI_SERIAL_ASSERT(battery);
 
+    if (acpi_batteries_initialized)
+           return(0);
+
     error = ENXIO;
     dev = devclass_get_device(devclass_find("acpi"), 0);
     if (dev == NULL)
        goto out;
     sc = device_get_softc(dev);
 
-    error = acpi_register_ioctl(ACPIIO_BATT_GET_UNITS, acpi_battery_ioctl,
-       NULL);
-    if (error != 0)
-       goto out;
-    error = acpi_register_ioctl(ACPIIO_BATT_GET_BATTINFO, acpi_battery_ioctl,
-       NULL);
-    if (error != 0)
-       goto out;
-    error = acpi_register_ioctl(ACPIIO_BATT_GET_BIF, acpi_battery_ioctl, NULL);
-    if (error != 0)
-       goto out;
-    error = acpi_register_ioctl(ACPIIO_BATT_GET_BST, acpi_battery_ioctl, NULL);
-    if (error != 0)
-       goto out;
+#define        ACPI_REGISTER_IOCTL(a, b, c) do {       \
+    error = acpi_register_ioctl(a, b, c);      \
+    if (error)                                 \
+       goto out;                               \
+    } while (0)
 
+    ACPI_REGISTER_IOCTL(ACPIIO_BATT_GET_UNITS, acpi_battery_ioctl, NULL);
+    ACPI_REGISTER_IOCTL(ACPIIO_BATT_GET_BATTINFO, acpi_battery_ioctl, NULL);
+    ACPI_REGISTER_IOCTL(ACPIIO_BATT_GET_BATTINFO_V1, acpi_battery_ioctl, NULL);
+    ACPI_REGISTER_IOCTL(ACPIIO_BATT_GET_BIF, acpi_battery_ioctl, NULL);
+    ACPI_REGISTER_IOCTL(ACPIIO_BATT_GET_BIX, acpi_battery_ioctl, NULL);
+    ACPI_REGISTER_IOCTL(ACPIIO_BATT_GET_BST, acpi_battery_ioctl, NULL);
+    ACPI_REGISTER_IOCTL(ACPIIO_BATT_GET_BST_V1, acpi_battery_ioctl, NULL);
+#undef ACPI_REGISTER_IOCTL
+
     sysctl_ctx_init(&acpi_battery_sysctl_ctx);
     acpi_battery_sysctl_tree = SYSCTL_ADD_NODE(&acpi_battery_sysctl_ctx,
        SYSCTL_CHILDREN(sc->acpi_sysctl_tree), OID_AUTO, "battery", CTLFLAG_RD,
@@ -508,14 +525,17 @@ acpi_battery_init(void)
        &acpi_battery_info_expire, 0,
        "time in seconds until info is refreshed");
 
-    acpi_batteries_initted = TRUE;
+    acpi_batteries_initialized = TRUE;
 
 out:
-    if (error != 0) {
+    if (error) {
        acpi_deregister_ioctl(ACPIIO_BATT_GET_UNITS, acpi_battery_ioctl);
        acpi_deregister_ioctl(ACPIIO_BATT_GET_BATTINFO, acpi_battery_ioctl);
+       acpi_deregister_ioctl(ACPIIO_BATT_GET_BATTINFO_V1, acpi_battery_ioctl);
        acpi_deregister_ioctl(ACPIIO_BATT_GET_BIF, acpi_battery_ioctl);
+       acpi_deregister_ioctl(ACPIIO_BATT_GET_BIX, acpi_battery_ioctl);
        acpi_deregister_ioctl(ACPIIO_BATT_GET_BST, acpi_battery_ioctl);
+       acpi_deregister_ioctl(ACPIIO_BATT_GET_BST_V1, acpi_battery_ioctl);
     }
     return (error);
 }

Modified: stable/11/sys/dev/acpica/acpi_cmbat.c
==============================================================================
--- stable/11/sys/dev/acpica/acpi_cmbat.c       Wed Mar 18 17:42:18 2020        
(r359075)
+++ stable/11/sys/dev/acpica/acpi_cmbat.c       Wed Mar 18 18:02:33 2020        
(r359076)
@@ -61,12 +61,13 @@ ACPI_MODULE_NAME("BATTERY")
 
 #define        ACPI_BATTERY_BST_CHANGE 0x80
 #define        ACPI_BATTERY_BIF_CHANGE 0x81
+#define        ACPI_BATTERY_BIX_CHANGE ACPI_BATTERY_BIF_CHANGE
 
 struct acpi_cmbat_softc {
     device_t       dev;
     int                    flags;
 
-    struct acpi_bif bif;
+    struct acpi_bix bix;
     struct acpi_bst bst;
     struct timespec bst_lastupdated;
 };
@@ -82,10 +83,10 @@ static void         acpi_cmbat_notify_handler(ACPI_HANDLE 
h, 
 static int             acpi_cmbat_info_expired(struct timespec *lastupdated);
 static void            acpi_cmbat_info_updated(struct timespec *lastupdated);
 static void            acpi_cmbat_get_bst(void *arg);
-static void            acpi_cmbat_get_bif_task(void *arg);
-static void            acpi_cmbat_get_bif(void *arg);
-static int             acpi_cmbat_bst(device_t dev, struct acpi_bst *bstp);
-static int             acpi_cmbat_bif(device_t dev, struct acpi_bif *bifp);
+static void            acpi_cmbat_get_bix_task(void *arg);
+static void            acpi_cmbat_get_bix(void *arg);
+static int             acpi_cmbat_bst(device_t, struct acpi_bst *);
+static int             acpi_cmbat_bix(device_t, void *, size_t);
 static void            acpi_cmbat_init_battery(void *arg);
 
 static device_method_t acpi_cmbat_methods[] = {
@@ -96,7 +97,7 @@ static device_method_t acpi_cmbat_methods[] = {
     DEVMETHOD(device_resume,   acpi_cmbat_resume),
 
     /* ACPI battery interface */
-    DEVMETHOD(acpi_batt_get_info, acpi_cmbat_bif),
+    DEVMETHOD(acpi_batt_get_info, acpi_cmbat_bix),
     DEVMETHOD(acpi_batt_get_status, acpi_cmbat_bst),
 
     DEVMETHOD_END
@@ -204,12 +205,12 @@ acpi_cmbat_notify_handler(ACPI_HANDLE h, UINT32 notify
        timespecclear(&sc->bst_lastupdated);
        break;
     case ACPI_NOTIFY_BUS_CHECK:
-    case ACPI_BATTERY_BIF_CHANGE:
+    case ACPI_BATTERY_BIX_CHANGE:
        /*
         * Queue a callback to get the current battery info from thread
         * context.  It's not safe to block in a notify handler.
         */
-       AcpiOsExecute(OSL_NOTIFY_HANDLER, acpi_cmbat_get_bif_task, dev);
+       AcpiOsExecute(OSL_NOTIFY_HANDLER, acpi_cmbat_get_bix_task, dev);
        break;
     }
 
@@ -268,15 +269,15 @@ acpi_cmbat_get_bst(void *arg)
     as = AcpiEvaluateObject(h, "_BST", NULL, &bst_buffer);
     if (ACPI_FAILURE(as)) {
        ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
-                   "error fetching current battery status -- %s\n",
-                   AcpiFormatException(as));
+           "error fetching current battery status -- %s\n",
+           AcpiFormatException(as));
        goto end;
     }
 
     res = (ACPI_OBJECT *)bst_buffer.Pointer;
     if (!ACPI_PKG_VALID(res, 4)) {
        ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
-                   "battery status corrupted\n");
+           "battery status corrupted\n");
        goto end;
     }
 
@@ -306,119 +307,207 @@ acpi_cmbat_get_bst(void *arg)
        sc->flags &= ~ACPI_BATT_STAT_CRITICAL;
 
 end:
-    if (bst_buffer.Pointer != NULL)
-       AcpiOsFree(bst_buffer.Pointer);
+    AcpiOsFree(bst_buffer.Pointer);
 }
 
 /* XXX There should be a cleaner way to do this locking. */
 static void
-acpi_cmbat_get_bif_task(void *arg)
+acpi_cmbat_get_bix_task(void *arg)
 {
 
     ACPI_SERIAL_BEGIN(cmbat);
-    acpi_cmbat_get_bif(arg);
+    acpi_cmbat_get_bix(arg);
     ACPI_SERIAL_END(cmbat);
 }
 
 static void
-acpi_cmbat_get_bif(void *arg)
+acpi_cmbat_get_bix(void *arg)
 {
     struct acpi_cmbat_softc *sc;
     ACPI_STATUS        as;
     ACPI_OBJECT        *res;
     ACPI_HANDLE        h;
-    ACPI_BUFFER        bif_buffer;
+    ACPI_BUFFER        bix_buffer;
     device_t dev;
+    int i, n;
+    const struct {
+           enum { _BIX, _BIF } type;
+           char *name;
+    } bobjs[] = {
+           { _BIX, "_BIX"},
+           { _BIF, "_BIF"},
+    };
 
     ACPI_SERIAL_ASSERT(cmbat);
 
     dev = arg;
     sc = device_get_softc(dev);
     h = acpi_get_handle(dev);
-    bif_buffer.Pointer = NULL;
-    bif_buffer.Length = ACPI_ALLOCATE_BUFFER;
+    bix_buffer.Pointer = NULL;
+    bix_buffer.Length = ACPI_ALLOCATE_BUFFER;
 
-    as = AcpiEvaluateObject(h, "_BIF", NULL, &bif_buffer);
-    if (ACPI_FAILURE(as)) {
+    for (n = 0; n < sizeof(bobjs); n++) {
+       as = AcpiEvaluateObject(h, bobjs[n].name, NULL, &bix_buffer);
+       if (!ACPI_FAILURE(as)) {
+           res = (ACPI_OBJECT *)bix_buffer.Pointer;
+           break;
+       }
+       AcpiOsFree(bix_buffer.Pointer);
+        bix_buffer.Pointer = NULL;
+        bix_buffer.Length = ACPI_ALLOCATE_BUFFER;
+    }
+    /* Both _BIF and _BIX were not found. */
+    if (n == sizeof(bobjs)) {
        ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
-                   "error fetching current battery info -- %s\n",
-                   AcpiFormatException(as));
+           "error fetching current battery info -- %s\n",
+           AcpiFormatException(as));
        goto end;
     }
 
-    res = (ACPI_OBJECT *)bif_buffer.Pointer;
-    if (!ACPI_PKG_VALID(res, 13)) {
-       ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
-                   "battery info corrupted\n");
-       goto end;
+    /*
+     * ACPI _BIX and _BIF revision mismatch check:
+     *
+     * 1. _BIF has no revision field.  The number of fields must be 13.
+     *
+     * 2. _BIX has a revision field.  As of ACPI 6.3 it must be "0" or
+     *    "1".  The number of fields will be checked---20 and 21,
+     *    respectively.
+     *
+     *    If the revision number is grater than "1" and the number of
+     *    fields is grater than 21, it will be treated as compatible with
+     *    ACPI 6.0 _BIX.  If not, it will be ignored.
+     */
+    i = 0;
+    switch (bobjs[n].type) {
+    case _BIX:
+       if (acpi_PkgInt16(res, i++, &sc->bix.rev) != 0) {
+           ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
+               "_BIX revision error\n");
+           goto end;
+       }
+#define        ACPI_BIX_REV_MISMATCH_ERR(x, r) do {                    \
+       ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),     \
+           "_BIX revision mismatch (%u != %u)\n", x, r);       \
+       goto end;                                               \
+       } while (0)
+
+       if (ACPI_PKG_VALID_EQ(res, 21)) {       /* ACPI 6.0 _BIX */
+           /*
+            * Some models have rev.0 _BIX with 21 members.
+            * In that case, treat the first 20 members as rev.0 _BIX.
+            */
+           if (sc->bix.rev != ACPI_BIX_REV_0 &&
+               sc->bix.rev != ACPI_BIX_REV_1)
+               ACPI_BIX_REV_MISMATCH_ERR(sc->bix.rev, ACPI_BIX_REV_1);
+       } else if (ACPI_PKG_VALID_EQ(res, 20)) {/* ACPI 4.0 _BIX */
+           if (sc->bix.rev != ACPI_BIX_REV_0)
+               ACPI_BIX_REV_MISMATCH_ERR(sc->bix.rev, ACPI_BIX_REV_0);
+       } else if (ACPI_PKG_VALID(res, 22)) {
+           /* _BIX with 22 or more members. */
+           if (ACPI_BIX_REV_MIN_CHECK(sc->bix.rev, ACPI_BIX_REV_1 + 1)) {
+               /*
+                * Unknown revision number.
+                * Assume 21 members are compatible with 6.0 _BIX.
+                */
+               ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
+                   "Unknown _BIX revision(%u). "
+                   "Assuming compatible with revision %u.\n",
+                   sc->bix.rev, ACPI_BIX_REV_1);
+           } else {
+               /*
+                * Known revision number.  Ignore the extra members.
+                */
+               ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
+                   "Extra objects found in _BIX were ignored.\n");
+           }
+       } else {
+               /* Invalid _BIX.  Ignore it. */
+               ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
+                   "Invalid _BIX found (rev=%u, count=%u).  Ignored.\n",
+                   sc->bix.rev, res->Package.Count);
+               goto end;
+       }
+       break;
+#undef ACPI_BIX_REV_MISMATCH_ERR
+    case _BIF:
+       if (ACPI_PKG_VALID_EQ(res, 13)) /* _BIF */
+           sc->bix.rev = ACPI_BIX_REV_BIF;
+       else {
+               ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
+                   "Invalid _BIF found (count=%u).  Ignored.\n",
+                   res->Package.Count);
+               goto end;
+       }
+       break;
     }
 
-    if (acpi_PkgInt32(res, 0, &sc->bif.units) != 0)
-       goto end;
-    if (acpi_PkgInt32(res, 1, &sc->bif.dcap) != 0)
-       goto end;
-    if (acpi_PkgInt32(res, 2, &sc->bif.lfcap) != 0)
-       goto end;
-    if (acpi_PkgInt32(res, 3, &sc->bif.btech) != 0)
-       goto end;
-    if (acpi_PkgInt32(res, 4, &sc->bif.dvol) != 0)
-       goto end;
-    if (acpi_PkgInt32(res, 5, &sc->bif.wcap) != 0)
-       goto end;
-    if (acpi_PkgInt32(res, 6, &sc->bif.lcap) != 0)
-       goto end;
-    if (acpi_PkgInt32(res, 7, &sc->bif.gra1) != 0)
-       goto end;
-    if (acpi_PkgInt32(res, 8, &sc->bif.gra2) != 0)
-       goto end;
-    if (acpi_PkgStr(res,  9, sc->bif.model, ACPI_CMBAT_MAXSTRLEN) != 0)
-       goto end;
-    if (acpi_PkgStr(res, 10, sc->bif.serial, ACPI_CMBAT_MAXSTRLEN) != 0)
-       goto end;
-    if (acpi_PkgStr(res, 11, sc->bif.type, ACPI_CMBAT_MAXSTRLEN) != 0)
-       goto end;
-    if (acpi_PkgStr(res, 12, sc->bif.oeminfo, ACPI_CMBAT_MAXSTRLEN) != 0)
-       goto end;
+    ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
+       "rev = %04x\n", sc->bix.rev);
+#define        BIX_GETU32(NAME)        do {                    \
+    ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),        \
+       #NAME " = %u\n", sc->bix.NAME);                 \
+    if (acpi_PkgInt32(res, i++, &sc->bix.NAME) != 0)   \
+           goto end;                                   \
+    } while (0)
 
+    BIX_GETU32(units);
+    BIX_GETU32(dcap);
+    BIX_GETU32(lfcap);
+    BIX_GETU32(btech);
+    BIX_GETU32(dvol);
+    BIX_GETU32(wcap);
+    BIX_GETU32(lcap);
+    if (ACPI_BIX_REV_MIN_CHECK(sc->bix.rev, ACPI_BIX_REV_0)) {
+           BIX_GETU32(cycles);
+           BIX_GETU32(accuracy);
+           BIX_GETU32(stmax);
+           BIX_GETU32(stmin);
+           BIX_GETU32(aimax);
+           BIX_GETU32(aimin);
+    }
+    BIX_GETU32(gra1);
+    BIX_GETU32(gra2);
+    if (acpi_PkgStr(res, i++, sc->bix.model, ACPI_CMBAT_MAXSTRLEN) != 0)
+           goto end;
+    if (acpi_PkgStr(res, i++, sc->bix.serial, ACPI_CMBAT_MAXSTRLEN) != 0)
+           goto end;
+    if (acpi_PkgStr(res, i++, sc->bix.type, ACPI_CMBAT_MAXSTRLEN) != 0)
+           goto end;
+    if (acpi_PkgStr(res, i++, sc->bix.oeminfo, ACPI_CMBAT_MAXSTRLEN) != 0)
+           goto end;
+    if (ACPI_BIX_REV_MIN_CHECK(sc->bix.rev, ACPI_BIX_REV_1))
+           BIX_GETU32(scap);
+#undef BIX_GETU32
 end:
-    if (bif_buffer.Pointer != NULL)
-       AcpiOsFree(bif_buffer.Pointer);
+    AcpiOsFree(bix_buffer.Pointer);
 }
 
 static int
-acpi_cmbat_bif(device_t dev, struct acpi_bif *bifp)
+acpi_cmbat_bix(device_t dev, void *bix, size_t len)
 {
     struct acpi_cmbat_softc *sc;
 
+    if (len != sizeof(struct acpi_bix) &&
+       len != sizeof(struct acpi_bif))
+           return (-1);
+
     sc = device_get_softc(dev);
 
     /*
      * Just copy the data.  The only value that should change is the
      * last-full capacity, so we only update when we get a notify that says
      * the info has changed.  Many systems apparently take a long time to
-     * process a _BIF call so we avoid it if possible.
+     * process a _BI[FX] call so we avoid it if possible.
      */
     ACPI_SERIAL_BEGIN(cmbat);
-    bifp->units = sc->bif.units;
-    bifp->dcap = sc->bif.dcap;
-    bifp->lfcap = sc->bif.lfcap;
-    bifp->btech = sc->bif.btech;
-    bifp->dvol = sc->bif.dvol;
-    bifp->wcap = sc->bif.wcap;
-    bifp->lcap = sc->bif.lcap;
-    bifp->gra1 = sc->bif.gra1;
-    bifp->gra2 = sc->bif.gra2;
-    strncpy(bifp->model, sc->bif.model, sizeof(sc->bif.model));
-    strncpy(bifp->serial, sc->bif.serial, sizeof(sc->bif.serial));
-    strncpy(bifp->type, sc->bif.type, sizeof(sc->bif.type));
-    strncpy(bifp->oeminfo, sc->bif.oeminfo, sizeof(sc->bif.oeminfo));
+    memcpy(bix, &sc->bix, len);
     ACPI_SERIAL_END(cmbat);
 
     return (0);
 }
 
 static int
-acpi_cmbat_bst(device_t dev, struct acpi_bst *bstp)
+acpi_cmbat_bst(device_t dev, struct acpi_bst *bst)
 {
     struct acpi_cmbat_softc *sc;
 
@@ -427,12 +516,9 @@ acpi_cmbat_bst(device_t dev, struct acpi_bst *bstp)
     ACPI_SERIAL_BEGIN(cmbat);
     if (acpi_BatteryIsPresent(dev)) {
        acpi_cmbat_get_bst(dev);
-       bstp->state = sc->bst.state;
-       bstp->rate = sc->bst.rate;
-       bstp->cap = sc->bst.cap;
-       bstp->volt = sc->bst.volt;
+       memcpy(bst, &sc->bst, sizeof(*bst));
     } else
-       bstp->state = ACPI_BATT_STAT_NOT_PRESENT;
+       bst->state = ACPI_BATT_STAT_NOT_PRESENT;
     ACPI_SERIAL_END(cmbat);
 
     return (0);
@@ -447,7 +533,7 @@ acpi_cmbat_init_battery(void *arg)
 
     dev = (device_t)arg;
     ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
-               "battery initialization start\n");
+       "battery enitialization start\n");
 
     /*
      * Try repeatedly to get valid data from the battery.  Since the
@@ -486,11 +572,11 @@ acpi_cmbat_init_battery(void *arg)
            timespecclear(&sc->bst_lastupdated);
            acpi_cmbat_get_bst(dev);
        }
-       if (retry == 0 || !acpi_battery_bif_valid(&sc->bif))
-           acpi_cmbat_get_bif(dev);
+       if (retry == 0 || !acpi_battery_bix_valid(&sc->bix))
+           acpi_cmbat_get_bix(dev);
 
        valid = acpi_battery_bst_valid(&sc->bst) &&
-           acpi_battery_bif_valid(&sc->bif);

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to