/*++ 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; } }