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