Leaked source code of windows server 2003
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.
 
 
 
 
 
 

1003 lines
25 KiB

/*++
Copyright (c) 1997-2000 Microsoft Corporation
Module Name:
fdo.c
Abstract:
This module provides the functions which answer IRPs to functional devices.
Author:
(Derived from MF)
Revision History:
--*/
#include "SpSim.h"
#include "spsimioct.h"
/*++
The majority of functions in this file are called based on their presence
in Pnp and Po dispatch tables. In the interests of brevity the arguments
to all those functions will be described below:
NTSTATUS
SpSimXxxFdo(
IN PIRP Irp,
IN PSPSIM_EXTENSION SpSim,
IN PIO_STACK_LOCATION IrpStack
)
Routine Description:
This function handles the Xxx requests for multifunction FDO's
Arguments:
Irp - Points to the IRP associated with this request.
SpSim - Points to the parent FDO's device extension.
IrpStack - Points to the current stack location for this request.
Return Value:
Status code that indicates whether or not the function was successful.
STATUS_NOT_SUPPORTED indicates that the IRP should be passed down without
changing the Irp->IoStatus.Status field otherwise it is updated with this
status.
--*/
NTSTATUS
SpSimDeferProcessingFdo(
IN PSPSIM_EXTENSION SpSim,
IN OUT PIRP Irp
);
NTSTATUS
SpSimStartFdo(
IN PIRP Irp,
IN PSPSIM_EXTENSION SpSim,
IN PIO_STACK_LOCATION IrpStack
);
NTSTATUS
SpSimStartFdoCompletion(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
);
NTSTATUS
SpSimQueryStopFdo(
IN PIRP Irp,
IN PSPSIM_EXTENSION SpSim,
IN PIO_STACK_LOCATION IrpStack
);
NTSTATUS
SpSimCancelStopFdo(
IN PIRP Irp,
IN PSPSIM_EXTENSION SpSim,
IN PIO_STACK_LOCATION IrpStack
);
NTSTATUS
SpSimQueryRemoveFdo(
IN PIRP Irp,
IN PSPSIM_EXTENSION SpSim,
IN PIO_STACK_LOCATION IrpStack
);
NTSTATUS
SpSimRemoveFdo(
IN PIRP Irp,
IN PSPSIM_EXTENSION SpSim,
IN PIO_STACK_LOCATION IrpStack
);
NTSTATUS
SpSimQueryCapabilitiesFdo(
IN PIRP Irp,
IN PSPSIM_EXTENSION SpSim,
IN PIO_STACK_LOCATION IrpStack
);
NTSTATUS
SpSimSurpriseRemoveFdo(
IN PIRP Irp,
IN PSPSIM_EXTENSION SpSim,
IN PIO_STACK_LOCATION IrpStack
);
NTSTATUS
SpSimCancelRemoveFdo(
IN PIRP Irp,
IN PSPSIM_EXTENSION SpSim,
IN PIO_STACK_LOCATION IrpStack
);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, SpSimCancelRemoveFdo)
#pragma alloc_text(PAGE, SpSimCancelStopFdo)
#pragma alloc_text(PAGE, SpSimCreateFdo)
#pragma alloc_text(PAGE, SpSimDeferProcessingFdo)
#pragma alloc_text(PAGE, SpSimDispatchPnpFdo)
#pragma alloc_text(PAGE, SpSimPassIrp)
#pragma alloc_text(PAGE, SpSimQueryRemoveFdo)
#pragma alloc_text(PAGE, SpSimQueryStopFdo)
#pragma alloc_text(PAGE, SpSimRemoveFdo)
#pragma alloc_text(PAGE, SpSimStartFdo)
#pragma alloc_text(PAGE, SpSimQueryCapabilitiesFdo)
#pragma alloc_text(PAGE, SpSimSurpriseRemoveFdo)
#endif
PSPSIM_DISPATCH SpSimPnpDispatchTableFdo[] = {
SpSimStartFdo, // IRP_MN_START_DEVICE
SpSimQueryRemoveFdo, // IRP_MN_QUERY_REMOVE_DEVICE
SpSimRemoveFdo, // IRP_MN_REMOVE_DEVICE
SpSimCancelRemoveFdo, // IRP_MN_CANCEL_REMOVE_DEVICE
SpSimPassIrp, // IRP_MN_STOP_DEVICE
SpSimQueryStopFdo, // IRP_MN_QUERY_STOP_DEVICE
SpSimCancelStopFdo, // IRP_MN_CANCEL_STOP_DEVICE
SpSimPassIrp, // IRP_MN_QUERY_DEVICE_RELATIONS
SpSimPassIrp, // IRP_MN_QUERY_INTERFACE
SpSimQueryCapabilitiesFdo, // IRP_MN_QUERY_CAPABILITIES
SpSimPassIrp, // IRP_MN_QUERY_RESOURCES
SpSimPassIrp, // IRP_MN_QUERY_RESOURCE_REQUIREMENTS
SpSimPassIrp, // IRP_MN_QUERY_DEVICE_TEXT
SpSimPassIrp, // IRP_MN_FILTER_RESOURCE_REQUIREMENTS
SpSimPassIrp, // Unused
SpSimPassIrp, // IRP_MN_READ_CONFIG
SpSimPassIrp, // IRP_MN_WRITE_CONFIG
SpSimPassIrp, // IRP_MN_EJECT
SpSimPassIrp, // IRP_MN_SET_LOCK
SpSimPassIrp, // IRP_MN_QUERY_ID
SpSimPassIrp, // IRP_MN_QUERY_PNP_DEVICE_STATE
SpSimPassIrp, // IRP_MN_QUERY_BUS_INFORMATION
SpSimPassIrp, // IRP_MN_DEVICE_USAGE_NOTIFICATION
SpSimSurpriseRemoveFdo, // IRP_MN_SURPRISE_REMOVAL
};
NTSTATUS
SpSimCreateFdo(
OUT PDEVICE_OBJECT *Fdo
)
/*++
Routine Description:
This function creates a new FDO and initializes it.
Arguments:
Fdo - Pointer to where the FDO should be returned
Return Value:
Status code that indicates whether or not the function was successful.
--*/
{
NTSTATUS status;
PSPSIM_EXTENSION extension;
PAGED_CODE();
ASSERT((sizeof(SpSimPnpDispatchTableFdo) / sizeof(PSPSIM_DISPATCH)) - 1
== IRP_MN_PNP_MAXIMUM_FUNCTION);
#if 0
ASSERT((sizeof(SpSimPoDispatchTableFdo) / sizeof(PSPSIM_DISPATCH)) -1
== IRP_MN_PO_MAXIMUM_FUNCTION);
#endif
*Fdo = NULL;
status = IoCreateDevice(SpSimDriverObject,
sizeof(SPSIM_EXTENSION),
NULL,
FILE_DEVICE_BUS_EXTENDER,
0,
FALSE,
Fdo
);
if (!NT_SUCCESS(status)) {
goto cleanup;
}
//
// Initialize the extension
//
extension = (PSPSIM_EXTENSION) (*Fdo)->DeviceExtension;
extension->Self = *Fdo;
IoInitializeRemoveLock(&extension->RemoveLock, 0, 1, 20);
extension->PowerState = PowerDeviceD3;
DEBUG_MSG(1, ("Created FDO @ 0x%08x\n", *Fdo));
return status;
cleanup:
if (*Fdo) {
IoDeleteDevice(*Fdo);
}
return status;
}
VOID
SpSimDeleteFdo(
IN PDEVICE_OBJECT Fdo
)
{
PSPSIM_EXTENSION SpSim = Fdo->DeviceExtension;
if (SpSim->DeviceState & SPSIM_DEVICE_DELETED) {
//
// Trying to delete twice
//
ASSERT(!(SpSim->DeviceState & SPSIM_DEVICE_DELETED));
return;
}
SpSim->DeviceState = SPSIM_DEVICE_DELETED;
SpSimDeleteStaOpRegion(SpSim);
SpSimDeleteMemOpRegion(SpSim);
RtlFreeUnicodeString(&SpSim->SymbolicLinkName);
//
// Free up any memory we have allocated
//
IoDeleteDevice(Fdo);
DEBUG_MSG(1, ("Deleted FDO @ 0x%08x\n", Fdo));
}
NTSTATUS
SpSimPassIrp(
IN PIRP Irp,
IN PSPSIM_EXTENSION SpSim,
IN PIO_STACK_LOCATION IrpStack
)
{
PAGED_CODE();
IoSkipCurrentIrpStackLocation(Irp);
return IoCallDriver(SpSim->AttachedDevice, Irp);
}
NTSTATUS
SpSimDispatchPnpFdo(
IN PDEVICE_OBJECT DeviceObject,
IN PSPSIM_EXTENSION SpSim,
IN PIO_STACK_LOCATION IrpStack,
IN OUT PIRP Irp
)
/*++
Routine Description:
This routine handles IRP_MJ_PNP IRPs for FDOs.
Arguments:
DeviceObject - Pointer to the FDO for which this IRP applies.
SpSim - FDO extension
IrpStack - Current stack location
Irp - Pointer to the IRP_MJ_PNP IRP to dispatch.
Return Value:
NT status.
--*/
{
NTSTATUS status;
BOOLEAN isRemoveDevice;
PAGED_CODE();
//
// Get a pointer to our stack location and take appropriate action based
// on the minor function.
//
IoAcquireRemoveLock(&SpSim->RemoveLock, (PVOID) Irp);
isRemoveDevice = IrpStack->MinorFunction == IRP_MN_REMOVE_DEVICE;
if (IrpStack->MinorFunction > IRP_MN_PNP_MAXIMUM_FUNCTION) {
status = SpSimPassIrp(Irp, SpSim, IrpStack);
} else {
status =
SpSimPnpDispatchTableFdo[IrpStack->MinorFunction](Irp,
SpSim,
IrpStack
);
}
if (!isRemoveDevice) {
IoReleaseRemoveLock(&SpSim->RemoveLock, (PVOID) Irp);
}
return status;
}
NTSTATUS
SpSimPnPFdoCompletion(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
/*++
Routine Description:
This routine is used to defer processing of an IRP until drivers
lower in the stack including the bus driver have done their
processing.
This routine triggers the event to indicate that processing of the
irp can now continue.
Arguments:
DeviceObject - Pointer to the FDO for which this IRP applies.
Irp - Pointer to the IRP_MJ_PNP IRP to dispatch.
Return Value:
NT status.
--*/
{
KeSetEvent((PKEVENT) Context, EVENT_INCREMENT, FALSE);
return STATUS_MORE_PROCESSING_REQUIRED;
}
NTSTATUS
SpSimDeferProcessingFdo(
IN PSPSIM_EXTENSION SpSim,
IN OUT PIRP Irp
)
/*++
Routine Description:
This routine is used to defer processing of an IRP until drivers
lower in the stack including the bus driver have done their
processing.
This routine uses an IoCompletion routine along with an event to
wait until the lower level drivers have completed processing of
the irp.
Arguments:
SpSim - FDO extension for the FDO devobj in question
Irp - Pointer to the IRP_MJ_PNP IRP to defer
Return Value:
NT status.
--*/
{
KEVENT event;
NTSTATUS status;
PAGED_CODE();
KeInitializeEvent(&event, NotificationEvent, FALSE);
//
// Set our completion routine
//
IoCopyCurrentIrpStackLocationToNext(Irp);
IoSetCompletionRoutine(Irp,
SpSimPnPFdoCompletion,
&event,
TRUE,
TRUE,
TRUE
);
status = IoCallDriver(SpSim->AttachedDevice, Irp);
if (status == STATUS_PENDING) {
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
status = Irp->IoStatus.Status;
}
return status;
}
NTSTATUS
SpSimStartFdo(
IN PIRP Irp,
IN PSPSIM_EXTENSION SpSim,
IN PIO_STACK_LOCATION IrpStack
)
{
NTSTATUS status;
IO_STACK_LOCATION location;
POWER_STATE power;
PWSTR string;
PAGED_CODE();
status = SpSimDeferProcessingFdo(SpSim, Irp);
if (!NT_SUCCESS(status)) {
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return status;
}
power.DeviceState = PowerDeviceD0;
PoSetPowerState(SpSim->Self, DevicePowerState, power);
SpSim->PowerState = PowerDeviceD0;
status = SpSimCreateStaOpRegion(SpSim);
if (!NT_SUCCESS(status)) {
goto cleanup;
}
status = SpSimCreateMemOpRegion(SpSim);
if (!NT_SUCCESS(status)) {
SpSimDeleteStaOpRegion(SpSim);
goto cleanup;
}
status = SpSimInstallStaOpRegionHandler(SpSim);
if (!NT_SUCCESS(status)) {
SpSimDeleteStaOpRegion(SpSim);
goto cleanup;
}
status = SpSimInstallMemOpRegionHandler(SpSim);
if (!NT_SUCCESS(status)) {
SpSimDeleteStaOpRegion(SpSim);
goto cleanup;
}
status = IoSetDeviceInterfaceState(&SpSim->SymbolicLinkName, TRUE);
cleanup:
Irp->IoStatus.Status = status;
if (!NT_SUCCESS(status)) {
SpSimRemoveStaOpRegionHandler(SpSim);
SpSimDeleteStaOpRegion(SpSim);
SpSimRemoveMemOpRegionHandler(SpSim);
SpSimDeleteMemOpRegion(SpSim);
} else {
//
// We are now started!
//
}
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return status;
}
NTSTATUS
SpSimQueryStopFdo(
IN PIRP Irp,
IN PSPSIM_EXTENSION SpSim,
IN PIO_STACK_LOCATION IrpStack
)
{
PAGED_CODE();
Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_UNSUCCESSFUL;
}
NTSTATUS
SpSimCancelStopFdo(
IN PIRP Irp,
IN PSPSIM_EXTENSION SpSim,
IN PIO_STACK_LOCATION IrpStack
)
{
NTSTATUS status;
PAGED_CODE();
status = SpSimDeferProcessingFdo(SpSim, Irp);
// NTRAID#53498
// ASSERT(status == STATUS_SUCCESS);
// Uncomment after PCI state machine is fixed to not fail bogus stops
Irp->IoStatus.Status = STATUS_SUCCESS;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
NTSTATUS
SpSimQueryRemoveFdo(
IN PIRP Irp,
IN PSPSIM_EXTENSION SpSim,
IN PIO_STACK_LOCATION IrpStack
)
{
PAGED_CODE();
Irp->IoStatus.Status = STATUS_SUCCESS;
return SpSimPassIrp(Irp, SpSim, IrpStack);
}
NTSTATUS
SpSimRemoveFdo(
IN PIRP Irp,
IN PSPSIM_EXTENSION SpSim,
IN PIO_STACK_LOCATION IrpStack
)
{
NTSTATUS status;
POWER_STATE power;
power.DeviceState = PowerDeviceD3;
PoSetPowerState(SpSim->Self, DevicePowerState, power);
SpSim->PowerState = PowerDeviceD3;
(VOID) IoSetDeviceInterfaceState(&SpSim->SymbolicLinkName, FALSE);
SpSimRemoveStaOpRegionHandler(SpSim);
SpSimRemoveMemOpRegionHandler(SpSim);
Irp->IoStatus.Status = STATUS_SUCCESS;
status = SpSimPassIrp(Irp, SpSim, IrpStack);
ASSERT(status == STATUS_SUCCESS);
IoReleaseRemoveLockAndWait(&SpSim->RemoveLock, (PVOID) Irp);
//
// Detach and delete myself
//
IoDetachDevice(SpSim->AttachedDevice);
SpSim->AttachedDevice = NULL;
SpSimDeleteFdo(SpSim->Self);
return STATUS_SUCCESS;
}
NTSTATUS
SpSimQueryCapabilitiesFdo(
IN PIRP Irp,
IN PSPSIM_EXTENSION SpSim,
IN PIO_STACK_LOCATION IrpStack
)
{
NTSTATUS status;
ULONG i;
PAGED_CODE();
status = SpSimDeferProcessingFdo(SpSim, Irp);
if (!NT_SUCCESS(status)) {
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return status;
}
if (IrpStack->Parameters.DeviceCapabilities.Capabilities->Version != 1) {
Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_INVALID_PARAMETER;
}
for (i = 0; i < PowerSystemMaximum; i++) {
SpSim->DeviceStateMapping[i] =
IrpStack->Parameters.DeviceCapabilities.Capabilities->DeviceState[i];
}
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
NTSTATUS
SpSimSurpriseRemoveFdo(
IN PIRP Irp,
IN PSPSIM_EXTENSION SpSim,
IN PIO_STACK_LOCATION IrpStack
)
{
PAGED_CODE();
SpSim->DeviceState |= SPSIM_DEVICE_SURPRISE_REMOVED;
Irp->IoStatus.Status = STATUS_SUCCESS;
return SpSimPassIrp(Irp, SpSim, IrpStack);
}
NTSTATUS
SpSimCancelRemoveFdo(
IN PIRP Irp,
IN PSPSIM_EXTENSION SpSim,
IN PIO_STACK_LOCATION IrpStack
)
{
NTSTATUS status;
PAGED_CODE();
status = SpSimDeferProcessingFdo(SpSim, Irp);
// NTRAID#53498
// ASSERT(status == STATUS_SUCCESS);
// Uncomment after PCI state machine is fixed to not fail bogus stops
Irp->IoStatus.Status = STATUS_SUCCESS;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
NTSTATUS
SpSimSendIoctl(
IN PDEVICE_OBJECT Device,
IN ULONG IoctlCode,
IN PVOID InputBuffer OPTIONAL,
IN ULONG InputBufferLength,
IN PVOID OutputBuffer OPTIONAL,
IN ULONG OutputBufferLength
)
/*++
Description:
Builds and send an IOCTL to a device and return the results
Arguments:
Device - a device on the device stack to receive the IOCTL - the
irp is always sent to the top of the stack
IoctlCode - the IOCTL to run
InputBuffer - arguments to the IOCTL
InputBufferLength - length in bytes of the InputBuffer
OutputBuffer - data returned by the IOCTL
OnputBufferLength - the size in bytes of the OutputBuffer
Return Value:
Status
--*/
{
NTSTATUS status;
IO_STATUS_BLOCK ioStatus;
KEVENT event;
PIRP irp;
PDEVICE_OBJECT targetDevice = NULL;
PAGED_CODE();
KeInitializeEvent(&event, SynchronizationEvent, FALSE);
//
// Get the top of the stack to send the IRP to
//
targetDevice = IoGetAttachedDeviceReference(Device);
if (!targetDevice) {
status = STATUS_INVALID_PARAMETER;
goto exit;
}
//
// Get Io to build the IRP for us
//
irp = IoBuildDeviceIoControlRequest(IoctlCode,
targetDevice,
InputBuffer,
InputBufferLength,
OutputBuffer,
OutputBufferLength,
FALSE, // InternalDeviceIoControl
&event,
&ioStatus
);
if (!irp) {
status = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
//
// Send the IRP and wait for it to complete
//
status = IoCallDriver(targetDevice, irp);
if (status == STATUS_PENDING) {
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
status = ioStatus.Status;
}
exit:
if (targetDevice) {
ObDereferenceObject(targetDevice);
}
return status;
}
NTSTATUS
SpSimDevControl(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
DeviceIoControl handler. It can handle both IOCTL_MEC_BIOS_OP_ACCESS and IOCTL_MEC_LOCAL_OP_ACCESS
calls.
For example purposes this handles running ACPI methods in the bios.
Arguments:
DeviceObject - Pointer to class device object.
Irp - Pointer to the request packet.
Return Value:
ntStatus
--*/
{
PIO_STACK_LOCATION CurrentIrpStack;
PSPSIM_EXTENSION spsim = (PSPSIM_EXTENSION) DeviceObject->DeviceExtension;
NTSTATUS status;
if (Irp == NULL) {
return STATUS_INVALID_PARAMETER_2;
}
if (!(CurrentIrpStack=IoGetCurrentIrpStackLocation(Irp))) {
Irp->IoStatus.Status = STATUS_INVALID_PARAMETER_2;
IoCompleteRequest(Irp, 0);
return STATUS_INVALID_PARAMETER_2;
}
switch(CurrentIrpStack->Parameters.DeviceIoControl.IoControlCode) {
case IOCTL_SPSIM_GET_MANAGED_DEVICES:
status = SpSimGetManagedDevicesIoctl(spsim, Irp, CurrentIrpStack);
break;
case IOCTL_SPSIM_ACCESS_STA:
status = SpSimAccessStaIoctl(spsim, Irp, CurrentIrpStack);
break;
case IOCTL_SPSIM_NOTIFY_DEVICE:
status = SpSimNotifyDeviceIoctl(spsim, Irp, CurrentIrpStack);
break;
case IOCTL_SPSIM_GET_DEVICE_NAME:
status = SpSimGetDeviceName(spsim, Irp, CurrentIrpStack);
break;
default:
status = SpSimPassIrp(Irp, spsim, CurrentIrpStack);
return status;
}
Irp->IoStatus.Status = status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return status;
}
VOID
SpSimPowerCallback(
IN PDEVICE_OBJECT DeviceObject,
IN UCHAR MinorFunction,
IN POWER_STATE PowerState,
IN PVOID Context,
IN PIO_STATUS_BLOCK IoStatus
)
{
PSPSIM_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
SpSimPowerCompletion(
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;
PSPSIM_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];
PoRequestPowerIrp(DeviceObject,
irpStack->MinorFunction,
power,
SpSimPowerCallback,
Irp,
NULL);
return STATUS_MORE_PROCESSING_REQUIRED;
} else {
status = Irp->IoStatus.Status;
PoStartNextPowerIrp(Irp);
IoCompleteRequest(Irp, IO_NO_INCREMENT);
IoReleaseRemoveLock(&deviceExtension->RemoveLock, Irp);
return STATUS_MORE_PROCESSING_REQUIRED;
}
} else {
if (NT_SUCCESS(Irp->IoStatus.Status)) {
PoSetPowerState(DeviceObject, DevicePowerState,
irpStack->Parameters.Power.State);
deviceExtension->PowerState =
irpStack->Parameters.Power.State.DeviceState;
}
PoStartNextPowerIrp(Irp);
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_MORE_PROCESSING_REQUIRED;
}
}
NTSTATUS
SpSimDispatchPower(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
PSPSIM_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:
IoCopyCurrentIrpStackLocationToNext(Irp);
IoSetCompletionRoutine(Irp,
SpSimPowerCompletion,
NULL, //Context
TRUE, //InvokeOnSuccess
TRUE, //InvokeOnError
TRUE //InvokeOnCancel
);
return PoCallDriver(deviceExtension->AttachedDevice, Irp);
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) {
IoCopyCurrentIrpStackLocationToNext(Irp);
IoSetCompletionRoutine(Irp,
SpSimPowerCompletion,
NULL, //Context
TRUE, //InvokeOnSuccess
TRUE, //InvokeOnError
TRUE //InvokeOnCancel
);
break;
} else {
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;
}
}