mirror of
https://github.com/reactos/reactos.git
synced 2025-02-28 19:32:59 +00:00
[COMPBATT] Implement CompBattQueryStatus and CompBattSetStatusNotify
This commit is contained in:
parent
ee9914c712
commit
a6d4998c6c
1 changed files with 539 additions and 4 deletions
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue