svn commit: r359076 - in stable: 11/share/man/man4 11/sys/dev/acpica 11/usr.sbin/acpi/acpiconf 12/share/man/man4 12/sys/dev/acpica 12/usr.sbin/acpi/acpiconf

Hiroki Sato hrs at FreeBSD.org
Wed Mar 18 18:02:35 UTC 2020


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/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)

Changes in other areas also in this revision:
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)

Modified: stable/12/share/man/man4/Makefile
==============================================================================
--- stable/12/share/man/man4/Makefile	Wed Mar 18 17:42:18 2020	(r359075)
+++ stable/12/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/12/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/12/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 takawata at FreeBSD.org ,
 .An Mitsuru IWASAKI Aq Mt iwasaki at FreeBSD.org ,
+.An Hans Petter Selasky Aq Mt hselasky at FreeBSD.org ,
 and
-.An Hans Petter Selasky Aq Mt hselasky at FreeBSD.org .
+.An Hiroki Sato Aq Mt hrs at FreeBSD.org .
 .Pp
 This manual page was written by
-.An Takanori Watanabe Aq Mt takawata at FreeBSD.org .
+.An Takanori Watanabe Aq Mt takawata at FreeBSD.org
+and
+.An Hiroki Sato Aq Mt hrs at FreeBSD.org .

Modified: stable/12/sys/dev/acpica/acpi_battery.c
==============================================================================
--- stable/12/sys/dev/acpica/acpi_battery.c	Wed Mar 18 17:42:18 2020	(r359075)
+++ stable/12/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/12/sys/dev/acpica/acpi_cmbat.c
==============================================================================
--- stable/12/sys/dev/acpica/acpi_cmbat.c	Wed Mar 18 17:42:18 2020	(r359075)
+++ stable/12/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 ***


More information about the svn-src-all mailing list