www.pudn.com > driver.zip > PnPManagement.c
/******************************************************************************
* * File Name:
* * PlugPlay.c
* * Description:
* * Plug 'n' Play handler functions
* * Revision History:
* * 10-11-07 : Silicon Image 1.00
*******************************************************************************/
#define INITGUID // Initialize WDMIO_GUID in this module
#include "Sil3124.h"
#include "GUIDs.h"
#pragma code_seg("PAGE") // start PAGE section
/******************************************************************************
*
* Function : AddDevice
*
* Description: Add a new functional device object for a physical one
*
******************************************************************************/
NTSTATUS AddDevice(IN PDRIVER_OBJECT pDriverObject,
IN PDEVICE_OBJECT pdo)
{ // AddDevice
NTSTATUS status;
POWER_STATE state;
PDEVICE_OBJECT fdo;
PDEVICE_EXTENSION pdx;
DebugPrint("AddDevice Start...............Version:1.0.0");
//Create a functional device object to represent the hardware we're managing.
//Create Device
status = IoCreateDevice(pDriverObject, sizeof(DEVICE_EXTENSION), NULL,
FILE_DEVICE_UNKNOWN, 0, FALSE, &fdo); //DeviceCharacteristics be setted 0
if (!NT_SUCCESS(status))
{ // can't create device object
DebugPrint("Sil3124 IoCreateDevice failed %x\n",status);
return(status);
} // can't create device object
pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension;
// From this point forward, any error will have side effects that need to
// be cleaned up. Using a try-finally block allows us to modify the program
// easily without losing track of the side effects.
__try
{
//Initialize device extension
pdx->pDeviceObject = fdo;
pdx->pPhysicalDeviceObject = pdo;
KeInitializeEvent(&pdx->StoppingEvent,NotificationEvent,FALSE);
pdx->bStopping = FALSE;
pdx->GotResource = FALSE;
// Indicate the I/O Manager buffer management method
//once initial,can not be changed
fdo->Flags |= DO_BUFFERED_IO;
// fdo->Flags |= DO_DIRECT_IO;
// Initialize DPC object
IoInitializeDpcRequest(fdo, DpcForIsr);
// Register a device interface
status = IoRegisterDeviceInterface(pdo,&GUID_INTERFACE_Sil3124,
NULL,&pdx->InterfaceName);
if (!NT_SUCCESS(status))
{ // unable to register interface
DebugPrint("Sil3124: - IoRegisterDeviceInterface failed - %x.", status);
//IoDeleteDevice(fdo);
//return(status);
__leave;
} // unable to register interface
// Link our device object into the stack leading to the PDO
pdx->pLowerDeviceObject = IoAttachDeviceToDeviceStack(fdo, pdo);
if (!pdx->pLowerDeviceObject)
{ // can't attach device
DebugPrint("Sil3124: - IoAttachDeviceToDeviceStack failed.");
status = STATUS_DEVICE_REMOVED;
//return(status);
__leave;
} // can't attach device
//set deviceInterface state
IoSetDeviceInterfaceState(&pdx->InterfaceName, TRUE);
// Indicate that our initial power state is D0 (fully on). Also indicate that
// we have a pagable power handler (otherwise, we'll never get idle shutdown
// messages!)
pdx->SystemPower = PowerSystemWorking;
pdx->DevicePower = PowerDeviceD0;
fdo->Flags |= DO_POWER_PAGABLE;
state.DeviceState = PowerDeviceD0;
PoSetPowerState(fdo, DevicePowerState, state);
DebugPrint("Adddevice End.");
// Clear the "initializing" flag so that we can get IRPs
fdo->Flags &= ~DO_DEVICE_INITIALIZING;
} // finish initialization
__finally
{ // cleanup side effects
if (!NT_SUCCESS(status))
{ // need to cleanup
if (pdx->InterfaceName.Buffer)
RtlFreeUnicodeString(&pdx->InterfaceName);
if (pdx->pLowerDeviceObject)
IoDetachDevice(pdx->pLowerDeviceObject);
IoDeleteDevice(fdo);
} // need to cleanup
// cleanup side effects
}
return(STATUS_SUCCESS);
} // AddDevice
/******************************************************************************
*
* Function : DispatchPnp
*
* Description: Handle PnP requests
*
******************************************************************************/
NTSTATUS DispatchPnp(IN PDEVICE_OBJECT fdo,
IN PIRP pIrp)
{ //DispatchPnp
NTSTATUS status;
PIO_STACK_LOCATION stack;
PDEVICE_EXTENSION pdx;
DebugPrint("Pnp Start....");
pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension;
stack = IoGetCurrentIrpStackLocation(pIrp);
// Check minor code
//if check no exist,default handling
switch (stack->MinorFunction)
{
case IRP_MN_START_DEVICE: //must be implemented
DebugPrint("IRP_MN_START_DEVICE.");
status = PnpStartDevice(fdo,pIrp);
//status = DefaultPnpHandler(fdo,pIrp);
break;
case IRP_MN_STOP_DEVICE:
DebugPrint("IRP_MN_STOP_DEVICE.");
status = PnpStopDevice(fdo,pIrp);
//status = DefaultPnpHandler(fdo,pIrp);
break;
case IRP_MN_REMOVE_DEVICE:
DebugPrint("IRP_MN_REMOVE_DEVICE.");
status = PnpRemoveDevice(fdo,pIrp);
//status = DefaultPnpHandler(fdo,pIrp);
return status;
break;
case IRP_MN_QUERY_REMOVE_DEVICE:
DebugPrint("IRP_MN_QUERY_REMOVE_DEVICE.");
status = PnpQueryRemoveDeviceHandler(fdo,pIrp);
//status = DefaultPnpHandler(fdo,pIrp);
break;
case IRP_MN_CANCEL_REMOVE_DEVICE:
DebugPrint("IRP_MN_CANCEL_REMOVE_DEVICE.");
status = DefaultPnpHandler(fdo,pIrp);
break;
case IRP_MN_QUERY_STOP_DEVICE:
DebugPrint("IRP_MN_QUERY_STOP_DEVICE.");
status = DefaultPnpHandler(fdo,pIrp);
break;
case IRP_MN_CANCEL_STOP_DEVICE:
DebugPrint("IRP_MN_CANCEL_STOP_DEVICE.");
status = DefaultPnpHandler(fdo,pIrp);
break;
case IRP_MN_QUERY_DEVICE_RELATIONS:
DebugPrint("IRP_MN_QUERY_DEVICE_RELATIONS.");
status = DefaultPnpHandler(fdo,pIrp);
break;
case IRP_MN_QUERY_INTERFACE:
DebugPrint("IRP_MN_QUERY_INTERFACE.");
status = DefaultPnpHandler(fdo,pIrp);
break;
case IRP_MN_QUERY_CAPABILITIES:
DebugPrint("IRP_MN_QUERY_CAPABILITIES.");
status = DefaultPnpHandler(fdo,pIrp);
//status = PnpQueryCapabilitiesHandler(fdo,pIrp);
break;
case IRP_MN_QUERY_RESOURCES:
DebugPrint("IRP_MN_QUERY_RESOURCES.");
status = DefaultPnpHandler(fdo,pIrp);
break;
case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
DebugPrint("IRP_MN_QUERY_RESOURCE_REQUIREMENTS.");
status = DefaultPnpHandler(fdo,pIrp);
break;
case IRP_MN_QUERY_DEVICE_TEXT:
DebugPrint("IRP_MN_QUERY_DEVICE_TEXT.");
status = DefaultPnpHandler(fdo,pIrp);
break;
case IRP_MN_FILTER_RESOURCE_REQUIREMENTS:
DebugPrint("IRP_MN_FILTER_RESOURCE_REQUIREMENTS.");
status = DefaultPnpHandler(fdo,pIrp);
break;
case IRP_MN_READ_CONFIG:
DebugPrint("IRP_MN_READ_CONFIG.");
status = DefaultPnpHandler(fdo,pIrp);
break;
case IRP_MN_WRITE_CONFIG:
DebugPrint("IRP_MN_WRITE_CONFIG.");
status = DefaultPnpHandler(fdo,pIrp);
break;
case IRP_MN_EJECT:
DebugPrint("IRP_MN_EJECT.");
status = DefaultPnpHandler(fdo,pIrp);
break;
case IRP_MN_SET_LOCK:
DebugPrint("IRP_MN_SET_LOCK.");
status = DefaultPnpHandler(fdo,pIrp);
break;
case IRP_MN_QUERY_ID:
DebugPrint("IRP_MN_QUERY_ID.");
status = DefaultPnpHandler(fdo,pIrp);
break;
case IRP_MN_QUERY_PNP_DEVICE_STATE:
DebugPrint("IRP_MN_QUERY_PNP_DEVICE_STATE.");
status = DefaultPnpHandler(fdo,pIrp);
break;
case IRP_MN_QUERY_BUS_INFORMATION:
DebugPrint("IRP_MN_QUERY_BUS_INFORMATION.");
status = DefaultPnpHandler(fdo,pIrp);
break;
case IRP_MN_DEVICE_USAGE_NOTIFICATION:
DebugPrint("IRP_MN_DEVICE_USAGE_NOTIFICATION.");
status = DefaultPnpHandler(fdo,pIrp);
break;
case IRP_MN_SURPRISE_REMOVAL:
DebugPrint("IRP_MN_SURPRISE_REMOVAL.");
status = DefaultPnpHandler(fdo,pIrp);
break;
default:
DebugPrint("Unsupported IRP_MN_Xxx (0x%x).", stack->MinorFunction);
status = DefaultPnpHandler(fdo,pIrp);
break;
}
DebugPrint("Pnp End.");
return(status);
} //DispatchPnp
/******************************************************************************
*
* Function : DefaultPnpHandler
*
* Description: Handle standard PnP requests
*
******************************************************************************/
NTSTATUS DefaultPnpHandler(IN PDEVICE_OBJECT fdo,
IN PIRP pIrp)
{ //DefaultPnpHandler
DebugPrintMsg("PnpDefaultHandler");
IoSkipCurrentIrpStackLocation(pIrp);
return IoCallDriver(((DEVICE_EXTENSION *)fdo->DeviceExtension)->pLowerDeviceObject,
pIrp);
} //DefaultPnpHandler
/******************************************************************************
*
* Function : HandleStartDevice
*
* Description: Handle the IRP_MN_START_DEVICE PnP request
*
******************************************************************************/
NTSTATUS PnpStartDevice(IN PDEVICE_OBJECT fdo,
IN PIRP pIrp )
{ //HandleStartDevice
NTSTATUS status;
PIO_STACK_LOCATION stack;
//First let all lower-level drivers handle this request.
pIrp->IoStatus.Status = STATUS_SUCCESS;
status = ForwardAndWait(fdo,pIrp); //Send IRP to lower driver(Bus Driver) and wait for finishing
if (!NT_SUCCESS(status))
{
return(CompleteRequest(pIrp, status));
}
stack = IoGetCurrentIrpStackLocation(pIrp);
// Assign resources to the devices
status = StartDevice(fdo,
&stack->Parameters.StartDevice.AllocatedResources->List[0].PartialResourceList,
&stack->Parameters.StartDevice.AllocatedResourcesTranslated->List[0].PartialResourceList);
return(CompleteRequestInfo(pIrp,status,0));
} //HandleStartDevice
/******************************************************************************
*
* Function : StartDevice
*
* Description: Start a device
*
******************************************************************************/
NTSTATUS StartDevice(IN PDEVICE_OBJECT fdo,
IN PCM_PARTIAL_RESOURCE_LIST ResourceListRaw,
IN PCM_PARTIAL_RESOURCE_LIST ResourceList)
{ //StartDevice
ULONG i;
ULONG m;
NTSTATUS status;
PDEVICE_EXTENSION pdx;
PUCHAR MappedAddress;
PCM_PARTIAL_RESOURCE_DESCRIPTOR ResourceRaw;
PCM_PARTIAL_RESOURCE_DESCRIPTOR Resource;
DEVICE_DESCRIPTION deviceDescription ; // device descriptor
pdx = (PDEVICE_EXTENSION)fdo->DeviceExtension;
ResourceRaw = ResourceListRaw->PartialDescriptors;
Resource = ResourceList->PartialDescriptors;
#define MAX_DMA_LENGTH 0x100000 // 0x100000 is 1 MB
//initialize the device descriptor
// Zero the device descriptor struct before fill
RtlZeroMemory(&deviceDescription, sizeof(deviceDescription));
deviceDescription.Version = DEVICE_DESCRIPTION_VERSION ;
deviceDescription.Master = TRUE ; // bus master.
deviceDescription.ScatterGather = TRUE ;
deviceDescription.DemandMode = FALSE ; //Indicates whether to use the system DMA controller's demand mode. Not used for busmaster DMA.
deviceDescription.AutoInitialize = FALSE ; // We don't use autoinitialize
deviceDescription.Dma32BitAddresses = TRUE ;
deviceDescription.IgnoreCount = FALSE;
deviceDescription.InterfaceType = PCIBus ;
deviceDescription.DmaWidth = Width32Bits ; //PCI default width
deviceDescription.DmaSpeed = Compatible ;
deviceDescription.MaximumLength = MAX_DMA_LENGTH ;
//get adapter object
pdx->AdapterObject = IoGetDmaAdapter(pdx->pPhysicalDeviceObject,&deviceDescription,
&pdx->MaximumMapRegisters) ;
DebugPrint("the # of map register system provide is:%u\n",pdx->MaximumMapRegisters);
// If IoGetDmaAdapter fails, it is mostly likely that one of the parameters
// supplied in the DEVICE_DESCRIPTION structure is not valid. It can also fail because of insufficient
// resource, but not very likely.
if (pdx->AdapterObject == NULL) {
DebugPrint ("Sil3124: IoGetDmaAdapter failed.\n") ;
status = STATUS_DEVICE_CONFIGURATION_ERROR ;
return status;
}
DebugPrint("Start Device Start.");
DebugPrint("the ResourceListRaw->count is %x\n",ResourceListRaw->Count);
for (i = 0,m = 0; i < ResourceListRaw->Count; ++i, ++Resource, ++ResourceRaw)
{
switch (ResourceRaw->Type)
{
case CmResourceTypePort: //IO Port Resource
DebugPrint("ResourceType:Registers that provide indirect access to the registers of sil3124");
pdx->BaseAddress_Indirect_Access = Resource->u.Port.Start;
pdx->IORangeBytes = Resource->u.Port.Length;
DebugPrint("Indirect Access Register base address : 0x%x\n",pdx->BaseAddress_Indirect_Access);
DebugPrint("Indirect Access register's length :%ubytes\n",pdx->IORangeBytes);
if(ResourceRaw->Flags & CM_RESOURCE_PORT_IO)
{
DebugPrint("The TaskFile register of channel#0 is accessed in IO address space");
}
else
{
DebugPrint("The TaskFile register of channel#0 is accessed in Memory address space");
}
break;
case CmResourceTypeMemory: //Memory Resources
DebugPrint("ResourceType:Memory Registers that provide access for Global Register and 4 PCI Ports ");
switch(m)
{
case 0: //Base Address 0 Global register base address
pdx->BaseAddress_GlobalRegister = Resource->u.Memory.Start;
pdx->GlobalRegisterBytes = Resource->u.Memory.Length;
DebugPrint("Global register base address : 0x%x\n",pdx->BaseAddress_GlobalRegister);
DebugPrint("Global register's length :%ubytes\n",pdx->GlobalRegisterBytes);
if(ResourceRaw->Flags == CM_RESOURCE_MEMORY_READ_WRITE)
{
DebugPrint("the global registers could be read & write");
}
else
{
DebugPrint("the global registers could be read OR write");
}
pdx->Map_GlobalRegister = NULL;
break;
case 1: //Base Address 1 Port register and LRAM base address for 4 ports
pdx->BaseAddress_PortRegister = Resource->u.Memory.Start;
pdx->PortRegisterBytes = Resource->u.Memory.Length;
DebugPrint("Port register base address : 0x%x\n",pdx->BaseAddress_PortRegister);
DebugPrint("Port register's length :%ubytes\n",pdx->PortRegisterBytes);
if(ResourceRaw->Flags & CM_RESOURCE_MEMORY_READ_WRITE)
{
DebugPrint("the Port registers could be read & write");
}
else
{
DebugPrint("the Port registers could be read OR write");
}
pdx->Map_PortRegister = NULL;
break;
}
m++;
break;
case CmResourceTypeInterrupt: //Interrupt Resources
pdx->GotInterrupt = TRUE;
pdx->IrqL = (KIRQL) Resource->u.Interrupt.Level;
pdx->vector = Resource->u.Interrupt.Vector;
pdx->affinity = Resource->u.Interrupt.Affinity;
DebugPrint("the Interrupt Flags:%x\n",ResourceRaw->Flags);
if (ResourceRaw->Flags == CM_RESOURCE_INTERRUPT_LATCHED)
{
pdx->mode = Latched;
}
else
{
pdx->mode = LevelSensitive;
}
pdx->irqshare = Resource->ShareDisposition == CmResourceShareShared;
DebugPrint("ResouceType: Interrupt:Vector:0x%x(Translated=0x%x)",
ResourceRaw->u.Interrupt.Vector, pdx->vector);
DebugPrint(" IRQL:0x%x(Translated=0x%x)Affinity:0x%x(Translated=0x%x).",
ResourceRaw->u.Interrupt.Level, pdx->IrqL,
ResourceRaw->u.Interrupt.Affinity, pdx->affinity);
break;
default:
DebugPrint("Type: ?Unknown Resource Type?");
break;
}
}
//connect to interrupt
if (pdx->GotInterrupt)
{
DebugPrint("Get Interrupt.");
// firstly,Disable the PCI interrupt
//DisablePciInterrupt(pdx);
//connect interrupt
status = IoConnectInterrupt(&pdx->InterruptObject,(PKSERVICE_ROUTINE)OnInterrupt,
(PVOID)pdx,NULL,pdx->vector,pdx->IrqL,pdx->IrqL,pdx->mode,pdx->irqshare,pdx->affinity,FALSE);
if (!NT_SUCCESS(status))
{
pdx->InterruptObject = NULL;
return status;
}
DebugPrint("OK, I haved Connect Interruput!");
}
else
{
DebugPrint("Sil3124: No interrupt found.");
pdx->InterruptObject = NULL;
}
// Initialize DPC object
IoInitializeDpcRequest(fdo, DpcForIsr);
pdx->NeedToHandle =FALSE;
DebugPrint("Start Device end.");
pdx->GotResource = TRUE;
return STATUS_SUCCESS;
}
//StartDevice
/******************************************************************************
*
* Function : OnRequestComplete
*
* Description: Set an event when a lower driver complete an IRP.
*
******************************************************************************/
NTSTATUS OnRequestComplete(IN PDEVICE_OBJECT fdo,
IN PIRP pIrp,
IN PKEVENT pKEvent)
{ //OnRequestComplete
KeSetEvent(pKEvent,(KPRIORITY)0,FALSE);
return(STATUS_MORE_PROCESSING_REQUIRED);
} //OnRequestComplete
/******************************************************************************
*
* Function : HandleStopDevice
*
* Description: Handle the IRP_MN_STOP_DEVICE PnP request
*
******************************************************************************/
NTSTATUS PnpStopDevice(IN PDEVICE_OBJECT fdo,
IN PIRP pIrp)
{
DebugPrintMsg("PnpStopDeviceHandler");
// Wait for I/O to complete and stop device
StopDevice(fdo);
return DefaultPnpHandler(fdo,pIrp);
} //HandleStopDevice
/******************************************************************************
*
* Function : StopDevice
*
* Description: Stop a device
*
******************************************************************************/
VOID StopDevice(IN PDEVICE_OBJECT fdo)
{ //StopDevice
DEVICE_EXTENSION *pdx;
pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension;
if (!pdx->GotResource)
return;
pdx->bStopping = TRUE;
DebugPrintMsg("StopDevice");
if( !pdx->GotResource)
return;
pdx->GotResource = FALSE;
} //StopDevice
/////////////////////////////////////////////////////////////////////////////
// PnpQueryRemoveDeviceHandler: Handle PnP query remove device
NTSTATUS PnpQueryRemoveDeviceHandler( IN PDEVICE_OBJECT fdo, IN PIRP Irp)
{
PDEVICE_EXTENSION pdx=(PDEVICE_EXTENSION)fdo->DeviceExtension;
DebugPrintMsg("PnpQueryRemoveDeviceHandler");
if( pdx->OpenHandleCount>0)
{
DebugPrint("PnpQueryRemoveDeviceHandler: %d handles still open",pdx->OpenHandleCount);
return CompleteRequestInfo( Irp, STATUS_UNSUCCESSFUL, 0);
}
return DefaultPnpHandler(fdo,Irp);
}
/******************************************************************************
*
* Function : PnpRemoveDevice
*
* Description: Handle the IRP_MN_REMOVE_DEVICE PnP request
*
******************************************************************************/
NTSTATUS PnpRemoveDevice(IN PDEVICE_OBJECT fdo,
IN PIRP pIrp)
{ //HandleRemoveDevice
NTSTATUS status;
DEVICE_EXTENSION *pdx;
// Wait for any pending I/O operations to complete
pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension;
pIrp->IoStatus.Status = STATUS_SUCCESS; // flag that we handled this IRP
DebugPrintMsg("call StopDevice");
StopDevice(fdo);
// disconnect the interrupt
if (pdx->InterruptObject != NULL)
{
// KeSynchronizeExecution(pdx->pInterruptObject,
// (PKSYNCHRONIZE_ROUTINE)DisablePciInterrupt,(PVOID)pdx);
IoDisconnectInterrupt(pdx->InterruptObject);
pdx->InterruptObject = NULL;
}
// free the adapter object
if(pdx->AdapterObject!=NULL)
{
(pdx->AdapterObject->DmaOperations->PutDmaAdapter)(pdx->AdapterObject);
pdx->AdapterObject = NULL;
}
// Let lower-level drivers handle this request & ignore the result
status = DefaultPnpHandler(fdo,pIrp);
IoSetDeviceInterfaceState(&pdx->InterfaceName, FALSE);
RtlFreeUnicodeString(&pdx->InterfaceName);
DebugPrint("the InterfaceName has been free");
// Detach device from the device object stack
if (pdx->pLowerDeviceObject)
{
IoDetachDevice(pdx->pLowerDeviceObject);
}
DebugPrint("Sil3124: Deleting device object...");
// Delete the functional device object
IoDeleteDevice(fdo);
DebugPrint("Sil3124 is removed.");
return status;
} //HandleRemoveDevice
/////////////////////////////////////////////////////////////////////////////
// PnpQueryCapabilitiesHandler: Print pdo device capabilities
#define SetMostPoweredState( SystemState, OurDeviceState) \
dps = deviceCapabilities->DeviceState[SystemState]; \
if( dps==PowerDeviceUnspecified || dps>OurDeviceState) \
deviceCapabilities->DeviceState[SystemState] = OurDeviceState
NTSTATUS PnpQueryCapabilitiesHandler( IN PDEVICE_OBJECT fdo, IN PIRP Irp)
{
NTSTATUS status = ForwardAndWait( fdo, Irp);
int ds;
DEVICE_POWER_STATE dps;
if( NT_SUCCESS(status))
{
PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp);
PDEVICE_CAPABILITIES deviceCapabilities;
deviceCapabilities = IrpStack->Parameters.DeviceCapabilities.Capabilities;
#if DBG
for(ds=PowerSystemWorking;dsDeviceState[ds]);
#endif
SetMostPoweredState( PowerSystemWorking, PowerDeviceD0);
SetMostPoweredState( PowerSystemSleeping1, PowerDeviceD3);
SetMostPoweredState( PowerSystemSleeping2, PowerDeviceD3);
SetMostPoweredState( PowerSystemSleeping3, PowerDeviceD3);
SetMostPoweredState( PowerSystemHibernate, PowerDeviceD3);
SetMostPoweredState( PowerSystemShutdown, PowerDeviceD3);
#if DBG
for(ds=PowerSystemWorking;dsDeviceState[ds]);
#endif
}
return CompleteRequestInfo( Irp, status, Irp->IoStatus.Information);
}
/******************************************************************************
*
* Function : ForwardAndWait
*
* Description: Forward request to lower level and await completion, used
* in PnP's IRP_MN_START_DEVICE
*
******************************************************************************/
#pragma code_seg() // end PAGE section
NTSTATUS ForwardAndWait(PDEVICE_OBJECT fdo,PIRP pIrp)
{ // ForwardAndWait
KEVENT event;
NTSTATUS status;
// Initialize a kernel event object to use in waiting for the lower-level
// driver to finish processing the object.
KeInitializeEvent(&event,NotificationEvent,FALSE);
DebugPrint("ForwardAndWait Start.");
IoCopyCurrentIrpStackLocationToNext(pIrp);
IoSetCompletionRoutine(pIrp,(PIO_COMPLETION_ROUTINE) OnRequestComplete,
(PVOID) &event,TRUE,TRUE,TRUE);
status = IoCallDriver(
((DEVICE_EXTENSION *) fdo->DeviceExtension)->pLowerDeviceObject,
pIrp);
if (status == STATUS_PENDING)
{
// Wait for completion
DebugPrintMsg("ForwardIrpAndWait: waiting for completion");
KeWaitForSingleObject((PVOID)&event,Executive,KernelMode,FALSE,NULL);
return pIrp->IoStatus.Status;
}
DebugPrint("ForwardAndWait End.");
return(pIrp->IoStatus.Status); //status;
} // ForwardAndWait