Bug 260214 - acpi_battery: Should provide current/max battery charge in Wh (wine expects them)
Summary: acpi_battery: Should provide current/max battery charge in Wh (wine expects t...
Status: Open
Alias: None
Product: Base System
Classification: Unclassified
Component: kern (show other bugs)
Version: 13.0-RELEASE
Hardware: Any Any
: --- Affects Some People
Assignee: freebsd-bugs (Nobody)
Keywords: needs-patch, needs-qa
Depends on:
Reported: 2021-12-04 13:23 UTC by Damjan Jovanovic
Modified: 2021-12-25 14:05 UTC (History)
3 users (show)

See Also:
koobs: maintainer-feedback? (hrs)
koobs: mfc-stable13?
koobs: mfc-stable12?


Note You need to log in before you can comment on or make changes to this bug.
Description Damjan Jovanovic 2021-12-04 13:23:37 UTC
We currently have these power level related acpi_battery sysctls:
hw.acpi.battery.rate in mW
hw.acpi.battery.time in minutes
hw.acpi.battery.life in %

While discharging, the maximum battery capacity in Wh can be calculated from those, as per below. But there is no way to determine current or maximum battery capacity when not discharging, as time == -1, and rate could be 0. Can't we have sysctls for that too? Windows and Linux and Mac provide this, and Wine expects them.

Remaining capacity
= rate (mW) * time (minutes)
= (rate/1000 (Watts or Joules/second)) * (60*time (seconds))
= rate/1000*60*time (Joules)
= rate/1000*60*time/3600 (in Wh)

Total capacity = remaining capacity / life * 100 Wh
Comment 1 Kubilay Kocak freebsd_committer freebsd_triage 2021-12-05 02:24:31 UTC
@reporter, can you include (as an attachment) all hw.acpi.battery* sysctl OID values

man acpi_battery also notes a ACPIIO_BATT_GET_BIX ioctl which can return tons of information, in particular, among others..

 dcap    The Battery's design capacity,
 lfcap   Predicted battery capacity when fully charged. 
 dvol    Design voltage in mV

I am not sure to what extent this information is made available via sysctl oid's
Comment 2 Damjan Jovanovic 2021-12-05 03:47:41 UTC
(In reply to Kubilay Kocak from comment #1)

There's only 6 sysctls in hw.acpi.battery, and they're useful to compare between a working battery on a new laptop, and a broken battery on an old laptop, while charging and discharging, so I'll post them inline:

                           Broken      Working       Working
                           battery     battery       battery
                           AC power    discharging   AC power
hw.acpi.battery.info_expire   5           5            5
hw.acpi.battery.units         1           1            1
hw.acpi.battery.state         0           1            2
hw.acpi.battery.rate          0       11959            0
hw.acpi.battery.time         -1          97           -1
hw.acpi.battery.life          0          72           44

time == -1 and rate == 0 can't be used to calculate battery capacity Wh while charging (not that they're particularly accurate even when discharging; the life% especially lacks sufficient granularity).

Yes, the ioctl is better, but /dev/acpi is owned by root:operator, and even though it's
when I successfully open it as non-root user with O_RDONLY, the ioctl() gets:
ioctl: Operation not permitted
Comment 3 georg.lastname 2021-12-24 14:08:11 UTC
Why does wine care about battery capacity when we are charging anyways?

acpi.battery is an abstraction layer. A possible new sysctl acpi.battery.capacity would therefore report the capacity of all batteries combined.
For control method batteries it should be possible to get the last full capacity of each battery, add those values, and report them to acpi.battery.

Not sure whether it's possible with smart batteries.

If it's a script, acpiconf(8) can be used.
Comment 4 georg.lastname 2021-12-24 14:16:46 UTC
(In reply to Damjan Jovanovic from comment #2)
"when I successfully open it as non-root user with O_RDONLY, the ioctl() gets:
ioctl: Operation not permitted"

This is commented in sys/dev/acpi.c (line 4000)
     * Core ioctls are not permitted for non-writable user.
     * Currently, other ioctls just fetch information.
     * Not changing system behavior.
    if ((flag & FWRITE) == 0)
	return (EPERM);


Just delete the if statement? xD
Comment 5 georg.lastname 2021-12-25 14:05:07 UTC
Or maybe we can calculate the remaining time even when charging. I'm not sure whether it would result in a bogus output. Maybe remove the second condition here:

In src/sys/dev/acpi_battery (line 238):
	 * If the queried battery has no discharge rate or is charging,
	 * report that we don't know the remaining time.
	if (valid_rate == 0 || (battinfo->state & ACPI_BATT_STAT_CHARGING))
	    battinfo->min = -1;