https://git.reactos.org/?p=reactos.git;a=commitdiff;h=a97fcf19ecd2d73def84f…
commit a97fcf19ecd2d73def84fc60d206372883599631
Author: George Bișoc <george.bisoc(a)reactos.org>
AuthorDate: Fri Jan 10 22:23:23 2025 +0100
Commit: George Bișoc <george.bisoc(a)reactos.org>
CommitDate: Sun Jan 12 20:00:14 2025 +0100
[CMBATT] Minor improvements to estimated battery time code
- Declare CMBATT_DISCHARGE_TIME and CMBATT_CAPACITY_BOGUS constructs
- Determine if the battery was already discharging and if not, update the time when it's being discharged
- Fix the condition where it checks if the battery has been discharging for quite some time
- Default the time to BATTERY_UNKNOWN_TIME if querying the estimated battery time request fails or if the battery has just started discharging not over 15 seconds
CORE-18969
CORE-19452
---
drivers/bus/acpi/cmbatt/cmbatt.c | 21 ++++++++++++++++-----
drivers/bus/acpi/cmbatt/cmbatt.h | 12 ++++++++++++
2 files changed, 28 insertions(+), 5 deletions(-)
diff --git a/drivers/bus/acpi/cmbatt/cmbatt.c b/drivers/bus/acpi/cmbatt/cmbatt.c
index 407fa149572..dd01f8b22be 100644
--- a/drivers/bus/acpi/cmbatt/cmbatt.c
+++ b/drivers/bus/acpi/cmbatt/cmbatt.c
@@ -1085,6 +1085,7 @@ CmBattGetBatteryStatus(IN PCMBATT_DEVICE_EXTENSION DeviceExtension,
{
ULONG PsrData = 0;
NTSTATUS Status;
+ BOOLEAN WasDischarging;
ULONG BstState;
ULONG PowerUnit;
ULONG DesignVoltage, PresentRate, RemainingCapacity;
@@ -1113,6 +1114,9 @@ CmBattGetBatteryStatus(IN PCMBATT_DEVICE_EXTENSION DeviceExtension,
return Status;
}
+ /* Remember if the battery was discharging at the time of querying new status */
+ WasDischarging = !!(DeviceExtension->State & BATTERY_DISCHARGING);
+
/* Clear current BST information */
DeviceExtension->State = 0;
DeviceExtension->RemainingCapacity = 0;
@@ -1135,9 +1139,9 @@ CmBattGetBatteryStatus(IN PCMBATT_DEVICE_EXTENSION DeviceExtension,
{
/* Set power state and check if it just started discharging now */
DeviceExtension->State |= BATTERY_DISCHARGING;
- if (!(DeviceExtension->State & ACPI_BATT_STAT_DISCHARG))
+ if (!WasDischarging)
{
- /* Remember the time when the state changed */
+ /* The battery is discharging now and not before, remember the time when the state changed */
DeviceExtension->InterruptTime = KeQueryInterruptTime();
}
}
@@ -1363,8 +1367,8 @@ CmBattQueryInformation(IN PCMBATT_DEVICE_EXTENSION FdoExtension,
case BatteryEstimatedTime:
- /* Check if it's been more than 2 1/2 minutes since the last change */
- if ((KeQueryInterruptTime() - 150000000) > (FdoExtension->InterruptTime))
+ /* Check if it's been more than 15 seconds since the last change */
+ if (KeQueryInterruptTime() > (FdoExtension->InterruptTime + CMBATT_DISCHARGE_TIME))
{
/* Get new battery status */
CmBattGetBatteryStatus(FdoExtension, FdoExtension->Tag);
@@ -1379,6 +1383,9 @@ CmBattQueryInformation(IN PCMBATT_DEVICE_EXTENSION FdoExtension,
/* Grab the remaining capacity */
RemainingCapacity = FdoExtension->RemainingCapacity;
+ /* Default time to unknown if we fail the request later */
+ RemainingTime = BATTERY_UNKNOWN_TIME;
+
/* See if we don't know one or the other */
if ((Rate == BATTERY_UNKNOWN_RATE) ||
(RemainingCapacity == BATTERY_UNKNOWN_CAPACITY))
@@ -1410,7 +1417,7 @@ CmBattQueryInformation(IN PCMBATT_DEVICE_EXTENSION FdoExtension,
else
{
/* We have data, but is it valid? */
- if (RemainingCapacity > 0x123456)
+ if (RemainingCapacity > CMBATT_CAPACITY_BOGUS)
{
/* The capacity seems bogus, so don't use it */
if (CmBattDebug & CMBATT_ACPI_WARNING)
@@ -1423,6 +1430,10 @@ CmBattQueryInformation(IN PCMBATT_DEVICE_EXTENSION FdoExtension,
}
}
}
+ else
+ {
+ RemainingTime = BATTERY_UNKNOWN_TIME;
+ }
/* Return the remaining time */
QueryData = &RemainingTime;
diff --git a/drivers/bus/acpi/cmbatt/cmbatt.h b/drivers/bus/acpi/cmbatt/cmbatt.h
index e6ab5f029bd..4a2ec81acd3 100644
--- a/drivers/bus/acpi/cmbatt/cmbatt.h
+++ b/drivers/bus/acpi/cmbatt/cmbatt.h
@@ -42,6 +42,18 @@
#define CMBATT_PNP_ENTRY_EXIT 0x200
#define CMBATT_ACPI_ASSERT 0x400
+//
+// Constant used to determine if the battery was discharging
+// for over 15 seconds since last time the AC adapter got unplugged.
+//
+#define CMBATT_DISCHARGE_TIME 150000000
+
+//
+// Bogus constant used to determine if the remaining battery capacity
+// overflows which is returned by the hardware.
+//
+#define CMBATT_CAPACITY_BOGUS 0x100000
+
typedef enum _CMBATT_EXTENSION_TYPE
{
CmBattAcAdapter,
https://git.reactos.org/?p=reactos.git;a=commitdiff;h=e5a6b0f8e572ee1872b98…
commit e5a6b0f8e572ee1872b987ad7d10418eac073cdf
Author: Oleg Dubinskiy <oleg.dubinskij30(a)gmail.com>
AuthorDate: Fri Jan 10 20:45:43 2025 +0100
Commit: GitHub <noreply(a)github.com>
CommitDate: Fri Jan 10 20:45:43 2025 +0100
[SHELL32] SHELL_ArgifyW(): don't use SearchPathW() for receiving a path to a file (#7605)
Get rid from bogus SearchPathW() call, which is marked as most likely not needed in the comment above (by Wine). Simply get a length of the file name and use the file name directly instead, with checking for its validity too. Similarly as it's done for other cases.
That call seems actually not needed because it is already done using SearchPathW() in another parts of the code in this file, before calling SHELL_ArgifyW().
Fixes another heap corruption when trying to login via OAuth menthod in SpotifyXP 2.0.3 Beta (nightly build). The previous commit did not fix the bug fully, as I discovered it later.
CORE-19953
---
dll/win32/shell32/shlexec.cpp | 18 +++++-------------
1 file changed, 5 insertions(+), 13 deletions(-)
diff --git a/dll/win32/shell32/shlexec.cpp b/dll/win32/shell32/shlexec.cpp
index 85c7feab0ff..f03db3de0e7 100644
--- a/dll/win32/shell32/shlexec.cpp
+++ b/dll/win32/shell32/shlexec.cpp
@@ -197,11 +197,9 @@ static void ParseTildeEffect(PWSTR &res, LPCWSTR &args, DWORD &len, DWORD &used,
static BOOL SHELL_ArgifyW(WCHAR* out, DWORD len, const WCHAR* fmt, const WCHAR* lpFile, LPITEMIDLIST pidl, LPCWSTR args, DWORD* out_len, const WCHAR* lpDir)
{
- WCHAR xlpFile[1024];
BOOL done = FALSE;
BOOL found_p1 = FALSE;
PWSTR res = out;
- PCWSTR cmd;
DWORD used = 0;
bool tildeEffect = false;
@@ -279,20 +277,14 @@ static BOOL SHELL_ArgifyW(WCHAR* out, DWORD len, const WCHAR* fmt, const WCHAR*
break;
case '1':
- if (!done || (*fmt == '1'))
+ if ((!done || (*fmt == '1')) && lpFile)
{
- /*FIXME Is the call to SearchPathW() really needed? We already have separated out the parameter string in args. */
- if (SearchPathW(lpDir, lpFile, L".exe", ARRAY_SIZE(xlpFile), xlpFile, NULL))
- cmd = xlpFile;
- else
- cmd = lpFile;
-
- SIZE_T cmdlen = wcslen(cmd);
- used += cmdlen;
+ SIZE_T filelen = wcslen(lpFile);
+ used += filelen;
if (used < len)
{
- wcscpy(res, cmd);
- res += cmdlen;
+ wcscpy(res, lpFile);
+ res += filelen;
}
}
found_p1 = TRUE;
https://git.reactos.org/?p=reactos.git;a=commitdiff;h=02032b71068c9d5808f20…
commit 02032b71068c9d5808f20dbd7401674b84cb1a2f
Author: George Bișoc <george.bisoc(a)reactos.org>
AuthorDate: Wed Jan 8 23:49:15 2025 +0100
Commit: George Bișoc <george.bisoc(a)reactos.org>
CommitDate: Wed Jan 8 23:49:15 2025 +0100
[PSDK] Fix BATTERY_UNKNOWN_TIME value constant
Windows SDKs define this constant to 0xFFFFFFFF but we define it to 0x80000000.
As a result, when our COMPBATT driver is being tested on Windows (namely XP, Vista and 7), BATTERY_UNKNOWN_TIME is not interpreted as UNKNOWN TIME but entirely something else.
CORE-18969
CORE-19452
---
sdk/include/psdk/batclass.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/sdk/include/psdk/batclass.h b/sdk/include/psdk/batclass.h
index f97140d9b05..02641a65f86 100644
--- a/sdk/include/psdk/batclass.h
+++ b/sdk/include/psdk/batclass.h
@@ -65,7 +65,7 @@ DEFINE_GUID(BATTERY_TAG_CHANGE_WMI_GUID,
#define BATTERY_UNKNOWN_CAPACITY 0xFFFFFFFF
/* BatteryEstimatedTime constant */
-#define BATTERY_UNKNOWN_TIME 0x80000000
+#define BATTERY_UNKNOWN_TIME 0xFFFFFFFF
#define MAX_BATTERY_STRING_SIZE 128
https://git.reactos.org/?p=reactos.git;a=commitdiff;h=13b394c1a7e0df384443a…
commit 13b394c1a7e0df384443a7c1caacf95ec13858a9
Author: George Bișoc <george.bisoc(a)reactos.org>
AuthorDate: Mon Dec 16 17:20:33 2024 +0100
Commit: George Bișoc <george.bisoc(a)reactos.org>
CommitDate: Wed Jan 8 23:20:09 2025 +0100
[COMPBATT] Document COMPBATT_BATTERY_DATA and COMPBATT_DEVICE_EXTENSION structures
CORE-18969
CORE-19452
CORE-19888
---
drivers/bus/acpi/compbatt/compbatt.h | 92 ++++++++++++++++++++++++++++++++++++
1 file changed, 92 insertions(+)
diff --git a/drivers/bus/acpi/compbatt/compbatt.h b/drivers/bus/acpi/compbatt/compbatt.h
index 66307defbc4..58f812c5fd7 100644
--- a/drivers/bus/acpi/compbatt/compbatt.h
+++ b/drivers/bus/acpi/compbatt/compbatt.h
@@ -78,24 +78,73 @@
//
typedef struct _COMPBATT_BATTERY_DATA
{
+ /* The linked battery with the Composite Battery */
LIST_ENTRY BatteryLink;
+
+ /* I/O remove lock which protects the battery from being removed */
IO_REMOVE_LOCK RemoveLock;
+
+ /*
+ * The associated device object (usually CMBATT) and the I/O battery packet
+ * which is used to transport and gather battery data.
+ */
PDEVICE_OBJECT DeviceObject;
PIRP Irp;
+
+ /*
+ * The Executive work item, which serves as a worker item for the
+ * IRP battery monitor worker.
+ */
WORK_QUEUE_ITEM WorkItem;
+
+ /*
+ * Execution state mode of the individual battery. Only two modes are valid:
+ *
+ * COMPBATT_QUERY_TAG - The battery is currently waiting for a tag to get assigned;
+ * COMPBATT_READ_STATUS - The battery is querying battery status.
+ */
UCHAR Mode;
+
+ /*
+ * The battery wait configuration settings, set up by the SetStatusNotify method.
+ * These values are used to instruct CMBATT when the battery status should be retrieved.
+ */
BATTERY_WAIT_STATUS WaitStatus;
+
+ /*
+ * A union that serves as the buffer which holds battery monitor IRP data, specifically
+ * managed by CompBattMonitorIrpCompleteWorker, to avoid allocating separate memory pools.
+ */
union
{
BATTERY_WAIT_STATUS WorkerWaitStatus;
BATTERY_STATUS WorkerStatus;
ULONG WorkerTag;
} WorkerBuffer;
+
+ /* The ID of the battery that associates the identification of this battery */
ULONG Tag;
+
+ /*
+ * The battery flags that govern the behavior of the battery. The valid flags are:
+ *
+ * COMPBATT_BATTERY_INFORMATION_PRESENT - The static battery information ha been
+ * queried. Re-querying such information is not needed.
+ *
+ * COMPBATT_STATUS_NOTIFY_SET - The current notification wait settings are valid.
+ *
+ * COMPBATT_TAG_ASSIGNED - The battery has a tag assigned and it can be read.
+ */
ULONG Flags;
+
+ /* The static battery information and battery status */
BATTERY_INFORMATION BatteryInformation;
BATTERY_STATUS BatteryStatus;
+
+ /* The interrupt time of which the battery status was last read */
ULONGLONG InterruptTime;
+
+ /* A uniquely given name of the battery that associates it */
UNICODE_STRING BatteryName;
} COMPBATT_BATTERY_DATA, *PCOMPBATT_BATTERY_DATA;
@@ -104,18 +153,61 @@ typedef struct _COMPBATT_BATTERY_DATA
//
typedef struct _COMPBATT_DEVICE_EXTENSION
{
+ /*
+ * The class data initialized and used by Battery Class. It contains information
+ * such as miniport data used for registration and communication between the
+ * Composite Battery and Battery Class, wait and context events, etc.
+ */
PVOID ClassData;
+
+ /*
+ * The successor computed tag. This field is used when there are more upcoming
+ * batteries to be connected with the Composite Battery, of which the tag is
+ * incremented by 1 by each new battery that is connected.
+ */
ULONG NextTag;
+
+ /* A list of linked batteries connected with the Composite Battery */
LIST_ENTRY BatteryList;
+
+ /* A mutex lock which ensures proper synchronization of Composite Battery operations */
FAST_MUTEX Lock;
+
+ /* The ID of the Composite Battery */
ULONG Tag;
+
+ /*
+ * The battery flags that govern the behavior of the battery. The valid flags are:
+ *
+ * COMPBATT_BATTERY_INFORMATION_PRESENT - The static battery information has been
+ * queried. Re-querying such information is not needed.
+ *
+ * COMPBATT_STATUS_NOTIFY_SET - The current notification wait settings are valid.
+ *
+ * COMPBATT_TAG_ASSIGNED - The battery has a tag assigned and it can be read.
+ */
ULONG Flags;
+
+ /*
+ * The Composite Battery static information, status and wait status settings.
+ * Note that both the battery information and status are combined, based upon
+ * the individual information and status of each linked battery.
+ */
BATTERY_INFORMATION BatteryInformation;
BATTERY_STATUS BatteryStatus;
BATTERY_WAIT_STATUS WaitNotifyStatus;
+
+ /* The interrupt time of which the battery status was last read */
ULONGLONG InterruptTime;
+
+ /*
+ * The physical device object that associates the Composite Battery and
+ * the attached device, typically the ACPI driver.
+ */
PDEVICE_OBJECT AttachedDevice;
PDEVICE_OBJECT DeviceObject;
+
+ /* The notification entry that identifies the registered I/O PnP notification */
PVOID NotificationEntry;
} COMPBATT_DEVICE_EXTENSION, *PCOMPBATT_DEVICE_EXTENSION;
https://git.reactos.org/?p=reactos.git;a=commitdiff;h=f58f37e944c54942eaf65…
commit f58f37e944c54942eaf65db674362ed2275ed9a5
Author: George Bișoc <george.bisoc(a)reactos.org>
AuthorDate: Mon Dec 16 00:40:54 2024 +0100
Commit: George Bișoc <george.bisoc(a)reactos.org>
CommitDate: Wed Jan 8 23:20:09 2025 +0100
[COMPBATT] Document the newly added code
---
drivers/bus/acpi/compbatt/compbatt.c | 144 +++++++++++++++++++++++++++++++++++
1 file changed, 144 insertions(+)
diff --git a/drivers/bus/acpi/compbatt/compbatt.c b/drivers/bus/acpi/compbatt/compbatt.c
index 533c32e4991..3edb3fb78a8 100644
--- a/drivers/bus/acpi/compbatt/compbatt.c
+++ b/drivers/bus/acpi/compbatt/compbatt.c
@@ -67,6 +67,26 @@ CompBattSystemControl(
return Status;
}
+/**
+ * @brief
+ * Queues a work item thread worker which is bound to the individual
+ * CM (Control Method) ACPI battery to handle the IRP.
+ *
+ * @param[in] DeviceObject
+ * A pointer to a device object, this parameter is unused.
+ *
+ * @param[in] Irp
+ * A pointer to an I/O request packet. It is used to gather the I/O stack
+ * location which contains the data of the individual battery.
+ *
+ * @param[in] Context
+ * An aribtrary pointer that points to context data, this paramater
+ * is unused.
+ *
+ * @return
+ * Returns STATUS_MORE_PROCESSING_REQUIRED to indicate the I/O request
+ * is still in action, therefore the IRP is not freed.
+ */
NTSTATUS
NTAPI
CompBattMonitorIrpComplete(
@@ -89,6 +109,17 @@ CompBattMonitorIrpComplete(
return STATUS_MORE_PROCESSING_REQUIRED;
}
+/**
+ * @brief
+ * The brains of the battery IRP worker. It monitors the state of the
+ * IRP as well as sends the IRP down the device stack to gather battery
+ * related data, such tag and status. It also serves as the I/O
+ * completion routine of which it elaborates the gathered data.
+ *
+ * @param[in] BatteryData
+ * A pointer to battery data of an individual battery that contains
+ * the IRP to be send down the device stack.
+ */
VOID
NTAPI
CompBattMonitorIrpCompleteWorker(
@@ -481,6 +512,29 @@ CompBattDisableStatusNotify(
return STATUS_SUCCESS;
}
+/**
+ * @brief
+ * Calculates the total discharging/charging rate flow of each individual
+ * battery linked with the composite battery and determines whether at
+ * least one battery is behaving improperly.
+ *
+ * @param[in] DeviceExtension
+ * A pointer to a device extension which describes the composite battery
+ * itself. It is used to gather each connected battery in the list with
+ * the composite battery.
+ *
+ * @param[out] TotalRate
+ * A pointer returned to caller that describes the total accumulated
+ * rate flow of all batteries.
+ *
+ * @param[out] BatteriesCount
+ * A pointer returned to caller that describes the batteries present.
+ *
+ * @return
+ * Returns TRUE if at least one battery is behaving improperly, FALSE
+ * otherwise. This is determined by the fact if a battery has a negative
+ * rate but is charging, or if it has a positive rate but is discharging.
+ */
static
BOOLEAN
CompBattCalculateTotalRateAndLinkedBatteries(
@@ -590,6 +644,33 @@ CompBattCalculateTotalRateAndLinkedBatteries(
return BadBattery;
}
+/**
+ * @brief
+ * Sets a new configuration battery wait status settings of each battery.
+ * The purpose of this is so that the composite battery gets notified
+ * of new battery status as if it was a single battery.
+ *
+ * @param[in] DeviceExtension
+ * A pointer to a device extension which describes the composite battery
+ * itself. It is used to gather each connected battery in the list with
+ * the composite battery.
+ *
+ * @param[in] BatteryTag
+ * A battery tag supplied by the caller. This is typically the tag of
+ * the composite battery which is used to check against the cached tag
+ * of the composite battery if it has changed or not.
+ *
+ * @param[in] BatteryNotify
+ * A pointer to a structure filled with battery notification settings,
+ * supplied by the caller. It is used as the new values for the
+ * configuration wait settings.
+ *
+ * @return
+ * Returns STATUS_NO_SUCH_DEVICE if the supplied battery tag does not match
+ * with that of the cached composite battery's tag or if the composite
+ * battery currently does not have a tag assigned. Otherwise STATUS_SUCCESS
+ * is returned.
+ */
NTSTATUS
NTAPI
CompBattSetStatusNotify(
@@ -819,6 +900,33 @@ CompBattSetStatusNotify(
return STATUS_SUCCESS;
}
+/**
+ * @brief
+ * Queries the battery status of each individiual connected battery with
+ * the composite battery and combines all the retrieved data as one
+ * single battery status for the composite battery.
+ *
+ * @param[in] DeviceExtension
+ * A pointer to a device extension which describes the composite battery
+ * itself. It is used to gather each connected battery in the list with
+ * the composite battery.
+ *
+ * @param[in] Tag
+ * A battery tag supplied by the caller. This is typically the tag of
+ * the composite battery which is used to check against the cached tag
+ * of the composite battery if it has changed or not.
+ *
+ * @param[out] BatteryStatus
+ * A pointer to a battery status that contains the combined data, returned
+ * to the caller. It serves as the battery status for the composite battery.
+ *
+ * @return
+ * Returns STATUS_NO_SUCH_DEVICE if the supplied battery tag does not match
+ * with that of the cached composite battery's tag or if the composite
+ * battery currently does not have a tag assigned. Otherwise STATUS_SUCCESS
+ * is returned, which it will also return success if the composite battery's
+ * cached battery status is fresh which indicates it has already been computed.
+ */
NTSTATUS
NTAPI
CompBattQueryStatus(
@@ -1282,6 +1390,20 @@ CompBattGetBatteryGranularity(
return STATUS_SUCCESS;
}
+/**
+ * @brief
+ * Calculates the "At Rate" flow of the composite battery based on the
+ * sum of all connected batteries, in order to retrieve the precise
+ * battery time estimation.
+ *
+ * @param[in] DeviceExtension
+ * A pointer to a device extension which describes the composite battery
+ * itself. It is used to gather each connected battery in the list with
+ * the composite battery.
+ *
+ * @return
+ * Returns the computed "At Rate" flow to the caller.
+ */
static
LONG
CompBattCalculateAtRateTime(
@@ -1351,6 +1473,28 @@ CompBattCalculateAtRateTime(
return ComputedAtRate;
}
+/**
+ * @brief
+ * Retrieves the estimated time of the composite battery based on the
+ * power drain rate of all the batteries present in the system.
+ *
+ * @param[out] Time
+ * A pointer to the computed estimated time of the composite battery,
+ * returned to caller. Note that if there are not any batteries that
+ * are draining power, or if the system is powered by external AC source,
+ * the estimated time is unknown
+ *
+ * @param[in] DeviceExtension
+ * A pointer to a device extension which describes the composite battery
+ * itself. It is used to gather each connected battery in the list with
+ * the composite battery.
+ *
+ * @return
+ * Returns STATUS_NO_SUCH_DEVICE if the supplied battery tag does not match
+ * with that of the cached composite battery's tag or if the composite
+ * battery currently does not have a tag assigned. Otherwise STATUS_SUCCESS
+ * is returned.
+ */
NTSTATUS
NTAPI
CompBattGetEstimatedTime(
https://git.reactos.org/?p=reactos.git;a=commitdiff;h=c439c5849b60920d9aec1…
commit c439c5849b60920d9aec198e4f5234339ef7c9a5
Author: George Bișoc <george.bisoc(a)reactos.org>
AuthorDate: Sat Dec 14 22:52:58 2024 +0100
Commit: George Bișoc <george.bisoc(a)reactos.org>
CommitDate: Wed Jan 8 23:20:08 2025 +0100
[COMPBATT] Implement CompBattGetEstimatedTime
---
drivers/bus/acpi/compbatt/compbatt.c | 219 ++++++++++++++++++++++++++++++++++-
1 file changed, 217 insertions(+), 2 deletions(-)
diff --git a/drivers/bus/acpi/compbatt/compbatt.c b/drivers/bus/acpi/compbatt/compbatt.c
index 7e55887be60..740f1f18cb4 100644
--- a/drivers/bus/acpi/compbatt/compbatt.c
+++ b/drivers/bus/acpi/compbatt/compbatt.c
@@ -1282,14 +1282,229 @@ CompBattGetBatteryGranularity(
return STATUS_SUCCESS;
}
+static
+LONG
+CompBattCalculateAtRateTime(
+ _In_ PCOMPBATT_DEVICE_EXTENSION DeviceExtension)
+{
+ NTSTATUS Status;
+ PCOMPBATT_BATTERY_DATA BatteryData;
+ BATTERY_QUERY_INFORMATION QueryInformation;
+ PLIST_ENTRY ListHead, NextEntry;
+ ULONG Time;
+ LONG ComputedAtRate = 0;
+
+ /* Walk over the linked batteries list to poll for "At Rate" value of each battery */
+ ExAcquireFastMutex(&DeviceExtension->Lock);
+ ListHead = &DeviceExtension->BatteryList;
+ for (NextEntry = ListHead->Flink;
+ NextEntry != ListHead;
+ NextEntry = NextEntry->Flink)
+ {
+ /* Acquire the remove lock so this battery does not disappear under us */
+ BatteryData = CONTAINING_RECORD(NextEntry, COMPBATT_BATTERY_DATA, BatteryLink);
+ if (!NT_SUCCESS(IoAcquireRemoveLock(&BatteryData->RemoveLock, BatteryData->Irp)))
+ continue;
+
+ /* Now release the device lock since the battery can't go away */
+ ExReleaseFastMutex(&DeviceExtension->Lock);
+
+ /* Build the necessary information in order to query the battery estimated time */
+ QueryInformation.BatteryTag = BatteryData->Tag;
+ QueryInformation.InformationLevel = BatteryEstimatedTime;
+ QueryInformation.AtRate = 0;
+
+ /* Make sure this battery has a valid tag before issuing the IOCTL */
+ if (BatteryData->Tag != BATTERY_TAG_INVALID)
+ {
+ /*
+ * Now it is time to issue the IOCTL to the battery device.
+ * We are calculating the "At Rate" counter based on each linked
+ * battery that is discharging, one at a time. This ensures
+ * that when we will actually retrieve the estimation time of each
+ * individual battery and sum it all up as one time for the composite
+ * battery, that the estimated time is accurate enough.
+ */
+ Status = BatteryIoctl(IOCTL_BATTERY_QUERY_INFORMATION,
+ BatteryData->DeviceObject,
+ &QueryInformation,
+ sizeof(QueryInformation),
+ &Time,
+ sizeof(Time),
+ FALSE);
+ if (NT_SUCCESS(Status))
+ {
+ if ((Time != 0) && (Time != BATTERY_UNKNOWN_TIME))
+ {
+ ComputedAtRate -= COMPUTE_ATRATE_DRAIN(BatteryData, Time);
+ }
+ }
+ }
+
+ /* We are done with this battery */
+ ExAcquireFastMutex(&DeviceExtension->Lock);
+ IoReleaseRemoveLock(&BatteryData->RemoveLock, BatteryData->Irp);
+ }
+
+ /* Release the lock as we are no longer poking through the batteries list */
+ ExReleaseFastMutex(&DeviceExtension->Lock);
+ return ComputedAtRate;
+}
+
NTSTATUS
NTAPI
CompBattGetEstimatedTime(
_Out_ PULONG Time,
_In_ PCOMPBATT_DEVICE_EXTENSION DeviceExtension)
{
- UNIMPLEMENTED;
- return STATUS_NOT_IMPLEMENTED;
+ NTSTATUS Status;
+ PCOMPBATT_BATTERY_DATA BatteryData;
+ BATTERY_STATUS BatteryStatus;
+ BATTERY_QUERY_INFORMATION QueryInformation;
+ PLIST_ENTRY ListHead, NextEntry;
+ ULONG ReturnedTime;
+ LONG ComputedAtRate;
+
+ /* Assume the battery time is not estimated yet */
+ *Time = BATTERY_UNKNOWN_TIME;
+
+ /*
+ * Before we are querying the composite estimated battery time we must
+ * refresh the battery status cache if we have not done it so.
+ */
+ Status = CompBattQueryStatus(DeviceExtension,
+ DeviceExtension->Tag,
+ &BatteryStatus);
+ if (!NT_SUCCESS(Status))
+ {
+ if (CompBattDebug & COMPBATT_DEBUG_ERR)
+ DbgPrint("CompBatt: Failed to refresh composite battery's status (Status 0x%08lx)\n", Status);
+
+ return Status;
+ }
+
+ /* Print out battery status data that has been polled */
+ if (CompBattDebug & COMPBATT_DEBUG_INFO)
+ DbgPrint("CompBatt: Latest composite battery status (when querying for estimated time)\n"
+ " PowerState -> 0x%lx\n"
+ " Capacity -> %u\n"
+ " Voltage -> %u\n"
+ " Rate -> %d\n",
+ BatteryStatus.PowerState,
+ BatteryStatus.Capacity,
+ BatteryStatus.Voltage,
+ BatteryStatus.Rate);
+
+ /*
+ * If the batteries are not being discharged and the system is directly
+ * being powered by external AC source then it makes no sense to
+ * compute the battery estimated time because that construct is for
+ * WHEN the system is powered directly from batteries and it drains power.
+ */
+ if (DeviceExtension->BatteryStatus.PowerState & BATTERY_POWER_ON_LINE)
+ {
+ if (CompBattDebug & COMPBATT_DEBUG_WARN)
+ {
+ DbgPrint("CompBatt: The system is powered by AC source, estimated time is not available\n");
+ }
+
+ return STATUS_SUCCESS;
+ }
+
+ /* Determine the draining "At Rate" counter for all batteries */
+ ComputedAtRate = CompBattCalculateAtRateTime(DeviceExtension);
+
+ /*
+ * A rate of 0 indicates none of the batteries that are linked with
+ * the composite are being drained therefore we cannot estimate the
+ * run time of the composite as it is not discharging.
+ */
+ if (ComputedAtRate == 0)
+ {
+ if (CompBattDebug & COMPBATT_DEBUG_WARN)
+ DbgPrint("CompBatt: No battery is discharging and no power is being drained, cannot estimate the run time\n");
+
+ return STATUS_SUCCESS;
+ }
+
+ /* Walk over the linked batteries list and determine the exact estimated time */
+ ExAcquireFastMutex(&DeviceExtension->Lock);
+ ListHead = &DeviceExtension->BatteryList;
+ for (NextEntry = ListHead->Flink;
+ NextEntry != ListHead;
+ NextEntry = NextEntry->Flink)
+ {
+ /* Acquire the remove lock so this battery does not disappear under us */
+ BatteryData = CONTAINING_RECORD(NextEntry, COMPBATT_BATTERY_DATA, BatteryLink);
+ if (!NT_SUCCESS(IoAcquireRemoveLock(&BatteryData->RemoveLock, BatteryData->Irp)))
+ continue;
+
+ /* Now release the device lock since the battery can't go away */
+ ExReleaseFastMutex(&DeviceExtension->Lock);
+
+ /* Build the necessary information in order to query the battery estimated time */
+ QueryInformation.BatteryTag = BatteryData->Tag;
+ QueryInformation.InformationLevel = BatteryEstimatedTime;
+ QueryInformation.AtRate = ComputedAtRate;
+
+ /* Make sure this battery has a valid tag before issuing the IOCTL */
+ if (BatteryData->Tag != BATTERY_TAG_INVALID)
+ {
+ Status = BatteryIoctl(IOCTL_BATTERY_QUERY_INFORMATION,
+ BatteryData->DeviceObject,
+ &QueryInformation,
+ sizeof(QueryInformation),
+ &ReturnedTime,
+ sizeof(ReturnedTime),
+ FALSE);
+ if (!NT_SUCCESS(Status))
+ {
+ /*
+ * If the device is being suddenly removed then we must invalidate
+ * both this battery and composite tags.
+ */
+ if (Status == STATUS_DEVICE_REMOVED)
+ {
+ Status = STATUS_NO_SUCH_DEVICE;
+ }
+
+ ExAcquireFastMutex(&DeviceExtension->Lock);
+ IoReleaseRemoveLock(&BatteryData->RemoveLock, BatteryData->Irp);
+
+ /*
+ * In other places we are ceasing the execution of the loop but
+ * here we want to continue looking for other linked batteries.
+ * This is because we are querying for the estimated battery time
+ * at the time the last battery status was valid. Also bear in
+ * mind IOCTL_BATTERY_QUERY_INFORMATION with InformationLevel as
+ * BatteryEstimatedTime might not be a valid request supported
+ * by this battery.
+ */
+ continue;
+ }
+
+ /* Now sum up the estimated battery time */
+ if (ReturnedTime != BATTERY_UNKNOWN_TIME)
+ {
+ if (*Time != BATTERY_UNKNOWN_TIME)
+ {
+ *Time += ReturnedTime;
+ }
+ else
+ {
+ *Time = ReturnedTime;
+ }
+ }
+ }
+
+ /* We are done with this battery */
+ ExAcquireFastMutex(&DeviceExtension->Lock);
+ IoReleaseRemoveLock(&BatteryData->RemoveLock, BatteryData->Irp);
+ }
+
+ /* Release the lock as we are no longer poking through the batteries list */
+ ExReleaseFastMutex(&DeviceExtension->Lock);
+ return Status;
}
NTSTATUS