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
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;
|
|
}
|
|
}
|