1448 lines
37 KiB
C
1448 lines
37 KiB
C
/*++
|
||
|
||
Copyright (c) 1996 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
cmbpnp.c
|
||
|
||
Abstract:
|
||
|
||
Control Method Battery Plug and Play support
|
||
|
||
Author:
|
||
|
||
Ron Mosgrove
|
||
|
||
Environment:
|
||
|
||
Kernel mode
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include "CmBattp.h"
|
||
#include <wdmguid.h>
|
||
#include <string.h>
|
||
|
||
//
|
||
// Device Names
|
||
//
|
||
PCWSTR CmBattDeviceName = L"\\Device\\ControlMethodBattery";
|
||
PCWSTR AcAdapterName = L"\\Device\\AcAdapter";
|
||
|
||
//
|
||
// Power Source Type registry key
|
||
//
|
||
PCWSTR PowerSourceType = L"PowerSourceType";
|
||
#define POWER_SOURCE_TYPE_BATTERY 0
|
||
#define POWER_SOURCE_TYPE_AC_ADAPTER 1
|
||
|
||
//
|
||
// WaitWake registry key
|
||
//
|
||
PCWSTR WaitWakeEnableKey = L"WaitWakeEnabled";
|
||
|
||
//
|
||
// Globals
|
||
//
|
||
PDEVICE_OBJECT AcAdapterPdo = NULL;
|
||
|
||
//
|
||
// Prototypes
|
||
//
|
||
NTSTATUS
|
||
CmBattAddDevice(
|
||
IN PDRIVER_OBJECT DriverObject,
|
||
IN PDEVICE_OBJECT Pdo
|
||
);
|
||
|
||
NTSTATUS
|
||
CmBattRemoveDevice(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
);
|
||
|
||
NTSTATUS
|
||
CmBattGetAcpiInterfaces(
|
||
IN PDEVICE_OBJECT LowerDevice,
|
||
OUT PACPI_INTERFACE_STANDARD AcpiInterfaces
|
||
);
|
||
|
||
NTSTATUS
|
||
CmBattAddBattery(
|
||
IN PDRIVER_OBJECT DriverObject,
|
||
IN PDEVICE_OBJECT Pdo
|
||
);
|
||
|
||
NTSTATUS
|
||
CmBattAddAcAdapter(
|
||
IN PDRIVER_OBJECT DriverObject,
|
||
IN PDEVICE_OBJECT Pdo
|
||
);
|
||
|
||
NTSTATUS
|
||
CmBattCreateFdo(
|
||
IN PDRIVER_OBJECT DriverObject,
|
||
IN PDEVICE_OBJECT Pdo,
|
||
IN PWSTR DeviceName,
|
||
IN ULONG ExtensionSize,
|
||
OUT PDEVICE_OBJECT *NewFdo
|
||
);
|
||
|
||
VOID
|
||
CmBattDestroyFdo(
|
||
IN PDEVICE_OBJECT Fdo
|
||
);
|
||
|
||
|
||
|
||
NTSTATUS
|
||
CmBattIoCompletion(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp,
|
||
IN PKEVENT pdoIoCompletedEvent
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine catches completion notifications.
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - Pointer to class device object.
|
||
Irp - Pointer to the request packet.
|
||
pdoIoCompletedEvent - the just completed event
|
||
|
||
Return Value:
|
||
|
||
Status is returned.
|
||
|
||
--*/
|
||
{
|
||
|
||
CmBattPrint (CMBATT_TRACE, ("CmBattIoCompletion: Event (%x)\n", pdoIoCompletedEvent));
|
||
|
||
KeSetEvent(pdoIoCompletedEvent, IO_NO_INCREMENT, FALSE);
|
||
return STATUS_MORE_PROCESSING_REQUIRED;
|
||
}
|
||
|
||
|
||
|
||
NTSTATUS
|
||
CmBattAddDevice(
|
||
IN PDRIVER_OBJECT DriverObject,
|
||
IN PDEVICE_OBJECT Pdo
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine creates functional device objects for each CmBatt controller in the
|
||
system and attaches them to the physical device objects for the controllers
|
||
|
||
|
||
Arguments:
|
||
|
||
DriverObject - a pointer to the object for this driver
|
||
PhysicalDeviceObject - a pointer to the physical object we need to attach to
|
||
|
||
Return Value:
|
||
|
||
Status from device creation and initialization
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
HANDLE handle;
|
||
UNICODE_STRING unicodeString;
|
||
CHAR buffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION)+sizeof(ULONG)];
|
||
ULONG unused;
|
||
|
||
PAGED_CODE();
|
||
|
||
CmBattPrint ((CMBATT_TRACE | CMBATT_PNP), ("CmBattAddDevice: Entered with pdo %x\n", Pdo));
|
||
|
||
if (Pdo == NULL) {
|
||
|
||
//
|
||
// Have we been asked to do detection on our own?
|
||
// if so just return no more devices
|
||
//
|
||
|
||
CmBattPrint((CMBATT_WARN | CMBATT_PNP), ("CmBattAddDevice: Asked to do detection\n"));
|
||
return STATUS_NO_MORE_ENTRIES;
|
||
}
|
||
|
||
//
|
||
// Get the software branch.
|
||
//
|
||
Status = IoOpenDeviceRegistryKey (Pdo,
|
||
PLUGPLAY_REGKEY_DRIVER,
|
||
STANDARD_RIGHTS_READ,
|
||
&handle);
|
||
if (!NT_SUCCESS(Status)) {
|
||
CmBattPrint(CMBATT_ERROR, ("CmBattAddDevice: Could not get the software branch: %x\n", Status));
|
||
return Status;
|
||
}
|
||
|
||
//
|
||
// Check if this is for an AC adapter or a battery.
|
||
//
|
||
RtlInitUnicodeString (&unicodeString, PowerSourceType);
|
||
Status = ZwQueryValueKey(
|
||
handle,
|
||
&unicodeString,
|
||
KeyValuePartialInformation,
|
||
&buffer,
|
||
sizeof(buffer),
|
||
&unused
|
||
);
|
||
|
||
ZwClose( handle );
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
CmBattPrint(CMBATT_ERROR, ("CmBattAddDevice: Could not read the power type identifier: %x\n", Status));
|
||
|
||
} else {
|
||
|
||
switch (*(PULONG)&((PKEY_VALUE_PARTIAL_INFORMATION)buffer)->Data) {
|
||
|
||
case POWER_SOURCE_TYPE_BATTERY:
|
||
Status = CmBattAddBattery (DriverObject, Pdo);
|
||
break;
|
||
|
||
case POWER_SOURCE_TYPE_AC_ADAPTER:
|
||
Status = CmBattAddAcAdapter (DriverObject, Pdo);
|
||
break;
|
||
|
||
default:
|
||
CmBattPrint(CMBATT_ERROR, ("CmBattAddDevice: Invalid POWER_SOURCE_TYPE == %d \n", *(PULONG)&((PKEY_VALUE_PARTIAL_INFORMATION)buffer)->Data));
|
||
Status = STATUS_UNSUCCESSFUL;
|
||
break;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Return the status.
|
||
//
|
||
return Status;
|
||
}
|
||
|
||
|
||
|
||
NTSTATUS
|
||
CmBattAddBattery(
|
||
IN PDRIVER_OBJECT DriverObject,
|
||
IN PDEVICE_OBJECT Pdo
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine creates a functional device object for a CM battery, and attache it
|
||
to the physical device object for the battery.
|
||
|
||
Arguments:
|
||
|
||
DriverObject - a pointer to the object for this driver
|
||
PhysicalDeviceObject - a pointer to the physical object we need to attach to
|
||
|
||
Return Value:
|
||
|
||
Status from device creation and initialization
|
||
|
||
--*/
|
||
|
||
{
|
||
PDEVICE_OBJECT Fdo = NULL;
|
||
PCM_BATT CmBatt;
|
||
NTSTATUS Status;
|
||
BATTERY_MINIPORT_INFO BattInit;
|
||
|
||
PAGED_CODE();
|
||
|
||
CmBattPrint ((CMBATT_TRACE | CMBATT_PNP), ("CmBattAddBattery: pdo %x\n", Pdo));
|
||
|
||
//
|
||
// Create and initialize the new functional device object
|
||
//
|
||
Status = CmBattCreateFdo(DriverObject, Pdo, (PWSTR) CmBattDeviceName, sizeof(CM_BATT), &Fdo);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
CmBattPrint(CMBATT_ERROR, ("CmBattAddBattery: error (0x%x) creating Fdo\n", Status));
|
||
return Status;
|
||
}
|
||
|
||
//
|
||
// Initialize Fdo device extension data
|
||
//
|
||
|
||
CmBatt = (PCM_BATT) Fdo->DeviceExtension;
|
||
CmBatt->Type = CM_BATTERY_TYPE;
|
||
CmBatt->IsStarted = FALSE;
|
||
CmBatt->ReCheckSta = TRUE;
|
||
InterlockedExchange (&CmBatt->CacheState, 0);
|
||
|
||
CmBatt->Info.Tag = BATTERY_TAG_INVALID;
|
||
CmBatt->Alarm.Setting = CM_ALARM_INVALID;
|
||
CmBatt->DischargeTime = KeQueryInterruptTime();
|
||
|
||
if (CmBattSetTripPpoint (CmBatt, 0) == STATUS_OBJECT_NAME_NOT_FOUND) {
|
||
CmBatt->Info.BtpExists = FALSE;
|
||
} else {
|
||
CmBatt->Info.BtpExists = TRUE;
|
||
}
|
||
|
||
//
|
||
// Attach to the Class Driver
|
||
//
|
||
|
||
RtlZeroMemory (&BattInit, sizeof(BattInit));
|
||
BattInit.MajorVersion = BATTERY_CLASS_MAJOR_VERSION;
|
||
BattInit.MinorVersion = BATTERY_CLASS_MINOR_VERSION;
|
||
BattInit.Context = CmBatt;
|
||
BattInit.QueryTag = CmBattQueryTag;
|
||
BattInit.QueryInformation = CmBattQueryInformation;
|
||
BattInit.SetInformation = NULL; // tbd
|
||
BattInit.QueryStatus = CmBattQueryStatus;
|
||
BattInit.SetStatusNotify = CmBattSetStatusNotify;
|
||
BattInit.DisableStatusNotify = CmBattDisableStatusNotify;
|
||
|
||
BattInit.Pdo = Pdo;
|
||
BattInit.DeviceName = CmBatt->DeviceName;
|
||
|
||
Status = BatteryClassInitializeDevice (&BattInit, &CmBatt->Class);
|
||
if (!NT_SUCCESS(Status)) {
|
||
//
|
||
// if we can't attach to class driver we're toast
|
||
//
|
||
CmBattPrint(CMBATT_ERROR, ("CmBattAddBattery: error (0x%x) registering with class\n", Status));
|
||
IoDetachDevice (CmBatt->LowerDeviceObject);
|
||
CmBattDestroyFdo (CmBatt->Fdo);
|
||
return Status;
|
||
}
|
||
|
||
//
|
||
// Register WMI support.
|
||
//
|
||
Status = CmBattWmiRegistration(CmBatt);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
//
|
||
// WMI support is not critical to operation. Just log an error.
|
||
//
|
||
|
||
CmBattPrint(CMBATT_ERROR,
|
||
("CmBattAddBattery: Could not register as a WMI provider, status = %Lx\n", Status));
|
||
}
|
||
|
||
//
|
||
// Register the battery notify handler for this battery with ACPI
|
||
// This registration is performed after registering with the battery
|
||
// class because CmBattNotifyHandler must not be run until the battery
|
||
// class is ready.
|
||
//
|
||
Status = CmBatt->AcpiInterfaces.RegisterForDeviceNotifications (
|
||
CmBatt->AcpiInterfaces.Context,
|
||
CmBattNotifyHandler,
|
||
CmBatt);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
CmBattPrint(CMBATT_ERROR,
|
||
("CmBattAddBattery: Could not register for battery notify, status = %Lx\n", Status));
|
||
CmBattWmiDeRegistration(CmBatt);
|
||
BatteryClassUnload (CmBatt->Class);
|
||
IoDetachDevice (CmBatt->LowerDeviceObject);
|
||
CmBattDestroyFdo (CmBatt->Fdo);
|
||
return Status;
|
||
}
|
||
|
||
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
CmBattAddAcAdapter(
|
||
IN PDRIVER_OBJECT DriverObject,
|
||
IN PDEVICE_OBJECT Pdo
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine registers a notify handler for the AC Adapter. And saves the PDO so we can run
|
||
the _STA method against it to get the AC status.
|
||
|
||
Arguments:
|
||
|
||
DriverObject - a pointer to the object for this driver
|
||
Pdo - a pointer to the Pdo
|
||
|
||
Return Value:
|
||
|
||
Status from device creation and initialization
|
||
|
||
--*/
|
||
|
||
{
|
||
PDEVICE_OBJECT Fdo;
|
||
NTSTATUS Status;
|
||
PAC_ADAPTER acExtension;
|
||
|
||
PAGED_CODE();
|
||
|
||
CmBattPrint ((CMBATT_TRACE | CMBATT_PNP), ("CmBattAddAcAdapter: pdo %x\n", Pdo));
|
||
|
||
//
|
||
// Save PDO so we can run _STA method on it later
|
||
//
|
||
|
||
if (AcAdapterPdo != NULL) {
|
||
CmBattPrint(CMBATT_ERROR, ("CmBatt: Second AC adapter found. Current version of driver only supports 1 aadapter.\n"));
|
||
} else {
|
||
AcAdapterPdo = Pdo;
|
||
}
|
||
|
||
Status = CmBattCreateFdo(DriverObject, Pdo, (PWSTR) AcAdapterName, sizeof(AC_ADAPTER), &Fdo);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
CmBattPrint(CMBATT_ERROR, ("CmBattAddAcAdapter: error (0x%x) creating Fdo\n", Status));
|
||
return Status;
|
||
}
|
||
|
||
//
|
||
// Initialize Fdo device extension data
|
||
//
|
||
|
||
acExtension = (PAC_ADAPTER) Fdo->DeviceExtension;
|
||
acExtension->Type = AC_ADAPTER_TYPE;
|
||
|
||
//
|
||
// Register WMI support.
|
||
//
|
||
Status = CmBattWmiRegistration((PCM_BATT)acExtension);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
//
|
||
// WMI support is not critical to operation. Just log an error.
|
||
//
|
||
|
||
CmBattPrint(CMBATT_ERROR,
|
||
("CmBattAddBattery: Could not register as a WMI provider, status = %Lx\n", Status));
|
||
}
|
||
|
||
//
|
||
// Register the AC adapter notify handler with ACPI
|
||
//
|
||
Status = acExtension->AcpiInterfaces.RegisterForDeviceNotifications (
|
||
acExtension->AcpiInterfaces.Context,
|
||
CmBattNotifyHandler,
|
||
acExtension);
|
||
|
||
//
|
||
// We will ignore errors, since this is not a critical operation
|
||
//
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
CmBattPrint(CMBATT_ERROR,
|
||
("CmBattAddAcAdapter: Could not register for power notify, status = %Lx\n", Status));
|
||
}
|
||
|
||
//
|
||
// Give one notification, to make sure all batteries get updated.
|
||
//
|
||
|
||
CmBattNotifyHandler (acExtension, BATTERY_STATUS_CHANGE);
|
||
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
|
||
|
||
NTSTATUS
|
||
CmBattGetAcpiInterfaces(
|
||
IN PDEVICE_OBJECT LowerDevice,
|
||
OUT PACPI_INTERFACE_STANDARD AcpiInterfaces
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Call ACPI driver to get the direct-call interfaces. It does
|
||
this the first time it is called, no more.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
Status
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status = STATUS_SUCCESS;
|
||
PIRP Irp;
|
||
PIO_STACK_LOCATION IrpSp;
|
||
KEVENT syncEvent;
|
||
|
||
//
|
||
// Allocate an IRP for below
|
||
//
|
||
Irp = IoAllocateIrp (LowerDevice->StackSize, FALSE); // Get stack size from PDO
|
||
|
||
if (!Irp) {
|
||
CmBattPrint((CMBATT_ERROR),
|
||
("CmBattGetAcpiInterfaces: Failed to allocate Irp\n"));
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
IrpSp = IoGetNextIrpStackLocation(Irp);
|
||
|
||
//
|
||
// Use QUERY_INTERFACE to get the address of the direct-call ACPI interfaces.
|
||
//
|
||
IrpSp->MajorFunction = IRP_MJ_PNP;
|
||
IrpSp->MinorFunction = IRP_MN_QUERY_INTERFACE;
|
||
Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
|
||
|
||
IrpSp->Parameters.QueryInterface.InterfaceType = (LPGUID) &GUID_ACPI_INTERFACE_STANDARD;
|
||
IrpSp->Parameters.QueryInterface.Version = 1;
|
||
IrpSp->Parameters.QueryInterface.Size = sizeof (*AcpiInterfaces);
|
||
IrpSp->Parameters.QueryInterface.Interface = (PINTERFACE) AcpiInterfaces;
|
||
IrpSp->Parameters.QueryInterface.InterfaceSpecificData = NULL;
|
||
|
||
//
|
||
// Initialize an event so this will be a syncronous call.
|
||
//
|
||
|
||
KeInitializeEvent(&syncEvent, SynchronizationEvent, FALSE);
|
||
|
||
IoSetCompletionRoutine (Irp, CmBattIoCompletion, &syncEvent, TRUE, TRUE, TRUE);
|
||
|
||
//
|
||
// Call ACPI
|
||
//
|
||
|
||
Status = IoCallDriver (LowerDevice, Irp);
|
||
|
||
//
|
||
// Wait if necessary, then clean up.
|
||
//
|
||
|
||
if (Status == STATUS_PENDING) {
|
||
KeWaitForSingleObject(&syncEvent, Executive, KernelMode, FALSE, NULL);
|
||
Status = Irp->IoStatus.Status;
|
||
}
|
||
|
||
IoFreeIrp (Irp);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
CmBattPrint(CMBATT_ERROR,
|
||
("CmBattGetAcpiInterfaces: Could not get ACPI driver interfaces, status = %x\n", Status));
|
||
}
|
||
|
||
return Status;
|
||
}
|
||
|
||
|
||
|
||
NTSTATUS
|
||
CmBattCreateFdo(
|
||
IN PDRIVER_OBJECT DriverObject,
|
||
IN PDEVICE_OBJECT Pdo,
|
||
IN PWSTR DeviceName,
|
||
IN ULONG ExtensionSize,
|
||
OUT PDEVICE_OBJECT *NewFdo
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine will create and initialize a functional device object to
|
||
be attached to a Control Method Battery PDO.
|
||
|
||
Arguments:
|
||
|
||
DriverObject - a pointer to the driver object this is created under
|
||
DeviceName - The namde of the device to create
|
||
ExtensionSize - device extension size: sizeof (CM_BATT) or sizeof (AC_ADAPTER)
|
||
NewFdo - a location to store the pointer to the new device object
|
||
|
||
Return Value:
|
||
|
||
STATUS_SUCCESS if everything was successful
|
||
reason for failure otherwise
|
||
|
||
--*/
|
||
|
||
{
|
||
PDEVICE_OBJECT fdo;
|
||
NTSTATUS status;
|
||
PCM_BATT cmBatt;
|
||
PUNICODE_STRING unicodeString;
|
||
ULONG uniqueId;
|
||
USHORT strLength = 0;
|
||
UNICODE_STRING numberString;
|
||
WCHAR numberBuffer[10];
|
||
HANDLE devInstRegKey;
|
||
UNICODE_STRING valueName;
|
||
CHAR buffer [sizeof(KEY_VALUE_PARTIAL_INFORMATION)+sizeof(ULONG)];
|
||
ULONG returnSize;
|
||
|
||
|
||
PAGED_CODE();
|
||
|
||
CmBattPrint ((CMBATT_TRACE | CMBATT_PNP), ("CmBattCreateFdo: Device = %ws\n", DeviceName));
|
||
|
||
//
|
||
// Create the PDO device name based on the _UID
|
||
//
|
||
|
||
numberString.MaximumLength = 10;
|
||
numberString.Length = 0;
|
||
numberString.Buffer = &numberBuffer[0];
|
||
|
||
//
|
||
// Get the unique ID of this device by running the _UID method.
|
||
// If this fails, assume one device. Append no device number.
|
||
//
|
||
status = CmBattGetUniqueId (Pdo, &uniqueId);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
CmBattPrint(CMBATT_NOTE, ("CmBattCreateFdo: Error %x from _UID, assuming unit #0\n", status));
|
||
uniqueId = 0;
|
||
|
||
} else {
|
||
RtlIntegerToUnicodeString (uniqueId, 10, &numberString);
|
||
}
|
||
|
||
//
|
||
// Allocate the UNICODE_STRING for the device name
|
||
//
|
||
|
||
strLength = (USHORT) (wcslen (DeviceName) * 2 + numberString.Length);
|
||
|
||
unicodeString = ExAllocatePoolWithTag (
|
||
PagedPool,
|
||
sizeof (UNICODE_STRING) + strLength,
|
||
'MtaB'
|
||
);
|
||
|
||
if (!unicodeString) {
|
||
CmBattPrint(CMBATT_ERROR, ("CmBattCreateFdo: could not allocate unicode string\n"));
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
unicodeString->MaximumLength = strLength;
|
||
unicodeString->Length = 0;
|
||
unicodeString->Buffer = (PWSTR) (unicodeString + 1);
|
||
|
||
RtlAppendUnicodeToString (unicodeString, DeviceName);
|
||
RtlAppendUnicodeStringToString (unicodeString, &numberString);
|
||
|
||
//
|
||
// Create the FDO
|
||
//
|
||
|
||
status = IoCreateDevice(
|
||
DriverObject,
|
||
ExtensionSize,
|
||
unicodeString,
|
||
FILE_DEVICE_BATTERY,
|
||
0,
|
||
FALSE,
|
||
&fdo
|
||
);
|
||
|
||
if (status != STATUS_SUCCESS) {
|
||
CmBattPrint(CMBATT_ERROR, ("CmBattCreateFdo: error (0x%x) creating device object\n", status));
|
||
ExFreePool (unicodeString);
|
||
return(status);
|
||
}
|
||
|
||
fdo->Flags |= DO_BUFFERED_IO;
|
||
fdo->Flags |= DO_POWER_PAGABLE; // Don't want power Irps at irql 2
|
||
fdo->Flags &= ~DO_DEVICE_INITIALIZING;
|
||
|
||
//
|
||
// Initialize Fdo device extension data
|
||
//
|
||
|
||
cmBatt = (PCM_BATT) fdo->DeviceExtension;
|
||
|
||
//
|
||
// Note: This is note necessarily a battery. It could be an AC adapter, so only fields
|
||
// common to both should be initialized here.
|
||
//
|
||
|
||
RtlZeroMemory(cmBatt, ExtensionSize);
|
||
//CmBatt->Type must be initialized after this call.
|
||
cmBatt->DeviceObject = fdo;
|
||
cmBatt->Fdo = fdo;
|
||
cmBatt->Pdo = Pdo;
|
||
|
||
//
|
||
// Connect to lower device
|
||
//
|
||
|
||
cmBatt->LowerDeviceObject = IoAttachDeviceToDeviceStack(fdo, Pdo);
|
||
if (!cmBatt->LowerDeviceObject) {
|
||
CmBattPrint(CMBATT_ERROR, ("CmBattCreateFdo: IoAttachDeviceToDeviceStack failed.\n"));
|
||
CmBattDestroyFdo (cmBatt->Fdo);
|
||
return STATUS_UNSUCCESSFUL;
|
||
}
|
||
|
||
//
|
||
// Get the direct-call ACPI interfaces
|
||
//
|
||
status = CmBattGetAcpiInterfaces (cmBatt->LowerDeviceObject, &cmBatt->AcpiInterfaces);
|
||
if (!NT_SUCCESS(status)) {
|
||
CmBattPrint(CMBATT_ERROR, ("CmBattCreateFdor: Could not get ACPI interfaces: %x\n", status));
|
||
IoDetachDevice (cmBatt->LowerDeviceObject);
|
||
CmBattDestroyFdo (cmBatt->Fdo);
|
||
return status;
|
||
}
|
||
|
||
//
|
||
// Initializes File handle tracking.
|
||
//
|
||
ExInitializeFastMutex (&cmBatt->OpenCloseMutex);
|
||
cmBatt->OpenCount = 0;
|
||
|
||
//
|
||
// Removal lock initialization
|
||
//
|
||
cmBatt->WantToRemove = FALSE;
|
||
cmBatt->InUseCount = 1;
|
||
KeInitializeEvent(&cmBatt->ReadyToRemove, SynchronizationEvent, FALSE);
|
||
|
||
cmBatt->DeviceNumber = uniqueId;
|
||
cmBatt->DeviceName = unicodeString;
|
||
cmBatt->Sleeping = FALSE;
|
||
cmBatt->ActionRequired = CMBATT_AR_NO_ACTION;
|
||
|
||
//
|
||
// Determine if wake on Battery should be enabled
|
||
//
|
||
cmBatt->WakeEnabled = FALSE;
|
||
|
||
status = IoOpenDeviceRegistryKey (Pdo,
|
||
PLUGPLAY_REGKEY_DEVICE,
|
||
STANDARD_RIGHTS_ALL,
|
||
&devInstRegKey);
|
||
|
||
if (NT_SUCCESS (status)) {
|
||
RtlInitUnicodeString (&valueName, WaitWakeEnableKey);
|
||
status = ZwQueryValueKey(
|
||
devInstRegKey,
|
||
&valueName,
|
||
KeyValuePartialInformation,
|
||
&buffer,
|
||
sizeof(buffer),
|
||
&returnSize
|
||
);
|
||
|
||
if (NT_SUCCESS (status)) {
|
||
cmBatt->WakeEnabled = (*(PULONG)((PKEY_VALUE_PARTIAL_INFORMATION)buffer)->Data ? TRUE : FALSE);
|
||
}
|
||
ZwClose(devInstRegKey);
|
||
}
|
||
|
||
*NewFdo = fdo;
|
||
|
||
CmBattPrint((CMBATT_TRACE | CMBATT_PNP), ("CmBattCreateFdo: Created FDO %x\n", fdo));
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
|
||
|
||
VOID
|
||
CmBattDestroyFdo(
|
||
IN PDEVICE_OBJECT Fdo
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine will deallocate a functional device object.
|
||
This includes deallocating the DeviceName and calling IoDeleteDevice.
|
||
|
||
Arguments:
|
||
|
||
Fdo - a pointer to the FDO to destroy.
|
||
|
||
Return Value:
|
||
|
||
STATUS_SUCCESS if everything was successful
|
||
reason for failure otherwise
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
PAGED_CODE();
|
||
|
||
CmBattPrint ((CMBATT_TRACE | CMBATT_PNP), ("CmBattDestroyFdo, Battery.\n"));
|
||
|
||
//
|
||
// Deallocate the UNICODE_STRING for the device name
|
||
//
|
||
|
||
ExFreePool (((PCM_BATT)Fdo->DeviceExtension)->DeviceName);
|
||
((PCM_BATT)Fdo->DeviceExtension)->DeviceName = NULL;
|
||
|
||
IoDeleteDevice (Fdo);
|
||
|
||
CmBattPrint((CMBATT_TRACE | CMBATT_PNP), ("CmBattDestroyFdo: done.\n"));
|
||
}
|
||
|
||
|
||
|
||
NTSTATUS
|
||
CmBattPnpDispatch(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is the dispatch routine for plug and play requests.
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - Pointer to class device object.
|
||
Irp - Pointer to the request packet.
|
||
|
||
Return Value:
|
||
|
||
Status is returned.
|
||
|
||
--*/
|
||
|
||
{
|
||
PIO_STACK_LOCATION irpStack;
|
||
PCM_BATT CmBatt;
|
||
NTSTATUS status;
|
||
KEVENT syncEvent;
|
||
|
||
PAGED_CODE();
|
||
|
||
status = STATUS_NOT_SUPPORTED;
|
||
|
||
//
|
||
// Get a pointer to the current parameters for this request. The
|
||
// information is contained in the current stack location.
|
||
//
|
||
|
||
irpStack = IoGetCurrentIrpStackLocation(Irp);
|
||
CmBatt = DeviceObject->DeviceExtension;
|
||
|
||
//
|
||
// Aquire remove lock
|
||
//
|
||
|
||
InterlockedIncrement (&CmBatt->InUseCount);
|
||
if (CmBatt->WantToRemove == TRUE) {
|
||
//
|
||
// Failed to acquire remove lock.
|
||
//
|
||
status = STATUS_DEVICE_REMOVED;
|
||
} else {
|
||
//
|
||
// Remove lock acquired.
|
||
//
|
||
|
||
//
|
||
// Dispatch minor function
|
||
//
|
||
switch (irpStack->MinorFunction) {
|
||
|
||
case IRP_MN_START_DEVICE: {
|
||
CmBattPrint (CMBATT_PNP, ("CmBattPnpDispatch: IRP_MN_START_DEVICE\n"));
|
||
|
||
if (CmBatt->Type == CM_BATTERY_TYPE) {
|
||
//
|
||
// We only want to handle batteries, not AC adapters.
|
||
//
|
||
|
||
CmBatt->IsStarted = TRUE;
|
||
|
||
}
|
||
status = STATUS_SUCCESS;
|
||
|
||
break;
|
||
} // IRP_MN_START_DEVICE
|
||
|
||
case IRP_MN_STOP_DEVICE: {
|
||
CmBattPrint (CMBATT_PNP, ("CmBattPnpDispatch: IRP_MN_STOP_DEVICE\n"));
|
||
|
||
if (CmBatt->Type == CM_BATTERY_TYPE) {
|
||
CmBatt->IsStarted = FALSE;
|
||
}
|
||
status = STATUS_SUCCESS;
|
||
|
||
break;
|
||
} // IRP_MN_STOP_DEVICE
|
||
|
||
case IRP_MN_REMOVE_DEVICE: {
|
||
CmBattPrint (CMBATT_PNP, ("CmBattPnpDispatch: IRP_MN_REMOVE_DEVICE\n"));
|
||
|
||
status = CmBattRemoveDevice(DeviceObject, Irp);
|
||
break;
|
||
} // IRP_MN_REMOVE_DEVICE
|
||
|
||
case IRP_MN_SURPRISE_REMOVAL: {
|
||
CmBattPrint (CMBATT_PNP, ("CmBattPnpDispatch: IRP_MN_SURPRISE_REMOVAL\n"));
|
||
|
||
ExAcquireFastMutex (&CmBatt->OpenCloseMutex);
|
||
status = STATUS_SUCCESS;
|
||
|
||
CmBatt->OpenCount = (ULONG) -1;
|
||
|
||
ExReleaseFastMutex (&CmBatt->OpenCloseMutex);
|
||
|
||
break;
|
||
} // IRP_MN_QUERY_REMOVE_DEVICE
|
||
|
||
case IRP_MN_QUERY_REMOVE_DEVICE: {
|
||
CmBattPrint (CMBATT_PNP, ("CmBattPnpDispatch: IRP_MN_QUERY_REMOVE_DEVICE\n"));
|
||
|
||
ExAcquireFastMutex (&CmBatt->OpenCloseMutex);
|
||
status = STATUS_SUCCESS;
|
||
|
||
if (CmBatt->OpenCount == 0) {
|
||
CmBatt->OpenCount = (ULONG) -1;
|
||
} else if (CmBatt->OpenCount == (ULONG) -1) {
|
||
CmBattPrint (CMBATT_WARN, ("CmBattPnpDispatch: Recieved two consecutive QUERY_REMOVE requests.\n"));
|
||
|
||
} else {
|
||
status = STATUS_UNSUCCESSFUL;
|
||
}
|
||
|
||
ExReleaseFastMutex (&CmBatt->OpenCloseMutex);
|
||
|
||
break;
|
||
} // IRP_MN_QUERY_REMOVE_DEVICE
|
||
|
||
case IRP_MN_CANCEL_REMOVE_DEVICE: {
|
||
CmBattPrint (CMBATT_PNP, ("CmBattPnpDispatch: IRP_MN_CANCEL_REMOVE_DEVICE\n"));
|
||
|
||
ExAcquireFastMutex (&CmBatt->OpenCloseMutex);
|
||
|
||
if (CmBatt->OpenCount == (ULONG) -1) {
|
||
CmBatt->OpenCount = 0;
|
||
} else {
|
||
CmBattPrint (CMBATT_NOTE, ("CmBattPnpDispatch: Received CANCEL_REMOVE when OpenCount == %x\n",
|
||
CmBatt->OpenCount));
|
||
}
|
||
status = STATUS_SUCCESS;
|
||
|
||
ExReleaseFastMutex (&CmBatt->OpenCloseMutex);
|
||
|
||
break;
|
||
} // IRP_MN_CANCEL_REMOVE_DEVICE
|
||
|
||
case IRP_MN_QUERY_STOP_DEVICE: {
|
||
CmBattPrint (CMBATT_PNP, ("CmBattPnpDispatch: IRP_MN_QUERY_STOP_DEVICE\n"));
|
||
status = STATUS_NOT_IMPLEMENTED;
|
||
break;
|
||
} // IRP_MN_QUERY_STOP_DEVICE
|
||
|
||
case IRP_MN_CANCEL_STOP_DEVICE: {
|
||
CmBattPrint (CMBATT_PNP, ("CmBattPnpDispatch: IRP_MN_CANCEL_STOP_DEVICE\n"));
|
||
status = STATUS_NOT_IMPLEMENTED;
|
||
break;
|
||
} // IRP_MN_CANCEL_STOP_DEVICE
|
||
|
||
case IRP_MN_QUERY_PNP_DEVICE_STATE: {
|
||
|
||
IoCopyCurrentIrpStackLocationToNext (Irp);
|
||
|
||
KeInitializeEvent(&syncEvent, SynchronizationEvent, FALSE);
|
||
|
||
IoSetCompletionRoutine(Irp, CmBattIoCompletion, &syncEvent, TRUE, TRUE, TRUE);
|
||
|
||
status = IoCallDriver(CmBatt->LowerDeviceObject, Irp);
|
||
|
||
if (status == STATUS_PENDING) {
|
||
KeWaitForSingleObject(&syncEvent, Executive, KernelMode, FALSE, NULL);
|
||
status = Irp->IoStatus.Status;
|
||
}
|
||
|
||
Irp->IoStatus.Information &= ~PNP_DEVICE_NOT_DISABLEABLE;
|
||
|
||
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||
if (0 == InterlockedDecrement(&CmBatt->InUseCount)) {
|
||
KeSetEvent (&CmBatt->ReadyToRemove, IO_NO_INCREMENT, FALSE);
|
||
}
|
||
return status;
|
||
|
||
}
|
||
|
||
case IRP_MN_QUERY_CAPABILITIES: {
|
||
|
||
IoCopyCurrentIrpStackLocationToNext (Irp);
|
||
|
||
KeInitializeEvent(&syncEvent, SynchronizationEvent, FALSE);
|
||
|
||
IoSetCompletionRoutine(Irp, CmBattIoCompletion, &syncEvent, TRUE, TRUE, TRUE);
|
||
|
||
status = IoCallDriver(CmBatt->LowerDeviceObject, Irp);
|
||
|
||
if (status == STATUS_PENDING) {
|
||
KeWaitForSingleObject(&syncEvent, Executive, KernelMode, FALSE, NULL);
|
||
status = Irp->IoStatus.Status;
|
||
}
|
||
|
||
CmBatt->WakeSupportedState.SystemState = irpStack->Parameters.DeviceCapabilities.Capabilities->SystemWake;
|
||
CmBattPrint (CMBATT_PNP, ("CmBattPnpDispatch: IRP_MN_QUERY_CAPABILITIES %d Capabilities->SystemWake = %x\n", CmBatt->Type, CmBatt->WakeSupportedState.SystemState));
|
||
if (CmBatt->WakeSupportedState.SystemState != PowerSystemUnspecified) {
|
||
if (CmBatt->WaitWakeIrp == NULL && CmBatt->WakeEnabled) {
|
||
status = PoRequestPowerIrp(
|
||
CmBatt->DeviceObject,
|
||
IRP_MN_WAIT_WAKE,
|
||
CmBatt->WakeSupportedState,
|
||
CmBattWaitWakeLoop,
|
||
NULL,
|
||
&(CmBatt->WaitWakeIrp)
|
||
);
|
||
|
||
CmBattPrint (CMBATT_PNP, ("CmBattPnpDispatch: IRP_MN_QUERY_CAPABILITIES wait/Wake irp sent.\n"));
|
||
}
|
||
} else {
|
||
CmBatt->WakeEnabled=FALSE;
|
||
CmBattPrint (CMBATT_PNP, ("CmBattPnpDispatch: IRP_MN_QUERY_CAPABILITIES Wake not supported.\n"));
|
||
}
|
||
|
||
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||
if (0 == InterlockedDecrement(&CmBatt->InUseCount)) {
|
||
KeSetEvent (&CmBatt->ReadyToRemove, IO_NO_INCREMENT, FALSE);
|
||
}
|
||
return status;
|
||
|
||
}
|
||
|
||
default: {
|
||
//
|
||
// Unimplemented minor, Pass this down
|
||
//
|
||
CmBattPrint (CMBATT_PNP,
|
||
("CmBattPnpDispatch: Unimplemented minor %0x\n", \
|
||
irpStack->MinorFunction));
|
||
} // default
|
||
|
||
// Fall through...
|
||
|
||
case IRP_MN_QUERY_RESOURCES:
|
||
case IRP_MN_READ_CONFIG:
|
||
case IRP_MN_WRITE_CONFIG:
|
||
case IRP_MN_EJECT:
|
||
case IRP_MN_SET_LOCK:
|
||
case IRP_MN_QUERY_ID:
|
||
case IRP_MN_QUERY_DEVICE_RELATIONS: {
|
||
|
||
break ;
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
// Release remove lock
|
||
//
|
||
|
||
if (0 == InterlockedDecrement(&CmBatt->InUseCount)) {
|
||
KeSetEvent (&CmBatt->ReadyToRemove, IO_NO_INCREMENT, FALSE);
|
||
}
|
||
|
||
|
||
//
|
||
// Only set status if we have something to add
|
||
//
|
||
if (status != STATUS_NOT_SUPPORTED) {
|
||
|
||
Irp->IoStatus.Status = status;
|
||
|
||
}
|
||
|
||
//
|
||
// Do we need to send it down?
|
||
//
|
||
if (NT_SUCCESS(status) || (status == STATUS_NOT_SUPPORTED)) {
|
||
|
||
CmBattCallLowerDriver(status, CmBatt->LowerDeviceObject, Irp);
|
||
return status;
|
||
}
|
||
|
||
//
|
||
// At this point, it must have been passed down and needs recompletion,
|
||
// or the status is unsuccessful.
|
||
//
|
||
ASSERT(!NT_SUCCESS(status) && (status != STATUS_NOT_SUPPORTED));
|
||
|
||
status = Irp->IoStatus.Status ;
|
||
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||
return status;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
CmBattRemoveDevice(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine processes a IRP_MN_REMOVE_DEVICE
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - Pointer to class device object.
|
||
Irp - Pointer to the request packet.
|
||
|
||
Return Value:
|
||
|
||
Returns STATUS_SUCCESS. (This function must not fail.)
|
||
|
||
--*/
|
||
|
||
{
|
||
PCM_BATT cmBatt;
|
||
NTSTATUS status;
|
||
|
||
cmBatt = (PCM_BATT) DeviceObject->DeviceExtension;
|
||
CmBattPrint (CMBATT_TRACE, ("CmBattRemoveDevice: CmBatt (%x), Type %d, _UID %d\n",
|
||
cmBatt, cmBatt->Type, cmBatt->DeviceNumber));
|
||
|
||
|
||
//
|
||
// Remove device syncronization
|
||
//
|
||
|
||
//
|
||
// Prevent more locks from being acquired.
|
||
//
|
||
|
||
cmBatt->WantToRemove = TRUE;
|
||
|
||
//
|
||
// Release lock acquired at start of CmBattPnpDispatch
|
||
//
|
||
if (InterlockedDecrement (&cmBatt->InUseCount) <= 0) {
|
||
CmBattPrint (CMBATT_ERROR, ("CmBattRemoveDevice: Remove lock error.\n"));
|
||
ASSERT(FALSE);
|
||
}
|
||
|
||
//
|
||
// Final release and wait.
|
||
//
|
||
// Note: there will be one more relase at the end of CmBattPnpDispatch
|
||
// but it will decrement the InUseCount to -1 so it won't set the event.
|
||
//
|
||
if (InterlockedDecrement (&cmBatt->InUseCount) > 0) {
|
||
KeWaitForSingleObject (&cmBatt->ReadyToRemove,
|
||
Executive,
|
||
KernelMode,
|
||
FALSE,
|
||
NULL
|
||
);
|
||
}
|
||
|
||
//
|
||
// Cancel the Wait/wake IRP;
|
||
//
|
||
if (cmBatt->WaitWakeIrp != NULL) {
|
||
IoCancelIrp (cmBatt->WaitWakeIrp);
|
||
cmBatt->WaitWakeIrp = NULL;
|
||
}
|
||
|
||
if (cmBatt->Type == CM_BATTERY_TYPE) {
|
||
//
|
||
// This is a control method battery FDO
|
||
//
|
||
|
||
//
|
||
// Disconnect from receiving device (battery) notifications
|
||
//
|
||
|
||
cmBatt->AcpiInterfaces.UnregisterForDeviceNotifications (
|
||
cmBatt->AcpiInterfaces.Context,
|
||
CmBattNotifyHandler);
|
||
|
||
//
|
||
// Unregister as a WMI Provider.
|
||
//
|
||
CmBattWmiDeRegistration(cmBatt);
|
||
|
||
//
|
||
// Tell the class driver we are going away
|
||
//
|
||
status = BatteryClassUnload (cmBatt->Class);
|
||
ASSERT (NT_SUCCESS(status));
|
||
|
||
} else {
|
||
//
|
||
// This is an AC adapter FDO
|
||
//
|
||
|
||
//
|
||
// Disconnect from receiving device (battery) notifications
|
||
//
|
||
|
||
cmBatt->AcpiInterfaces.UnregisterForDeviceNotifications (
|
||
cmBatt->AcpiInterfaces.Context,
|
||
CmBattNotifyHandler);
|
||
|
||
//
|
||
// Unregister as a WMI Provider.
|
||
//
|
||
CmBattWmiDeRegistration(cmBatt);
|
||
|
||
AcAdapterPdo = NULL;
|
||
}
|
||
|
||
//
|
||
// Clean up, delete the string and the Fdo we created at AddDevice time
|
||
//
|
||
|
||
ExFreePool (cmBatt->DeviceName);
|
||
|
||
IoDetachDevice (cmBatt->LowerDeviceObject);
|
||
IoDeleteDevice (cmBatt->DeviceObject);
|
||
|
||
return STATUS_SUCCESS;
|
||
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
CmBattPowerDispatch(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is the dispatch routine for power requests.
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - Pointer to class device object.
|
||
Irp - Pointer to the request packet.
|
||
|
||
Return Value:
|
||
|
||
Status is returned.
|
||
|
||
--*/
|
||
{
|
||
PIO_STACK_LOCATION irpStack;
|
||
PCM_BATT CmBatt;
|
||
NTSTATUS Status;
|
||
|
||
//
|
||
// A remove lock is not needed in this dispatch function because
|
||
// all data accessed is in the device extension. If any other functionality
|
||
// was added to this routine, a remove lock might be neccesary.
|
||
//
|
||
|
||
CmBattPrint ((CMBATT_TRACE | CMBATT_POWER), ("CmBattPowerDispatch\n"));
|
||
|
||
//
|
||
// Get a pointer to the current parameters for this request. The
|
||
// information is contained in the current stack location.
|
||
//
|
||
irpStack = IoGetCurrentIrpStackLocation(Irp);
|
||
CmBatt = DeviceObject->DeviceExtension;
|
||
|
||
//
|
||
// Dispatch minor function
|
||
//
|
||
switch (irpStack->MinorFunction) {
|
||
|
||
case IRP_MN_WAIT_WAKE: {
|
||
CmBattPrint (CMBATT_POWER, ("CmBattPowerDispatch: IRP_MN_WAIT_WAKE\n"));
|
||
break;
|
||
}
|
||
|
||
case IRP_MN_POWER_SEQUENCE: {
|
||
CmBattPrint (CMBATT_POWER, ("CmBattPowerDispatch: IRP_MN_POWER_SEQUENCE\n"));
|
||
break;
|
||
}
|
||
|
||
case IRP_MN_SET_POWER: {
|
||
CmBattPrint (CMBATT_POWER, ("CmBattPowerDispatch: IRP_MN_SET_POWER type: %d, State: %d \n",
|
||
irpStack->Parameters.Power.Type,
|
||
irpStack->Parameters.Power.State));
|
||
break;
|
||
}
|
||
|
||
case IRP_MN_QUERY_POWER: {
|
||
CmBattPrint (CMBATT_POWER, ("CmBattPowerDispatch: IRP_MN_QUERY_POWER\n"));
|
||
break;
|
||
}
|
||
|
||
default: {
|
||
|
||
CmBattPrint(CMBATT_LOW, ("CmBattPowerDispatch: minor %d\n",
|
||
irpStack->MinorFunction));
|
||
|
||
break;
|
||
}
|
||
}
|
||
|
||
//
|
||
// What do we do with the irp?
|
||
//
|
||
PoStartNextPowerIrp( Irp );
|
||
if (CmBatt->LowerDeviceObject != NULL) {
|
||
|
||
//
|
||
// Forward the request along
|
||
//
|
||
IoSkipCurrentIrpStackLocation( Irp );
|
||
Status = PoCallDriver( CmBatt->LowerDeviceObject, Irp );
|
||
|
||
} else {
|
||
|
||
//
|
||
// Complete the request with the current status
|
||
//
|
||
Status = Irp->IoStatus.Status;
|
||
IoCompleteRequest( Irp, IO_NO_INCREMENT );
|
||
|
||
}
|
||
|
||
return Status;
|
||
}
|
||
|
||
|
||
|
||
NTSTATUS
|
||
CmBattForwardRequest(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine passes the request down the stack
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - The target
|
||
Irp - The request
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS status;
|
||
PCM_BATT cmBatt = DeviceObject->DeviceExtension;
|
||
|
||
//
|
||
// A remove lock is not needed in this dispatch function because
|
||
// all data accessed is in the device extension. If any other functionality was
|
||
// added to this routine, a remove lock might be neccesary.
|
||
//
|
||
|
||
if (cmBatt->LowerDeviceObject != NULL) {
|
||
|
||
IoSkipCurrentIrpStackLocation( Irp );
|
||
status = IoCallDriver( cmBatt->LowerDeviceObject, Irp );
|
||
|
||
} else {
|
||
|
||
Irp->IoStatus.Status = status = STATUS_NOT_SUPPORTED;
|
||
IoCompleteRequest( Irp, IO_NO_INCREMENT );
|
||
|
||
}
|
||
|
||
return status;
|
||
}
|
||
|
||
NTSTATUS
|
||
CmBattWaitWakeLoop(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN UCHAR MinorFunction,
|
||
IN POWER_STATE PowerState,
|
||
IN PVOID Context,
|
||
IN PIO_STATUS_BLOCK IoStatus
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is called after the WAIT_WAKE has been completed
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - The PDO
|
||
MinorFunction - IRP_MN_WAIT_WAKE
|
||
PowerState - The Sleep state that it could wake from
|
||
Context - NOT USED
|
||
IoStatus - The status of the request
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS status;
|
||
PCM_BATT cmBatt = (PCM_BATT) DeviceObject->DeviceExtension;
|
||
|
||
CmBattPrint (CMBATT_PNP, ("CmBattWaitWakeLoop: Entered.\n"));
|
||
if (!NT_SUCCESS(IoStatus->Status) || !cmBatt->WakeEnabled) {
|
||
|
||
CmBattPrint (CMBATT_ERROR, ("CmBattWaitWakeLoop: failed: status = 0x%08x.\n", IoStatus->Status));
|
||
cmBatt->WaitWakeIrp = NULL;
|
||
return IoStatus->Status;
|
||
|
||
} else {
|
||
CmBattPrint (CMBATT_NOTE, ("CmBattWaitWakeLoop: completed successfully\n"));
|
||
}
|
||
|
||
//
|
||
// In this case, we just cause the same thing to happen again
|
||
//
|
||
status = PoRequestPowerIrp(
|
||
DeviceObject,
|
||
MinorFunction,
|
||
PowerState,
|
||
CmBattWaitWakeLoop,
|
||
Context,
|
||
&(cmBatt->WaitWakeIrp)
|
||
);
|
||
|
||
CmBattPrint (CMBATT_NOTE, ("CmBattWaitWakeLoop: PoRequestPowerIrp: status = 0x%08x.\n", status));
|
||
|
||
//
|
||
// Done
|
||
//
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|