1000 lines
25 KiB
C
1000 lines
25 KiB
C
/*++
|
||
|
||
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 || !(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;
|
||
}
|
||
}
|