www.pudn.com > usbfx2lk_v1.1.zip > usbfx2lk_pnp.cpp
///////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright 2005 OSR Open Systems Resources, Inc.
// Copyright (c) 2000 Microsoft Corporation
// All Rights Reserved
//
// This sofware is supplied for instructional purposes only.
//
// OSR Open Systems Resources, Inc. (OSR) expressly disclaims any warranty
// for this software. THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY
// OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, WITHOUT LIMITATION,
// THE IMPLIED WARRANTIES OF MECHANTABILITY OR FITNESS FOR A PARTICULAR
// PURPOSE. THE ENTIRE RISK ARISING FROM THE USE OF THIS SOFTWARE REMAINS
// WITH YOU. OSR's entire liability and your exclusive remedy shall not
// exceed the price paid for this material. In no event shall OSR or its
// suppliers be liable for any damages whatsoever (including, without
// limitation, damages for loss of business profit, business interruption,
// loss of business information, or any other pecuniary loss) arising out
// of the use or inability to use this software, even if OSR has been
// advised of the possibility of such damages. Because some states/
// jurisdictions do not allow the exclusion or limitation of liability for
// consequential or incidental damages, the above limitation may not apply
// to you.
//
// OSR Open Systems Resources, Inc.
// 105 Route 101A Suite 19
// Amherst, NH 03031 (603) 595-6500 FAX: (603) 595-6503
// email bugs to: bugs@osr.com
//
//
// MODULE:
//
// USBFx2LK_PnP.cpp
//
// ABSTRACT:
//
// This file contains the routines that handle Plug and Play processing for the
// OSR USB FX2 Learning Kit Device
//
// AUTHOR(S):
//
// OSR Open Systems Resources, Inc.
//
///////////////////////////////////////////////////////////////////////////////
#include "usbfx2lk.h"
#ifdef WPP_TRACING
//
// Include the necessary tmh file - this is
// just a matter of course if you're using WPP tracing.
//
extern "C" {
#include "usbfx2lk_pnp.tmh"
}
#endif
LONG InstanceNumber = 0;
//
// Forward Definitions
//
static NTSTATUS OsrStartDevice(PUSBFX2LK_EXT DevExt);
static VOID OsrDecrementOutstandingIoCountAndWait(PUSBFX2LK_EXT DevExt);
static VOID OsrReturnResources(PUSBFX2LK_EXT DevExt);
static NTSTATUS OsrCanStopDevice(PUSBFX2LK_EXT DevExt, PIRP Irp);
static NTSTATUS OsrCanRemoveDevice(PUSBFX2LK_EXT DevExt, PIRP Irp) ;
//
// Informational Strings
//
static PSTR pnpMinorCodes[] =
{
"IRP_MN_START_DEVICE",
"IRP_MN_QUERY_REMOVE_DEVICE",
"IRP_MN_REMOVE_DEVICE",
"IRP_MN_CANCEL_REMOVE_DEVICE",
"IRP_MN_STOP_DEVICE",
"IRP_MN_QUERY_STOP_DEVICE",
"IRP_MN_CANCEL_STOP_DEVICE",
"IRP_MN_QUERY_DEVICE_RELATIONS",
"IRP_MN_QUERY_INTERFACE",
"IRP_MN_QUERY_CAPABILITIES",
"IRP_MN_QUERY_RESOURCES",
"IRP_MN_QUERY_RESOURCE_REQUIREMENTS",
"IRP_MN_QUERY_DEVICE_TEXT",
"IRP_MN_FILTER_RESOURCE_REQUIREMENTS",
"***** FUNCTION 0x0e",
"IRP_MN_READ_CONFIG",
"IRP_MN_WRITE_CONFIG",
"IRP_MN_EJECT",
"IRP_MN_SET_LOCK",
"IRP_MN_QUERY_ID",
"IRP_MN_QUERY_PNP_DEVICE_STATE",
"IRP_MN_QUERY_BUS_INFORMATION",
"IRP_MN_DEVICE_USAGE_NOTIFICATION",
"IRP_MN_SURPRISE_REMOVAL",
"IRP_MN_QUERY_LEGACY_BUS_INFORMATION"
};
CONST PCHAR OsrPrintState(PUSBFX2LK_EXT DevExt)
{
switch(DevExt->DevicePnPState) {
case STATE_REMOVED:
return "STATE_REMOVED";
case STATE_STARTED:
return "STATE_STARTED";
case STATE_REMOVE_PENDING:
return "STATE_REMOVE_PENDING";
case STATE_SURPRISE_REMOVED:
return "STATE_SURPRISE_REMOVED";
case STATE_STOP_PENDING:
return "STATE_STOP_PENDING";
case STATE_STOPPED:
return "STATE_STOPPED";
case STATE_NEVER_STARTED:
return "STATE_NEVER_STARTED";
default:
break;
}
return "*********UNKNOWN STATE Value";
}
///////////////////////////////////////////////////////////////////////////////
//
// UsbFx2LkAddDevice
//
// We are called at this entry point by the Plug and Play Manager
// to add a Functional Device Object for a Physical Device Object.
// Note that we may NOT access our device via the USB bus in this routine,
// we must wait until we have received an IRP_MJ_PNP/IRP_START_DEVICE before
// we can try to talk to our device
//
// INPUTS:
//
// DriverObject - Address of our DRIVER_OBJECT.
//
// PhysicalDeviceObject - Address of our physical device
// object (PDO)
//
// OUTPUTS:
//
// None.
//
// RETURNS:
//
// STATUS_SUCCESS if success, an appropriate error otherwise
//
// IRQL:
//
// This routine is called at IRQL == PASSIVE_LEVEL.
//
// CONTEXT:
//
// This routine is called in the context of the System process
//
// NOTES:
//
///////////////////////////////////////////////////////////////////////////////
NTSTATUS UsbFx2LkAddDevice(PDRIVER_OBJECT PDriverObject,
PDEVICE_OBJECT PPhysicalDeviceObject)
{
PUSBFX2LK_EXT devExt = NULL;
PDEVICE_OBJECT pFunctionalDeviceObject = NULL;
UNICODE_STRING devName;
NTSTATUS status = STATUS_SUCCESS;
WCHAR devNameBuffer[256];
size_t devNameBufferSize = sizeof(devNameBuffer);
OBJECT_ATTRIBUTES oa;
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO, ("UsbFx2LkAddDevice: Entered\n"));
//
// We're guaranteed to be called here at IRQL PASSIVE_LEVEL
//
ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
//
// Format a new device name string, based off a template and an instance
// number.
//
status = RtlStringCbPrintfW(devNameBuffer,devNameBufferSize,
L"\\Device\\USBFX2LK%d",InterlockedIncrement(&InstanceNumber));
//
// Make sure that the creation worked. If not, get out of here.
//
if(!NT_SUCCESS(status)) {
OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_PNP_INFO,
("UsbFx2LkAddDevice: RtlStringCbPrintfW Error 0x%x (%s)\n",status,OsrNtStatusToString(status)));
return status;
}
//
// Initialize the Unicode Name structure to be used for the Device Name.
//
RtlInitUnicodeString(&devName, devNameBuffer);
//
// Create the FDO for the device.
//
status = IoCreateDevice(PDriverObject,
sizeof(USBFX2LK_EXT),
&devName,
FILE_DEVICE_OSRUSBFX2LK,
FILE_DEVICE_SECURE_OPEN,
FALSE,
&pFunctionalDeviceObject);
if (!NT_SUCCESS(status)) {
OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_PNP_INFO,
("UsbFx2LkAddDevice: IoCreateDevice Error 0x%x (%s)\n",status,OsrNtStatusToString(status)));
return status;
}
//
// Get a pointer to the Device Extension and Initialize the fields that we need.
//
devExt = (PUSBFX2LK_EXT) pFunctionalDeviceObject->DeviceExtension;
RtlZeroMemory(devExt,sizeof(USBFX2LK_EXT));
devExt->MagicNumber = USBFX2LK_EXT_MAGIC_NUMBER;
devExt->InstanceNumber = InstanceNumber;
devExt->FunctionalDeviceObject = pFunctionalDeviceObject;
devExt->PhysicalDeviceObject = PPhysicalDeviceObject;
//
// Set the Initial PnP State.
//
devExt->DevicePnPState = STATE_NEVER_STARTED;
//
// The device and system are is implicitly in D0 when
// we arrive in the system
//
devExt->DevicePowerState = PowerDeviceD0;
devExt->SystemPowerState = PowerSystemWorking;
//
// Default to supporting selective suspend
//
devExt->SSEnabledByUser = TRUE;
devExt->SSState = SS_NOT_STARTED;
//
// Biased to 1. Transition to 0 during remove device
// means IO is finished. Transition to 1 means
// the device can be stopped.
//
devExt->OutStandingIoCount = 1;
//
// Initialize our stop and remove Events
//
KeInitializeEvent(&devExt->RemoveEvent,NotificationEvent,FALSE);
KeInitializeEvent(&devExt->StopEvent,NotificationEvent,TRUE);
//
// And initialize the other events used in selective suspend
// processing
//
KeInitializeEvent(&devExt->SSSubmissionThreadTerminateEvent,NotificationEvent,FALSE);
KeInitializeEvent(&devExt->SSDeviceNotSuspendedEvent,NotificationEvent,TRUE);
#ifndef W2K
KeInitializeEvent(&devExt->SSIdleCallbackCalled,NotificationEvent,FALSE);
KeInitializeEvent(&devExt->SSIdleCompletionRoutineCalled,NotificationEvent,FALSE);
#endif
//
// Initialize our locks...
//
KeInitializeSpinLock(&devExt->CancelSafeIoLock);
KeInitializeSpinLock(&devExt->IoStateLock);
KeInitializeSpinLock(&devExt->SSLock);
//
// ...and our list head...
//
InitializeListHead(&devExt->IoQueue);
//
// We need to create a thread for use in
// selective suspend
//
//
// We'll need a kernel handle for this thread
//
InitializeObjectAttributes(&oa, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);
//
// Create the thread
//
status = PsCreateSystemThread(&devExt->SSSubmissionThread,
THREAD_ALL_ACCESS,
&oa,
NULL,
NULL,
SSSubmissionThreadRoutine,
devExt);
if (!NT_SUCCESS(status)) {
OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_PNP_INFO,
("UsbFx2LkAddDevice: PsCreateSystemThread failed 0x%x (%s).\n",status,OsrNtStatusToString(status)));
IoDeleteDevice(devExt->FunctionalDeviceObject);
return status;
}
//
// We'll also need the object pointer for the thread
// so that we can wait for it to terminate when
// cleaning up selective suspend
//
status = ObReferenceObjectByHandle(devExt->SSSubmissionThread,
THREAD_ALL_ACCESS,
NULL,
KernelMode,
&devExt->SSSubmissionThreadObject,
NULL);
if (!NT_SUCCESS(status)) {
OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_SELECTIVE_SUSPEND,
("UsbFx2LkAddDevice: ObReferenceObjectByHandle failed 0x%x (%s).\n",status,OsrNtStatusToString(status)));
//
// Set the terminate thread event and close the HANDLE.
// Unfortunately we can't wait for the thread to terminate
// (we don't have an object to wait on) so we don't
// have any choice but to exit and hope that the thread
// terminates quickly (which it should).
//
// This call failing would be very strange indeed...
//
KeSetEvent(&devExt->SSSubmissionThreadTerminateEvent,
EVENT_INCREMENT, FALSE);
ZwClose(devExt->SSSubmissionThread);
IoDeleteDevice(devExt->FunctionalDeviceObject);
return status;
}
//
// Initialize the cancel safe I/O queue
//
#ifdef W2K3
status = IoCsqInitializeEx(&devExt->CancelSafeIoQueue,
OsrCsqInsertIoIrpEx,
OsrCsqRemoveIoIrp,
OsrCsqPeekNextIoIrp,
OsrCsqAcquireIoLock,
OsrCsqReleaseIoLock,
OsrCsqCompleteCancelledIoIrp);
#else // W2K3
status = IoCsqInitialize(&devExt->CancelSafeIoQueue,
OsrCsqInsertIoIrp,
OsrCsqRemoveIoIrp,
OsrCsqPeekNextIoIrp,
OsrCsqAcquireIoLock,
OsrCsqReleaseIoLock,
OsrCsqCompleteCancelledIoIrp);
#endif // W2K3
if(!NT_SUCCESS(status)) {
OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_PNP_INFO,
("UsbFx2LkAddDevice: IoCsqInitialize Error 0x%x (%s)\n",status,OsrNtStatusToString(status)));
IoDeleteDevice(devExt->FunctionalDeviceObject);
return status;
}
//
// Register the Device Interface for the Device. This will allow users to use the
// SetupDi interface API to connect to these devices.
//
status = IoRegisterDeviceInterface(PPhysicalDeviceObject,&GUID_OSR_USBFX2LK_INTERFACE,
NULL,
&devExt->InterfaceName);
if(!NT_SUCCESS(status)) {
OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_PNP_INFO,
("UsbFx2LkAddDevice: IoRegisterDeviceInterface Error 0x%x (%s)\n",status,OsrNtStatusToString(status)));
IoDeleteDevice(pFunctionalDeviceObject);
return status;
}
//
// Attach the FDO to the PDO. Remember to save the returned Device Object Address. This
// is the address of the Underlying PDO to which PnP and Power requests should be sent.
//
devExt->DeviceToSendIrpsTo = IoAttachDeviceToDeviceStack(devExt->FunctionalDeviceObject,
devExt->PhysicalDeviceObject);
if(!devExt->DeviceToSendIrpsTo) {
OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_PNP_INFO,
("UsbFx2LkAddDevice: IoAttachDeviceToDeviceStack Error 0x%x (%s)\n",status,OsrNtStatusToString(status)));
RtlFreeUnicodeString(&devExt->InterfaceName);
IoDeleteDevice(devExt->FunctionalDeviceObject);
return status;
}
//
// Tell the I/O Manager to user Direct I/O for our reads/writes
//
devExt->FunctionalDeviceObject->Flags |= DO_DIRECT_IO;
//
// See if we can set the Power pageable flag. We should because
// we are not in the power pageable Path.
//
if(devExt->DeviceToSendIrpsTo->Flags & DO_POWER_PAGABLE) {
devExt->FunctionalDeviceObject->Flags |= DO_POWER_PAGABLE;
}
//
// Clear the Device Initializing bit. This indicates to the I/O
// manager that we are now ready to begin processing requests on
// this device
//
devExt->FunctionalDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
//
// Register with WMI after having cleared the DO_DEVICE_INITIALIZING
// flag. This is to ensure that our device is prepared to receive
// WMI IRPs as soon as the system wants to start sending them
//
status = UsbFx2LkWmiRegistration(devExt);
if(!NT_SUCCESS(status)) {
OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_PNP_INFO,
("UsbFx2LkAddDevice: UsbFx2LkWmiRegistration Error 0x%x (%s)\n",status,OsrNtStatusToString(status)));
RtlFreeUnicodeString(&devExt->InterfaceName);
IoDetachDevice(devExt->DeviceToSendIrpsTo);
IoDeleteDevice(pFunctionalDeviceObject);
return status;
}
//
// You need to include this function call only when WPP tracing
// is enabled on and we're built for Win2K. Do NOT call this until
// we have successfully registered with WMI, as this call will
// begin sending WMI requests to the device, which isn't a
// good thing if our WMI module isn't properly initialized
//
#ifdef WPP_TRACING
#ifdef W2K
W2KInitializeWPPTracing(pFunctionalDeviceObject,&GlobalRegistryPath);
#endif // W2K
#endif // WPP_TRACING
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("UsbFx2LkAddDevice: Exits\n"));
return status;
}
///////////////////////////////////////////////////////////////////////////////
//
// PnpRequestComplete
//
// We are called at this entry point when an Irp forwarded to the driver
// below us completes.
//
//
// INPUTS:
//
// DeviceObject - Address of our DEVICE_OBJECT.
//
// Irp - Address of the completing Irp
//
// Context - Address of Event to set
//
// OUTPUTS:
//
// None.
//
// RETURNS:
//
// STATUS_MORE_PROCESSING_REQUIRED
//
// IRQL:
//
// This routine is called at IRQL <= DISPATCH_LEVEL.
//
// CONTEXT:
//
// This routine is called in an arbitrary context
//
// NOTES:
//
///////////////////////////////////////////////////////////////////////////////
#ifndef IoForwardIrpSynchronously
NTSTATUS PnpRequestComplete(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context)
{
PKEVENT pEvent = (PKEVENT) Context;
UNREFERENCED_PARAMETER(DeviceObject);
UNREFERENCED_PARAMETER(Irp);
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("PnpRequestComplete: Enter.\n"));
KeSetEvent(pEvent, 0, FALSE);
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("PnpRequestComplete: Exit\n"));
//
// Take the IRP back so that we can continue using it during
// the IRP_MN_START_DEVICE dispatch routine.
// NB: we will have to call IoCompleteRequest
//
return STATUS_MORE_PROCESSING_REQUIRED;
}
#endif //IoForwardIrpSynchronously
///////////////////////////////////////////////////////////////////////////////
//
// OsrForwardIrpSynchronous
//
// We call this entry point when we want to forward an Irp to a
// device and we want to wait for the request to complete. In
// other words, we want SYNCHRONOUS behavior.
//
//
// INPUTS:
//
// TargetDevice - Address of target device
//
// Irp - Address of the Irp to deliver
//
// OUTPUTS:
//
// None.
//
// RETURNS:
//
// STATUS_UNSUCESSFUL if Irp could not be forwarded, otherwise
// returns the status returned by the driver that the Irp was
// forwarded to.
//
// IRQL:
//
// This routine is called at IRQL == PASSIVE_LEVEL.
//
// CONTEXT:
//
// This routine is called in an arbitrary context
//
// NOTES:
//
///////////////////////////////////////////////////////////////////////////////
NTSTATUS OsrForwardIrpSynchronous(PUSBFX2LK_EXT DevExt,PIRP Irp)
{
NTSTATUS status;
ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("OsrForwardIrpSynchronous: Enter.\n"));
#ifdef IoForwardIrpSynchronously
if(IoForwardIrpSynchronously(DevExt->DeviceToSendIrpsTo,Irp)) {
status = Irp->IoStatus.Status;
} else {
status = STATUS_UNSUCCESSFUL;
}
#else //IoForwardIrpSynchronously
KEVENT eventWaitLowerDrivers;
KeInitializeEvent(&eventWaitLowerDrivers, NotificationEvent, FALSE);
//
// The BUS DRIVER handles this IRP before we do
//
IoCopyCurrentIrpStackLocationToNext(Irp);
//
// Call OsrPnpComplete() when this IRP is done...
//
IoSetCompletionRoutine(Irp,
PnpRequestComplete,
&eventWaitLowerDrivers,
TRUE,
TRUE,
TRUE);
//
// Send the IRP to the bus driver. Let's see what HE
// thinks.
//
status = IoCallDriver(DevExt->DeviceToSendIrpsTo, Irp);
if (status == STATUS_PENDING) {
OsrWaitForSingleObject(&eventWaitLowerDrivers);
status = Irp->IoStatus.Status;
}
#endif //IoForwardIrpSynchronously
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("OsrForwardIrpSynchronous: Exit.\n"));
return status;
}
///////////////////////////////////////////////////////////////////////////////
//
// UsbFx2LkPnp
//
// This routine is called by the IO Manager to process a IRP_MJ_PNP
// Irp.
//
//
// INPUTS:
//
// DeviceObject - One of our Device Objects.
// Irp - The Irp to process.
//
// OUTPUTS:
//
// None
//
// RETURNS:
//
// None
//
// IRQL:
//
// IRQL == PASSIVE_LEVEL
//
// CONTEXT:
//
// This routine is called either in an arbitrary thread context
// or in the context of the System thread, depending on the minor
// function code. You can find out which by consulting the DDK
// documentation for the particular minor function code.
//
// NOTES:
//
// There are several difficulties implementing Plug and Play.
// Perhaps the greatest difficulty is deciding precisely how you
// want your device to work, given the various requests the driver
// can receive and the states the device can be in. In our driver,
// we've decided to implement the following policies:
//
// 1) When a removal of the device is requested, we will reject
// any new IRPs we receive (completing them with an error
// status in the dispatch routine). We will wait until all IRPs
// that are already present on the device's queue are complete
// and then allow the remove.
//
// 2) When a stop of the device is requested, we'll queue any new
// Irps then wait until any IRPs that are presently ACTIVE on the
// device complete, and then allow the stop.
//
// 3) When a SUPRISE removal of the device is indicated, we
// process any close, clean-up, power and PnP requests
// but fail all others. This applies to in process, current
// queued and future irps
//
// Of course, the second complexity in implementing plug and play
// is getting the logic in your driver correct, so that it works
// as you intend. According to our experience, this is easier said
// than done. We've changed the code in this function now, oh,
// about ten million times.
//
///////////////////////////////////////////////////////////////////////////////
NTSTATUS UsbFx2LkPnp(PDEVICE_OBJECT DeviceObject,PIRP Irp)
{
PIO_STACK_LOCATION ioStack = IoGetCurrentIrpStackLocation(Irp);
NTSTATUS status = STATUS_SUCCESS;
PUSBFX2LK_EXT devExt = (PUSBFX2LK_EXT)DeviceObject->DeviceExtension;
POWER_STATE powerState;
BOOLEAN enableInterface = FALSE;
//
// We're guaranteed to be called here at IRQL PASSIVE_LEVEL
//
ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
//
// Increment the count of Outstanding IOs
//
OsrIncrementOutstandingIoCount(devExt,__FILE__,__LINE__);
if (ioStack->MinorFunction <= IRP_MN_SURPRISE_REMOVAL) {
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,
("OsrPnp: Entered at PnP State %s with Minor Function %s\n",
OsrPrintState(devExt),
OsrMinorFunctionToString(ioStack->MajorFunction,
ioStack->MinorFunction)));
} else {
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,
("OsrPnp: Entered at PnP State %s with unusual Minor Function 0x%x\n",
OsrPrintState(devExt),
ioStack->MinorFunction));
}
//
// Let's see what we have...
//
switch (devExt->DevicePnPState + ioStack->MinorFunction) {
//
// STATE: STOPPED or NEVER_STARTED
// IRP_MN: _START_DEVICE
//
// We're here if we've received an AddDevice() call, but we
// have not yet been told it's OK to talk to our device by
// the PnP Manager.
//
// We're also here if we've been stopped for a resource
// rebalance
//
// In either case, we pass the IRP all the way down. When it's
// done we can then read the list of device resources pointed to
// in the IRP Stack Location.
//
case (STATE_NEVER_STARTED + IRP_MN_START_DEVICE):
//
// If we've never been started, we'll need to
// enable our device interface.
//
// Note that we don't disable our interface on
// a STOP. It's really only a transient
// state and there's no reason why we shouldn't
// let users open up our device and queue I/O
// to it while we're in it.
//
enableInterface = TRUE;
//
// Fall through...
//
case (STATE_STOPPED + IRP_MN_START_DEVICE): {
//
// This is a BUS FIRST Irp. The bus driver is involved in
// the allocation of resources for us, so we must give
// it to him first to fill in our stack location with
// our resources.
//
status = OsrForwardIrpSynchronous(devExt,Irp);
//
// Is the bus driver OK with us starting?
//
if (NT_SUCCESS(status)) {
//
// Excellent...Try starting our device!
//
status = OsrStartDevice(devExt);
if (NT_SUCCESS(status)) {
//
// Indicate the initial power state of the device to the
// power manager by calling PoSetPowerState.
//
powerState.DeviceState = PowerDeviceD0;
PoSetPowerState(DeviceObject, DevicePowerState, powerState);
//
// Enable SS if the user wants it. The decision
// about whether or not SS is enabled by the user
// is done under lock within EnableSelectiveSuspend
//
EnableSelectiveSuspend(devExt);
OsrUpdateDeviceState(devExt, STATE_STARTED);
//
// IF you registered a device interface, using
// IoRegisterDeviceInterface(), and you're coming
// out of the NEVER_STARTED state, you'll also need to
// set the interface state here to ENABLED. This is
// done with the following call.
//
if (enableInterface) {
status = IoSetDeviceInterfaceState(
&devExt->InterfaceName,
TRUE);
if (!NT_SUCCESS(status)) {
//
// We won't consider this to be fatal. Currently the only reason
// for it happening is if the interface is already enabled, in
// which case it's a bug and this DbgPrint should suffice.
//
OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_PNP_INFO,
("OsrPnp: IoSetDeviceInterfaceState failed! Returned status 0x%8.8x (%s)\n",
status, OsrNtStatusToString(status)));
}
}
//
// Initialize WaitWake Information and queue a wait
// wake IRP to the host if waking is enabled for the device.
//
devExt->FlagWWOutstanding = 0;
devExt->FlagWWCancel = 0;
devExt->WaitWakeIrp = NULL;
if(devExt->DeviceCapabilitiesInitialized && devExt->WaitWakeEnable) {
IssueWaitWake(devExt);
}
//
// If we were stopped, our queues were stalled and
// we need to restart them. We are guaranteed to
// be powered up here.
//
OsrProcessQueuedRequests(devExt);
} else {
OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_PNP_INFO,
("OsrPnp: Unable to start device! Status = 0x%8.8x (%s)\n",
status, OsrNtStatusToString(status)));
}
} else {
OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_PNP_INFO,
("OsrPnp: Request to start failed! Status = 0x%8.8x (%s)\n",
status, OsrNtStatusToString(status)));
}
//
// Fill in the completion status...
//
Irp->IoStatus.Status = status;
Irp->IoStatus.Information = 0;
//
// We need to call IoCompleteRequest on it
// to finish processing.
//
IoCompleteRequest(Irp, IO_NO_INCREMENT);
//
// We're done with this request
//
OsrDecrementOutstandingIoCount(devExt,__FILE__,__LINE__);
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,
("OsrPnp: Finished! Leaving with state %s\n",
OsrPrintState(devExt)));
return status;
}
//
// STATE: STARTED
// IRP_MN: _QUERY_STOP_DEVICE
//
// We're here if we're running and the PnP Manager sends us
// a QUERY_STOP_DEVICE request. He'll do this if he wants to
// rebalance resources to see if we're willing to give up the
// anything we setup during our IRP_MN_START_DEVICE.
//
// To proess this QUERY_STOP, we check to see if the stop is
// acceptable to us (in this driver it always is), and then
// we just transition the device to STOP_PENDING state. In
// this state, new requests that arrive are queued. When a
// currently in-progress request is completed, a new request
// is NOT started. Thus, ON OUR DEVICE, we sort of hope that
// between the QUERY_STOP IRP arrive and actual STOP IRP arriving
// that any in-progress I/O will complete of its own accord.
// We like this scheme, particularly because at least on NT
// during startup the device seems to get lots of QUERY_STOP
// IRPs, that are just followed by CANCEL_STOP. Thus, we think
// it would be unfortunate to do anything radical with the
// outstanding requests (like cancel them) when we receive a
// QUERY_STOP.
//
case (STATE_STARTED + IRP_MN_QUERY_STOP_DEVICE): {
//
// See if we're OK with stopping the device at this point.
// We do NOT actually RETURN the resources here... we
// just affirm or deny that we're OK with returning them.
//
status = OsrCanStopDevice(devExt, Irp);
if (!NT_SUCCESS(status)) {
//
// Nope...We can't stop the device
// so there's no need to pass it
// down to see if anyone else can stop.
// Just complete the Irp and return...
//
Irp->IoStatus.Status = status;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
//
// We're done with this request
//
OsrDecrementOutstandingIoCount(devExt,__FILE__,__LINE__);
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,
("OsrPnp: Finished! Leaving with state %s\n",
OsrPrintState(devExt)));
return status;
}
//
// We're cool with being stopped.
//
//
// Power the device up if it isn't already.
// Do this before changing the device's
// PnP state.
//
SSPowerDeviceIfSuspended(devExt);
//
// If enabled, disable selective suspend. We'll
// enable it again if we get a cancel.
//
DisableSelectiveSuspend(devExt);
//
// Set new state. This state results in no new
// requests being started on the device, but incoming
// requests are still allowed and queued.
//
OsrUpdateDeviceState(devExt, STATE_STOP_PENDING);
//
// Wait until all active requests on the device have
// completed so that we can return our resources
// in the STOP case.
//
OsrDecrementOutstandingIoCount(devExt,__FILE__,__LINE__);
OsrWaitForStop(devExt);
//
// Replace status code that's in the IRP to indicate our
// opinion about stopping the device. If we're
// OK with being stopped this HAS to be
// STATUS_SUCCESS.
//
Irp->IoStatus.Status = STATUS_SUCCESS;
//
// Pass this request on down to the next driver
//
IoSkipCurrentIrpStackLocation(Irp);
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,
("OsrPnp: Finished! Leaving with state %s\n",
OsrPrintState(devExt)));
status = IoCallDriver(devExt->DeviceToSendIrpsTo, Irp);
return status;
}
//
// STATE: STOP_PENDING
// IRP_MN: _CANCEL_STOP_DEVICE
//
// We're here because we've already received a QUERY_STOP,
// that we've agreed to. We've completed any pending I/O
// requests. Now we've received a CANCEL_STOP_DEVICE
// IRP, that says "never mind" about that stop.
//
// We (hopefully) restart our queues and return to Started state.
//
case (STATE_STOP_PENDING + IRP_MN_CANCEL_STOP_DEVICE): {
//
// OK, so we're not going to be stopped...
//
//
// This is a BUS FIRST Irp.
//
status = OsrForwardIrpSynchronous(devExt,Irp);
if (NT_SUCCESS(status)) {
//
// We're now back to a STARTED state
//
OsrUpdateDeviceState(devExt, STATE_STARTED);
status = STATUS_SUCCESS;
//
// Start processing any I/O that may have
// been queued due to the QUERY_STOP...
//
OsrProcessQueuedRequests(devExt);
} else {
//
// EEP! This is a fatal error if you're running
// verifier. We'll print out and hope the
// machine stays standing. If a debugger is attached
// we'll break into it...
//
OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_PNP_INFO,
("OsrPnp: A device in the stack has FAILED CANCEL_STOP!! Returned status 0x%8.8x (%s)\n",
Irp->IoStatus.Status, OsrNtStatusToString(Irp->IoStatus.Status)));
//
// Use KdBreakPoint instead of DbgBreakPoint so that
// we only break in the checked build...
//
KdBreakPoint();
}
//
// Re-enable selective suspend (if enabled)
//
EnableSelectiveSuspend(devExt);
//
// Put the Completion Status into the Irp.
//
Irp->IoStatus.Status = status;
Irp->IoStatus.Information = 0;
//
// OsrForwardIrpSynchronous is just a nice little
// wrapper that sets a completion routine, calls
// the next lowest driver, waits, and then reclaims the Irp
// for us in the completion routine by returning
// STATUS_MORE_PROCESSING_REQUIRED (or calls
// IoForwardIrpSynchronously to do all of that if
// we're built for XP and later). Just as if we
// had carried these steps out by ourselves, we now
// own the Irp and need to call IoCompleteRequest on it
// to finish processing.
//
IoCompleteRequest(Irp, IO_NO_INCREMENT);
//
// We're done with this request
//
OsrDecrementOutstandingIoCount(devExt,__FILE__,__LINE__);
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,
("OsrPnp: Finished! Leaving with state %s\n",
OsrPrintState(devExt)));
return status;
}
//
// STATE: STOP_PENDING
// IRP_MN: _STOP_DEVICE
//
// We're in this state because we previously received a
// QUERY_STOP_DEVICE, that we agreed that we could grant.
// Thus, we're waiting to receive a STOP_DEVICE request.
// To process this request, we first wait for any in-progress
// requests to complete (note that no NEW requests have been
// started since the transition to STOP_PENDING state as a
// result of receiving the QUERY_STOP IRP). After all in-
// progress requests are complete, we return our resources
// and wait for further instructions from the PnP Manager (
// which better include a START_DEVICE someplace down the line!).
//
// While in this state, any IRPs we receive will be queued
// for processing until we get A START_DEVICE.
//
case (STATE_STOP_PENDING + IRP_MN_STOP_DEVICE): {
//
// We're stopped...
//
OsrUpdateDeviceState(devExt, STATE_STOPPED);
//
// We need to cancel our outstanding wait wake operation if there
// is one
//
if(devExt->WaitWakeEnable) {
CancelWaitWake(devExt);
}
//
// Return any allocated resources...
//
OsrReturnResources(devExt);
//
// Indicate that we've successfully processed the IRP.
// Note that we can't fail it (we agreed to the
// stop in the QUERY_STOP case)...
//
Irp->IoStatus.Status = STATUS_SUCCESS;
//
// Don't wait for the Irp to finish, don't set a completion
// routine and don't complete the Irp! Just foist it off to the
// PDO and propogate the returned status
//
IoSkipCurrentIrpStackLocation(Irp);
OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_PNP_INFO,
("OsrPnp: Finished! Leaving with state %s\n",
OsrPrintState(devExt)));
status = IoCallDriver(devExt->DeviceToSendIrpsTo, Irp);
//
// We're done with this request
//
OsrDecrementOutstandingIoCount(devExt,__FILE__,__LINE__);
return status;
}
//
// STATE: STARTED
// IRP_MN: _QUERY_REMOVE
//
// We're here because the PnP Manager wants to "nicely"
// remove our device. This is the orderly way the PnP Manager
// handles device disconnections (as opposed to doing a
// SURPRISE_REMOVAL).
//
// If we decide it's OK to remove the device, what we do here
// is (a) change the state of the device such that newly arriving
// requests will be rejected, (b) stall the queues so no new I/O
// with be started and wait for all in progress I/O to complete on
// the device, and (c) pass the request on down.
//
case (STATE_STARTED + IRP_MN_QUERY_REMOVE_DEVICE): {
//
// WE process this request FIRST
//
//
// See if we're OK with removing the device at this point.
// We do NOT actually RETURN the resources here... we
// just affirm or deny that we're OK with returning them.
//
status = OsrCanRemoveDevice(devExt, Irp);
if (!NT_SUCCESS(status)) {
//
// Nope...We can't remove the device
// so there's no need to pass it
// down to see if anyone else can remove.
// Just complete the Irp and return...
//
Irp->IoStatus.Status = status;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
//
// We're done with this request
//
OsrDecrementOutstandingIoCount(devExt,__FILE__,__LINE__);
OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_PNP_INFO,
("OsrPnp: Finished! Leaving with state %s\n",
OsrPrintState(devExt)));
return status;
}
//
// We're cool with being removed...
//
//
// We handle this request before the bus driver
//
//
// Power the device up if it isn't already.
// Do this before changing the device's
// PnP state.
//
SSPowerDeviceIfSuspended(devExt);
//
// If enabled, disable selective suspend. We'll
// enable again if we get a cancel
//
DisableSelectiveSuspend(devExt);
//
// Set new state -- This state results in any new
// requests received at our dispath entry points
// being QUEUED
//
OsrUpdateDeviceState(devExt, STATE_REMOVE_PENDING);
//
// Wait for any in progress I/O to finish.
// Note that even though this is called
// OsrWaitForStop, it is the right function
// to call here because it waits for any
// in progress I/O to finish, but having
// I/O in the queues is fine. This is what
// we want since we might get a CANCEL_REMOVE,
// in which case we'll go back and process any
// queued up requests...
//
OsrDecrementOutstandingIoCount(devExt,__FILE__,__LINE__);
OsrWaitForStop(devExt);
//
// Replace status code that's in the IRP to indicate our
// opinion about stopping the device. If we're
// OK with being removed this HAS to be
// STATUS_SUCCESS.
//
Irp->IoStatus.Status = STATUS_SUCCESS;
//
// Pass this request on down to the next driver
//
IoSkipCurrentIrpStackLocation(Irp);
OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_PNP_INFO,
("OsrPnp: Finished! Leaving with state %s\n",
OsrPrintState(devExt)));
status = IoCallDriver(devExt->DeviceToSendIrpsTo, Irp);
//
// We're done with this request
//
return status;
}
//
// STATE: REMOVE_PENDING
// IRP_MN: _CANCEL_REMOVE_DEVICE
//
// We're here because we've already received a QUERY_REMOVE,
// that we've agreed to. We've completed any pending I/O
// requests. Now we've received a CANCEL_REMOVE_DEVICE
// IRP, that sort of says "never mind" about that remove.
//
// We (hopefully) restart our queues and return to the Started
// state
//
case (STATE_REMOVE_PENDING + IRP_MN_CANCEL_REMOVE_DEVICE): {
//
// This is a BUS FIRST Irp.
//
status = OsrForwardIrpSynchronous(devExt,Irp);
if (NT_SUCCESS(status)) {
//
// We're now back to a STARTED state
//
OsrUpdateDeviceState(devExt, STATE_STARTED);
//
// Go and start any I/O that may have been
// queued while in the REMOVE_PENDING
// state...
//
OsrProcessQueuedRequests(devExt);
} else {
//
// If we're here one of the drivers below us is
// busted, you can never fail this Irp. We'll just
// stay right where we are and break into a debugger
// if possible
//
OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_PNP_INFO,
("OsrPnp: Lower level device FAILED CANCEL_REMOVE?? Returned status 0x%8.8x (%s)\n",
Irp->IoStatus.Status, OsrNtStatusToString(Irp->IoStatus.Status)));
//
// Use KdBreakPoint instead of DbgBreakPoint so that
// we only break in the checked build...
//
KdBreakPoint();
}
//
// Enable selective suspend again (if enabled)
//
EnableSelectiveSuspend(devExt);
//
// Complete the Irp with whatever status the lower driver returned
//
Irp->IoStatus.Status = status;
Irp->IoStatus.Information = 0;
//
// OsrForwardIrpSynchronous is just a nice little
// wrapper that sets a completion routine, calls
// the next lowest driver, waits, and then reclaims the Irp
// for us in the completion routine by returning
// STATUS_MORE_PROCESSING_REQUIRED (or calls
// IoForwardIrpSynchronously to do all of that if
// we're built for XP and later). Just as if we
// had carried these steps out by ourselves, we now
// own the Irp and need to call IoCompleteRequest on it
// to finish processing.
//
IoCompleteRequest(Irp, IO_NO_INCREMENT);
//
// We're done with this request
//
OsrDecrementOutstandingIoCount(devExt,__FILE__,__LINE__);
OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_PNP_INFO,
("OsrPnp: Finished! Leaving with state %s\n",
OsrPrintState(devExt)));
return status;
}
//
// STATE: STOPPED, STARTED, _STOP_PENDING, or _REMOVE_PENDING
// IRP_MN: _SURPRISE_REMOVAL
//
// We're here when the device is forcibly removed. The PnP
// Manager will send us a remove device IRP when all open handles
// are close and when we're supposed to actually detach and
// delete the device object
//
case (STATE_STARTED + IRP_MN_SURPRISE_REMOVAL):
case (STATE_STOPPED + IRP_MN_SURPRISE_REMOVAL):
case (STATE_STOP_PENDING + IRP_MN_SURPRISE_REMOVAL):
case (STATE_REMOVE_PENDING + IRP_MN_SURPRISE_REMOVAL): {
//
// A surprise removed device must still handle subsequent
// close, clean-up, power and PnP requests. A removed device
// handles NO subsequent requests
//
//
// Power the device up if it isn't already.
// Do this before changing the device's
// PnP state.
//
// Though the device doesn't exist anymore, we're
// doing this to indicate to the hub that it
// should power the port that the device
// was plugged into.
//
SSPowerDeviceIfSuspended(devExt);
//
// If enabled, disable selective suspend
//
DisableSelectiveSuspend(devExt);
//
// Update our Device State
//
OsrUpdateDeviceState(devExt, STATE_SURPRISE_REMOVED);
//
// Because we registered a device interface we need to disable
// it now...
//
status = IoSetDeviceInterfaceState(&devExt->InterfaceName,
FALSE);
if (!NT_SUCCESS(status)) {
//
// Eh, big deal. Just print out some info and
// keep going...
//
OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_PNP_INFO,
("OsrPnp: IoSetDeviceInterfaceState failed! Returned status 0x%8.8x (%s)\n",
status, OsrNtStatusToString(status)));
}
//
// Fail any queued I/O requests...
//
OsrClearQueues(devExt);
//
// Tell the thread that we have out there to terminate itself
//
KeSetEvent(&devExt->SSSubmissionThreadTerminateEvent,
EVENT_INCREMENT, FALSE);
//
// And wait for the thread to terminate
//
(VOID)OsrWaitForSingleObject(devExt->SSSubmissionThreadObject);
//
// Close the HANDLE that we opened to the thread
//
ZwClose(devExt->SSSubmissionThread);
//
// And drop our reference to the object
//
ObDereferenceObject(devExt->SSSubmissionThreadObject);
//
// We need to cancel our outstanding wait wake operation if there
// is one
//
if(devExt->WaitWakeEnable) {
CancelWaitWake(devExt);
}
//
// Return our allocated resources...
//
OsrReturnResources(devExt);
//
// Indicate that we've successfully processed the IRP,
// since we can't fail it anyway (our hardware is GONE,
// what would failing this Irp mean??)...
//
Irp->IoStatus.Status = STATUS_SUCCESS;
//
// Don't wait for the Irp to finish, don't set a completion
// routine and don't complete the Irp! Just foist it off to the
// PDO and propogate the returned status
//
IoSkipCurrentIrpStackLocation(Irp);
OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_PNP_INFO,
("OsrPnp: Finished! Leaving with state %s\n",
OsrPrintState(devExt)));
status = IoCallDriver(devExt->DeviceToSendIrpsTo, Irp);
//
// We're done with this request
//
OsrDecrementOutstandingIoCount(devExt,__FILE__,__LINE__);
return status;
}
//
// STATE: REMOVE_PENDING or STATE_NEVER_STARTED
// IRP_MN: _REMOVE
//
// We're here if we've received an IRP_MN_REMOVE_DEVICE IRP
// after receiving a QUERY_REMOVE or if our Start Device
// failed. This is the preferred, "everything is going dandy"
// route for being removed.
//
case (STATE_NEVER_STARTED + IRP_MN_REMOVE_DEVICE):
case (STATE_REMOVE_PENDING + IRP_MN_REMOVE_DEVICE): {
//
// We handle this request before the bus driver
//
//
// We're removed...
//
OsrUpdateDeviceState(devExt, STATE_REMOVED);
//
// Deregister with WMI.
//
status = UsbFx2LkWmiDeRegistration(devExt);
if (!NT_SUCCESS(status)) {
//
// Eh, big deal. Just print out some info and
// keep going...
//
OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_PNP_INFO,
("OsrPnp: UsbFx2LkWmiDeRegistration failed! Returned status 0x%8.8x (%s)\n",
status, OsrNtStatusToString(status)));
}
//
// Tell the thread that we have out there to terminate itself
//
KeSetEvent(&devExt->SSSubmissionThreadTerminateEvent,
EVENT_INCREMENT, FALSE);
//
// And wait for the thread to terminate
//
(VOID)OsrWaitForSingleObject(devExt->SSSubmissionThreadObject);
//
// Close the HANDLE that we opened to the thread
//
ZwClose(devExt->SSSubmissionThread);
//
// And drop our reference to the object
//
ObDereferenceObject(devExt->SSSubmissionThreadObject);
//
// We need to cancel our outstanding wait wake operation if there
// is one
//
if(devExt->WaitWakeEnable) {
CancelWaitWake(devExt);
}
//
// Because we registered a device interface we need to disable
// it now...
//
status = IoSetDeviceInterfaceState(&devExt->InterfaceName,
FALSE);
if (!NT_SUCCESS(status)) {
//
// Eh, big deal. Just print out some info and
// keep going...
//
OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_PNP_INFO,
("OsrPnp: IoSetDeviceInterfaceState failed! Returned status 0x%8.8x (%s)\n",
status, OsrNtStatusToString(status)));
}
//
// Delete the Interface Name that was allocated for us
//
if(devExt->InterfaceName.Buffer) {
RtlFreeUnicodeString(&devExt->InterfaceName);
}
//
// Fail any queued I/O requests...
//
OsrClearQueues(devExt);
//
// Return our hardware resources...
//
OsrReturnResources(devExt);
//
// Note that the OutStandingIoCount has to be
// decremented here to account for the
//
OsrDecrementOutstandingIoCount(devExt,__FILE__,__LINE__);
//
// Release our lock.and wait for any in progress I/O to finish...
//
OsrDecrementOutstandingIoCountAndWait(devExt);
//
// A remove constitutes a power down, we change
// our internal power state and notify the Power manager.
//
devExt->DevicePowerState = PowerDeviceD3;
powerState.DeviceState = PowerDeviceD3;
PoSetPowerState(DeviceObject, DevicePowerState, powerState);
//
// Indicate that we've successfully processed the IRP
//
Irp->IoStatus.Status = STATUS_SUCCESS;
//
// Don't wait for the Irp to finish, don't set a completion
// routine and don't complete the Irp! Just foist it off to the
// PDO and propogate the returned status
//
IoSkipCurrentIrpStackLocation(Irp);
status = IoCallDriver(devExt->DeviceToSendIrpsTo, Irp);
//
// Detach from the device below us. Since it never hurts
// to point out the obvious...Make sure this is done
// AFTER the call to IoCallDriver!
//
IoDetachDevice(devExt->DeviceToSendIrpsTo);
//
// Cleanup Tracing for W2k
//
#ifdef WPP_TRACING
#ifdef W2K
W2KCleanupWPPTracing(devExt->FunctionalDeviceObject);
#endif // W2K
#endif // WPP_TRACING
//
// Return our device object
//
IoDeleteDevice(devExt->FunctionalDeviceObject);
OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_PNP_INFO,
("OsrPnp: Finished! Leaving with state %s\n",
OsrPrintState(devExt)));
return status;
}
//
// STATE: SURPRISE_REMOVED
// IRP_MN: _REMOVE_DEVICE
//
// We're here because we've previously received notification
// of a "surprise" removal.
//
case (STATE_SURPRISE_REMOVED + IRP_MN_REMOVE_DEVICE): {
//
// If we were surprise removed, all I/O has been
// finished, our symbolic link has been deleted,
// our interface disabled and our resources
// returned so we don't need to do it again here...
//
//
// Deregister with WMI.
//
status = UsbFx2LkWmiDeRegistration(devExt);
if (!NT_SUCCESS(status)) {
//
// Eh, big deal. Just print out some info and
// keep going...
//
OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_PNP_INFO,
("OsrPnp: UsbFx2LkWmiDeRegistration failed! Returned status 0x%8.8x (%s)\n",
status, OsrNtStatusToString(status)));
}
//
// We're removed...
//
OsrUpdateDeviceState(devExt, STATE_REMOVED);
//
// A remove constitutes a power down, we change
// our internal power state and notify the Power manager.
//
devExt->DevicePowerState = PowerDeviceD3;
powerState.DeviceState = PowerDeviceD3;
PoSetPowerState(DeviceObject, DevicePowerState, powerState);
//
// The only Irps outstanding are going to be power, PnP, clean up, or
// close Irps. All I/O Irps between the _SURPRISE_REMOVAL and
// REMOVE_DEVICE have been failed (good thing cause our hardware is
// gone...)
//
//
// Note that the OutStandingIoCount has to be
// decremented here to account for the OsrIncrementOutstandingIoCount call
// at the beginning of the routine.
//
OsrDecrementOutstandingIoCount(devExt,__FILE__,__LINE__);
//
// Release our lock.and wait for any in progress I/O to finish...
//
OsrDecrementOutstandingIoCountAndWait(devExt);
//
// Indicate that we've successfully processed the IRP
//
Irp->IoStatus.Status = STATUS_SUCCESS;
//
// Don't wait for the Irp to finish, don't set a completion
// routine and don't complete the Irp! Just foist it off to the
// PDO and propogate the returned status
//
IoSkipCurrentIrpStackLocation(Irp);
status = IoCallDriver(devExt->DeviceToSendIrpsTo, Irp);
//
// Detach from the device below us. Since it never hurts
// to point out the obvious...Make sure this is done
// AFTER the call to IoCallDriver!
//
IoDetachDevice(devExt->DeviceToSendIrpsTo);
//
// Return our device object
//
IoDeleteDevice(devExt->FunctionalDeviceObject);
OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_PNP_INFO,
("OsrPnp: Finished! Leaving with state %s\n",
OsrPrintState(devExt)));
return status;
}
//
// STATE: STARTED
// IRP_MN: _QUERY_CAPABILITIES
//
// We're here if we're running and the PnP Manager or another
// driver sends us a QUERY_CAPABILITIES request. This will
// happen once the device is enumerated and again once all
// drivers for the device have started. A driver can also
// send this request to get the capabilities for the device.
//
// To proess this QUERY_CAPABILITIES, we just copy the system
// to device power mappings that we'll need for power management
// because we're the power policy owner for the stack. See
// the power management code in POWER.CPP to find out
// what the heck I'm talking about...
//
case (STATE_STARTED + IRP_MN_QUERY_CAPABILITIES): {
PDEVICE_CAPABILITIES deviceCaps;
//
// This is a BUS FIRST Irp.
//
status = OsrForwardIrpSynchronous(devExt,Irp);
if (NT_SUCCESS(status)) {
//
// Get a copy of all of the pnp/power capabilities of
// our device
//
deviceCaps = ioStack->Parameters.DeviceCapabilities.Capabilities;
RtlCopyMemory(&devExt->DeviceCapabilities, deviceCaps,
sizeof(DEVICE_CAPABILITIES));
PrintDeviceCapabilities(&devExt->DeviceCapabilities,(PUCHAR) "Received Device Capabilities");
//
// Copy over the array of system power state to
// device power state mappings...
//
OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_PNP_INFO,
("OsrPnp: Copying the System power state to Device power state mappings...\n"));
RtlCopyMemory(devExt->SystemToDevicePowerMappings,
deviceCaps->DeviceState,
sizeof(DEVICE_POWER_STATE) * PowerSystemMaximum);
//
// Iterate over all of the mappings and determine the lowest
// power state that our device supports. We will store this
// away and use it to determine which power state to lower
// our device to when doing selective suspend
//
for(ULONG i = PowerSystemSleeping1; i <= PowerSystemSleeping3; i++) {
if(devExt->DeviceCapabilities.DeviceState[i] < PowerDeviceD3) {
devExt->PowerDownLevel =
devExt->DeviceCapabilities.DeviceState[i];
}
}
//
// If we didn't get anything, default to D2
//
if(devExt->PowerDownLevel == PowerDeviceUnspecified ||
devExt->PowerDownLevel <= PowerDeviceD0) {
devExt->PowerDownLevel = PowerDeviceD2;
}
//
// Indicate the surprise removal of our device is OK.
// This will prevent the annoying "A device was removed"
// dialog from popping up on Windows 2000 and will prevent
// an event log entry from being created on XP and later
//
deviceCaps->SurpriseRemovalOK = TRUE;
//
// Indicate that the DeviceCapabilities have been initialized. We need
// to make sure that we have these in order for us to know what our
// Power Down Level is going to be.
//
devExt->DeviceCapabilitiesInitialized = TRUE;
//
// Enable WaitWake if enabled.
//
if(devExt->WaitWakeEnable) {
IssueWaitWake(devExt);
}
OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_PNP_INFO,
("OsrPnp: Device PowerDownLevel set to %s\n",
OsrPrintDevicePowerState((DEVICE_POWER_STATE) devExt->PowerDownLevel)));
} else {
OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_PNP_INFO,
("OsrPnp: Request for device capabilities failed! Status = 0x%8.8x (%s)\n",
status, OsrNtStatusToString(status)));
}
//
// Fill in the completion status...
//
Irp->IoStatus.Status = status;
Irp->IoStatus.Information = 0;
//
// OsrForwardIrpSynchronous is just a nice little
// wrapper that sets a completion routine, calls
// the next lowest driver, waits, and then reclaims the Irp
// for us in the completion routine by returning
// STATUS_MORE_PROCESSING_REQUIRED (or calls
// IoForwardIrpSynchronously to do all of that if
// we're built for XP and later). Just as if we
// had carried these steps out by ourselves, we now
// own the Irp and need to call IoCompleteRequest on it
// to finish processing.
//
IoCompleteRequest(Irp, IO_NO_INCREMENT);
//
// We're done with this request
//
OsrDecrementOutstandingIoCount(devExt,__FILE__,__LINE__);
OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_PNP_INFO,
("OsrPnp: Finished! Leaving with state %s\n",
OsrPrintState(devExt)));
return status;
}
//
// STATE: STARTED
// IRP_MN: _BOGUS
//
// We're here if Driver Verifier is currently
// running on our driver.
//
case (STATE_STARTED + IRP_MN_BOGUS): {
//
// Since we don't handle this request,
// just pass the request to the lower driver
//
OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_PNP_INFO,
("OsrPnp: Received IRP_MN_BOGUS: Just pass it along...\n"));
IoSkipCurrentIrpStackLocation(Irp);
OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_PNP_INFO,
("OsrPnp: Finished! Leaving with state %s\n",
OsrPrintState(devExt)));
status = IoCallDriver (devExt->DeviceToSendIrpsTo, Irp);
//
// We're done with this request
//
OsrDecrementOutstandingIoCount(devExt,__FILE__,__LINE__);
return status;
}
default: {
//
// DEFAULT CASE
// Just pass the request to the lower driver
//
OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_PNP_INFO,
("OsrPnp: Default case: Just pass it along...\n"));
IoSkipCurrentIrpStackLocation(Irp);
OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_PNP_INFO,
("OsrPnp: Finished! Leaving with state %s\n",
OsrPrintState(devExt)));
status = IoCallDriver (devExt->DeviceToSendIrpsTo, Irp);
//
// We're done with this request
//
OsrDecrementOutstandingIoCount(devExt,__FILE__,__LINE__);
return status;
}
}
//
// We should never get here...
//
OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_PNP_INFO,
("OsrPnp: Should never reach the end! Breaking into the debugger if attached...\n"));
//
// Use KdBreakPoint instead of DbgBreakPoint so that
// we only break in the checked build...
//
KdBreakPoint();
return STATUS_UNSUCCESSFUL;
}
///////////////////////////////////////////////////////////////////////////////
//
// OsrStartDevice
//
// This function is called from the DispatchPnp Entry Point to
// actually start our device.
//
// INPUTS:
//
// DevExt - Address of our device extension.
//
// OUTPUTS:
//
// None.
//
// RETURNS:
//
// STATUS_SUCCESS if successful, an appropriate error otherwise
//
// IRQL:
//
// This routine is called at IRQL == PASSIVE_LEVEL
//
// CONTEXT:
//
// This routine is called in an arbitrary thread context
//
// NOTES:
//
//
///////////////////////////////////////////////////////////////////////////////
NTSTATUS OsrStartDevice(PUSBFX2LK_EXT DevExt)
{
NTSTATUS status;
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("OsrStartDevice: Entered.\n"));
//
// Read the Device Descriptor, Configuration Descriptors, and select the
// interface.
//
status = ReadandSelectUsbDescriptors(DevExt);
if(!NT_SUCCESS(status)) {
OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_PNP_INFO,
("OsrStartDevice: ReadandSelectUsbDescriptors Error 0x%x (%s).\n",status,OsrNtStatusToString(status)));
return status;
}
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("OsrStartDevice: Exit.\n"));
return STATUS_SUCCESS;
}
///////////////////////////////////////////////////////////////////////////////
//
// OsrCanStopDevice
//
// This routine determines if the device cab be safely stopped. In
// our case we'll assume you can always stop the device. A device
// might not be able to be stopped, for example, if it doesn't have
// a queue for incoming requests or if it was notified that it is
// in the paging path.
//
// INPUTS:
//
// DevExt - Address of our device extension.
// Irp - Address of the input IRP.
//
// OUTPUTS:
//
// None.
//
// RETURNS:
//
// STATUS_SUCCESS;
//
// IRQL:
//
// Any
//
// CONTEXT:
//
// This routine can be called from anywhere in the driver
// so the context should be assumed arbitrary
//
// NOTES:
//
//
///////////////////////////////////////////////////////////////////////////////
NTSTATUS OsrCanStopDevice(PUSBFX2LK_EXT DevExt, PIRP Irp)
{
UNREFERENCED_PARAMETER(DevExt);
UNREFERENCED_PARAMETER(Irp);
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("OsrCanStopDevice: Entered.\n"));
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("OsrCanStopDevice: Exit.\n"));
return STATUS_SUCCESS;
}
///////////////////////////////////////////////////////////////////////////////
//
// OsrWaitForStop
//
// Using the event set by the DpcForIsr, this function waits until
// the device can be stopped.
//
// On our device, STOP implies there are no active requests on
// the device, even though there are queued requests.
//
// INPUTS:
//
// DevExt - Address of our device extension.
//
// OUTPUTS:
//
// None.
//
// RETURNS:
//
// None
//
// IRQL:
//
// This routine is called at IRQL == PASSIVE_LEVEL
//
// CONTEXT:
//
// This routine is called from the PnP handler so the
// context is arbitrary
//
// NOTES:
//
//
///////////////////////////////////////////////////////////////////////////////
VOID OsrWaitForStop(PUSBFX2LK_EXT DevExt)
{
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("OsrWaitForStop: Entered.\n"));
#if DBG
LARGE_INTEGER timeout;
NTSTATUS status;
timeout.QuadPart = -5*10*1000*1000; // 5 seconds
wait_again:
status = KeWaitForSingleObject(
&DevExt->StopEvent,
Executive,
KernelMode,
FALSE,
&timeout);
if(status == STATUS_TIMEOUT) {
OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_PNP_INFO,
("OsrWaitForStop: *** Still Waiting for activity to stop on device??\n"));
goto wait_again;
}
if(status != STATUS_SUCCESS) {
OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_PNP_INFO,
("OsrWaitForStop: *** Wait not ended with success, and not with timeout?? Status = 0x%x\n",
status));
}
#else
KeWaitForSingleObject(&DevExt->StopEvent,
Executive,
KernelMode,
FALSE,
NULL);
#endif
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("OsrWaitForStop: Exit.\n"));
}
///////////////////////////////////////////////////////////////////////////////
//
// OsrCanRemoveDevice
//
// This routine determines if the device can be safely removed. In our case
// we'll assume you can always remove the device. A device might note be able to
// be removed, for example, if it has opened handles or removing the device would
// result in the loss of data.
//
// INPUTS:
//
// DevExt - Address of our device extension.
// Irp - Address of the input IRP.
//
// OUTPUTS:
//
// None.
//
// RETURNS:
//
// STATUS_SUCCESS;
//
// IRQL:
//
// Any
//
// CONTEXT:
//
// This routine can be called from anywhere in the driver
// so the context should be assumed arbitrary
//
// NOTES:
//
//
///////////////////////////////////////////////////////////////////////////////
NTSTATUS OsrCanRemoveDevice(PUSBFX2LK_EXT DevExt, PIRP Irp)
{
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("OsrCanRemoveDevice: Entered.\n"));
UNREFERENCED_PARAMETER(DevExt);
UNREFERENCED_PARAMETER(Irp);
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("OsrCanRemoveDevice: Exit.\n"));
return STATUS_SUCCESS;
}
///////////////////////////////////////////////////////////////////////////////
//
// OsrReturnResources
//
// This function is called to return any resources which
// have been allocated for the device. Note that we do NOT return our
// Device Object here.
//
// INPUTS:
//
// DevExt - Address of our device extension.
//
// OUTPUTS:
//
// None.
//
// RETURNS:
//
// None
//
// IRQL:
//
// This routine is called at IRQL == PASSIVE_LEVEL
//
// CONTEXT:
//
// This routine is called in an arbitrary thread context
//
// NOTES:
//
//
///////////////////////////////////////////////////////////////////////////////
VOID OsrReturnResources(PUSBFX2LK_EXT DevExt)
{
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("OsrReturnResources: Entered.\n"));
//
// Deconfigure the USB device
//
DeconfigureUsbDevice(DevExt);
//
// Delete the Memory containing the descriptors and context we have for the
// USB device.
//
if(DevExt->UsbConfigurationDescriptor) {
ExFreePool(DevExt->UsbConfigurationDescriptor);
}
if (DevExt->UsbDeviceDescriptor) {
ExFreePool(DevExt->UsbDeviceDescriptor);
}
if(DevExt->UsbInterface) {
ExFreePool(DevExt->UsbInterface);
}
if(DevExt->PipeContext) {
ExFreePool(DevExt->PipeContext);
}
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("OsrReturnResources: Exit.\n"));
}
///////////////////////////////////////////////////////////////////////////////
//
// OsrDecrementOutstandingIoCountAndWait
//
// This routine releases the current hold on the remove
// lock and waits for the remove event to become
// signalled
//
// INPUTS:
//
// DevExt - Address of our device extension.
//
// OUTPUTS:
//
// None.
//
// RETURNS:
//
// None
//
// IRQL:
//
// This routine is called at IRQL < DISPATCH_LEVEL
//
// CONTEXT:
//
// This routine can be called from anywhere in the driver
// so the context should be assumed arbitrary
//
// NOTES:
//
//
///////////////////////////////////////////////////////////////////////////////
VOID OsrDecrementOutstandingIoCountAndWait(PUSBFX2LK_EXT DevExt)
{
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("OsrDecrementOutstandingIoCountAndWait: Entered.\n"));
#if DBG
LARGE_INTEGER timeout;
NTSTATUS status;
timeout.QuadPart = -5*10*1000*1000; // 5 seconds
#endif
ASSERT(DevExt->DevicePnPState < STATE_ALL_BELOW_FAIL);
ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
OsrDecrementOutstandingIoCount(DevExt,__FILE__,__LINE__);
#if DBG
wait_again:
status = KeWaitForSingleObject(
&DevExt->RemoveEvent,
Executive,
KernelMode,
FALSE,
&timeout);
if(status == STATUS_TIMEOUT) {
OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_PNP_INFO,
("*** Still Waiting for activity to stop on device?? %d. requests reamin\n",
DevExt->OutStandingIoCount));
goto wait_again;
}
if(status != STATUS_SUCCESS) {
OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_PNP_INFO,
("*** Wait not ended with success, and not with timeout?? Status = 0x%x\n",
status));
}
#else
KeWaitForSingleObject(&DevExt->RemoveEvent,
Executive,
KernelMode,
FALSE,
NULL);
#endif
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("OsrDecrementOutstandingIoCountAndWait: Exit.\n"));
}
///////////////////////////////////////////////////////////////////////////////
//
// OsrIncrementOutstandingIoCount
//
// This function is used to increment the number of I/O requests that
// are presently queued to the underlying device.
//
// INPUTS:
//
// DevExt - Address of our device extension.
//
// OUTPUTS:
//
// None.
//
// RETURNS:
//
// None
//
// IRQL:
//
// This routine is called at IRQL <= DISPATCH_LEVEL
//
// CONTEXT:
//
// This routine can be called from anywhere in the driver
// so the context should be assumed arbitrary
//
// NOTES:
//
//
///////////////////////////////////////////////////////////////////////////////
VOID OsrIncrementOutstandingIoCount(PUSBFX2LK_EXT PDevExt,const char* FileName,ULONG LineNumber)
{
KIRQL oldIrql;
VALID_DEVEXT(PDevExt);
ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
KeAcquireSpinLock(&PDevExt->IoStateLock,&oldIrql);
PDevExt->OutStandingIoCount++;
LONG count = PDevExt->OutStandingIoCount;
if(count == 2) {
KeClearEvent(&PDevExt->StopEvent);
}
KeReleaseSpinLock(&PDevExt->IoStateLock,oldIrql);
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_REFERENCE_COUNT,
("OsrIncrementOutstandingIoCount: %d %s %d\n",count,FileName,LineNumber));
return;
}
///////////////////////////////////////////////////////////////////////////////
//
// OsrDecrementOutstandingIoCount
//
// This function is used to decrement the number of requests that
// are queued to the underlying device
//
// INPUTS:
//
// DevExt - Address of our device extension.
//
// OUTPUTS:
//
// None.
//
// RETURNS:
//
// None
//
// IRQL:
//
// This routine is called at IRQL <= DISPATCH_LEVEL
//
// CONTEXT:
//
// This routine can be called from anywhere in the driver
// so the context should be assumed arbitrary
//
// NOTES:
//
//
///////////////////////////////////////////////////////////////////////////////
VOID OsrDecrementOutstandingIoCount(PUSBFX2LK_EXT PDevExt,const char* FileName,ULONG LineNumber)
{
KIRQL oldIrql;
VALID_DEVEXT(PDevExt);
ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
ASSERT(PDevExt->OutStandingIoCount);
KeAcquireSpinLock(&PDevExt->SSLock,&oldIrql);
KeAcquireSpinLockAtDpcLevel(&PDevExt->IoStateLock);
PDevExt->OutStandingIoCount--;
LONG count = PDevExt->OutStandingIoCount;
if(count == 1) {
//
// The device is becoming idle. We'll let the SS code
// know if it can suspend the device or not and we'll
// also indicate when the device became idle by
// querying the current system time
//
PDevExt->SSDeviceCanNowSuspend =
PDevExt->SSEnabledByUser && PDevExt->SSInitialized;
KeQuerySystemTime(&PDevExt->SSTimeOfLastActivity);
KeSetEvent(&PDevExt->StopEvent,EVENT_INCREMENT,FALSE);
}
if(count == 0) {
KeSetEvent(&PDevExt->RemoveEvent,EVENT_INCREMENT,FALSE);
}
KeReleaseSpinLockFromDpcLevel(&PDevExt->IoStateLock);
KeReleaseSpinLock(&PDevExt->SSLock,oldIrql);
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_REFERENCE_COUNT,
("OsrDecrementOutstandingIoCount: %d %s %d\n",count,FileName,LineNumber));
return;
}
///////////////////////////////////////////////////////////////////////////////
//
// OsrUpdateDeviceState
//
// Set the State member of the device extension to
// the given state
//
// INPUTS:
//
// DevExt - Pointer to our device extension
// State - New PnP/Power state
//
// OUTPUTS:
//
// None.
//
// RETURNS:
//
// None
//
// IRQL:
//
// This routine runs at IRQL <= DISPATCH_LEVEL
//
// CONTEXT:
//
// Arbitrary
//
// NOTES:
//
//
///////////////////////////////////////////////////////////////////////////////
VOID OsrUpdateDeviceState(PUSBFX2LK_EXT DevExt,PNP_DEVICESTATE State)
{
KIRQL oldIrql;
ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("OsrUpdateDeviceState: Entered.\n"));
//
// The state of the device effects the state of the
// IoQueue, so the lock must be
// held while updating the state
//
KeAcquireSpinLock(&DevExt->IoStateLock, &oldIrql);
OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_PNP_INFO,("OsrUpdateDeviceState: Old State %s\n",
OsrPrintState(DevExt)));
//
// Set the new state
//
DevExt->DevicePnPState = State;
OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_PNP_INFO,("OsrUpdateDeviceState: New State %s\n",
OsrPrintState(DevExt)));
//
// Drop the read lock and the IRQL;
//
KeReleaseSpinLock(&DevExt->IoStateLock, oldIrql);
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("OsrUpdateDeviceState: Exit.\n"));
return;
}
///////////////////////////////////////////////////////////////////////////////
//
// OsrWaitForSingleObject
//
// Convenient routine to inform us of an object is not being
// signalled when running in the debug build
//
// INPUTS:
//
// Object - The object to wait on
//
// OUTPUTS:
//
// None.
//
// RETURNS:
//
// None
//
// IRQL:
//
// This routine runs at IRQL == PASSIVE_LEVEL
//
// CONTEXT:
//
// Arbitrary
//
// NOTES:
//
///////////////////////////////////////////////////////////////////////////////
NTSTATUS OsrWaitForSingleObject(PVOID Object)
{
NTSTATUS status;
#if DBG
LARGE_INTEGER timeout;
timeout.QuadPart = -5*10*1000*1000; // 5 seconds
#endif
#if DBG
wait_again:
status = KeWaitForSingleObject(
Object,
Executive,
KernelMode,
FALSE,
&timeout);
if(status == STATUS_TIMEOUT) {
OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_WAIT_FOR_OBJECT,
("*** Still Waiting for Object 0x%p??\n",
Object));
goto wait_again;
}
if(status != STATUS_SUCCESS) {
OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_WAIT_FOR_OBJECT,
("*** Wait not ended with success, and not with timeout?? Status = 0x%x\n",
status));
}
#else
status = KeWaitForSingleObject(Object,
Executive,
KernelMode,
FALSE,
NULL);
#endif
return status;
}
///////////////////////////////////////////////////////////////////////////////
//
// OsrWaitForSingleObject
//
// Convenient routine to inform us of an object is not being
// signalled when running in the debug build
//
// INPUTS:
//
// Object - The object to wait on
//
// OUTPUTS:
//
// None.
//
// RETURNS:
//
// None
//
// IRQL:
//
// This routine runs at IRQL == PASSIVE_LEVEL
//
// CONTEXT:
//
// Arbitrary
//
// NOTES:
//
///////////////////////////////////////////////////////////////////////////////
NTSTATUS OsrWaitForMultipleObjects(ULONG ObjectCount, PVOID *Objects,
WAIT_TYPE WaitType,
PKWAIT_BLOCK WaitBlockArray)
{
NTSTATUS status;
#if DBG
LARGE_INTEGER timeout;
timeout.QuadPart = -5*10*1000*1000; // 5 seconds
#endif
#if DBG
wait_again:
status = KeWaitForMultipleObjects(ObjectCount,
Objects,
WaitType,
Executive,
KernelMode,
FALSE,
&timeout,
WaitBlockArray);
if(status == STATUS_TIMEOUT) {
OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_WAIT_FOR_OBJECT,
("*** Still Waiting for Objects 0x%p??\n",
Objects));
goto wait_again;
}
if(status != STATUS_SUCCESS) {
OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_WAIT_FOR_OBJECT,
("*** Wait not ended with success, and not with timeout?? Status = 0x%x\n",
status));
}
#else
status = KeWaitForMultipleObjects(ObjectCount,
Objects,
WaitType,
Executive,
KernelMode,
FALSE,
NULL,
WaitBlockArray);
#endif
return status;
}