2007 lines
61 KiB
C
2007 lines
61 KiB
C
/*++
|
||
|
||
Copyright (c) 1990 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
bsrv.c
|
||
|
||
Abstract:
|
||
|
||
Service battery class device
|
||
|
||
Author:
|
||
|
||
Ken Reneris
|
||
|
||
Environment:
|
||
|
||
Notes:
|
||
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include "battcp.h"
|
||
|
||
VOID
|
||
BattCIoctl (
|
||
IN PBATT_INFO BattInfo,
|
||
IN PIRP Irp,
|
||
IN PIO_STACK_LOCATION IrpSp
|
||
);
|
||
|
||
VOID
|
||
BattCCheckTagQueue (
|
||
IN PBATT_NP_INFO BattNPInfo,
|
||
IN PBATT_INFO BattInfo
|
||
);
|
||
|
||
VOID
|
||
BattCCheckStatusQueue (
|
||
IN PBATT_NP_INFO BattNPInfo,
|
||
IN PBATT_INFO BattInfo
|
||
);
|
||
|
||
VOID
|
||
BattCWmi (
|
||
IN PBATT_NP_INFO BattNPInfo,
|
||
IN PBATT_INFO BattInfo,
|
||
IN PBATT_WMI_REQUEST WmiRequest
|
||
);
|
||
|
||
VOID
|
||
BattCMiniportStatus (
|
||
IN PBATT_INFO BattInfo,
|
||
IN NTSTATUS Status
|
||
);
|
||
|
||
VOID
|
||
BattCCompleteIrpQueue (
|
||
IN PLIST_ENTRY Queue,
|
||
IN NTSTATUS Status
|
||
);
|
||
|
||
VOID
|
||
BattCCompleteWmiQueue (
|
||
IN PLIST_ENTRY Queue,
|
||
IN NTSTATUS Status
|
||
);
|
||
|
||
|
||
#ifdef ALLOC_PRAGMA
|
||
#pragma alloc_text(PAGE,BattCCheckStatusQueue)
|
||
#pragma alloc_text(PAGE,BattCCheckTagQueue)
|
||
#pragma alloc_text(PAGE,BattCWorkerThread)
|
||
#pragma alloc_text(PAGE,BattCIoctl)
|
||
#endif
|
||
|
||
VOID
|
||
BattCWorkerDpc (
|
||
IN struct _KDPC *Dpc,
|
||
IN PVOID DeferredContext,
|
||
IN PVOID SystemArgument1,
|
||
IN PVOID SystemArgument2
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
DPC used to get worker thread when status needs to be checked.
|
||
|
||
Arguments:
|
||
|
||
Dpc - the worker dpc
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
PBATT_NP_INFO BattNPInfo;
|
||
|
||
BattNPInfo = (PBATT_NP_INFO) DeferredContext;
|
||
BattCQueueWorker (BattNPInfo, TRUE);
|
||
// Release Removal Lock
|
||
if (0 == InterlockedDecrement(&BattNPInfo->InUseCount)) {
|
||
KeSetEvent (&BattNPInfo->ReadyToRemove, IO_NO_INCREMENT, FALSE);
|
||
}
|
||
BattPrint ((BATT_LOCK), ("BattCWorkerDpc: Released remove lock %d (count = %d)\n", BattNPInfo->DeviceNum, BattNPInfo->InUseCount));
|
||
|
||
}
|
||
|
||
|
||
|
||
VOID
|
||
BattCTagDpc (
|
||
IN struct _KDPC *Dpc,
|
||
IN PVOID DeferredContext,
|
||
IN PVOID SystemArgument1,
|
||
IN PVOID SystemArgument2
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
DPC used to get worker thread when status needs to be checked.
|
||
|
||
Arguments:
|
||
|
||
Dpc - the worker dpc
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
PBATT_NP_INFO BattNPInfo;
|
||
|
||
BattNPInfo = (PBATT_NP_INFO) DeferredContext;
|
||
InterlockedExchange(&BattNPInfo->CheckTag, 1);
|
||
BattCQueueWorker (BattNPInfo, FALSE);
|
||
// Release Removal Lock
|
||
if (0 == InterlockedDecrement(&BattNPInfo->InUseCount)) {
|
||
KeSetEvent (&BattNPInfo->ReadyToRemove, IO_NO_INCREMENT, FALSE);
|
||
}
|
||
BattPrint ((BATT_LOCK), ("BattCTagDpc: Released remove lock %d (count = %d)\n", BattNPInfo->DeviceNum, BattNPInfo->InUseCount));
|
||
}
|
||
|
||
|
||
|
||
VOID
|
||
BattCCancelStatus (
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Queued status IRP is being canceled
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - Device object of the miniport. Not useful to the
|
||
class driver - ignored.
|
||
|
||
Irp - Irp being cancelled
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
PIO_STACK_LOCATION IrpNextSp;
|
||
PBATT_NP_INFO BattNPInfo;
|
||
|
||
//
|
||
// IRP is flagged as needing cancled, cause a check status which will
|
||
// complete any pending cancled irps
|
||
//
|
||
|
||
IrpNextSp = IoGetNextIrpStackLocation(Irp);
|
||
BattNPInfo = (PBATT_NP_INFO) IrpNextSp->Parameters.Others.Argument4;
|
||
|
||
BattPrint ((BATT_TRACE), ("BattC (%d): BatteryCCancelStatus. Irp - %08x\n", BattNPInfo->DeviceNum, Irp));
|
||
|
||
BattCQueueWorker (BattNPInfo, TRUE);
|
||
|
||
//
|
||
// The cancel Spinlock must be released after attempting to queue the
|
||
// worker thread so that there is no timeing problems on remove.
|
||
//
|
||
IoReleaseCancelSpinLock(Irp->CancelIrql);
|
||
}
|
||
|
||
|
||
|
||
VOID
|
||
BattCCancelTag (
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Queued tag IRP is being canceled
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - Device object of the miniport. Not useful to the
|
||
class driver - ignored.
|
||
|
||
Irp - Irp being cancelled
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
PIO_STACK_LOCATION IrpNextSp;
|
||
PBATT_NP_INFO BattNPInfo;
|
||
|
||
//
|
||
// IRP is flagged as needing canceled. Cause a check tag which will
|
||
// complete any pending cancled irps
|
||
//
|
||
|
||
IrpNextSp = IoGetNextIrpStackLocation(Irp);
|
||
BattNPInfo = (PBATT_NP_INFO) IrpNextSp->Parameters.Others.Argument4;
|
||
|
||
BattPrint ((BATT_TRACE), ("BattC (%d): BatteryCCancelTag. Irp - %08x\n", BattNPInfo->DeviceNum, Irp));
|
||
|
||
InterlockedExchange(&BattNPInfo->CheckTag, 1);
|
||
BattCQueueWorker (BattNPInfo, FALSE);
|
||
|
||
//
|
||
// The cancel Spinlock must be released after attempting to queue the
|
||
// worker thread so that there is no timeing problems on remove.
|
||
//
|
||
IoReleaseCancelSpinLock(Irp->CancelIrql);
|
||
}
|
||
|
||
|
||
|
||
VOID
|
||
BattCQueueWorker (
|
||
IN PBATT_NP_INFO BattNPInfo,
|
||
IN BOOLEAN CheckStatus
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Get worker thread to check the battery state (IoQueue). The
|
||
battery IOs are serialized here as only one worker thread is
|
||
used to process the battery IOs. If the worker thread is already
|
||
running, it is flagged to loop are re-check the state. If the
|
||
worker thread is not running, one is queued.
|
||
|
||
If CheckStatus is set, the worker thread is informed that the
|
||
batteries current status is read and the pending status queue
|
||
is checked.
|
||
|
||
Arguments:
|
||
|
||
BattNPInfo - Battery to check
|
||
|
||
CheckStatus - Whether or not the status also needs checked
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
PBATT_INFO BattInfo = BattNPInfo->BattInfo;
|
||
|
||
//
|
||
// Add 1 to the WorkerActive value, if this is the first count
|
||
// queue a worker thread
|
||
//
|
||
|
||
BattPrint ((BATT_TRACE), ("BattC (%d): BatteryCQueueWorker.\n", BattNPInfo->DeviceNum));
|
||
|
||
if (CheckStatus) {
|
||
InterlockedExchange(&BattNPInfo->CheckStatus, 1);
|
||
InterlockedExchange (&BattNPInfo->CheckTag, 1);
|
||
}
|
||
|
||
//
|
||
// Increment WorkerActive count. If the worker thread is already running,
|
||
// there is no need to requeue it.
|
||
//
|
||
if (InterlockedIncrement(&BattNPInfo->WorkerActive) == 1) {
|
||
// Removal lock.
|
||
if ((BattNPInfo->WantToRemove == TRUE) && (KeGetCurrentIrql() == PASSIVE_LEVEL)) {
|
||
// Check Irql to make sure this wasn't called by an ISR. If so,
|
||
// queue the worker rather than complete the requests in this thread.
|
||
|
||
//
|
||
// Empty IRP queues.
|
||
//
|
||
BattCCompleteIrpQueue(&(BattInfo->IoQueue), STATUS_DEVICE_REMOVED);
|
||
BattCCompleteIrpQueue(&(BattInfo->TagQueue), STATUS_DEVICE_REMOVED);
|
||
BattCCompleteIrpQueue(&(BattInfo->StatusQueue), STATUS_DEVICE_REMOVED);
|
||
BattCCompleteIrpQueue(&(BattInfo->WmiQueue), STATUS_DEVICE_REMOVED);
|
||
|
||
//
|
||
// Remove lock and trigger Remove function if necessary.
|
||
//
|
||
if (0 == InterlockedDecrement(&BattNPInfo->InUseCount)) {
|
||
KeSetEvent (&BattNPInfo->ReadyToRemove, IO_NO_INCREMENT, FALSE);
|
||
}
|
||
BattPrint ((BATT_LOCK), ("BattCQueueWorker: Released remove lock %d (count = %d)\n", BattNPInfo->DeviceNum, BattNPInfo->InUseCount));
|
||
|
||
} else {
|
||
ExQueueWorkItem (&BattNPInfo->WorkerThread, DelayedWorkQueue);
|
||
}
|
||
}
|
||
}
|
||
|
||
VOID
|
||
BattCWorkerThread (
|
||
IN PVOID Context
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Battery IO worker thread entry point.
|
||
|
||
N.B. There is only one worker thread handling the battery at any one time
|
||
|
||
Arguments:
|
||
|
||
Context - BattInfo. Battery to check
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
PBATT_INFO BattInfo;
|
||
PBATT_NP_INFO BattNPInfo;
|
||
PLIST_ENTRY Entry;
|
||
PIRP Irp;
|
||
PIO_STACK_LOCATION IrpSp;
|
||
ULONG i;
|
||
|
||
|
||
PAGED_CODE();
|
||
|
||
BattNPInfo = (PBATT_NP_INFO) Context;
|
||
BattInfo = BattNPInfo->BattInfo;
|
||
|
||
BattPrint ((BATT_TRACE), ("BattC (%d): BatteryCWorkerThread entered.\n", BattNPInfo->DeviceNum));
|
||
|
||
|
||
//
|
||
// Loop while there is work to check
|
||
//
|
||
|
||
for (; ;) {
|
||
// Removal code. This makes sure that the structures aren't freed in the middle of
|
||
// processing. All Irp Queues will be emptied by BatteryClassUnload.
|
||
if (BattNPInfo->WantToRemove == TRUE) {
|
||
//
|
||
// Empty IRP queues.
|
||
//
|
||
BattCCompleteIrpQueue(&(BattInfo->IoQueue), STATUS_DEVICE_REMOVED);
|
||
BattCCompleteIrpQueue(&(BattInfo->TagQueue), STATUS_DEVICE_REMOVED);
|
||
BattCCompleteIrpQueue(&(BattInfo->StatusQueue), STATUS_DEVICE_REMOVED);
|
||
BattCCompleteIrpQueue(&(BattInfo->WmiQueue), STATUS_DEVICE_REMOVED);
|
||
//
|
||
// Signal BatteryClassUnload that it is safe to return.
|
||
//
|
||
if (0 == InterlockedDecrement(&BattNPInfo->InUseCount)) {
|
||
KeSetEvent (&BattNPInfo->ReadyToRemove, IO_NO_INCREMENT, FALSE);
|
||
}
|
||
BattPrint ((BATT_LOCK), ("BattCWorkerThread: Released remove lock %d (count = %d)\n", BattNPInfo->DeviceNum, BattNPInfo->InUseCount));
|
||
|
||
return;
|
||
}
|
||
|
||
//
|
||
// Acquire queue locks
|
||
//
|
||
|
||
ExAcquireFastMutex (&BattNPInfo->Mutex);
|
||
|
||
//
|
||
// While there are IRPs in the IoQueue handle them
|
||
//
|
||
|
||
while (!IsListEmpty(&BattInfo->IoQueue)) {
|
||
|
||
//
|
||
// Remove entry from IoQueue and drop device lock
|
||
//
|
||
|
||
Entry = RemoveHeadList(&BattInfo->IoQueue);
|
||
ExReleaseFastMutex (&BattNPInfo->Mutex);
|
||
|
||
|
||
//
|
||
// Handle this entry
|
||
//
|
||
|
||
Irp = CONTAINING_RECORD (
|
||
Entry,
|
||
IRP,
|
||
Tail.Overlay.ListEntry
|
||
);
|
||
|
||
BattPrint (BATT_IOCTL, ("BattC (%d): WorkerThread, Got Irp - %x\n", BattNPInfo->DeviceNum, Irp));
|
||
|
||
IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
||
|
||
|
||
if (IrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_BATTERY_QUERY_STATUS &&
|
||
IrpSp->Parameters.DeviceIoControl.InputBufferLength == sizeof (BATTERY_WAIT_STATUS) &&
|
||
IrpSp->Parameters.DeviceIoControl.OutputBufferLength == sizeof (BATTERY_STATUS)) {
|
||
|
||
BattPrint (BATT_IOCTL,
|
||
("BattC (%d): Received QueryStatus Irp - %x, timeout - %x\n",
|
||
BattNPInfo->DeviceNum,
|
||
Irp,
|
||
((PBATTERY_WAIT_STATUS)Irp->AssociatedIrp.SystemBuffer)->Timeout));
|
||
|
||
//
|
||
// Valid query status irp, put it on the StatusQueue and handle later
|
||
//
|
||
|
||
InterlockedExchange (&BattNPInfo->CheckStatus, 1);
|
||
IrpSp = IoGetNextIrpStackLocation(Irp);
|
||
IrpSp->Parameters.Others.Argument1 = (PVOID) 0;
|
||
IrpSp->Parameters.Others.Argument2 = (PVOID) 0;
|
||
IrpSp->Parameters.Others.Argument3 = NULL;
|
||
IrpSp->Parameters.Others.Argument4 = BattNPInfo;
|
||
|
||
//
|
||
// Set IRPs cancel routine
|
||
//
|
||
|
||
IoSetCancelRoutine (Irp, BattCCancelStatus);
|
||
|
||
//
|
||
// Queue it
|
||
//
|
||
|
||
InsertTailList (
|
||
&BattInfo->StatusQueue,
|
||
&Irp->Tail.Overlay.ListEntry
|
||
);
|
||
|
||
} else if (IrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_BATTERY_QUERY_TAG &&
|
||
(IrpSp->Parameters.DeviceIoControl.InputBufferLength == sizeof (ULONG) ||
|
||
IrpSp->Parameters.DeviceIoControl.InputBufferLength == 0) &&
|
||
IrpSp->Parameters.DeviceIoControl.OutputBufferLength == sizeof (ULONG)) {
|
||
|
||
BattPrint (BATT_IOCTL,
|
||
("BattC (%d): Received QueryTag with timeout %x\n",
|
||
BattNPInfo->DeviceNum,
|
||
*((PULONG) Irp->AssociatedIrp.SystemBuffer))
|
||
);
|
||
|
||
//
|
||
// Valid query tag irp, put it on the TagQueue and handle later
|
||
//
|
||
|
||
InterlockedExchange (&BattNPInfo->CheckTag, 1);
|
||
IrpSp = IoGetNextIrpStackLocation(Irp);
|
||
IrpSp->Parameters.Others.Argument1 = (PVOID) 0;
|
||
IrpSp->Parameters.Others.Argument2 = (PVOID) 0;
|
||
IrpSp->Parameters.Others.Argument3 = NULL;
|
||
IrpSp->Parameters.Others.Argument4 = BattNPInfo;
|
||
|
||
|
||
//
|
||
// Set IRPs cancel routine
|
||
//
|
||
|
||
IoSetCancelRoutine (Irp, BattCCancelTag);
|
||
|
||
InsertTailList (
|
||
&BattInfo->TagQueue,
|
||
&Irp->Tail.Overlay.ListEntry
|
||
);
|
||
|
||
} else {
|
||
//
|
||
// Handle IRP now
|
||
//
|
||
|
||
BattPrint (BATT_IOCTL, ("BattC (%d): Calling BattCIoctl with irp %x\n", BattNPInfo->DeviceNum, Irp));
|
||
BattCIoctl (BattInfo, Irp, IrpSp);
|
||
}
|
||
|
||
//
|
||
// Acquire IoQueue lock and check for anything else in the IoQueueu
|
||
//
|
||
|
||
ExAcquireFastMutex (&BattNPInfo->Mutex);
|
||
}
|
||
|
||
//
|
||
// Done with the IoQueue
|
||
//
|
||
|
||
ExReleaseFastMutex (&BattNPInfo->Mutex);
|
||
|
||
//
|
||
// Check pending status queue
|
||
//
|
||
|
||
if (BattNPInfo->CheckStatus) {
|
||
BattCCheckStatusQueue (BattNPInfo, BattInfo);
|
||
}
|
||
|
||
|
||
//
|
||
// Check pending tag queue
|
||
//
|
||
|
||
if (BattNPInfo->CheckTag) {
|
||
BattCCheckTagQueue (BattNPInfo, BattInfo);
|
||
}
|
||
|
||
|
||
//
|
||
// Acquire queue locks
|
||
//
|
||
|
||
ExAcquireFastMutex (&BattNPInfo->Mutex);
|
||
|
||
//
|
||
// While there are outstanding WMI requests handle them
|
||
//
|
||
|
||
while (!IsListEmpty(&BattInfo->WmiQueue)) {
|
||
PBATT_WMI_REQUEST WmiRequest;
|
||
|
||
//
|
||
// Remove entry from WmiQueue and drop device lock
|
||
//
|
||
|
||
Entry = RemoveHeadList(&BattInfo->WmiQueue);
|
||
ExReleaseFastMutex (&BattNPInfo->Mutex);
|
||
|
||
|
||
//
|
||
// Handle this entry
|
||
//
|
||
|
||
WmiRequest = CONTAINING_RECORD (
|
||
Entry,
|
||
BATT_WMI_REQUEST,
|
||
ListEntry
|
||
);
|
||
|
||
BattPrint (BATT_WMI, ("BattC (%d): WorkerThread, Got WMI Rewest - %x\n", BattNPInfo->DeviceNum, WmiRequest));
|
||
|
||
//
|
||
// Process the request here.
|
||
//
|
||
|
||
BattCWmi (BattNPInfo, BattInfo, WmiRequest);
|
||
|
||
//
|
||
// Acquire IoQueue lock and check for anything else in the IoQueueu
|
||
//
|
||
|
||
ExAcquireFastMutex (&BattNPInfo->Mutex);
|
||
}
|
||
|
||
//
|
||
// Done with the IoQueue
|
||
//
|
||
|
||
ExReleaseFastMutex (&BattNPInfo->Mutex);
|
||
|
||
//
|
||
// See if we need to recheck
|
||
//
|
||
|
||
i = InterlockedDecrement(&BattNPInfo->WorkerActive);
|
||
BattPrint (BATT_TRACE, ("BattC (%d): WorkerActive count=%x\n", BattNPInfo->DeviceNum, i));
|
||
|
||
|
||
if (i == 0) {
|
||
// done
|
||
BattPrint (BATT_TRACE, ("BattC (%d): WorkerActive count is zero!\n", BattNPInfo->DeviceNum));
|
||
break;
|
||
}
|
||
|
||
//
|
||
// No need to loop multiple times, if count is not one lower it
|
||
//
|
||
|
||
if (i != 1) {
|
||
BattPrint (BATT_TRACE, ("BattC (%d): WorkerActive set to 1\n", BattNPInfo->DeviceNum));
|
||
InterlockedExchange(&BattNPInfo->WorkerActive, 1);
|
||
}
|
||
}
|
||
|
||
BattPrint ((BATT_TRACE), ("BattC (%d): BatteryCWorkerThread exiting.\n", BattNPInfo->DeviceNum));
|
||
|
||
}
|
||
|
||
VOID
|
||
BattCIoctl (
|
||
IN PBATT_INFO BattInfo,
|
||
IN PIRP Irp,
|
||
IN PIO_STACK_LOCATION IrpSp
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Completes the battery IOCTL request.
|
||
|
||
N.B. must be invoked from the non-rentrant worker thread
|
||
|
||
Arguments:
|
||
|
||
BattInfo - Battery
|
||
|
||
Irp - IOCTL request
|
||
|
||
IrpSp - Current stack location
|
||
|
||
|
||
Return Value:
|
||
|
||
IRP has been completed
|
||
|
||
--*/
|
||
{
|
||
ULONG InputLen, OutputLen;
|
||
PVOID IOBuffer;
|
||
NTSTATUS Status;
|
||
PBATTERY_QUERY_INFORMATION QueryInfo;
|
||
PBATTERY_SET_INFORMATION SetInformation;
|
||
#if DEBUG
|
||
BATTERY_QUERY_INFORMATION_LEVEL inflevel;
|
||
#endif
|
||
|
||
PAGED_CODE();
|
||
|
||
BattPrint ((BATT_TRACE), ("BattC (%d): BattCIoctl called\n", BattInfo->BattNPInfo->DeviceNum));
|
||
|
||
IOBuffer = Irp->AssociatedIrp.SystemBuffer;
|
||
InputLen = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
|
||
OutputLen = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
|
||
|
||
//
|
||
// Dispatch IOCtl request to proper miniport function
|
||
//
|
||
|
||
Status = STATUS_INVALID_BUFFER_SIZE;
|
||
switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) {
|
||
case IOCTL_BATTERY_QUERY_TAG:
|
||
//
|
||
// Query tag only gets here if the input or output buffer lengths are
|
||
// wrong. Return STATUS_INVALID_BUFFER_SIZE
|
||
//
|
||
break;
|
||
|
||
case IOCTL_BATTERY_QUERY_INFORMATION:
|
||
if (InputLen != sizeof (BATTERY_QUERY_INFORMATION)) {
|
||
//
|
||
// Don't check size of the output buffer since it is variable size.
|
||
// This is checked in Mp.QueryInformation
|
||
//
|
||
// Return STATUS_INVALID_BUFFER_SIZE
|
||
//
|
||
break;
|
||
}
|
||
QueryInfo = (PBATTERY_QUERY_INFORMATION) IOBuffer;
|
||
|
||
#if DEBUG
|
||
inflevel = QueryInfo->InformationLevel;
|
||
#endif
|
||
|
||
Status = BattInfo->Mp.QueryInformation (
|
||
BattInfo->Mp.Context,
|
||
QueryInfo->BatteryTag,
|
||
QueryInfo->InformationLevel,
|
||
QueryInfo->AtRate,
|
||
IOBuffer,
|
||
OutputLen,
|
||
&OutputLen
|
||
);
|
||
#if DEBUG
|
||
if (inflevel == BatteryInformation) {
|
||
BattInfo->FullChargedCap = ((PBATTERY_INFORMATION)IOBuffer)->FullChargedCapacity;
|
||
}
|
||
#endif
|
||
BattPrint ((BATT_MP_DATA), ("BattC (%d): Mp.QueryInformation status = %08x, Level = %d\n",
|
||
BattInfo->BattNPInfo->DeviceNum, Status, QueryInfo->InformationLevel));
|
||
break;
|
||
|
||
case IOCTL_BATTERY_QUERY_STATUS:
|
||
|
||
//
|
||
// Query status only gets here if the input or output buffer lengths are
|
||
// wrong. Return STATUS_INVALID_BUFFER_SIZE
|
||
//
|
||
break;
|
||
|
||
case IOCTL_BATTERY_SET_INFORMATION:
|
||
if ((InputLen != sizeof(BATTERY_SET_INFORMATION)) || (OutputLen != 0)) {
|
||
break;
|
||
}
|
||
|
||
SetInformation = (PBATTERY_SET_INFORMATION) IOBuffer;
|
||
if (BattInfo->Mp.SetInformation != NULL) {
|
||
Status = BattInfo->Mp.SetInformation (
|
||
BattInfo->Mp.Context,
|
||
SetInformation->BatteryTag,
|
||
SetInformation->InformationLevel,
|
||
SetInformation->Buffer
|
||
);
|
||
BattPrint ((BATT_MP_DATA), ("BattC (%d): Mp.SetInformation status = %08x, Level = %d\n",
|
||
BattInfo->BattNPInfo->DeviceNum, Status, SetInformation->InformationLevel));
|
||
} else {
|
||
Status = STATUS_NOT_SUPPORTED;
|
||
}
|
||
|
||
break;
|
||
|
||
default:
|
||
Status = STATUS_NOT_IMPLEMENTED;
|
||
break;
|
||
}
|
||
|
||
BattCMiniportStatus (BattInfo, Status);
|
||
Irp->IoStatus.Status = Status;
|
||
Irp->IoStatus.Information = OutputLen;
|
||
IoCompleteRequest (Irp, IO_NO_INCREMENT);
|
||
}
|
||
|
||
VOID
|
||
BattCCheckStatusQueue (
|
||
IN PBATT_NP_INFO BattNPInfo,
|
||
IN PBATT_INFO BattInfo
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Gets the batteries current status, and checks the pending
|
||
status queue for possible IRP completion. Resets the miniport
|
||
notification settings if needed.
|
||
|
||
N.B. Must be invoked from the non-rentrant worker thread.
|
||
BattNPInfo->CheckStatus must be non-zero.
|
||
|
||
Arguments:
|
||
|
||
BattNPInfo - Battery
|
||
|
||
BattInfo - Battery
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
{
|
||
PLIST_ENTRY Entry;
|
||
PBATTERY_WAIT_STATUS BatteryWaitStatus;
|
||
PIRP Irp;
|
||
PIO_STACK_LOCATION IrpSp, IrpNextSp;
|
||
BATTERY_NOTIFY Notify;
|
||
LARGE_INTEGER NextTime;
|
||
LARGE_INTEGER CurrentTime;
|
||
LARGE_INTEGER li;
|
||
ULONG TimeIncrement;
|
||
BOOLEAN ReturnCurrentStatus;
|
||
NTSTATUS Status;
|
||
BOOLEAN StatusNotified;
|
||
|
||
BattPrint ((BATT_TRACE), ("BattC (%d): BattCCheckStatusQueue called\n", BattInfo->BattNPInfo->DeviceNum));
|
||
|
||
PAGED_CODE();
|
||
TimeIncrement = KeQueryTimeIncrement();
|
||
|
||
//
|
||
// Loop while status needs checked, check pending status IRPs
|
||
//
|
||
|
||
while (InterlockedExchange(&BattNPInfo->CheckStatus, 0)) {
|
||
|
||
Notify.PowerState = BattInfo->Status.PowerState;
|
||
Notify.LowCapacity = 0;
|
||
Notify.HighCapacity = (ULONG) -1;
|
||
|
||
//
|
||
// Set to recheck no later than MIN_STATUS_POLL_RATE (3 min) from now.
|
||
//
|
||
|
||
NextTime.QuadPart = MIN_STATUS_POLL_RATE;
|
||
|
||
|
||
//
|
||
// If the StatusQueue is empty, the status doesn't need to be read
|
||
// at this time. BattNPInfo->StatusNotified is not modified
|
||
// so the next time an IRP comes through, we'll re-read the status.
|
||
// The local value of StatusNotified needs to be set correctly to
|
||
// disable notifications if necessary.
|
||
//
|
||
|
||
if (IsListEmpty (&BattInfo->StatusQueue)) {
|
||
StatusNotified = (BOOLEAN)BattNPInfo->StatusNotified;
|
||
break;
|
||
}
|
||
|
||
StatusNotified = FALSE;
|
||
|
||
//
|
||
// Pickup status notified flag
|
||
//
|
||
|
||
if (BattNPInfo->StatusNotified) {
|
||
|
||
InterlockedExchange (&BattNPInfo->StatusNotified, 0);
|
||
StatusNotified = TRUE;
|
||
|
||
// Reset the invalid data retry count when we get a notification.
|
||
#if DEBUG
|
||
if (BattInfo->InvalidRetryCount != 0) {
|
||
BattPrint (BATT_DEBUG, ("BattC (%d) Reset InvalidRetryCount\n", BattNPInfo->DeviceNum));
|
||
}
|
||
#endif
|
||
BattInfo->InvalidRetryCount = 0;
|
||
}
|
||
|
||
KeQueryTickCount (&CurrentTime);
|
||
CurrentTime.QuadPart = CurrentTime.QuadPart * TimeIncrement;
|
||
|
||
if (StatusNotified ||
|
||
CurrentTime.QuadPart - BattInfo->StatusTime > STATUS_VALID_TIME) {
|
||
|
||
//
|
||
// Get the batteries current status
|
||
//
|
||
|
||
Status = BattInfo->Mp.QueryStatus (
|
||
BattInfo->Mp.Context,
|
||
BattInfo->Tag,
|
||
&BattInfo->Status
|
||
);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
//
|
||
// Battery status is not valid, complete all pending status irps
|
||
//
|
||
|
||
BattPrint ((BATT_MP_ERROR), ("BattC (%d) CheckStatus: Status read err = %x\n", BattNPInfo->DeviceNum, Status));
|
||
|
||
BattCCompleteIrpQueue (&(BattInfo->StatusQueue), Status);
|
||
break;
|
||
}
|
||
|
||
BattPrint ((BATT_MP_DATA), ("BattC (%d) MP.QueryStatus: st[%08X] Cap[%08X] V[%08x] R[%08x]\n",
|
||
BattNPInfo->DeviceNum,
|
||
BattInfo->Status.PowerState,
|
||
BattInfo->Status.Capacity,
|
||
BattInfo->Status.Voltage,
|
||
BattInfo->Status.Rate
|
||
));
|
||
|
||
Notify.PowerState = BattInfo->Status.PowerState;
|
||
|
||
//
|
||
// Get the current time to compute timeouts on status query requests
|
||
//
|
||
|
||
KeQueryTickCount (&CurrentTime);
|
||
CurrentTime.QuadPart = CurrentTime.QuadPart * TimeIncrement;
|
||
BattInfo->StatusTime = CurrentTime.QuadPart;
|
||
}
|
||
|
||
//
|
||
// Check each pending Status IRP
|
||
//
|
||
|
||
BattPrint ((BATT_IOCTL_QUEUE), ("BattC (%d) Processing StatusQueue\n", BattNPInfo->DeviceNum));
|
||
|
||
Entry = BattInfo->StatusQueue.Flink;
|
||
while (Entry != &BattInfo->StatusQueue) {
|
||
|
||
//
|
||
// Get IRP to check
|
||
//
|
||
|
||
Irp = CONTAINING_RECORD (
|
||
Entry,
|
||
IRP,
|
||
Tail.Overlay.ListEntry
|
||
);
|
||
|
||
IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
||
IrpNextSp = IoGetNextIrpStackLocation(Irp);
|
||
BatteryWaitStatus = (PBATTERY_WAIT_STATUS) Irp->AssociatedIrp.SystemBuffer;
|
||
|
||
#if DEBUG
|
||
if (BattInfo->FullChargedCap == 0) {
|
||
BattInfo->FullChargedCap = 1000;
|
||
}
|
||
#endif
|
||
BattPrint ((BATT_IOCTL_QUEUE), ("BattC (%d) StatusQueue: 0x%08x=%d -- 0x%08x=%d time=%08x, st=%08x\n",
|
||
BattNPInfo->DeviceNum,
|
||
BatteryWaitStatus->HighCapacity, (ULONG) (((LONGLONG) BatteryWaitStatus->HighCapacity * 1000) / BattInfo->FullChargedCap),
|
||
BatteryWaitStatus->LowCapacity, (ULONG) (((LONGLONG) BatteryWaitStatus->LowCapacity * 1000) / BattInfo->FullChargedCap),
|
||
BatteryWaitStatus->Timeout,
|
||
BatteryWaitStatus->PowerState));
|
||
|
||
//
|
||
// Get next request
|
||
//
|
||
|
||
Entry = Entry->Flink;
|
||
|
||
//
|
||
// If status is in error, or tag no longer matches abort the
|
||
// request accordingly
|
||
//
|
||
|
||
if (BattInfo->Tag != BatteryWaitStatus->BatteryTag) {
|
||
Irp->IoStatus.Status = STATUS_NO_SUCH_DEVICE;
|
||
}
|
||
|
||
//
|
||
// If IRP is flagged as cancelled, complete it
|
||
//
|
||
|
||
if (Irp->Cancel) {
|
||
Irp->IoStatus.Status = STATUS_CANCELLED;
|
||
}
|
||
|
||
//
|
||
// If request is still pending, check it
|
||
//
|
||
|
||
if (Irp->IoStatus.Status == STATUS_PENDING) {
|
||
|
||
ReturnCurrentStatus = FALSE;
|
||
|
||
if (BattInfo->Status.PowerState != BatteryWaitStatus->PowerState ||
|
||
BattInfo->Status.Capacity < BatteryWaitStatus->LowCapacity ||
|
||
BattInfo->Status.Capacity > BatteryWaitStatus->HighCapacity) {
|
||
|
||
BattPrint((BATT_IOCTL_DATA), ("BattC (%d) CheckStatusQueue, Returning Current Status, Asked For:\n"
|
||
"----------- Irp.PowerState = %x\n"
|
||
"----------- Irp.LowCapacity = %x\n"
|
||
"----------- Irp.HighCapacity = %x\n"
|
||
"----------- BattInfo.PowerState = %x\n"
|
||
"----------- BattInfo.Capacity = %x\n",
|
||
BattNPInfo->DeviceNum,
|
||
BatteryWaitStatus->PowerState,
|
||
BatteryWaitStatus->LowCapacity,
|
||
BatteryWaitStatus->HighCapacity,
|
||
BattInfo->Status.PowerState,
|
||
BattInfo->Status.Capacity)
|
||
);
|
||
|
||
//
|
||
// Complete this IRP with the current status
|
||
//
|
||
|
||
ReturnCurrentStatus = TRUE;
|
||
|
||
} else {
|
||
|
||
//
|
||
// Compute time when the request expires
|
||
//
|
||
|
||
BattPrint ((BATT_IOCTL_DATA), ("BattC (%d) CheckStatusQueue: Status Request %x Waiting For:\n"
|
||
"----------- Timeout = %x\n"
|
||
"----------- Irp.PowerState = %x\n"
|
||
"----------- Irp.LowCapacity = %x\n"
|
||
"----------- Irp.HighCapacity = %x\n",
|
||
BattNPInfo->DeviceNum,
|
||
Irp,
|
||
BatteryWaitStatus->Timeout,
|
||
BatteryWaitStatus->PowerState,
|
||
BatteryWaitStatus->LowCapacity,
|
||
BatteryWaitStatus->HighCapacity)
|
||
);
|
||
|
||
if (BatteryWaitStatus->Timeout &&
|
||
IrpNextSp->Parameters.Others.Argument1 == NULL &&
|
||
IrpNextSp->Parameters.Others.Argument2 == NULL) {
|
||
|
||
// initialize it
|
||
li.QuadPart = CurrentTime.QuadPart +
|
||
((ULONGLONG) BatteryWaitStatus->Timeout * NTMS);
|
||
|
||
IrpNextSp->Parameters.Others.Argument1 = (PVOID)((ULONG_PTR)li.LowPart);
|
||
IrpNextSp->Parameters.Others.Argument2 = (PVOID)((ULONG_PTR)li.HighPart);
|
||
}
|
||
|
||
li.LowPart = (ULONG)((ULONG_PTR)IrpNextSp->Parameters.Others.Argument1);
|
||
li.HighPart = (ULONG)((ULONG_PTR)IrpNextSp->Parameters.Others.Argument2);
|
||
li.QuadPart -= CurrentTime.QuadPart;
|
||
|
||
if (li.QuadPart <= 0) {
|
||
|
||
//
|
||
// Time's up, complete it
|
||
//
|
||
|
||
ReturnCurrentStatus = TRUE;
|
||
|
||
} else {
|
||
|
||
//
|
||
// If waiting forever, no need to set a timer
|
||
//
|
||
if (BatteryWaitStatus->Timeout != 0xFFFFFFFF) {
|
||
|
||
//
|
||
// Check if this will be the next timeout time -- we will use
|
||
// the minimum timeout of the pending requests.
|
||
//
|
||
|
||
if (li.QuadPart < NextTime.QuadPart) {
|
||
NextTime.QuadPart = li.QuadPart;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
if (!ReturnCurrentStatus) {
|
||
|
||
//
|
||
// IRP is still pending, calculate LCD of all waiting IRPs
|
||
//
|
||
|
||
if (BatteryWaitStatus->LowCapacity > Notify.LowCapacity) {
|
||
Notify.LowCapacity = BatteryWaitStatus->LowCapacity;
|
||
}
|
||
|
||
if (BatteryWaitStatus->HighCapacity < Notify.HighCapacity) {
|
||
Notify.HighCapacity = BatteryWaitStatus->HighCapacity;
|
||
}
|
||
|
||
} else {
|
||
|
||
//
|
||
// Return current battery status
|
||
//
|
||
|
||
Irp->IoStatus.Status = STATUS_SUCCESS;
|
||
Irp->IoStatus.Information = sizeof(BattInfo->Status);
|
||
RtlCopyMemory (
|
||
Irp->AssociatedIrp.SystemBuffer,
|
||
&BattInfo->Status,
|
||
sizeof(BattInfo->Status)
|
||
);
|
||
}
|
||
}
|
||
|
||
//
|
||
// If this request is no longer pending, complete it
|
||
//
|
||
|
||
if (Irp->IoStatus.Status != STATUS_PENDING) {
|
||
BattPrint (BATT_IOCTL,
|
||
("BattC (%d): completing QueryStatus irp - %x, status - %x\n",
|
||
BattNPInfo->DeviceNum,
|
||
Irp,
|
||
Irp->IoStatus.Status));
|
||
|
||
RemoveEntryList (&Irp->Tail.Overlay.ListEntry);
|
||
IoSetCancelRoutine (Irp, NULL);
|
||
IoCompleteRequest (Irp, IO_NO_INCREMENT);
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
// Status check complete
|
||
//
|
||
|
||
if (IsListEmpty (&BattInfo->StatusQueue)) {
|
||
|
||
//
|
||
// Nothing pending, if being notified disable the notifications
|
||
//
|
||
|
||
if (StatusNotified) {
|
||
BattInfo->Mp.DisableStatusNotify (BattInfo->Mp.Context);
|
||
BattInfo->StatusTime = 0;
|
||
BattPrint ((BATT_MP_DATA), ("BattC (%d) CheckStatus: called Mp.DisableStatusNotify\n", BattNPInfo->DeviceNum));
|
||
}
|
||
|
||
} else {
|
||
|
||
//
|
||
// Set notification setting
|
||
//
|
||
|
||
Status = BattInfo->Mp.SetStatusNotify (
|
||
BattInfo->Mp.Context,
|
||
BattInfo->Tag,
|
||
&Notify
|
||
);
|
||
|
||
if (NT_SUCCESS(Status)) {
|
||
|
||
//
|
||
// New notification set, remember it
|
||
//
|
||
|
||
BattPrint (BATT_MP_DATA, ("BattC (%d) Mp.SetStatusNotify: Notify set for: State=%x, Low=%x, High=%x\n",
|
||
BattNPInfo->DeviceNum,
|
||
Notify.PowerState,
|
||
Notify.LowCapacity,
|
||
Notify.HighCapacity
|
||
));
|
||
|
||
} else {
|
||
|
||
//
|
||
// Could not set notification, handle error
|
||
//
|
||
|
||
BattPrint (BATT_MP_ERROR, ("BattC (%d) Mp.SetStatusNotify: failed (%x), will poll\n", BattNPInfo->DeviceNum, Status));
|
||
BattCMiniportStatus (BattInfo, Status);
|
||
|
||
//
|
||
// Compute poll time
|
||
//
|
||
|
||
li.QuadPart = MIN_STATUS_POLL_RATE;
|
||
if (BattInfo->Status.Capacity == BATTERY_UNKNOWN_CAPACITY) {
|
||
// Retry 10 times at a polling rate of 1 second.
|
||
// Then revert to the slow polling rate.
|
||
if (BattInfo->InvalidRetryCount < INVALID_DATA_MAX_RETRY) {
|
||
BattInfo->InvalidRetryCount++;
|
||
li.QuadPart = INVALID_DATA_POLL_RATE;
|
||
BattPrint (BATT_DEBUG, ("BattC (%d) InvalidRetryCount = %d\n",
|
||
BattNPInfo->DeviceNum, BattInfo->InvalidRetryCount));
|
||
} else {
|
||
BattPrint (BATT_DEBUG, ("BattC (%d) InvalidRetryCount = %d. Using slow polling rate.\n",
|
||
BattNPInfo->DeviceNum, BattInfo->InvalidRetryCount));
|
||
li.QuadPart = MIN_STATUS_POLL_RATE;
|
||
}
|
||
} else if ((BattInfo->Status.Rate != 0) && (BattInfo->Status.Rate != BATTERY_UNKNOWN_RATE)) {
|
||
|
||
if (BattInfo->Status.Rate > 0) {
|
||
|
||
li.QuadPart = Notify.HighCapacity - BattInfo->Status.Capacity;
|
||
|
||
} else if (BattInfo->Status.Rate < 0) {
|
||
|
||
li.QuadPart = Notify.LowCapacity - BattInfo->Status.Capacity;
|
||
}
|
||
|
||
// convert to 3/4 its target time
|
||
|
||
li.QuadPart = li.QuadPart * ((ULONGLONG) NTMIN * 45);
|
||
li.QuadPart = li.QuadPart / (LONGLONG)(BattInfo->Status.Rate);
|
||
|
||
//
|
||
// Bound it
|
||
//
|
||
|
||
if (li.QuadPart > MIN_STATUS_POLL_RATE) {
|
||
// poll at least this fast
|
||
li.QuadPart = MIN_STATUS_POLL_RATE;
|
||
} else if (li.QuadPart < MAX_STATUS_POLL_RATE) {
|
||
// but not faster then this
|
||
li.QuadPart = MAX_STATUS_POLL_RATE;
|
||
}
|
||
}
|
||
|
||
//
|
||
// If sooner then NextTime, adjust NextTime
|
||
//
|
||
|
||
if (li.QuadPart < NextTime.QuadPart) {
|
||
NextTime.QuadPart = li.QuadPart;
|
||
}
|
||
}
|
||
|
||
//
|
||
// If there's a NextTime, queue the timer to recheck
|
||
//
|
||
|
||
if (NextTime.QuadPart) {
|
||
NextTime.QuadPart = -NextTime.QuadPart;
|
||
|
||
//
|
||
// Acquire a remove lock.
|
||
//
|
||
|
||
InterlockedIncrement (&BattNPInfo->InUseCount);
|
||
BattPrint ((BATT_LOCK), ("BattCCheckStatusQueue: Aqcuired remove lock %d (count = %d)\n", BattNPInfo->DeviceNum, BattNPInfo->InUseCount));
|
||
|
||
if (BattNPInfo->WantToRemove == TRUE) {
|
||
//
|
||
// If BatteryClassUnload is waiting to remove the device:
|
||
// Don't set the timer.
|
||
// Release the remove lock just acquired.
|
||
// No need to notify BatteryclassUnload because
|
||
// at this point there is at least one other lock held.
|
||
//
|
||
|
||
InterlockedDecrement(&BattNPInfo->InUseCount);
|
||
BattPrint (BATT_NOTE,
|
||
("BattC (%d) CheckStatus: Poll cancel because of device removal.\n",
|
||
BattNPInfo->DeviceNum));
|
||
BattPrint ((BATT_LOCK), ("BattCCheckStatusQueue: Released remove lock %d (count = %d)\n", BattNPInfo->DeviceNum, BattNPInfo->InUseCount));
|
||
|
||
} else {
|
||
if (KeSetTimer (&BattNPInfo->WorkerTimer, NextTime, &BattNPInfo->WorkerDpc)) {
|
||
//
|
||
// If the timer was already set, we need to release a remove lock since
|
||
// there was already one aquired the last time this timer was set.
|
||
//
|
||
|
||
InterlockedDecrement(&BattNPInfo->InUseCount);
|
||
BattPrint ((BATT_LOCK), ("BattCCheckStatusQueue: Released extra remove lock %d (count = %d)\n", BattNPInfo->DeviceNum, BattNPInfo->InUseCount));
|
||
}
|
||
#if DEBUG
|
||
NextTime.QuadPart = (-NextTime.QuadPart) / (ULONGLONG) NTSEC;
|
||
BattPrint (BATT_NOTE, ("BattC (%d) CheckStatus: Poll in %d seconds (%d minutes)\n",
|
||
BattNPInfo->DeviceNum, NextTime.LowPart, NextTime.LowPart/60));
|
||
#endif
|
||
}
|
||
|
||
} else {
|
||
//
|
||
// There should always be a NextTime.
|
||
//
|
||
ASSERT(FALSE);
|
||
}
|
||
} // if (IsListEmpty (&BattInfo->StatusQueue)) {...} else
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
VOID
|
||
BattCCheckTagQueue (
|
||
IN PBATT_NP_INFO BattNPInfo,
|
||
IN PBATT_INFO BattInfo
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Gets the batteries current tag, and checks the pending
|
||
tag queue for possible IRP completion. Resets the miniport
|
||
notification settings if needed.
|
||
|
||
N.B. must be invoked from the non-reentrant worker thread
|
||
|
||
Arguments:
|
||
|
||
BattNPInfo - Battery
|
||
|
||
BattInfo - Battery
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
{
|
||
PLIST_ENTRY Entry;
|
||
PIRP Irp;
|
||
PIO_STACK_LOCATION IrpSp, IrpNextSp;
|
||
LARGE_INTEGER NextTime;
|
||
LARGE_INTEGER CurrentTime;
|
||
LARGE_INTEGER li;
|
||
ULONG TimeIncrement;
|
||
BOOLEAN ReturnCurrentStatus;
|
||
NTSTATUS Status;
|
||
ULONG batteryTimeout;
|
||
BOOLEAN TagNotified;
|
||
|
||
ULONG tmpTag = BATTERY_TAG_INVALID;
|
||
|
||
BattPrint ((BATT_TRACE), ("BattC (%d): BattCCheckTagQueue called\n", BattInfo->BattNPInfo->DeviceNum));
|
||
|
||
PAGED_CODE();
|
||
TimeIncrement = KeQueryTimeIncrement();
|
||
|
||
//
|
||
// Loop while tag needs checked, check pending tag IRPs
|
||
//
|
||
|
||
while (InterlockedExchange(&BattNPInfo->CheckTag, 0)) {
|
||
NextTime.QuadPart = 0;
|
||
|
||
//
|
||
// If the Tag Queue is empty, done
|
||
// but we need to make sure that we leave TagNotified set to TRUE
|
||
// so the next time an IRP comes through,we'll re-read the tag.
|
||
//
|
||
|
||
if (IsListEmpty (&BattInfo->TagQueue)) {
|
||
break;
|
||
}
|
||
|
||
TagNotified = FALSE;
|
||
|
||
//
|
||
// Pickup tag notified flag
|
||
//
|
||
|
||
if (BattNPInfo->TagNotified) {
|
||
InterlockedExchange (&BattNPInfo->TagNotified, 0);
|
||
TagNotified = TRUE;
|
||
}
|
||
|
||
KeQueryTickCount (&CurrentTime);
|
||
CurrentTime.QuadPart = CurrentTime.QuadPart * TimeIncrement;
|
||
|
||
if (TagNotified ||
|
||
CurrentTime.QuadPart - BattInfo->TagTime > STATUS_VALID_TIME) {
|
||
|
||
//
|
||
// Get the battery's current tag
|
||
//
|
||
|
||
tmpTag = 0;
|
||
Status = BattInfo->Mp.QueryTag (
|
||
BattInfo->Mp.Context,
|
||
&tmpTag
|
||
);
|
||
|
||
|
||
if (!NT_SUCCESS(Status) && (Status != STATUS_NO_SUCH_DEVICE)) {
|
||
//
|
||
// Something went wrong, complete all pending tag irps
|
||
//
|
||
|
||
BattPrint (BATT_MP_ERROR, ("BattC (%d) CheckTag: Tag read err = %x\n", BattNPInfo->DeviceNum, Status));
|
||
BattCMiniportStatus (BattInfo, Status);
|
||
break;
|
||
}
|
||
BattPrint (BATT_MP_DATA, ("BattC (%d) MP.QueryTag: Status = %08x, Tag = %08x\n",
|
||
BattNPInfo->DeviceNum, Status, tmpTag));
|
||
|
||
|
||
if (Status == STATUS_NO_SUCH_DEVICE) {
|
||
//
|
||
// Get the current time to compute timeouts on tag query requests
|
||
//
|
||
|
||
KeQueryTickCount (&CurrentTime);
|
||
CurrentTime.QuadPart = CurrentTime.QuadPart * TimeIncrement;
|
||
BattInfo->TagTime = CurrentTime.QuadPart;
|
||
|
||
}
|
||
}
|
||
|
||
//
|
||
// Check each pending Tag IRP
|
||
//
|
||
|
||
Entry = BattInfo->TagQueue.Flink;
|
||
while (Entry != &BattInfo->TagQueue) {
|
||
|
||
//
|
||
// Get IRP to check
|
||
//
|
||
|
||
Irp = CONTAINING_RECORD (
|
||
Entry,
|
||
IRP,
|
||
Tail.Overlay.ListEntry
|
||
);
|
||
|
||
IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
||
IrpNextSp = IoGetNextIrpStackLocation(Irp);
|
||
if (IrpSp->Parameters.DeviceIoControl.InputBufferLength == 0) {
|
||
//
|
||
// If no input was given, then use timeout of 0.
|
||
//
|
||
batteryTimeout = 0;
|
||
} else {
|
||
batteryTimeout = *((PULONG) Irp->AssociatedIrp.SystemBuffer);
|
||
}
|
||
|
||
//
|
||
// Get next request
|
||
//
|
||
|
||
Entry = Entry->Flink;
|
||
|
||
|
||
//
|
||
// If IRP is flagged as cancelled, complete it
|
||
//
|
||
|
||
if (Irp->Cancel) {
|
||
BattPrint (BATT_IOCTL, ("BattC (%d): QueryTag irp cancelled - %x\n", BattNPInfo->DeviceNum, Irp));
|
||
Irp->IoStatus.Status = STATUS_CANCELLED;
|
||
}
|
||
|
||
|
||
//
|
||
// If request is still pending, check it
|
||
//
|
||
|
||
if (Irp->IoStatus.Status == STATUS_PENDING) {
|
||
|
||
ReturnCurrentStatus = FALSE;
|
||
if (tmpTag != BATTERY_TAG_INVALID) {
|
||
|
||
//
|
||
// Complete this IRP with the current tag
|
||
//
|
||
|
||
ReturnCurrentStatus = TRUE;
|
||
Irp->IoStatus.Status = STATUS_SUCCESS;
|
||
} else {
|
||
|
||
//
|
||
// Compute time when the request expires, the battery tag
|
||
// is an input parameter that holds the timeout.
|
||
//
|
||
|
||
if (batteryTimeout &&
|
||
IrpNextSp->Parameters.Others.Argument1 == NULL &&
|
||
IrpNextSp->Parameters.Others.Argument2 == NULL) {
|
||
|
||
// initialize it
|
||
li.QuadPart = CurrentTime.QuadPart + ((ULONGLONG) batteryTimeout * NTMS);
|
||
|
||
IrpNextSp->Parameters.Others.Argument1 = (PVOID)((ULONG_PTR)li.LowPart);
|
||
IrpNextSp->Parameters.Others.Argument2 = (PVOID)((ULONG_PTR)li.HighPart);
|
||
|
||
}
|
||
|
||
li.LowPart = (ULONG)((ULONG_PTR)IrpNextSp->Parameters.Others.Argument1);
|
||
li.HighPart = (ULONG)((ULONG_PTR)IrpNextSp->Parameters.Others.Argument2);
|
||
li.QuadPart -= CurrentTime.QuadPart;
|
||
|
||
if (li.QuadPart <= 0) {
|
||
|
||
//
|
||
// Time's up, complete it
|
||
//
|
||
|
||
BattPrint ((BATT_NOTE | BATT_IOCTL), ("BattC (%d): QueryTag irp timeout - %x\n", BattNPInfo->DeviceNum, Irp));
|
||
ReturnCurrentStatus = TRUE;
|
||
Irp->IoStatus.Status = STATUS_NO_SUCH_DEVICE;
|
||
|
||
} else {
|
||
|
||
//
|
||
// If waiting forever, no need to set a timer
|
||
//
|
||
if (batteryTimeout != 0xFFFFFFFF) {
|
||
|
||
//
|
||
// Check if this is the next timeout time
|
||
//
|
||
|
||
if (NextTime.QuadPart == 0 || li.QuadPart < NextTime.QuadPart) {
|
||
NextTime.QuadPart = li.QuadPart;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
if (ReturnCurrentStatus) {
|
||
|
||
//
|
||
// Return current battery status
|
||
//
|
||
|
||
*((PULONG) Irp->AssociatedIrp.SystemBuffer) = tmpTag;
|
||
Irp->IoStatus.Information = sizeof(ULONG);
|
||
if (BattInfo->Tag != tmpTag) {
|
||
|
||
//
|
||
// This is a new battery tag, capture tag
|
||
//
|
||
|
||
BattInfo->Tag = tmpTag;
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
// If this request is no longer pending, complete it
|
||
//
|
||
|
||
if (Irp->IoStatus.Status != STATUS_PENDING) {
|
||
RemoveEntryList (&Irp->Tail.Overlay.ListEntry);
|
||
IoSetCancelRoutine (Irp, NULL);
|
||
|
||
BattPrint (
|
||
(BATT_IOCTL),
|
||
("BattC (%d): CheckTag completing request, IRP = %x, status = %x\n",
|
||
BattNPInfo->DeviceNum,
|
||
Irp,
|
||
Irp->IoStatus.Status)
|
||
);
|
||
|
||
IoCompleteRequest (Irp, IO_NO_INCREMENT);
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
// If there's a NextTime, queue the timer to recheck.
|
||
// This means there is a tag request with a timout other than 0 or -1.
|
||
//
|
||
|
||
if (NextTime.QuadPart) {
|
||
NextTime.QuadPart = -NextTime.QuadPart;
|
||
|
||
//
|
||
// Acquire a remove lock.
|
||
//
|
||
|
||
InterlockedIncrement (&BattNPInfo->InUseCount);
|
||
BattPrint ((BATT_LOCK), ("BattCCheckTagQueue: Aqcuired remove lock %d (count = %d)\n", BattNPInfo->DeviceNum, BattNPInfo->InUseCount));
|
||
|
||
if (BattNPInfo->WantToRemove == TRUE) {
|
||
//
|
||
// If BatteryClassUnload is waiting to remove the device:
|
||
// Don't set the timer.
|
||
// Release the remove lock just acquired.
|
||
// No need to notify BatteryclassUnload because
|
||
// at this point there is at least one other lock held.
|
||
//
|
||
|
||
InterlockedDecrement(&BattNPInfo->InUseCount);
|
||
BattPrint (BATT_NOTE,
|
||
("BattC (%d) CheckTag: Poll cancel because of device removal.\n",
|
||
BattNPInfo->DeviceNum));
|
||
BattPrint ((BATT_LOCK), ("BattCCheckTagQueue: Released remove lock %d (count = %d)\n", BattNPInfo->DeviceNum, BattNPInfo->InUseCount));
|
||
} else {
|
||
if (KeSetTimer (&BattNPInfo->TagTimer, NextTime, &BattNPInfo->TagDpc)){
|
||
//
|
||
// If the timer was already set, we need to release a remove lock since
|
||
// there was already one aquired the last time this timer was set.
|
||
//
|
||
|
||
InterlockedDecrement(&BattNPInfo->InUseCount);
|
||
BattPrint ((BATT_LOCK), ("BattCCheckTagQueue: Released extra remove lock %d (count = %d)\n", BattNPInfo->DeviceNum, BattNPInfo->InUseCount));
|
||
}
|
||
#if DEBUG
|
||
NextTime.QuadPart = NextTime.QuadPart / -NTSEC;
|
||
BattPrint (BATT_NOTE, ("BattC (%d) CheckTag: Poll in %x seconds\n", BattNPInfo->DeviceNum, NextTime.LowPart));
|
||
#endif
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
|
||
|
||
VOID
|
||
BattCWmi (
|
||
IN PBATT_NP_INFO BattNPInfo,
|
||
IN PBATT_INFO BattInfo,
|
||
IN PBATT_WMI_REQUEST WmiRequest
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Processes a single WMI request.
|
||
|
||
N.B. must be invoked from the non-reentrant worker thread
|
||
|
||
Arguments:
|
||
|
||
BattNPInfo - Battery
|
||
|
||
BattInfo - Battery
|
||
|
||
WmiRequest - Wmi Request to process
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
{
|
||
|
||
NTSTATUS status = STATUS_SUCCESS;
|
||
ULONG size = 0;
|
||
ULONG OutputLen;
|
||
BATTERY_INFORMATION batteryInformation;
|
||
PWCHAR tempString;
|
||
|
||
BattPrint((BATT_WMI), ("BattCWmi (%d): GuidIndex = 0x%x\n",
|
||
BattNPInfo->DeviceNum, WmiRequest->GuidIndex));
|
||
|
||
switch (WmiRequest->GuidIndex) {
|
||
case BattWmiStatusId:
|
||
size = sizeof (BATTERY_WMI_STATUS);
|
||
((PBATTERY_WMI_STATUS) WmiRequest->Buffer)->Tag = BattInfo->Tag;
|
||
((PBATTERY_WMI_STATUS) WmiRequest->Buffer)->RemainingCapacity = BattInfo->Status.Capacity;
|
||
if (BattInfo->Status.Rate < 0) {
|
||
((PBATTERY_WMI_STATUS) WmiRequest->Buffer)->ChargeRate = 0;
|
||
((PBATTERY_WMI_STATUS) WmiRequest->Buffer)->DischargeRate = -BattInfo->Status.Rate;
|
||
} else {
|
||
((PBATTERY_WMI_STATUS) WmiRequest->Buffer)->ChargeRate = BattInfo->Status.Rate;
|
||
((PBATTERY_WMI_STATUS) WmiRequest->Buffer)->DischargeRate = 0;
|
||
}
|
||
((PBATTERY_WMI_STATUS) WmiRequest->Buffer)->Voltage = BattInfo->Status.Voltage;
|
||
((PBATTERY_WMI_STATUS) WmiRequest->Buffer)->PowerOnline =
|
||
(BattInfo->Status.PowerState & BATTERY_POWER_ON_LINE) ? TRUE : FALSE;
|
||
((PBATTERY_WMI_STATUS) WmiRequest->Buffer)->Charging =
|
||
(BattInfo->Status.PowerState & BATTERY_CHARGING) ? TRUE : FALSE;
|
||
((PBATTERY_WMI_STATUS) WmiRequest->Buffer)->Discharging =
|
||
(BattInfo->Status.PowerState & BATTERY_DISCHARGING) ? TRUE : FALSE;
|
||
((PBATTERY_WMI_STATUS) WmiRequest->Buffer)->Critical =
|
||
(BattInfo->Status.PowerState & BATTERY_CRITICAL) ? TRUE : FALSE;
|
||
BattPrint((BATT_WMI), ("BattCWmi (%d): BatteryStatus\n",
|
||
BattNPInfo->DeviceNum));
|
||
break;
|
||
case BattWmiRuntimeId:
|
||
size = sizeof (BATTERY_WMI_RUNTIME);
|
||
((PBATTERY_WMI_RUNTIME) WmiRequest->Buffer)->Tag = BattInfo->Tag;
|
||
status = BattInfo->Mp.QueryInformation (
|
||
BattInfo->Mp.Context,
|
||
BattInfo->Tag,
|
||
BatteryEstimatedTime,
|
||
0,
|
||
&((PBATTERY_WMI_RUNTIME) WmiRequest->Buffer)->EstimatedRuntime,
|
||
sizeof(ULONG),
|
||
&OutputLen
|
||
);
|
||
|
||
BattPrint((BATT_WMI), ("BattCWmi (%d): EstimateRuntime = %08x, Status = 0x%08x\n",
|
||
BattNPInfo->DeviceNum, &((PBATTERY_WMI_RUNTIME) WmiRequest->Buffer)->EstimatedRuntime, status));
|
||
break;
|
||
case BattWmiTemperatureId:
|
||
size = sizeof (BATTERY_WMI_TEMPERATURE);
|
||
((PBATTERY_WMI_TEMPERATURE) WmiRequest->Buffer)->Tag = BattInfo->Tag;
|
||
status = BattInfo->Mp.QueryInformation (
|
||
BattInfo->Mp.Context,
|
||
BattInfo->Tag,
|
||
BatteryTemperature,
|
||
0,
|
||
&((PBATTERY_WMI_TEMPERATURE) WmiRequest->Buffer)->Temperature,
|
||
sizeof(ULONG),
|
||
&OutputLen
|
||
);
|
||
|
||
BattPrint((BATT_WMI), ("BattCWmi (%d): Temperature = %08x, Status = 0x%08x\n",
|
||
BattNPInfo->DeviceNum, &((PBATTERY_WMI_TEMPERATURE) WmiRequest->Buffer)->Temperature, status));
|
||
break;
|
||
case BattWmiFullChargedCapacityId:
|
||
size = sizeof (BATTERY_WMI_FULL_CHARGED_CAPACITY);
|
||
((PBATTERY_WMI_FULL_CHARGED_CAPACITY) WmiRequest->Buffer)->Tag = BattInfo->Tag;
|
||
status = BattInfo->Mp.QueryInformation (
|
||
BattInfo->Mp.Context,
|
||
BattInfo->Tag,
|
||
BatteryInformation,
|
||
0,
|
||
&batteryInformation,
|
||
sizeof(BATTERY_INFORMATION),
|
||
&OutputLen
|
||
);
|
||
((PBATTERY_WMI_FULL_CHARGED_CAPACITY) WmiRequest->Buffer)->FullChargedCapacity =
|
||
batteryInformation.FullChargedCapacity;
|
||
|
||
BattPrint((BATT_WMI), ("BattCWmi (%d): FullChargedCapacity = %08x, Status = 0x%08x\n",
|
||
BattNPInfo->DeviceNum, ((PBATTERY_WMI_FULL_CHARGED_CAPACITY) WmiRequest->Buffer)->FullChargedCapacity, status));
|
||
break;
|
||
case BattWmiCycleCountId:
|
||
size = sizeof (BATTERY_WMI_CYCLE_COUNT);
|
||
((PBATTERY_WMI_CYCLE_COUNT) WmiRequest->Buffer)->Tag = BattInfo->Tag;
|
||
status = BattInfo->Mp.QueryInformation (
|
||
BattInfo->Mp.Context,
|
||
BattInfo->Tag,
|
||
BatteryInformation,
|
||
0,
|
||
&batteryInformation,
|
||
sizeof(BATTERY_INFORMATION),
|
||
&OutputLen
|
||
);
|
||
((PBATTERY_WMI_CYCLE_COUNT) WmiRequest->Buffer)->CycleCount =
|
||
batteryInformation.CycleCount;
|
||
|
||
BattPrint((BATT_WMI), ("BattCWmi (%d): CycleCount = %08x, Status = 0x%08x\n",
|
||
BattNPInfo->DeviceNum, ((PBATTERY_WMI_CYCLE_COUNT) WmiRequest->Buffer)->CycleCount, status));
|
||
break;
|
||
case BattWmiStaticDataId:
|
||
size = sizeof(BATTERY_WMI_STATIC_DATA)+4*MAX_BATTERY_STRING_SIZE*sizeof(WCHAR);
|
||
((PBATTERY_WMI_STATIC_DATA) WmiRequest->Buffer)->Tag = BattInfo->Tag;
|
||
// ((PBATTERY_WMI_STATIC_DATA) WmiRequest->Buffer)->ManufacturerDate[0] =
|
||
// ((PBATTERY_WMI_STATIC_DATA) WmiRequest->Buffer)->Granularity =
|
||
|
||
status = BattInfo->Mp.QueryInformation (
|
||
BattInfo->Mp.Context,
|
||
BattInfo->Tag,
|
||
BatteryInformation,
|
||
0,
|
||
&batteryInformation,
|
||
sizeof(BATTERY_INFORMATION),
|
||
&OutputLen
|
||
);
|
||
|
||
if (NT_SUCCESS(status)) {
|
||
|
||
((PBATTERY_WMI_STATIC_DATA) WmiRequest->Buffer)->Capabilities =
|
||
batteryInformation.Capabilities;
|
||
((PBATTERY_WMI_STATIC_DATA) WmiRequest->Buffer)->Technology =
|
||
batteryInformation.Technology;
|
||
((PBATTERY_WMI_STATIC_DATA) WmiRequest->Buffer)->Chemistry =
|
||
*(PULONG)batteryInformation.Chemistry;
|
||
((PBATTERY_WMI_STATIC_DATA) WmiRequest->Buffer)->DesignedCapacity =
|
||
batteryInformation.DesignedCapacity;
|
||
((PBATTERY_WMI_STATIC_DATA) WmiRequest->Buffer)->DefaultAlert1 =
|
||
batteryInformation.DefaultAlert1;
|
||
((PBATTERY_WMI_STATIC_DATA) WmiRequest->Buffer)->DefaultAlert2 =
|
||
batteryInformation.DefaultAlert2;
|
||
((PBATTERY_WMI_STATIC_DATA) WmiRequest->Buffer)->CriticalBias =
|
||
batteryInformation.CriticalBias;
|
||
|
||
tempString = ((PBATTERY_WMI_STATIC_DATA) WmiRequest->Buffer)->Strings;
|
||
status = BattInfo->Mp.QueryInformation (
|
||
BattInfo->Mp.Context,
|
||
BattInfo->Tag,
|
||
BatteryDeviceName,
|
||
0,
|
||
&tempString[1],
|
||
MAX_BATTERY_STRING_SIZE,
|
||
&OutputLen
|
||
);
|
||
if (!NT_SUCCESS(status)) {
|
||
// Some batteries may not support some types of Information Queries
|
||
// Don't fail request, simply leave this one blank.
|
||
OutputLen = 0;
|
||
}
|
||
|
||
tempString[0] = (USHORT) OutputLen;
|
||
|
||
tempString = (PWCHAR) ((PCHAR) &tempString[1] + tempString[0]);
|
||
status = BattInfo->Mp.QueryInformation (
|
||
BattInfo->Mp.Context,
|
||
BattInfo->Tag,
|
||
BatteryManufactureName,
|
||
0,
|
||
&tempString[1],
|
||
MAX_BATTERY_STRING_SIZE,
|
||
&OutputLen
|
||
);
|
||
if (!NT_SUCCESS(status)) {
|
||
// Some batteries may not support some types of Information Queries
|
||
// Don't fail request, simply leave this one blank.
|
||
OutputLen = 0;
|
||
}
|
||
|
||
tempString[0] = (USHORT) OutputLen;
|
||
|
||
tempString = (PWCHAR) ((PCHAR) &tempString[1] + tempString[0]);
|
||
status = BattInfo->Mp.QueryInformation (
|
||
BattInfo->Mp.Context,
|
||
BattInfo->Tag,
|
||
BatterySerialNumber,
|
||
0,
|
||
&tempString[1],
|
||
MAX_BATTERY_STRING_SIZE,
|
||
&OutputLen
|
||
);
|
||
if (!NT_SUCCESS(status)) {
|
||
// Some batteries may not support some types of Information Queries
|
||
// Don't fail request, simply leave this one blank.
|
||
OutputLen = 0;
|
||
}
|
||
|
||
tempString[0] = (USHORT) OutputLen;
|
||
|
||
tempString = (PWCHAR) ((PCHAR) &tempString[1] + tempString[0]);
|
||
status = BattInfo->Mp.QueryInformation (
|
||
BattInfo->Mp.Context,
|
||
BattInfo->Tag,
|
||
BatteryUniqueID,
|
||
0,
|
||
&tempString[1],
|
||
MAX_BATTERY_STRING_SIZE,
|
||
&OutputLen
|
||
);
|
||
if (!NT_SUCCESS(status)) {
|
||
// Some batteries may not support some types of Information Queries
|
||
// Don't fail request, simply leave this one blank.
|
||
OutputLen = 0;
|
||
status = STATUS_SUCCESS;
|
||
}
|
||
|
||
tempString[0] = (USHORT) OutputLen;
|
||
|
||
tempString = (PWCHAR) ((PCHAR) &tempString[1] + tempString[0]);
|
||
size = (ULONG)(sizeof(BATTERY_WMI_STATIC_DATA)+(tempString - ((PBATTERY_WMI_STATIC_DATA) WmiRequest->Buffer)->Strings));
|
||
}
|
||
|
||
break;
|
||
default:
|
||
status = STATUS_WMI_GUID_NOT_FOUND;
|
||
}
|
||
|
||
*WmiRequest->InstanceLengthArray = size;
|
||
status = WmiCompleteRequest(WmiRequest->DeviceObject,
|
||
WmiRequest->Irp,
|
||
status,
|
||
size,
|
||
IO_NO_INCREMENT);
|
||
|
||
|
||
}
|
||
|
||
|
||
|
||
|
||
VOID
|
||
BattCMiniportStatus (
|
||
IN PBATT_INFO BattInfo,
|
||
IN NTSTATUS Status
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Function to return status from miniport. If the battery tag has gone
|
||
invalid the pending statuses are aborted.
|
||
|
||
N.B. must be invoked from the non-rentrant worker thread
|
||
|
||
Arguments:
|
||
|
||
BattInfo - Battery
|
||
|
||
Status - Status from miniport.
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
{
|
||
if (NT_SUCCESS(Status)) {
|
||
return ;
|
||
}
|
||
|
||
switch (Status) {
|
||
#if DEBUG
|
||
case STATUS_SUCCESS:
|
||
case STATUS_NOT_IMPLEMENTED:
|
||
case STATUS_BUFFER_TOO_SMALL:
|
||
case STATUS_INVALID_BUFFER_SIZE:
|
||
case STATUS_NOT_SUPPORTED:
|
||
case STATUS_INVALID_PARAMETER:
|
||
case STATUS_OBJECT_NAME_NOT_FOUND:
|
||
case STATUS_INVALID_DEVICE_REQUEST:
|
||
// no action
|
||
break;
|
||
|
||
default:
|
||
BattPrint (BATT_ERROR, ("BattCMiniportStatus: unknown status from miniport: %x BattInfo %x\n",
|
||
Status, BattInfo));
|
||
break;
|
||
|
||
#endif
|
||
case STATUS_NO_SUCH_DEVICE:
|
||
|
||
//
|
||
// Our battery tag is wrong. Cancel any queued status irps
|
||
//
|
||
|
||
BattCCompleteIrpQueue (&(BattInfo->StatusQueue), Status);
|
||
break;
|
||
}
|
||
}
|
||
|
||
|
||
VOID
|
||
BattCCompleteIrpQueue (
|
||
IN PLIST_ENTRY Queue,
|
||
IN NTSTATUS Status
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Complete all pending Irps in the IoQueue, TagQueue, or StatusQueue.
|
||
|
||
N.B. must be invoked from the non-rentrant worker thread
|
||
|
||
Arguments:
|
||
|
||
BattInfo - Battery
|
||
|
||
Status - Error status to complete pending status request with
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
{
|
||
PLIST_ENTRY Entry;
|
||
PIRP Irp;
|
||
|
||
ASSERT (!NT_SUCCESS(Status));
|
||
|
||
BattPrint (BATT_TRACE, ("BattC: ENTERING BattCCompleteIrpQueue\n"));
|
||
|
||
while (!IsListEmpty(Queue)) {
|
||
Entry = RemoveHeadList (Queue);
|
||
|
||
Irp = CONTAINING_RECORD (
|
||
Entry,
|
||
IRP,
|
||
Tail.Overlay.ListEntry
|
||
);
|
||
|
||
//
|
||
// Use Cancel Spinlock to make sure that Completion routine isn't being called
|
||
//
|
||
|
||
IoAcquireCancelSpinLock (&Irp->CancelIrql);
|
||
IoSetCancelRoutine (Irp, NULL);
|
||
IoReleaseCancelSpinLock(Irp->CancelIrql);
|
||
|
||
BattPrint (BATT_NOTE, ("BattC: Completing IRP 0x%0lx at IRQL %d.\n", Irp, KeGetCurrentIrql()));
|
||
Irp->IoStatus.Status = Status;
|
||
IoCompleteRequest (Irp, IO_NO_INCREMENT);
|
||
}
|
||
|
||
BattPrint (BATT_TRACE, ("BattC: EXITING BattCCompleteIrpQueue\n"));
|
||
}
|
||
|
||
|
||
VOID
|
||
BattCCompleteWmiQueue (
|
||
IN PLIST_ENTRY Queue,
|
||
IN NTSTATUS Status
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Complete all pending Irps in the IoQueue, TagQueue, or StatusQueue.
|
||
|
||
N.B. must be invoked from the non-rentrant worker thread
|
||
|
||
Arguments:
|
||
|
||
BattInfo - Battery
|
||
|
||
Status - Error status to complete pending status request with
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
{
|
||
PLIST_ENTRY Entry;
|
||
PBATT_WMI_REQUEST WmiRequest;
|
||
|
||
ASSERT (!NT_SUCCESS(Status));
|
||
|
||
BattPrint (BATT_TRACE, ("BattC: ENTERING BattCCompleteWmiQueue\n"));
|
||
|
||
while (!IsListEmpty(Queue)) {
|
||
Entry = RemoveHeadList (Queue);
|
||
|
||
WmiRequest = CONTAINING_RECORD (
|
||
Entry,
|
||
BATT_WMI_REQUEST,
|
||
ListEntry
|
||
);
|
||
|
||
BattPrint (BATT_NOTE, ("BattC: Completing Wmi Request 0x%0lx at IRQL %d.\n", WmiRequest, KeGetCurrentIrql()));
|
||
|
||
*WmiRequest->InstanceLengthArray = 0;
|
||
WmiCompleteRequest(WmiRequest->DeviceObject,
|
||
WmiRequest->Irp,
|
||
Status,
|
||
0,
|
||
IO_NO_INCREMENT);
|
||
|
||
|
||
}
|
||
|
||
BattPrint (BATT_TRACE, ("BattC: EXITING BattCCompleteWmiQueue\n"));
|
||
}
|
||
|