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