470 lines
11 KiB
C
470 lines
11 KiB
C
/*++
|
|
|
|
Copyright (c) 1999-2001 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
pnpmem.c
|
|
|
|
Abstract:
|
|
|
|
This module implements the Plug and Play Memory driver entry points.
|
|
|
|
Author:
|
|
|
|
Dave Richards (daveri) 16-Aug-1999
|
|
|
|
Environment:
|
|
|
|
Kernel mode only.
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "pnpmem.h"
|
|
#include <initguid.h>
|
|
#include <poclass.h>
|
|
|
|
#define PM_DEBUG_BUFFER_SIZE 512
|
|
#define rgzMemoryManagement L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Session Manager\\Memory Management"
|
|
#define rgzMemoryRemovable L"Memory Removable"
|
|
|
|
NTSTATUS
|
|
DriverEntry(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PUNICODE_STRING RegistryPath
|
|
);
|
|
|
|
NTSTATUS
|
|
PmAddDevice(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PDEVICE_OBJECT Pdo
|
|
);
|
|
|
|
NTSTATUS
|
|
PmPnpDispatch(
|
|
IN PDEVICE_OBJECT Fdo,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
VOID
|
|
PmUnload(
|
|
IN PDRIVER_OBJECT DriverObject
|
|
);
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(INIT, DriverEntry)
|
|
#pragma alloc_text(PAGE, PmAddDevice)
|
|
#pragma alloc_text(PAGE, PmUnload)
|
|
#endif
|
|
|
|
ULONG DbgMask = 0xFFFFFFFF;
|
|
BOOLEAN MemoryRemovalSupported;
|
|
|
|
#if DBG
|
|
VOID
|
|
PmDebugPrint(
|
|
ULONG DebugPrintLevel,
|
|
PCCHAR DebugMessage,
|
|
...
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
DebugPrintLevel - The bit mask that when anded with the debuglevel, must
|
|
equal itself
|
|
DebugMessage - The string to feed through vsprintf
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
va_list ap;
|
|
UCHAR debugBuffer[PM_DEBUG_BUFFER_SIZE];
|
|
|
|
//
|
|
// Get the variable arguments
|
|
//
|
|
va_start( ap, DebugMessage );
|
|
|
|
//
|
|
// Call the kernel function to print the message
|
|
//
|
|
_vsnprintf( debugBuffer, PM_DEBUG_BUFFER_SIZE, DebugMessage, ap );
|
|
|
|
if (DebugPrintLevel & DbgMask) {
|
|
DbgPrint("%s", debugBuffer);
|
|
}
|
|
|
|
//
|
|
// We are done with the varargs
|
|
//
|
|
va_end( ap );
|
|
}
|
|
#endif
|
|
|
|
NTSTATUS
|
|
PmAddDevice(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PDEVICE_OBJECT PhysicalDeviceObject
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function creates a functional device object and attaches it to
|
|
the physical device object (device stack).
|
|
|
|
Arguments:
|
|
|
|
DriverObject - The driver object.
|
|
|
|
Pdo - The physical device object.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
|
|
{
|
|
PDEVICE_OBJECT functionalDeviceObject;
|
|
PDEVICE_OBJECT attachedDeviceObject;
|
|
PPM_DEVICE_EXTENSION deviceExtension;
|
|
NTSTATUS status;
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// Create the FDO.
|
|
//
|
|
|
|
status = IoCreateDevice(
|
|
DriverObject,
|
|
sizeof (PM_DEVICE_EXTENSION),
|
|
NULL,
|
|
FILE_DEVICE_UNKNOWN | FILE_DEVICE_SECURE_OPEN,
|
|
0,
|
|
FALSE,
|
|
&functionalDeviceObject
|
|
);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
return status;
|
|
}
|
|
|
|
//
|
|
// Attach the FDO (indirectly) to the PDO.
|
|
//
|
|
|
|
deviceExtension = functionalDeviceObject->DeviceExtension;
|
|
|
|
deviceExtension->AttachedDevice = IoAttachDeviceToDeviceStack(
|
|
functionalDeviceObject,
|
|
PhysicalDeviceObject
|
|
);
|
|
|
|
if (deviceExtension->AttachedDevice == NULL) {
|
|
IoDeleteDevice(functionalDeviceObject);
|
|
return STATUS_NO_SUCH_DEVICE;
|
|
}
|
|
|
|
IoInitializeRemoveLock(&deviceExtension->RemoveLock, 0, 1, 20);
|
|
|
|
functionalDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
|
|
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS
|
|
PmControlDispatch(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
{
|
|
PPM_DEVICE_EXTENSION deviceExtension;
|
|
|
|
deviceExtension = DeviceObject->DeviceExtension;
|
|
IoSkipCurrentIrpStackLocation(Irp);
|
|
|
|
return IoCallDriver(deviceExtension->AttachedDevice, Irp);
|
|
}
|
|
|
|
VOID
|
|
PmPowerCallback(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN UCHAR MinorFunction,
|
|
IN POWER_STATE PowerState,
|
|
IN PVOID Context,
|
|
IN PIO_STATUS_BLOCK IoStatus
|
|
)
|
|
{
|
|
PPM_DEVICE_EXTENSION deviceExtension;
|
|
PIRP Irp;
|
|
NTSTATUS status;
|
|
|
|
Irp = Context;
|
|
deviceExtension = DeviceObject->DeviceExtension;
|
|
|
|
Irp->IoStatus.Status = IoStatus->Status;
|
|
PoStartNextPowerIrp(Irp);
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
IoReleaseRemoveLock(&deviceExtension->RemoveLock, Irp);
|
|
}
|
|
|
|
NTSTATUS
|
|
PmPowerCompletion(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PVOID NotUsed
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The completion routine for Power
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - pointer to a device object.
|
|
|
|
Irp - pointer to an I/O Request Packet.
|
|
|
|
Not used - context pointer
|
|
|
|
Return Value:
|
|
|
|
NT status code
|
|
|
|
--*/
|
|
{
|
|
PIO_STACK_LOCATION irpStack;
|
|
PPM_DEVICE_EXTENSION deviceExtension;
|
|
NTSTATUS status;
|
|
|
|
irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
deviceExtension = DeviceObject->DeviceExtension;
|
|
|
|
if (irpStack->Parameters.Power.Type == SystemPowerState) {
|
|
SYSTEM_POWER_STATE system =
|
|
irpStack->Parameters.Power.State.SystemState;
|
|
POWER_STATE power;
|
|
|
|
if (NT_SUCCESS(Irp->IoStatus.Status)) {
|
|
|
|
power.DeviceState = deviceExtension->DeviceStateMapping[system];
|
|
|
|
status = PoRequestPowerIrp(DeviceObject,
|
|
irpStack->MinorFunction,
|
|
power,
|
|
PmPowerCallback,
|
|
Irp,
|
|
NULL);
|
|
if (NT_SUCCESS(status)) {
|
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
|
} else {
|
|
Irp->IoStatus.Status = status;
|
|
}
|
|
}
|
|
PoStartNextPowerIrp(Irp);
|
|
IoReleaseRemoveLock(&deviceExtension->RemoveLock, Irp);
|
|
return STATUS_SUCCESS;
|
|
} else {
|
|
if (NT_SUCCESS(Irp->IoStatus.Status)) {
|
|
PoSetPowerState(DeviceObject, DevicePowerState,
|
|
irpStack->Parameters.Power.State);
|
|
deviceExtension->PowerState =
|
|
irpStack->Parameters.Power.State.DeviceState;
|
|
}
|
|
PoStartNextPowerIrp(Irp);
|
|
IoReleaseRemoveLock(&deviceExtension->RemoveLock, Irp);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
}
|
|
NTSTATUS
|
|
PmPowerDispatch(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
{
|
|
PPM_DEVICE_EXTENSION deviceExtension;
|
|
PIO_STACK_LOCATION irpStack;
|
|
NTSTATUS status;
|
|
|
|
irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
deviceExtension = DeviceObject->DeviceExtension;
|
|
|
|
status = IoAcquireRemoveLock(&deviceExtension->RemoveLock, (PVOID) Irp);
|
|
if (status == STATUS_DELETE_PENDING) {
|
|
Irp->IoStatus.Status = STATUS_NO_SUCH_DEVICE;
|
|
PoStartNextPowerIrp(Irp);
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
return STATUS_NO_SUCH_DEVICE;
|
|
}
|
|
|
|
if (irpStack->Parameters.Power.Type == SystemPowerState) {
|
|
switch (irpStack->MinorFunction) {
|
|
case IRP_MN_QUERY_POWER:
|
|
case IRP_MN_SET_POWER:
|
|
IoMarkIrpPending(Irp);
|
|
IoCopyCurrentIrpStackLocationToNext(Irp);
|
|
IoSetCompletionRoutine(Irp,
|
|
PmPowerCompletion,
|
|
NULL, //Context
|
|
TRUE, //InvokeOnSuccess
|
|
TRUE, //InvokeOnError
|
|
TRUE //InvokeOnCancel
|
|
);
|
|
(VOID) PoCallDriver(deviceExtension->AttachedDevice, Irp);
|
|
return STATUS_PENDING;
|
|
default:
|
|
PoStartNextPowerIrp(Irp);
|
|
IoSkipCurrentIrpStackLocation(Irp);
|
|
status = PoCallDriver(deviceExtension->AttachedDevice, Irp);
|
|
IoReleaseRemoveLock(&deviceExtension->RemoveLock, Irp);
|
|
return status;
|
|
}
|
|
} else {
|
|
switch (irpStack->MinorFunction) {
|
|
case IRP_MN_SET_POWER:
|
|
|
|
if (irpStack->Parameters.Power.State.DeviceState <=
|
|
deviceExtension->PowerState) {
|
|
|
|
//
|
|
// Powering up device
|
|
//
|
|
|
|
IoCopyCurrentIrpStackLocationToNext(Irp);
|
|
IoSetCompletionRoutine(Irp,
|
|
PmPowerCompletion,
|
|
NULL, //Context
|
|
TRUE, //InvokeOnSuccess
|
|
TRUE, //InvokeOnError
|
|
TRUE //InvokeOnCancel
|
|
);
|
|
(VOID) PoCallDriver(deviceExtension->AttachedDevice, Irp);
|
|
return STATUS_PENDING;
|
|
|
|
} else {
|
|
|
|
//
|
|
// Powering down device
|
|
//
|
|
|
|
PoSetPowerState(DeviceObject, DevicePowerState,
|
|
irpStack->Parameters.Power.State);
|
|
deviceExtension->PowerState =
|
|
irpStack->Parameters.Power.State.DeviceState;
|
|
//
|
|
// Fall through ...
|
|
//
|
|
}
|
|
case IRP_MN_QUERY_POWER:
|
|
//
|
|
// Fall through as the bus driver will mark this
|
|
// STATUS_SUCCESS and complete it, if it gets that far.
|
|
//
|
|
default:
|
|
PoStartNextPowerIrp(Irp);
|
|
IoSkipCurrentIrpStackLocation(Irp);
|
|
break;
|
|
}
|
|
status = PoCallDriver(deviceExtension->AttachedDevice, Irp);
|
|
IoReleaseRemoveLock(&deviceExtension->RemoveLock, Irp);
|
|
return status;
|
|
}
|
|
}
|
|
|
|
NTSTATUS
|
|
DriverEntry(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PUNICODE_STRING RegistryPath
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function initializes the driver object.
|
|
|
|
Arguments:
|
|
|
|
DriverObject - The driver object.
|
|
|
|
RegistryPath - The registry path for the device.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS
|
|
|
|
--*/
|
|
|
|
{
|
|
OBJECT_ATTRIBUTES objectAttributes;
|
|
UNICODE_STRING unicodeString;
|
|
PKEY_VALUE_PARTIAL_INFORMATION valueInfo;
|
|
HANDLE hMemoryManagement;
|
|
NTSTATUS status;
|
|
|
|
PAGED_CODE();
|
|
|
|
RtlInitUnicodeString (&unicodeString, rgzMemoryManagement);
|
|
InitializeObjectAttributes (&objectAttributes,
|
|
&unicodeString,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL, // handle
|
|
NULL);
|
|
status = ZwOpenKey(&hMemoryManagement, KEY_READ, &objectAttributes);
|
|
if (NT_SUCCESS(status)) {
|
|
status = PmGetRegistryValue(hMemoryManagement,
|
|
rgzMemoryRemovable,
|
|
&valueInfo);
|
|
if (NT_SUCCESS(status)) {
|
|
if ((valueInfo->Type == REG_DWORD) &&
|
|
(valueInfo->DataLength >= sizeof(ULONG))) {
|
|
MemoryRemovalSupported = (BOOLEAN) *((PULONG)valueInfo->Data);
|
|
}
|
|
ExFreePool(valueInfo);
|
|
}
|
|
ZwClose(hMemoryManagement);
|
|
}
|
|
|
|
DriverObject->MajorFunction[IRP_MJ_PNP] = PmPnpDispatch;
|
|
DriverObject->MajorFunction[IRP_MJ_POWER] = PmPowerDispatch;
|
|
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = PmControlDispatch;
|
|
DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = PmControlDispatch;
|
|
DriverObject->DriverExtension->AddDevice = PmAddDevice;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
VOID
|
|
PmUnload(
|
|
IN PDRIVER_OBJECT DriverObject
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is called to reverse any operations performed in DriverEntry before a
|
|
driver is unloaded.
|
|
|
|
Arguments:
|
|
|
|
DriverObject - The system owned driver object for PNPMEM
|
|
|
|
--*/
|
|
{
|
|
PAGED_CODE();
|
|
|
|
return;
|
|
}
|