windows-nt/Source/XPSP1/NT/base/busdrv/acpi/battc/battc.c
2020-09-26 16:20:57 +08:00

923 lines
28 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 1990 Microsoft Corporation
Module Name:
battc.c
Abstract:
Battery Class Driver
Author:
Ken Reneris
Environment:
Notes:
Revision History:
--*/
#include "battcp.h"
#include <initguid.h>
#include <batclass.h>
WMIGUIDREGINFO BattWmiGuidList[BattWmiTotalGuids] =
{
{
&BATTERY_STATUS_WMI_GUID, 1, WMIREG_FLAG_INSTANCE_PDO
},
{
&BATTERY_RUNTIME_WMI_GUID, 1, WMIREG_FLAG_INSTANCE_PDO
},
{
&BATTERY_TEMPERATURE_WMI_GUID, 1, WMIREG_FLAG_INSTANCE_PDO
},
{
&BATTERY_FULL_CHARGED_CAPACITY_WMI_GUID, 1, WMIREG_FLAG_INSTANCE_PDO
},
{
&BATTERY_CYCLE_COUNT_WMI_GUID, 1, WMIREG_FLAG_INSTANCE_PDO
},
{
&BATTERY_STATIC_DATA_WMI_GUID, 1, WMIREG_FLAG_INSTANCE_PDO
},
{
&BATTERY_STATUS_CHANGE_WMI_GUID, 1, WMIREG_FLAG_INSTANCE_PDO
},
{
&BATTERY_TAG_CHANGE_WMI_GUID, 1, WMIREG_FLAG_INSTANCE_PDO
}
};
//
// Prototypes
//
NTSTATUS
DriverEntry (
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE,DriverEntry)
#pragma alloc_text(PAGE,BatteryClassInitializeDevice)
#pragma alloc_text(PAGE,BatteryClassUnload)
#pragma alloc_text(PAGE,BatteryClassIoctl)
#endif
#if DEBUG
#if DBG
ULONG BattDebug = BATT_ERROR|BATT_WARN;
#else
ULONG BattDebug = 0x0;
#endif
ULONG NextDeviceNum = 0; // Used to assign a unique number to each device for debugging.
#endif
NTSTATUS
DriverEntry (
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
{
return STATUS_SUCCESS;
}
NTSTATUS
BATTERYCLASSAPI
BatteryClassInitializeDevice (
IN PBATTERY_MINIPORT_INFO MiniportInfo,
IN PVOID *ClassData
)
/*++
Routine Description:
Initializes a new battery class device.
N.B. The caller needs to reserve 1 IRP stack location for the
battery class driver
Arguments:
MiniportInfo - Pointer to registration structure for driver
registering as a battery miniport
ClassData - Returned battery class handle for use by the
miniport when invoking furture battery class functions
Return Value:
On sucess the battery has been registered.
--*/
{
PBATT_NP_INFO BattNPInfo;
PBATT_INFO BattInfo;
NTSTATUS status = STATUS_SUCCESS;
PAGED_CODE();
#if DEBUG
if (MiniportInfo->DeviceName && MiniportInfo->DeviceName->Buffer) {
BattPrint ((BATT_TRACE), ("BattC (%d): InitializeDevice (Pdo = 0x%08lx) (DeviceName = %ws)\n", NextDeviceNum, MiniportInfo->Pdo, MiniportInfo->DeviceName->Buffer));
} else {
BattPrint ((BATT_TRACE), ("BattC (%d): InitializeDevice (Pdo = 0x%08lx)\n", NextDeviceNum, MiniportInfo->Pdo));
}
#endif
if (MiniportInfo->MajorVersion != BATTERY_CLASS_MAJOR_VERSION) {
return STATUS_REVISION_MISMATCH;
}
//
// Allocate space for the class info to be kept with this device instance
//
BattNPInfo = ExAllocatePoolWithTag(NonPagedPool, sizeof(BATT_NP_INFO), 'ttaB');
if (!BattNPInfo) {
return STATUS_INSUFFICIENT_RESOURCES;
}
BattInfo = ExAllocatePoolWithTag(PagedPool, sizeof(BATT_INFO), 'ttaB');
if (!BattInfo) {
ExFreePool (BattNPInfo);
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlZeroMemory (BattNPInfo, sizeof(*BattNPInfo));
RtlZeroMemory (BattInfo, sizeof(*BattInfo));
//
// Capture Miniport info
//
RtlCopyMemory (&BattInfo->Mp, MiniportInfo, sizeof(*MiniportInfo));
//
// Initilize class driver values
//
KeInitializeTimer (&BattNPInfo->WorkerTimer);
KeInitializeTimer (&BattNPInfo->TagTimer);
KeInitializeDpc (&BattNPInfo->WorkerDpc, BattCWorkerDpc, BattNPInfo);
KeInitializeDpc (&BattNPInfo->TagDpc, BattCTagDpc, BattNPInfo);
ExInitializeWorkItem (&BattNPInfo->WorkerThread, BattCWorkerThread, BattNPInfo);
ExInitializeFastMutex (&BattNPInfo->Mutex);
BattNPInfo->TagNotified = TRUE;
BattNPInfo->StatusNotified = TRUE;
BattNPInfo->BattInfo = BattInfo;
#if DEBUG
BattInfo->BattNPInfo = BattNPInfo;
#endif
BattInfo->Tag = BATTERY_TAG_INVALID;
InitializeListHead (&BattInfo->IoQueue);
InitializeListHead (&BattInfo->StatusQueue);
InitializeListHead (&BattInfo->TagQueue);
InitializeListHead (&BattInfo->WmiQueue);
//
// Removal lock initialization
//
BattNPInfo->WantToRemove = FALSE;
//
// InUseCount is set to 2. 1 lock is always held until the removal time.
// 1 additional lock is held for the worker thread which only releases it
// at removal time. Rather than aquiring and releasing each time, it just
// checks WantToRemove to determine if it should release the lock.
//
BattNPInfo->InUseCount = 2;
KeInitializeEvent(&BattNPInfo->ReadyToRemove, SynchronizationEvent, FALSE);
#if DEBUG // Set device Number for debug prints.
BattNPInfo->DeviceNum = NextDeviceNum;
NextDeviceNum++;
#endif
*ClassData = BattNPInfo;
//
// Check to see if this is a battery other than the composite
//
if (MiniportInfo->Pdo) {
// Blank UNICODE_STRING so IoRegisterDeviceInterface will allocate space.
RtlInitUnicodeString (&BattInfo->SymbolicLinkName, NULL);
//
// Create the symbolic link
//
status = IoRegisterDeviceInterface(
MiniportInfo->Pdo,
(LPGUID)&GUID_DEVICE_BATTERY,
NULL,
&BattInfo->SymbolicLinkName);
if (NT_SUCCESS(status)) {
//
// Now set the symbolic link for the association and store it..
//
BattPrint ((BATT_NOTE), ("BattC (%d): Making SetDeviceInterfaceState call.\n", BattNPInfo->DeviceNum));
status = IoSetDeviceInterfaceState(&BattInfo->SymbolicLinkName, TRUE);
if (status == STATUS_OBJECT_NAME_EXISTS) {
// The device interface was already enabled. Continue anyway.
BattPrint ((BATT_WARN), ("BattC (%d): Got STATUS_OBJECT_NAME_EXISTS for SetDeviceInterfaceState\n", BattNPInfo->DeviceNum));
status = STATUS_SUCCESS;
}
}
}
BattPrint ((BATT_TRACE), ("BattC (%d): BatteryClassInitializeDevice (status = 0x%08lx).\n", BattNPInfo->DeviceNum, status));
return status;
} // BatteryClassInitializeDevice
NTSTATUS
BATTERYCLASSAPI
BatteryClassUnload (
IN PVOID ClassData
)
/*++
Routine Description:
Called by the miniport when it has received a remove request.
The miniclass driver must syncronize itself so that this API is
not called while any of the others are not yet completed.
Arguments:
ClassData - Handle to class driver
Return Value:
This routine must not fail. It returns STATUS_SUCCESS
--*/
{
NTSTATUS status;
PBATT_INFO BattInfo;
PBATT_NP_INFO BattNPInfo;
PAGED_CODE();
BattNPInfo = (PBATT_NP_INFO) ClassData;
BattInfo = BattNPInfo->BattInfo;
BattPrint ((BATT_TRACE), ("BattC (%d): BatteryClassUnload called.\n", BattNPInfo->DeviceNum));
//
// Disable the symbolic link
//
ASSERT(BattInfo->SymbolicLinkName.Buffer);
status = IoSetDeviceInterfaceState(&BattInfo->SymbolicLinkName, FALSE);
if (!NT_SUCCESS(status)) {
BattPrint (BATT_ERROR, ("BattC (%d) Unload: IoSetDeviceInterface returned 0x%08lx\n", BattNPInfo->DeviceNum, status));
}
//
// Syncronization with the worker thread.
// We can't return because the worker may be in the middle of something.
// By returning, the battery class driver gives up the right to call miniport routines.
//
// This needs to be done before canceling the timers so that the worker
// thread doesn't reset them.
//
BattNPInfo->WantToRemove = TRUE;
//
// Cancel timers
// If a timer had been waiting,we need to release the remove lock that was
// aquired before the timer was set since it will not be released in the DPC.
//
if (KeCancelTimer (&BattNPInfo->WorkerTimer)) {
// Release Removal Lock
// "InUseCount can never be 0 after this operation.
InterlockedDecrement(&BattNPInfo->InUseCount);
BattPrint ((BATT_LOCK), ("BatteryClassUnload: Released WorkerTimer remove lock %d (count = %d)\n", BattNPInfo->DeviceNum, BattNPInfo->InUseCount));
}
if (KeCancelTimer (&BattNPInfo->TagTimer)) {
// Release Removal Lock
// "InUseCount can never be 0 after this operation.
InterlockedDecrement(&BattNPInfo->InUseCount);
BattPrint ((BATT_LOCK), ("BatteryClassUnload: Released TagTimer remove lock %d (count = %d)\n", BattNPInfo->DeviceNum, BattNPInfo->InUseCount));
}
//
// Queue the worker thread once more to make sure that the remove lock for
// the worker thread is released.
//
BattCQueueWorker (BattNPInfo, FALSE);
// Finish syncronization
if (InterlockedDecrement (&BattNPInfo->InUseCount) > 0) {
KeWaitForSingleObject (&BattNPInfo->ReadyToRemove,
Executive,
KernelMode,
FALSE,
NULL
);
}
BattPrint ((BATT_LOCK), ("BatteryClassUnload: Done waiting for remove lock %d (count = %d)\n", BattNPInfo->DeviceNum, BattNPInfo->InUseCount));
//
// Free Structures
//
ExFreePool (BattInfo->SymbolicLinkName.Buffer);
ExFreePool (BattInfo);
ExFreePool (BattNPInfo);
BattPrint ((BATT_TRACE), ("BattC (%d): BatteryClassUnload returning.\n", BattNPInfo->DeviceNum));
return STATUS_SUCCESS;
}
NTSTATUS
BATTERYCLASSAPI
BatteryClassIoctl (
IN PVOID ClassData,
IN PIRP Irp
)
/*++
Routine Description:
Called by the miniport to handle battery ioctl requests. If handled,
the battery class driver owns the IRP. If not handled, it belongs to
the caller.
Arguments:
ClassData - Handle to class driver
Irp - ICOTL irp to check
Return Value:
If handled, the battery class driver owns the IRP and will complete it
once its handled; otherwise, the error STATUS_NOT_SUPPORTED is returned.
--*/
{
NTSTATUS status;
PBATT_INFO BattInfo;
PBATT_NP_INFO BattNPInfo;
PIO_STACK_LOCATION IrpSp;
PAGED_CODE();
BattNPInfo = (PBATT_NP_INFO) ClassData;
BattInfo = BattNPInfo->BattInfo;
BattPrint ((BATT_TRACE), ("BattC (%d): BatteryClassIoctl called.\n", BattNPInfo->DeviceNum));
IrpSp = IoGetCurrentIrpStackLocation(Irp);
//
// Assume it's not our IRP
//
status = STATUS_NOT_SUPPORTED;
//
// Check IOCTL code to see if it's our IRP
//
switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) {
case IOCTL_BATTERY_QUERY_TAG:
case IOCTL_BATTERY_QUERY_INFORMATION:
case IOCTL_BATTERY_SET_INFORMATION:
case IOCTL_BATTERY_QUERY_STATUS:
//
// Acquire remove lock.
// We don't want to queue anything more if we're being removed.
//
InterlockedIncrement (&BattNPInfo->InUseCount);
BattPrint ((BATT_LOCK), ("BatteryClassIoctl: Aqcuired remove lock %d (count = %d)\n", BattNPInfo->DeviceNum, BattNPInfo->InUseCount));
if (BattNPInfo->WantToRemove == TRUE) {
if (0 == InterlockedDecrement(&BattNPInfo->InUseCount)) {
KeSetEvent (&BattNPInfo->ReadyToRemove, IO_NO_INCREMENT, FALSE);
}
BattPrint ((BATT_LOCK), ("BatteryClassIoctl: Released remove lock %d (count = %d)\n", BattNPInfo->DeviceNum, BattNPInfo->InUseCount));
status = STATUS_DEVICE_REMOVED;
} else {
//
// Irp to handle. Put it in the queue worker threads list
//
status = STATUS_PENDING;
Irp->IoStatus.Status = STATUS_PENDING;
IoMarkIrpPending (Irp);
ExAcquireFastMutex (&BattNPInfo->Mutex);
InsertTailList (&BattInfo->IoQueue, &Irp->Tail.Overlay.ListEntry);
ExReleaseFastMutex (&BattNPInfo->Mutex);
BattCQueueWorker (BattNPInfo, FALSE);
//
// Release Remove Lock.
//
if (0 == InterlockedDecrement(&BattNPInfo->InUseCount)) {
KeSetEvent (&BattNPInfo->ReadyToRemove, IO_NO_INCREMENT, FALSE);
}
BattPrint ((BATT_LOCK), ("BatteryClassIoctl: Released remove lock %d (count = %d)\n", BattNPInfo->DeviceNum, BattNPInfo->InUseCount));
}
break;
default:
BattPrint ((BATT_ERROR|BATT_IOCTL),
("BattC (%d): unknown battery ioctl - %x\n",
BattNPInfo->DeviceNum,
IrpSp->Parameters.DeviceIoControl.IoControlCode));
break;
}
if ((status != STATUS_PENDING) && (status != STATUS_NOT_SUPPORTED)) {
Irp->IoStatus.Status = status;
IoCompleteRequest (Irp, IO_NO_INCREMENT);
}
BattPrint ((BATT_TRACE), ("BattC (%d): BatteryClassIoctl returning (status = 0x%08lx).\n", BattNPInfo->DeviceNum, status));
return status;
}
NTSTATUS
BATTERYCLASSAPI
BatteryClassStatusNotify (
IN PVOID ClassData
)
/*++
Routine Description:
Called by the miniport to signify that something interesting concerning
the battery status has occured. Calling this function will cause the
battery class driver to obtain the battery status if there are any pending
status requests pending.
If the miniport supports SetNotify from the class driver, then the miniport
only needs to call this function once when the notification crtierea is
met.
If the miniport does not support SetNotify from the class driver, then
the class driver will poll (at a slow rate) but the miniport should still
call this function at least when the batteries power status changes such
that timely updates of at least the power status will occur in the UI.
Arguments:
ClassData - Handle to class driver
Return Value:
Status
--*/
{
PBATT_NP_INFO BattNPInfo;
BattNPInfo = (PBATT_NP_INFO) ClassData;
BattPrint ((BATT_TRACE), ("BattC (%d): BatteryClassStatusNotify called\n", BattNPInfo->DeviceNum));
InterlockedExchange (&BattNPInfo->StatusNotified, 1);
InterlockedExchange (&BattNPInfo->TagNotified, 1);
BattCQueueWorker (BattNPInfo, TRUE);
return STATUS_SUCCESS;
}
NTSTATUS
BATTERYCLASSAPI
BatteryClassSystemControl (
IN PVOID ClassData,
IN PWMILIB_CONTEXT WmiLibContext,
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
OUT PSYSCTL_IRP_DISPOSITION Disposition
)
/*++
Routine Description:
The miniport driver calls this instead of WmiSystemControl.
Arguments:
ClassData - Handle to class driver
The other parameters are the parameters for WmiSystemControl.
Return Value:
STATUS_SUCCESS or one of the following error codes:
STATUS_INVALID_DEVICE_REQUEST
STATUS_WMI_GUID_NOT_FOUND
STATUS_WMI_INSTANCE_NOT_FOUND
--*/
{
NTSTATUS status = STATUS_NOT_SUPPORTED;
PBATT_INFO BattInfo;
PBATT_NP_INFO BattNPInfo;
PIO_STACK_LOCATION IrpSp;
PAGED_CODE();
BattNPInfo = (PBATT_NP_INFO) ClassData;
BattInfo = BattNPInfo->BattInfo;
IrpSp = IoGetCurrentIrpStackLocation (Irp);
BattPrint ((BATT_TRACE), ("BattC (%d): BatteryClassSystemControl called.\n", BattNPInfo->DeviceNum));
//
// Initialize the WmiLibContext structure if this is the first time.
//
if (BattInfo->WmiLibContext.GuidCount == 0) {
RtlCopyMemory(&BattInfo->WmiLibContext,
WmiLibContext,
sizeof(*WmiLibContext));
BattInfo->WmiLibContext.GuidCount = WmiLibContext->GuidCount + BattWmiTotalGuids;
BattInfo->WmiGuidIndex = WmiLibContext->GuidCount;
BattInfo->WmiLibContext.GuidList = ExAllocatePoolWithTag(PagedPool, BattInfo->WmiLibContext.GuidCount * sizeof(WMIGUIDREGINFO), 'ttaB');
if (!BattInfo->WmiLibContext.GuidList) {
//
// Figure out how to fail gracefully.
//
}
RtlCopyMemory(BattInfo->WmiLibContext.GuidList,
WmiLibContext->GuidList,
WmiLibContext->GuidCount * sizeof(WMIGUIDREGINFO));
RtlCopyMemory(&BattInfo->WmiLibContext.GuidList [WmiLibContext->GuidCount],
BattWmiGuidList, BattWmiTotalGuids * sizeof(WMIGUIDREGINFO));
}
//
// Acquire remove lock.
// We don't want to queue anything more if we're being removed.
//
InterlockedIncrement (&BattNPInfo->InUseCount);
BattPrint ((BATT_LOCK), ("BatteryClassSystemControl: Aqcuired remove lock %d (count = %d)\n", BattNPInfo->DeviceNum, BattNPInfo->InUseCount));
if (BattNPInfo->WantToRemove == TRUE) {
if (0 == InterlockedDecrement(&BattNPInfo->InUseCount)) {
KeSetEvent (&BattNPInfo->ReadyToRemove, IO_NO_INCREMENT, FALSE);
}
BattPrint ((BATT_LOCK), ("BatteryClassSystemControl: Released remove lock %d (count = %d)\n", BattNPInfo->DeviceNum, BattNPInfo->InUseCount));
status = STATUS_DEVICE_REMOVED;
} else {
status = WmiSystemControl(&BattInfo->WmiLibContext,
DeviceObject,
Irp,
Disposition);
BattPrint ((BATT_DEBUG), ("BattC (%d): BatteryClassSystemControl Returned from WmiSystemControl (status = 0x%08x).\n", BattNPInfo->DeviceNum, status));
//
// For IRP_MN_REGINFO BattC needs to add additional data to the IRP
// about the battery class MOF resource.
//
if ((*Disposition == IrpNotCompleted) &&
((IrpSp->MinorFunction == IRP_MN_REGINFO) ||
(IrpSp->MinorFunction == IRP_MN_REGINFO_EX)) &&
(IrpSp->Parameters.WMI.DataPath == WMIREGISTER)) {
//
// Original structure
//
PWMIREGINFO regInfoPtr = IrpSp->Parameters.WMI.Buffer;
BattPrint ((BATT_DEBUG), ("BattC (%d): BatteryClassSystemControl Adding Resource.\n", BattNPInfo->DeviceNum));
//
// If WmiSystemControl returned STATUS_BUFFER_TOO_SMALL or entered
// the correct size as a ULONG in IoStatus.Information.
// Increase the required size to accomodate battery class data
// before returning
//
if (Irp->IoStatus.Information == sizeof(ULONG) ||
Irp->IoStatus.Status == STATUS_BUFFER_TOO_SMALL) {
//
// Aditional battery class data includes one WMIREGINFO structure
// Followed strings for the regstry path and resource name.
// (Plus two WCHARS because these need to be counted strings.)
// Round this up to the nearest 8 bytes.
//
regInfoPtr->BufferSize =
(regInfoPtr->BufferSize +
sizeof(WMIREGINFO) +
sizeof(MOFREGISTRYPATH) +
sizeof(MOFRESOURCENAME) + 2 * sizeof(WCHAR) + 7) & 0xFFFFFFF8;
BattPrint ((BATT_DEBUG), ("BattC (%d): BatteryClassSystemControl Buffer Too Small:\n"
" Information = %08x\n"
" BufferSize = %08x\n"
" NewSize = %08x\n",
BattNPInfo->DeviceNum,
Irp->IoStatus.Information,
IrpSp->Parameters.WMI.BufferSize,
regInfoPtr->BufferSize));
//
// Make sure IRP is set up to fail correctly.
//
Irp->IoStatus.Information = sizeof(ULONG);
Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
status = STATUS_BUFFER_TOO_SMALL;
} else {
ULONG size;
PWCHAR tempString;
//
// Assume that there is only one WmiRegInfo Structure so far.
//
ASSERT (regInfoPtr->NextWmiRegInfo == 0);
regInfoPtr->NextWmiRegInfo = (regInfoPtr->BufferSize + 7) & 0xFFFFFFF8;
size = regInfoPtr->NextWmiRegInfo + sizeof(WMIREGINFO) +
sizeof(MOFRESOURCENAME) + sizeof(MOFREGISTRYPATH) + 2 * sizeof(WCHAR);
//
// Set BufferSize Whether we succeed or not.
//
((PWMIREGINFO)IrpSp->Parameters.WMI.Buffer)->BufferSize = size;
if (size > IrpSp->Parameters.WMI.BufferSize) {
//
// If WmiSystemControl was successful, but there isnt room
// for the extra data, this request needs to fail
//
Irp->IoStatus.Information = sizeof(ULONG);
Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
status = STATUS_BUFFER_TOO_SMALL;
BattPrint ((BATT_DEBUG), ("BattC (%d): BatteryClassSystemControl Buffer Too Small.\n"
" BufferSize = %08x\n"
" Size = %08x\n",
BattNPInfo->DeviceNum,
IrpSp->Parameters.WMI.BufferSize,
size));
} else {
Irp->IoStatus.Information = size;
BattPrint ((BATT_DEBUG), ("BattC (%d): BatteryClassSystemControl Munging Structures:\n"
" Buffer = %08x\n"
" temp = %08x\n",
BattNPInfo->DeviceNum,
(ULONG_PTR) IrpSp->Parameters.WMI.Buffer,
(ULONG_PTR) regInfoPtr));
//
// Intialize new structure
//
// Set teporary pointer to point at data structure we are adding.
(ULONG_PTR)regInfoPtr += (ULONG_PTR)regInfoPtr->NextWmiRegInfo;
regInfoPtr->BufferSize = sizeof(WMIREGINFO) +
sizeof(MOFRESOURCENAME) +
sizeof(MOFREGISTRYPATH) + 2 * sizeof(WCHAR);
regInfoPtr->NextWmiRegInfo = 0;
// Initialize RegistryPath counted string.
regInfoPtr->RegistryPath = sizeof(WMIREGINFO);
tempString = (PWCHAR)((ULONG_PTR)regInfoPtr + sizeof(WMIREGINFO));
*tempString++ = sizeof(MOFREGISTRYPATH);
RtlCopyMemory(tempString, MOFREGISTRYPATH, sizeof(MOFREGISTRYPATH));
// Initialize MofResourceName counted string.
regInfoPtr->MofResourceName = sizeof(WMIREGINFO) + sizeof(MOFREGISTRYPATH) + sizeof(WCHAR);
tempString = (PWCHAR)((ULONG_PTR)regInfoPtr + regInfoPtr->MofResourceName);
*tempString++ = sizeof(MOFRESOURCENAME);
RtlCopyMemory(tempString, MOFRESOURCENAME, sizeof(MOFRESOURCENAME));
regInfoPtr->GuidCount = 0;
}
}
}
//
// Release Remove Lock.
//
if (0 == InterlockedDecrement(&BattNPInfo->InUseCount)) {
KeSetEvent (&BattNPInfo->ReadyToRemove, IO_NO_INCREMENT, FALSE);
}
BattPrint ((BATT_LOCK), ("BatteryClassSystemControl: Released remove lock %d (count = %d)\n", BattNPInfo->DeviceNum, BattNPInfo->InUseCount));
}
return status;
}
NTSTATUS
BATTERYCLASSAPI
BatteryClassQueryWmiDataBlock(
IN PVOID ClassData,
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN ULONG GuidIndex,
IN OUT PULONG InstanceLengthArray,
IN ULONG OutBufferSize,
OUT PUCHAR Buffer
)
/*++
Routine Description:
This routine is a callback into the driver to query for the contents of
a data block. When the driver has finished filling the data block it
must call WmiCompleteRequest to complete the irp. The driver can
return STATUS_PENDING if the irp cannot be completed immediately.
Arguments:
DeviceObject is the device whose data block is being queried
Irp is the Irp that makes this request
GuidIndex is the index into the list of guids provided when the
device registered
InstanceLengthArray is a pointer to an array of ULONG that returns the
lengths of each instance of the data block. If this is NULL then
there was not enough space in the output buffer to fulfill the request
so the irp should be completed with the buffer needed.
BufferAvail on has the maximum size available to write the data
block.
Buffer on return is filled with the returned data block
Return Value:
status
--*/
{
PBATT_NP_INFO BattNPInfo = (PBATT_NP_INFO) ClassData;
PBATT_INFO BattInfo = BattNPInfo->BattInfo;
PBATT_WMI_REQUEST WmiRequest;
NTSTATUS status = STATUS_SUCCESS;
ULONG size = 0;
PAGED_CODE();
BattPrint ((BATT_TRACE|BATT_WMI), ("Entered BatteryClassQueryWmiDataBlock\n"));
//
// Don't need to acquire remove lock. It is already head by SystemControl.
//
switch (GuidIndex - BattInfo->WmiGuidIndex) {
case BattWmiStatusId:
size = sizeof (BATTERY_WMI_STATUS);
break;
case BattWmiRuntimeId:
size = sizeof (BATTERY_WMI_RUNTIME);
break;
case BattWmiTemperatureId:
size = sizeof (BATTERY_WMI_TEMPERATURE);
break;
case BattWmiFullChargedCapacityId:
size = sizeof (BATTERY_WMI_FULL_CHARGED_CAPACITY);
break;
case BattWmiCycleCountId:
size = sizeof (BATTERY_WMI_CYCLE_COUNT);
break;
case BattWmiStaticDataId:
size = sizeof(BATTERY_WMI_STATIC_DATA)+4*MAX_BATTERY_STRING_SIZE*sizeof(WCHAR);
// data plus 4 strings
break;
default:
status = STATUS_WMI_GUID_NOT_FOUND;
}
if (status != STATUS_WMI_GUID_NOT_FOUND) {
if (OutBufferSize < size ) {
status = STATUS_BUFFER_TOO_SMALL;
*InstanceLengthArray = size;
status = WmiCompleteRequest( DeviceObject,
Irp,
status,
size,
IO_NO_INCREMENT);
return status;
}
WmiRequest = ExAllocatePoolWithTag (PagedPool, sizeof(BATT_WMI_REQUEST), 'ttaB');
if (!WmiRequest) {
BattPrint((BATT_ERROR), ("Failed to allocate memory for WMI request\n"));
status = STATUS_INSUFFICIENT_RESOURCES;
status = WmiCompleteRequest( DeviceObject,
Irp,
status,
size,
IO_NO_INCREMENT);
return status;
}
WmiRequest->DeviceObject = DeviceObject;
WmiRequest->Irp = Irp;
WmiRequest->GuidIndex = GuidIndex - BattInfo->WmiGuidIndex;
WmiRequest->InstanceLengthArray = InstanceLengthArray;
WmiRequest->OutBufferSize = OutBufferSize;
WmiRequest->Buffer = Buffer;
ExAcquireFastMutex (&BattNPInfo->Mutex);
InsertTailList (&BattInfo->WmiQueue, &WmiRequest->ListEntry);
ExReleaseFastMutex (&BattNPInfo->Mutex);
BattCQueueWorker (BattNPInfo, FALSE);
status = STATUS_PENDING;
}
return status;
}