mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
922 lines
28 KiB
922 lines
28 KiB
/*++
|
|
|
|
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;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|