https://git.reactos.org/?p=reactos.git;a=commitdiff;h=a6d4998c6c89abfb51cb5…
commit a6d4998c6c89abfb51cb561ce19f1f5aabc1bbe3
Author: George Bișoc <george.bisoc(a)reactos.org>
AuthorDate: Sat Dec 14 22:48:52 2024 +0100
Commit: George Bișoc <george.bisoc(a)reactos.org>
CommitDate: Wed Jan 8 23:20:08 2025 +0100
[COMPBATT] Implement CompBattQueryStatus and CompBattSetStatusNotify
---
drivers/bus/acpi/compbatt/compbatt.c | 543 ++++++++++++++++++++++++++++++++++-
1 file changed, 539 insertions(+), 4 deletions(-)
diff --git a/drivers/bus/acpi/compbatt/compbatt.c b/drivers/bus/acpi/compbatt/compbatt.c
index 9e0e5d3a782..7e55887be60 100644
--- a/drivers/bus/acpi/compbatt/compbatt.c
+++ b/drivers/bus/acpi/compbatt/compbatt.c
@@ -481,6 +481,115 @@ CompBattDisableStatusNotify(
return STATUS_SUCCESS;
}
+static
+BOOLEAN
+CompBattCalculateTotalRateAndLinkedBatteries(
+ _In_ PCOMPBATT_DEVICE_EXTENSION DeviceExtension,
+ _Out_ PULONG TotalRate,
+ _Out_ PULONG BatteriesCount)
+{
+ PCOMPBATT_BATTERY_DATA BatteryData;
+ PLIST_ENTRY ListHead, NextEntry;
+ BOOLEAN BadBattery = FALSE;
+ ULONG LinkedBatteries = 0;
+ ULONG BadBatteriesCount = 0;
+ ULONG ComputedRate = 0;
+
+ /* Loop over the linked batteries and sum up the total capacity rate */
+ 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;
+
+ /*
+ * Ensure this battery has a valid tag and that its rate capacity
+ * is not unknown. Reject unknown rates when calculating the total rate.
+ */
+ if ((BatteryData->Tag != BATTERY_TAG_INVALID) &&
+ (BatteryData->BatteryStatus.Rate != BATTERY_UNKNOWN_RATE))
+ {
+ /*
+ * Now the ultimate judgement for this battery is to determine
+ * if the battery behaves optimally based on its current power
+ * state it is and the rate flow of the battery.
+ *
+ * If the rate flow is positive the battery is receiving power
+ * which increases the chemical potential energy as electrons
+ * move around, THIS MEANS the battery is CHARGING. If the rate
+ * flow is negative the battery cells are producing way less
+ * electrical energy, thus the battery is DISCHARGING.
+ *
+ * A consistent battery is a battery of which power state matches
+ * the rate flow. If that were the case, then we have found a bad
+ * battery. The worst case is that a battery is physically damanged.
+ */
+ if ((BatteryData->BatteryStatus.PowerState & BATTERY_DISCHARGING)
&&
+ (BatteryData->BatteryStatus.Rate >= 0))
+ {
+ if (CompBattDebug & COMPBATT_DEBUG_WARN)
+ DbgPrint("CompBatt: The battery is discharging but in reality it
is charging... (Rate %d)\n",
+ BatteryData->BatteryStatus.Rate);
+
+ BadBattery = TRUE;
+ BadBatteriesCount++;
+ }
+
+ if ((BatteryData->BatteryStatus.PowerState & BATTERY_CHARGING)
&&
+ (BatteryData->BatteryStatus.Rate <= 0))
+ {
+ if (CompBattDebug & COMPBATT_DEBUG_WARN)
+ DbgPrint("CompBatt: The battery is charging but in reality it is
discharging... (Rate %d)\n",
+ BatteryData->BatteryStatus.Rate);
+
+ BadBattery = TRUE;
+ BadBatteriesCount++;
+ }
+
+ if (((BatteryData->BatteryStatus.PowerState & (BATTERY_CHARGING |
BATTERY_DISCHARGING)) == 0) &&
+ (BatteryData->BatteryStatus.Rate != 0))
+ {
+ if (CompBattDebug & COMPBATT_DEBUG_WARN)
+ DbgPrint("CompBatt: The battery is neither charging or
discharging but has a contradicting rate... (Rate %d)\n",
+ BatteryData->BatteryStatus.Rate);
+
+ BadBattery = TRUE;
+ BadBatteriesCount++;
+ }
+
+ /*
+ * Sum up the rate of this battery to make up the total, even if that means
+ * the battery may have incosistent rate. This is because it is still a
linked
+ * battery to the composite battery and it is used to power up the system
nonetheless.
+ */
+ ComputedRate += BatteryData->BatteryStatus.Rate;
+ }
+
+ /* We are done with this individual battery */
+ LinkedBatteries++;
+ IoReleaseRemoveLock(&BatteryData->RemoveLock, BatteryData->Irp);
+ }
+
+ /* Release the lock as we are no longer poking through the batteries list */
+ ExReleaseFastMutex(&DeviceExtension->Lock);
+
+ /* Print out the total count of bad batteries we have found */
+ if (BadBatteriesCount > 0)
+ {
+ if (CompBattDebug & COMPBATT_DEBUG_WARN)
+ DbgPrint("CompBatt: %lu bad batteries have been found!\n",
BadBatteriesCount);
+ }
+
+ *TotalRate = ComputedRate;
+ *BatteriesCount = LinkedBatteries;
+ return BadBattery;
+}
+
NTSTATUS
NTAPI
CompBattSetStatusNotify(
@@ -488,8 +597,226 @@ CompBattSetStatusNotify(
_In_ ULONG BatteryTag,
_In_ PBATTERY_NOTIFY BatteryNotify)
{
- UNIMPLEMENTED;
- return STATUS_NOT_IMPLEMENTED;
+ NTSTATUS Status;
+ BOOLEAN BadBattery;
+ ULONG TotalRate;
+ ULONG BatteriesCount;
+ ULONG HighestCapacity;
+ ULONG LowCapDifference, HighCapDifference, LowDelta, HighDelta;
+ BATTERY_STATUS BatteryStatus;
+ PCOMPBATT_BATTERY_DATA BatteryData;
+ PLIST_ENTRY ListHead, NextEntry;
+
+ /*
+ * The caller wants to set new status notification settings but the composite
+ * battery does not have a valid tag assigned, or the tag does not actually match.
+ */
+ if (!(DeviceExtension->Flags & COMPBATT_TAG_ASSIGNED) ||
+ (DeviceExtension->Tag != BatteryTag))
+ {
+ if (CompBattDebug & COMPBATT_DEBUG_WARN)
+ DbgPrint("CompBatt: Composite battery tag not assigned or not matching
(Tag -> %lu, Composite Tag -> %lu)\n",
+ BatteryTag, DeviceExtension->Tag);
+
+ return STATUS_NO_SUCH_DEVICE;
+ }
+
+ /*
+ * Before we are setting up new status wait notification points we need to
+ * refresh the composite status so that we get to know what values should be
+ * set for the current notification wait status.
+ */
+ Status = CompBattQueryStatus(DeviceExtension,
+ BatteryTag,
+ &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 setting notify
status)\n"
+ " PowerState -> 0x%lx\n"
+ " Capacity -> %u\n"
+ " Voltage -> %u\n"
+ " Rate -> %d\n",
+ BatteryStatus.PowerState,
+ BatteryStatus.Capacity,
+ BatteryStatus.Voltage,
+ BatteryStatus.Rate);
+
+ /* Calculate the high and low capacity differences based on the real summed capacity
of the composite */
+ LowCapDifference = DeviceExtension->BatteryStatus.Capacity -
BatteryNotify->LowCapacity;
+ HighCapDifference = BatteryNotify->HighCapacity -
DeviceExtension->BatteryStatus.Capacity;
+
+ /* Cache the notification parameters provided for later usage when polling for
battery status */
+ DeviceExtension->WaitNotifyStatus.PowerState = BatteryNotify->PowerState;
+ DeviceExtension->WaitNotifyStatus.LowCapacity = BatteryNotify->LowCapacity;
+ DeviceExtension->WaitNotifyStatus.HighCapacity = BatteryNotify->HighCapacity;
+
+ /* Toggle the valid notify flag as these are the newer notification settings */
+ DeviceExtension->Flags |= COMPBATT_STATUS_NOTIFY_SET;
+
+ /*
+ * Get the number of currently linked batteries to composite and total rate,
+ * we will use these counters later to determine the wait values for each
+ * individual battery.
+ */
+ BadBattery = CompBattCalculateTotalRateAndLinkedBatteries(DeviceExtension,
+ &TotalRate,
+ &BatteriesCount);
+
+ /*
+ * Of course we have to be sure that we have at least one battery linked
+ * with the composite battery at this time of getting invoked to set new
+ * notification wait settings.
+ */
+ ASSERT(BatteriesCount != 0);
+
+ /* Walk over the linked batteries list and set up new wait configuration settings
*/
+ 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);
+
+ /* Make sure this battery has a tag before setting new wait values */
+ if (BatteryData->Tag != BATTERY_TAG_INVALID)
+ {
+ /*
+ * And also make sure this battery does not have an unknown
+ * capacity, we cannot set up new configuration wait settings
+ * based on that. Default the low and high wait capacities.
+ */
+ if (BatteryData->BatteryStatus.Capacity != BATTERY_UNKNOWN_CAPACITY)
+ {
+ /*
+ * Calculate the low capacity wait setting. If at least one
+ * bad battery was found while we computed the total composite
+ * rate, then divide the difference between the total batteries.
+ * Otherwise compute the battery deltas of the composite based
+ * on total summed capacity rate. Otherwise if the total rate
+ * is 0, then the real wait low and high capacities will be on
+ * par with the real capacity.
+ */
+ if (BadBattery)
+ {
+ LowDelta = LowCapDifference / BatteriesCount;
+ HighDelta = HighCapDifference / BatteriesCount;
+ }
+ else
+ {
+ if (TotalRate)
+ {
+ LowDelta = COMPUTE_BATT_CAP_DELTA(LowCapDifference, BatteryData,
TotalRate);
+ HighDelta = COMPUTE_BATT_CAP_DELTA(HighCapDifference,
BatteryData, TotalRate);
+ }
+ else
+ {
+ LowDelta = 0;
+ HighDelta = 0;
+ }
+ }
+
+ /*
+ * Assign the wait low capacity setting ONLY if the battery delta
+ * is not high. Otherwise it has overflowed and we cannot use that
+ * for low capacity, of which we have to default it to 0.
+ */
+ if (BatteryData->BatteryStatus.Capacity > LowDelta)
+ {
+ BatteryData->WaitStatus.LowCapacity =
BatteryData->BatteryStatus.Capacity - LowDelta;
+ }
+ else
+ {
+ BatteryData->WaitStatus.LowCapacity =
COMPBATT_WAIT_MIN_LOW_CAPACITY;
+ }
+
+ /*
+ * Assign the wait high capacity setting ONLY if the real capacity
+ * is not above the maximum highest capacity constant.
+ */
+ HighestCapacity = COMPBATT_WAIT_MAX_HIGH_CAPACITY - HighDelta;
+ if (HighestCapacity < BatteryData->BatteryStatus.Capacity)
+ {
+ BatteryData->WaitStatus.HighCapacity = HighestCapacity;
+ }
+ else
+ {
+ BatteryData->WaitStatus.HighCapacity =
BatteryData->BatteryStatus.Capacity + HighDelta;
+ }
+
+ /*
+ * We have set up the wait values but they are in conflict with the
+ * ones set up by the IRP complete worker. We have to cancel the IRP
+ * so the worker will copy our wait configuration values.
+ */
+ if ((BatteryData->Mode == COMPBATT_READ_STATUS) &&
+ (BatteryData->WaitStatus.PowerState !=
BatteryData->WorkerBuffer.WorkerWaitStatus.PowerState ||
+ BatteryData->WaitStatus.LowCapacity !=
BatteryData->WorkerBuffer.WorkerWaitStatus.LowCapacity ||
+ BatteryData->WaitStatus.HighCapacity !=
BatteryData->WorkerBuffer.WorkerWaitStatus.HighCapacity))
+ {
+ if (CompBattDebug & COMPBATT_DEBUG_INFO)
+ DbgPrint("CompBatt: Configuration wait values are in
conflict\n"
+ " BatteryData->WaitStatus.PowerState
-> 0x%lx\n"
+ "
BatteryData->WorkerBuffer.WorkerWaitStatus.PowerState -> 0x%lx\n"
+ " BatteryData->WaitStatus.LowCapacity
-> %u\n"
+ "
BatteryData->WorkerBuffer.WorkerWaitStatus.LowCapacity -> %u\n"
+ " BatteryData->WaitStatus.HighCapacity
-> %u\n"
+ "
BatteryData->WorkerBuffer.WorkerWaitStatus.HighCapacity -> %u\n",
+ BatteryData->WaitStatus.PowerState,
+
BatteryData->WorkerBuffer.WorkerWaitStatus.PowerState,
+ BatteryData->WaitStatus.LowCapacity,
+
BatteryData->WorkerBuffer.WorkerWaitStatus.LowCapacity,
+ BatteryData->WaitStatus.HighCapacity,
+
BatteryData->WorkerBuffer.WorkerWaitStatus.HighCapacity);
+
+ IoCancelIrp(BatteryData->Irp);
+ }
+ }
+ else
+ {
+ BatteryData->WaitStatus.LowCapacity = BATTERY_UNKNOWN_CAPACITY;
+ BatteryData->WaitStatus.HighCapacity = BATTERY_UNKNOWN_CAPACITY;
+ }
+ }
+
+ /* 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);
+
+ /* Ensure the composite battery did not incur in drastic changes of tag */
+ if (!(DeviceExtension->Flags & COMPBATT_TAG_ASSIGNED) ||
+ (DeviceExtension->Tag != BatteryTag))
+ {
+ /*
+ * Either the last battery was removed (in this case the composite is no
+ * longer existing) or a battery was removed of which the whole battery
+ * information must be recomputed and such.
+ */
+ if (CompBattDebug & COMPBATT_DEBUG_WARN)
+ DbgPrint("CompBatt: Last battery or a battery was removed, the whole
composite data must be recomputed\n");
+
+ return STATUS_NO_SUCH_DEVICE;
+ }
+
+ return STATUS_SUCCESS;
}
NTSTATUS
@@ -499,8 +826,216 @@ CompBattQueryStatus(
_In_ ULONG Tag,
_Out_ PBATTERY_STATUS BatteryStatus)
{
- UNIMPLEMENTED;
- return STATUS_NOT_IMPLEMENTED;
+ PCOMPBATT_BATTERY_DATA BatteryData;
+ BATTERY_WAIT_STATUS Wait;
+ PLIST_ENTRY ListHead, NextEntry;
+ ULONGLONG LastReadTime, CurrentReadTime;
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ /*
+ * The caller wants to update the composite battery status but the composite
+ * itself does not have a valid tag assigned, or the tag does not actually match.
+ */
+ if (!(DeviceExtension->Flags & COMPBATT_TAG_ASSIGNED) ||
+ (DeviceExtension->Tag != Tag))
+ {
+ if (CompBattDebug & COMPBATT_DEBUG_WARN)
+ DbgPrint("CompBatt: Composite battery tag not assigned or not matching
(Tag -> %lu, Composite Tag -> %lu)\n",
+ Tag, DeviceExtension->Tag);
+
+ return STATUS_NO_SUCH_DEVICE;
+ }
+
+ /* Initialize the status and wait fields with zeros */
+ RtlZeroMemory(BatteryStatus, sizeof(*BatteryStatus));
+ RtlZeroMemory(&Wait, sizeof(Wait));
+
+ /*
+ * The battery status was already updated when the caller queried for new
+ * status. We do not need to update the status again for no reason.
+ * Just give them the data outright.
+ */
+ CurrentReadTime = KeQueryInterruptTime();
+ LastReadTime = CurrentReadTime - DeviceExtension->InterruptTime;
+ if (LastReadTime < COMPBATT_FRESH_STATUS_TIME)
+ {
+ if (CompBattDebug & COMPBATT_DEBUG_WARN)
+ DbgPrint("CompBatt: Composite battery status data is fresh, no need to
update it again\n");
+
+ RtlCopyMemory(BatteryStatus, &DeviceExtension->BatteryStatus,
sizeof(BATTERY_STATUS));
+ return STATUS_SUCCESS;
+ }
+
+ /*
+ * Initialize the battery status context with unknown defaults, until we get
+ * to retrieve the real data from each battery and compute the exact status.
+ * Assume the system is powered by AC source for now until we find out it is
+ * not the case.
+ */
+ BatteryStatus->PowerState = BATTERY_POWER_ON_LINE;
+ BatteryStatus->Capacity = BATTERY_UNKNOWN_CAPACITY;
+ BatteryStatus->Voltage = BATTERY_UNKNOWN_VOLTAGE;
+ BatteryStatus->Rate = BATTERY_UNKNOWN_RATE;
+
+ /* Iterate over all the present linked batteries and retrieve their status */
+ 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);
+
+ /* Setup the battery tag for the status wait which is needed to send off the
IOCTL */
+ Wait.BatteryTag = BatteryData->Tag;
+
+ /* Make sure this battery has a tag before we send off the IOCTL */
+ if (BatteryData->Tag != BATTERY_TAG_INVALID)
+ {
+ /* Only query new battery status data if it is no longer fresh */
+ LastReadTime = CurrentReadTime - BatteryData->InterruptTime;
+ if (LastReadTime > COMPBATT_FRESH_STATUS_TIME)
+ {
+ RtlZeroMemory(&BatteryData->BatteryStatus,
+ sizeof(BatteryData->BatteryStatus));
+ Status = BatteryIoctl(IOCTL_BATTERY_QUERY_STATUS,
+ BatteryData->DeviceObject,
+ &Wait,
+ sizeof(Wait),
+ &BatteryData->BatteryStatus,
+ sizeof(BatteryData->BatteryStatus),
+ 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);
+ break;
+ }
+
+ /* Update the timestamp of the current read of battery status */
+ BatteryData->InterruptTime = CurrentReadTime;
+ }
+
+ /*
+ * Now it is time to combine the data into the composite status.
+ * The battery is either charging or discharging. AC is present
+ * only if the charger supplies current to all batteries. And
+ * the composite is deemed as critical if at least one battery
+ * is discharging and it is in crtitical state.
+ */
+ BatteryStatus->PowerState |= (BatteryData->BatteryStatus.PowerState
& (BATTERY_CHARGING | BATTERY_DISCHARGING));
+ BatteryStatus->PowerState &= (BatteryData->BatteryStatus.PowerState
| ~BATTERY_POWER_ON_LINE);
+ if ((BatteryData->BatteryStatus.PowerState & BATTERY_CRITICAL)
&&
+ (BatteryData->BatteryStatus.PowerState & BATTERY_DISCHARGING))
+ {
+ BatteryStatus->PowerState |= BATTERY_CRITICAL;
+ }
+
+ /* Add up the battery capacity if it is not unknown */
+ if (BatteryData->BatteryStatus.Capacity != BATTERY_UNKNOWN_CAPACITY)
+ {
+ if (BatteryStatus->Capacity != BATTERY_UNKNOWN_CAPACITY)
+ {
+ BatteryStatus->Capacity +=
BatteryData->BatteryStatus.Capacity;
+ }
+ else
+ {
+ BatteryStatus->Capacity =
BatteryData->BatteryStatus.Capacity;
+ }
+ }
+
+ /* Always pick up the greatest voltage for the composite battery */
+ if (BatteryData->BatteryStatus.Voltage != BATTERY_UNKNOWN_VOLTAGE)
+ {
+ if (BatteryStatus->Voltage != BATTERY_UNKNOWN_VOLTAGE)
+ {
+ BatteryStatus->Voltage = max(BatteryStatus->Voltage,
+
BatteryData->BatteryStatus.Voltage);
+ }
+ else
+ {
+ BatteryStatus->Voltage = BatteryData->BatteryStatus.Voltage;
+ }
+ }
+
+ /* Add up the battery discharge rate if it is not unknown */
+ if (BatteryData->BatteryStatus.Rate != BATTERY_UNKNOWN_RATE)
+ {
+ if (BatteryStatus->Rate != BATTERY_UNKNOWN_RATE)
+ {
+ BatteryStatus->Rate += BatteryData->BatteryStatus.Rate;
+ }
+ else
+ {
+ BatteryStatus->Rate = BatteryData->BatteryStatus.Rate;
+ }
+ }
+ }
+
+ /* We are done combining data from 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);
+
+ /* Ensure the composite battery did not incur in drastic changes of tag */
+ if (!(DeviceExtension->Flags & COMPBATT_TAG_ASSIGNED) ||
+ (DeviceExtension->Tag != Tag))
+ {
+ /*
+ * Either the last battery was removed (in this case the composite is no
+ * longer existing) or a battery was removed of which the whole battery
+ * information must be recomputed and such.
+ */
+ if (CompBattDebug & COMPBATT_DEBUG_WARN)
+ DbgPrint("CompBatt: Last battery or a battery was removed, the whole
composite data must be recomputed\n");
+
+ return STATUS_NO_SUCH_DEVICE;
+ }
+
+ /*
+ * If there is a battery that is charging while another one discharging,
+ * then tell the caller the composite battery is actually discharging.
+ * This is less likely to happen on a multi-battery system like laptops
+ * as the charger would provide electricity to all the batteries.
+ * Perhaps the most likely case scenario would be if the system were
+ * to be powered by a UPS.
+ */
+ if ((BatteryStatus->PowerState & BATTERY_CHARGING) &&
+ (BatteryStatus->PowerState & BATTERY_DISCHARGING))
+ {
+ BatteryStatus->PowerState &= ~BATTERY_CHARGING;
+ }
+
+ /* Copy the combined status information to the composite battery */
+ if (NT_SUCCESS(Status))
+ {
+ RtlCopyMemory(&DeviceExtension->BatteryStatus,
+ BatteryStatus,
+ sizeof(DeviceExtension->BatteryStatus));
+
+ /* Update the last read battery status timestamp as well */
+ DeviceExtension->InterruptTime = CurrentReadTime;
+ }
+
+ return Status;
}
NTSTATUS