Index: head/share/man/man4/acpi_battery.4 =================================================================== --- head/share/man/man4/acpi_battery.4 +++ head/share/man/man4/acpi_battery.4 @@ -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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ .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 @@ .An Munehiro Matsuda , .An Takanori Watanabe Aq Mt takawata@FreeBSD.org , .An Mitsuru IWASAKI Aq Mt iwasaki@FreeBSD.org , +.An Hans Petter Selasky Aq Mt hselasky@FreeBSD.org , and -.An Hans Petter Selasky Aq Mt hselasky@FreeBSD.org . +.An Hiroki Sato Aq Mt hrs@FreeBSD.org . .Pp This manual page was written by -.An Takanori Watanabe Aq Mt takawata@FreeBSD.org . +.An Takanori Watanabe Aq Mt takawata@FreeBSD.org +and +.An Hiroki Sato Aq Mt hrs@FreeBSD.org . Index: head/sys/dev/acpica/acpi_battery.c =================================================================== --- head/sys/dev/acpica/acpi_battery.c +++ head/sys/dev/acpica/acpi_battery.c @@ -44,7 +44,7 @@ /* 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 @@ { 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 @@ 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 @@ 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 @@ /* * 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, @@ -173,12 +173,12 @@ * Be sure we can get various info from the battery. */ if (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; /* @@ -197,18 +197,18 @@ * 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; /* @@ -216,16 +216,16 @@ * "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; } /* @@ -291,12 +291,9 @@ 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); } @@ -365,7 +362,8 @@ 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) @@ -376,12 +374,14 @@ * 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); @@ -390,24 +390,19 @@ 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); @@ -417,6 +412,25 @@ 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); } @@ -450,27 +464,30 @@ 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, @@ -505,14 +522,17 @@ &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); } Index: head/sys/dev/acpica/acpi_cmbat.c =================================================================== --- head/sys/dev/acpica/acpi_cmbat.c +++ head/sys/dev/acpica/acpi_cmbat.c @@ -61,12 +61,13 @@ #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 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 @@ 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 @@ -205,12 +206,12 @@ 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; } @@ -269,15 +270,15 @@ 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; } @@ -307,119 +308,194 @@ 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 */ + if (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) && + ACPI_BIX_REV_MIN_CHECK(sc->bix.rev, ACPI_BIX_REV_1 + 1)) { + /* + * Unknown _BIX with 22 or more members. + * 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 { + /* 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; @@ -428,12 +504,9 @@ 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); @@ -448,7 +521,7 @@ 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 @@ -487,11 +560,11 @@ 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); + acpi_battery_bix_valid(&sc->bix); ACPI_SERIAL_END(cmbat); if (valid) @@ -500,9 +573,9 @@ if (retry == ACPI_CMBAT_RETRY_MAX) { ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev), - "battery initialization failed, giving up\n"); + "battery initialization failed, giving up\n"); } else { ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev), - "battery initialization done, tried %d times\n", retry + 1); + "battery initialization done, tried %d times\n", retry + 1); } } Index: head/sys/dev/acpica/acpi_if.m =================================================================== --- head/sys/dev/acpica/acpi_if.m +++ head/sys/dev/acpica/acpi_if.m @@ -53,6 +53,7 @@ typedef ACPI_STATUS (*acpi_scan_cb_t)(ACPI_HANDLE h, device_t *dev, int level, void *arg); + struct acpi_bix; struct acpi_bif; struct acpi_bst; }; @@ -210,14 +211,16 @@ }; # -# Get battery information (_BIF format) +# Get battery information (_BIF or _BIX format) # # device_t dev: Battery device -# struct acpi_bif *bif: Pointer to storage for _BIF results +# void *bix: Pointer to storage for _BIF or _BIX results +# size_t len: length of acpi_bif or acpi_bix. # METHOD int batt_get_info { device_t dev; - struct acpi_bif *bif; + void *bix; + size_t len; }; # Index: head/sys/dev/acpica/acpi_package.c =================================================================== --- head/sys/dev/acpica/acpi_package.c +++ head/sys/dev/acpica/acpi_package.c @@ -71,6 +71,19 @@ } int +acpi_PkgInt16(ACPI_OBJECT *res, int idx, uint16_t *dst) +{ + UINT64 tmp; + int error; + + error = acpi_PkgInt(res, idx, &tmp); + if (error == 0) + *dst = (uint16_t)tmp; + + return (error); +} + +int acpi_PkgStr(ACPI_OBJECT *res, int idx, void *dst, size_t size) { ACPI_OBJECT *obj; Index: head/sys/dev/acpica/acpi_smbat.c =================================================================== --- head/sys/dev/acpica/acpi_smbat.c +++ head/sys/dev/acpica/acpi_smbat.c @@ -46,9 +46,9 @@ uint8_t sb_base_addr; device_t ec_dev; - struct acpi_bif bif; + struct acpi_bix bix; struct acpi_bst bst; - struct timespec bif_lastupdated; + struct timespec bix_lastupdated; struct timespec bst_lastupdated; }; @@ -57,7 +57,7 @@ static int acpi_smbat_shutdown(device_t dev); static int acpi_smbat_info_expired(struct timespec *lastupdated); static void acpi_smbat_info_updated(struct timespec *lastupdated); -static int acpi_smbat_get_bif(device_t dev, struct acpi_bif *bif); +static int acpi_smbat_get_bix(device_t dev, void *, size_t); static int acpi_smbat_get_bst(device_t dev, struct acpi_bst *bst); ACPI_SERIAL_DECL(smbat, "ACPI Smart Battery"); @@ -87,7 +87,7 @@ /* ACPI battery interface */ DEVMETHOD(acpi_batt_get_status, acpi_smbat_get_bst), - DEVMETHOD(acpi_batt_get_info, acpi_smbat_get_bif), + DEVMETHOD(acpi_batt_get_info, acpi_smbat_get_bix), DEVMETHOD_END }; @@ -141,7 +141,7 @@ return (ENXIO); } - timespecclear(&sc->bif_lastupdated); + timespecclear(&sc->bix_lastupdated); timespecclear(&sc->bst_lastupdated); if (acpi_battery_register(dev) != 0) { @@ -415,7 +415,7 @@ } static int -acpi_smbat_get_bif(device_t dev, struct acpi_bif *bif) +acpi_smbat_get_bix(device_t dev, void *bix, size_t len) { struct acpi_smbat_softc *sc; int error; @@ -423,70 +423,76 @@ uint16_t val; uint8_t addr; + if (len != sizeof(struct acpi_bix) && + len != sizeof(struct acpi_bif)) + return (-1); + ACPI_SERIAL_BEGIN(smbat); addr = SMBATT_ADDRESS; error = ENXIO; sc = device_get_softc(dev); - if (!acpi_smbat_info_expired(&sc->bif_lastupdated)) { + if (!acpi_smbat_info_expired(&sc->bix_lastupdated)) { error = 0; goto out; } + sc->bix.rev = ACPI_BIX_REV_BIF; + if (acpi_smbus_read_2(sc, addr, SMBATT_CMD_BATTERY_MODE, &val)) goto out; if (val & SMBATT_BM_CAPACITY_MODE) { factor = 10; - sc->bif.units = ACPI_BIF_UNITS_MW; + sc->bix.units = ACPI_BIX_UNITS_MW; } else { factor = 1; - sc->bif.units = ACPI_BIF_UNITS_MA; + sc->bix.units = ACPI_BIX_UNITS_MA; } if (acpi_smbus_read_2(sc, addr, SMBATT_CMD_DESIGN_CAPACITY, &val)) goto out; - sc->bif.dcap = val * factor; + sc->bix.dcap = val * factor; if (acpi_smbus_read_2(sc, addr, SMBATT_CMD_FULL_CHARGE_CAPACITY, &val)) goto out; - sc->bif.lfcap = val * factor; - sc->bif.btech = 1; /* secondary (rechargeable) */ + sc->bix.lfcap = val * factor; + sc->bix.btech = 1; /* secondary (rechargeable) */ if (acpi_smbus_read_2(sc, addr, SMBATT_CMD_DESIGN_VOLTAGE, &val)) goto out; - sc->bif.dvol = val; + sc->bix.dvol = val; - sc->bif.wcap = sc->bif.dcap / 10; - sc->bif.lcap = sc->bif.dcap / 10; + sc->bix.wcap = sc->bix.dcap / 10; + sc->bix.lcap = sc->bix.dcap / 10; - sc->bif.gra1 = factor; /* not supported */ - sc->bif.gra2 = factor; /* not supported */ + sc->bix.gra1 = factor; /* not supported */ + sc->bix.gra2 = factor; /* not supported */ if (acpi_smbus_read_multi_1(sc, addr, SMBATT_CMD_DEVICE_NAME, - sc->bif.model, sizeof(sc->bif.model))) + sc->bix.model, sizeof(sc->bix.model))) goto out; if (acpi_smbus_read_2(sc, addr, SMBATT_CMD_SERIAL_NUMBER, &val)) goto out; - snprintf(sc->bif.serial, sizeof(sc->bif.serial), "0x%04x", val); + snprintf(sc->bix.serial, sizeof(sc->bix.serial), "0x%04x", val); if (acpi_smbus_read_multi_1(sc, addr, SMBATT_CMD_DEVICE_CHEMISTRY, - sc->bif.type, sizeof(sc->bif.type))) + sc->bix.type, sizeof(sc->bix.type))) goto out; if (acpi_smbus_read_multi_1(sc, addr, SMBATT_CMD_MANUFACTURER_DATA, - sc->bif.oeminfo, sizeof(sc->bif.oeminfo))) + sc->bix.oeminfo, sizeof(sc->bix.oeminfo))) goto out; /* XXX check if device was replugged during read? */ - acpi_smbat_info_updated(&sc->bif_lastupdated); + acpi_smbat_info_updated(&sc->bix_lastupdated); error = 0; out: if (error == 0) - memcpy(bif, &sc->bif, sizeof(sc->bif)); + memcpy(bix, &sc->bix, len); ACPI_SERIAL_END(smbat); return (error); } Index: head/sys/dev/acpica/acpiio.h =================================================================== --- head/sys/dev/acpica/acpiio.h +++ head/sys/dev/acpica/acpiio.h @@ -48,9 +48,13 @@ int rate; /* emptying rate */ }; +/* + * Battery Information object. Note that this object is deprecated in + * ACPI 4.0 + */ #define ACPI_CMBAT_MAXSTRLEN 32 struct acpi_bif { - uint32_t units; /* Units (mW or mA). */ + uint32_t units; /* Power Unit (mW or mA). */ #define ACPI_BIF_UNITS_MW 0 /* Capacity in mWh, rate in mW. */ #define ACPI_BIF_UNITS_MA 1 /* Capacity in mAh, rate in mA. */ uint32_t dcap; /* Design Capacity */ @@ -67,6 +71,76 @@ char oeminfo[ACPI_CMBAT_MAXSTRLEN]; /* OEM information */ }; +/* + * Members in acpi_bix are reordered so that the first part is compatible + * with acpi_bif. + */ +struct acpi_bix { +/* _BIF-compatible */ + uint32_t units; /* Power Unit (mW or mA). */ +#define ACPI_BIX_UNITS_MW 0 /* Capacity in mWh, rate in mW. */ +#define ACPI_BIX_UNITS_MA 1 /* Capacity in mAh, rate in mA. */ + uint32_t dcap; /* Design Capacity */ + uint32_t lfcap; /* Last Full capacity */ + uint32_t btech; /* Battery Technology */ + uint32_t dvol; /* Design voltage (mV) */ + uint32_t wcap; /* WARN capacity */ + uint32_t lcap; /* Low capacity */ + uint32_t gra1; /* Granularity 1 (Warn to Low) */ + uint32_t gra2; /* Granularity 2 (Full to Warn) */ + char model[ACPI_CMBAT_MAXSTRLEN]; /* model identifier */ + char serial[ACPI_CMBAT_MAXSTRLEN]; /* Serial number */ + char type[ACPI_CMBAT_MAXSTRLEN]; /* Type */ + char oeminfo[ACPI_CMBAT_MAXSTRLEN]; /* OEM information */ + /* ACPI 4.0 or later */ + uint16_t rev; /* Revision */ +#define ACPI_BIX_REV_0 0 /* ACPI 4.0 _BIX */ +#define ACPI_BIX_REV_1 1 /* ACPI 6.0 _BIX */ +#define ACPI_BIX_REV_BIF 0xffff /* _BIF */ +#define ACPI_BIX_REV_MIN_CHECK(x, min) \ + (((min) == ACPI_BIX_REV_BIF) ? ((x) == ACPI_BIX_REV_BIF) : \ + (((x) == ACPI_BIX_REV_BIF) ? 0 : ((x) >= (min)))) + uint32_t cycles; /* Cycle Count */ + uint32_t accuracy; /* Measurement Accuracy */ + uint32_t stmax; /* Max Sampling Time */ + uint32_t stmin; /* Min Sampling Time */ + uint32_t aimax; /* Max Average Interval */ + uint32_t aimin; /* Min Average Interval */ + /* ACPI 6.0 or later */ + uint32_t scap; /* Battery Swapping Capability */ +#define ACPI_BIX_SCAP_NO 0x00000000 +#define ACPI_BIX_SCAP_COLD 0x00000001 +#define ACPI_BIX_SCAP_HOT 0x00000010 + uint8_t bix_reserved[58]; /* padding */ +}; + +#if 0 +/* acpi_bix in the original order just for reference */ +struct acpi_bix { + uint16_t rev; /* Revision */ + uint32_t units; /* Power Unit (mW or mA). */ + uint32_t dcap; /* Design Capacity */ + uint32_t lfcap; /* Last Full capacity */ + uint32_t btech; /* Battery Technology */ + uint32_t dvol; /* Design voltage (mV) */ + uint32_t wcap; /* Design Capacity of Warning */ + uint32_t lcap; /* Design Capacity of Low */ + uint32_t cycles; /* Cycle Count */ + uint32_t accuracy; /* Measurement Accuracy */ + uint32_t stmax; /* Max Sampling Time */ + uint32_t stmin; /* Min Sampling Time */ + uint32_t aimax; /* Max Average Interval */ + uint32_t aimin; /* Min Average Interval */ + uint32_t gra1; /* Granularity 1 (Warn to Low) */ + uint32_t gra2; /* Granularity 2 (Full to Warn) */ + char model[ACPI_CMBAT_MAXSTRLEN]; /* model identifier */ + char serial[ACPI_CMBAT_MAXSTRLEN]; /* Serial number */ + char type[ACPI_CMBAT_MAXSTRLEN]; /* Type */ + char oeminfo[ACPI_CMBAT_MAXSTRLEN]; /* OEM information */ + uint32_t scap; /* Battery Swapping Capability */ +}; +#endif + struct acpi_bst { uint32_t state; /* Battery State */ uint32_t rate; /* Present Rate */ @@ -91,23 +165,36 @@ (ACPI_BATT_STAT_INVALID | ACPI_BATT_STAT_CRITICAL) #define ACPI_BATT_STAT_NOT_PRESENT ACPI_BATT_STAT_BST_MASK +/* For backward compatibility */ +union acpi_battery_ioctl_arg_v1 { + int unit; /* Device unit or ACPI_BATTERY_ALL_UNITS. */ + + struct acpi_battinfo battinfo; + + struct acpi_bif bif; + struct acpi_bst bst; +}; union acpi_battery_ioctl_arg { int unit; /* Device unit or ACPI_BATTERY_ALL_UNITS. */ struct acpi_battinfo battinfo; + struct acpi_bix bix; struct acpi_bif bif; struct acpi_bst bst; }; #define ACPI_BATTERY_ALL_UNITS (-1) -#define ACPI_BATT_UNKNOWN 0xffffffff /* _BST or _BIF value unknown. */ +#define ACPI_BATT_UNKNOWN 0xffffffff /* _BST or _BI[FX] value unknown. */ /* Common battery ioctls */ #define ACPIIO_BATT_GET_UNITS _IOR('B', 0x01, int) #define ACPIIO_BATT_GET_BATTINFO _IOWR('B', 0x03, union acpi_battery_ioctl_arg) -#define ACPIIO_BATT_GET_BIF _IOWR('B', 0x10, union acpi_battery_ioctl_arg) +#define ACPIIO_BATT_GET_BATTINFO_V1 _IOWR('B', 0x03, union acpi_battery_ioctl_arg_v1) +#define ACPIIO_BATT_GET_BIF _IOWR('B', 0x10, union acpi_battery_ioctl_arg_v1) +#define ACPIIO_BATT_GET_BIX _IOWR('B', 0x10, union acpi_battery_ioctl_arg) #define ACPIIO_BATT_GET_BST _IOWR('B', 0x11, union acpi_battery_ioctl_arg) +#define ACPIIO_BATT_GET_BST_V1 _IOWR('B', 0x11, union acpi_battery_ioctl_arg_v1) /* Control Method battery ioctls (deprecated) */ #define ACPIIO_CMBAT_GET_BIF ACPIIO_BATT_GET_BIF Index: head/sys/dev/acpica/acpivar.h =================================================================== --- head/sys/dev/acpica/acpivar.h +++ head/sys/dev/acpica/acpivar.h @@ -479,7 +479,7 @@ int acpi_battery_get_units(void); int acpi_battery_get_info_expire(void); int acpi_battery_bst_valid(struct acpi_bst *bst); -int acpi_battery_bif_valid(struct acpi_bif *bif); +int acpi_battery_bix_valid(struct acpi_bix *bix); int acpi_battery_get_battinfo(device_t dev, struct acpi_battinfo *info); @@ -493,8 +493,12 @@ #define ACPI_PKG_VALID(pkg, size) \ ((pkg) != NULL && (pkg)->Type == ACPI_TYPE_PACKAGE && \ (pkg)->Package.Count >= (size)) +#define ACPI_PKG_VALID_EQ(pkg, size) \ + ((pkg) != NULL && (pkg)->Type == ACPI_TYPE_PACKAGE && \ + (pkg)->Package.Count == (size)) int acpi_PkgInt(ACPI_OBJECT *res, int idx, UINT64 *dst); int acpi_PkgInt32(ACPI_OBJECT *res, int idx, uint32_t *dst); +int acpi_PkgInt16(ACPI_OBJECT *res, int idx, uint16_t *dst); int acpi_PkgStr(ACPI_OBJECT *res, int idx, void *dst, size_t size); int acpi_PkgGas(device_t dev, ACPI_OBJECT *res, int idx, int *type, int *rid, struct resource **dst, u_int flags); Index: head/usr.sbin/acpi/acpiconf/acpiconf.c =================================================================== --- head/usr.sbin/acpi/acpiconf/acpiconf.c +++ head/usr.sbin/acpi/acpiconf/acpiconf.c @@ -96,34 +96,61 @@ /* Print battery design information. */ battio.unit = num; - if (ioctl(acpifd, ACPIIO_BATT_GET_BIF, &battio) == -1) + if (ioctl(acpifd, ACPIIO_BATT_GET_BIX, &battio) == -1) err(EX_IOERR, "get battery info (%d) failed", num); - amp = battio.bif.units; + amp = battio.bix.units; pwr_units = amp ? "mA" : "mW"; - if (battio.bif.dcap == UNKNOWN_CAP) + if (battio.bix.dcap == UNKNOWN_CAP) printf("Design capacity:\tunknown\n"); else - printf("Design capacity:\t%d %sh\n", battio.bif.dcap, + printf("Design capacity:\t%d %sh\n", battio.bix.dcap, pwr_units); - if (battio.bif.lfcap == UNKNOWN_CAP) + if (battio.bix.lfcap == UNKNOWN_CAP) printf("Last full capacity:\tunknown\n"); else - printf("Last full capacity:\t%d %sh\n", battio.bif.lfcap, + printf("Last full capacity:\t%d %sh\n", battio.bix.lfcap, pwr_units); - printf("Technology:\t\t%s\n", battio.bif.btech == 0 ? + printf("Technology:\t\t%s\n", battio.bix.btech == 0 ? "primary (non-rechargeable)" : "secondary (rechargeable)"); - if (battio.bif.dvol == UNKNOWN_CAP) + if (ACPI_BIX_REV_MIN_CHECK(battio.bix.rev, ACPI_BIX_REV_1)) { + printf("Battery Swappable Capability:\t"); + if (battio.bix.scap == ACPI_BIX_SCAP_NO) + printf("Non-swappable\n"); + else if (battio.bix.scap == ACPI_BIX_SCAP_COLD) + printf("cold swap\n"); + else if (battio.bix.scap == ACPI_BIX_SCAP_HOT) + printf("hot swap\n"); + else + printf("unknown\n"); + } + if (battio.bix.dvol == UNKNOWN_CAP) printf("Design voltage:\t\tunknown\n"); else - printf("Design voltage:\t\t%d mV\n", battio.bif.dvol); - printf("Capacity (warn):\t%d %sh\n", battio.bif.wcap, pwr_units); - printf("Capacity (low):\t\t%d %sh\n", battio.bif.lcap, pwr_units); - printf("Low/warn granularity:\t%d %sh\n", battio.bif.gra1, pwr_units); - printf("Warn/full granularity:\t%d %sh\n", battio.bif.gra2, pwr_units); - printf("Model number:\t\t%s\n", battio.bif.model); - printf("Serial number:\t\t%s\n", battio.bif.serial); - printf("Type:\t\t\t%s\n", battio.bif.type); - printf("OEM info:\t\t%s\n", battio.bif.oeminfo); + printf("Design voltage:\t\t%d mV\n", battio.bix.dvol); + printf("Capacity (warn):\t%d %sh\n", battio.bix.wcap, pwr_units); + printf("Capacity (low):\t\t%d %sh\n", battio.bix.lcap, pwr_units); + if (ACPI_BIX_REV_MIN_CHECK(battio.bix.rev, ACPI_BIX_REV_0)) { + if (battio.bix.cycles != ACPI_BATT_UNKNOWN) + printf("Cycle Count:\t\t%d\n", battio.bix.cycles); + printf("Mesurement Accuracy:\t%d %%\n", + battio.bix.accuracy / 1000); + if (battio.bix.stmax != ACPI_BATT_UNKNOWN) + printf("Max Sampling Time:\t%d ms\n", + battio.bix.stmax); + if (battio.bix.stmin != ACPI_BATT_UNKNOWN) + printf("Min Sampling Time:\t%d ms\n", + battio.bix.stmin); + printf("Max Average Interval:\t%d ms\n", + battio.bix.aimax); + printf("Min Average Interval:\t%d ms\n", + battio.bix.aimin); + } + printf("Low/warn granularity:\t%d %sh\n", battio.bix.gra1, pwr_units); + printf("Warn/full granularity:\t%d %sh\n", battio.bix.gra2, pwr_units); + printf("Model number:\t\t%s\n", battio.bix.model); + printf("Serial number:\t\t%s\n", battio.bix.serial); + printf("Type:\t\t\t%s\n", battio.bix.type); + printf("OEM info:\t\t%s\n", battio.bix.oeminfo); /* Fetch battery voltage information. */ volt = UNKNOWN_VOLTAGE;