www.pudn.com > usbfx2lk_v1.1.zip > usbfx2lk_queue.cpp


/////////////////////////////////////////////////////////////////////////////// 
// 
//    (C) Copyright 2005 OSR Open Systems Resources, Inc. 
//    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_Queue.cpp 
// 
//    ABSTRACT: 
// 
//      This file contains the routines that handle cancel processing for the  
//      OSR USB FX2 Learning Kit device driver 
// 
//    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_queue.tmh" 
} 
 
#endif // WPP_TRACING 
 
 
 
/////////////////////////////////////////////////////////////////////////////// 
// 
// OsrCsqInsertIoIrp 
// 
//  This routine is called by the cancel safe queue library 
//   when it has a new Irp for us to queue 
// 
// 
//  INPUTS: 
// 
//      Csq  -  Our cancel safe queue 
// 
//      Irp  -  The Irp to enqueue 
// 
//  OUTPUTS: 
// 
//      None 
// 
//  RETURNS: 
// 
//      None 
// 
//  IRQL: 
// 
//      Because we're using a spinlcok for synchronization in 
//       OsrCsqAcquireIoLock/OsrCsqReleaseIoLock, this  
//       routine will be called at IRQL == DISPATCH_LEVEL..  
// 
//  CONTEXT: 
// 
//      Arbitrary 
// 
//  NOTES: 
// 
//      **Enters and exits with the CancelSafeWriteLock held** 
// 
/////////////////////////////////////////////////////////////////////////////// 
#ifdef W2K3 
NTSTATUS OsrCsqInsertIoIrpEx(PIO_CSQ Csq,PIRP Irp,PVOID InsertContext) 
#else // W2K3 
VOID OsrCsqInsertIoIrp(PIO_CSQ Csq,PIRP Irp)  
#endif // W2K3 
{ 
    PUSBFX2LK_EXT      devExt; 
//    PIO_STACK_LOCATION ioStack = IoGetCurrentIrpStackLocation(Irp);; 
 
    // 
    // We should never be here and not at DISPATCH_LEVEL 
    // 
    ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); 
 
    // 
    // Get a pointer to our device extension... 
    //  
#ifdef W2K3 
    devExt = (PUSBFX2LK_EXT) InsertContext; 
#else // W2K3 
    devExt = (PUSBFX2LK_EXT)CONTAINING_RECORD(Csq,USBFX2LK_EXT,CancelSafeIoQueue); 
#endif //W2K3 
 
 
    OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_READWRITE, 
                 ("OsrCsqInsertIoIrp: Inserting Irp 0x%p into the cancel safe queue...\n", 
                 Irp)); 
 
 
    // 
    // Insert this entry into our write queue. No extra synchronization 
    //  needs to be done here since this call will be wrapped in calls 
    //  to OsrCsqAcquireIoLock/OsrCsqReleaseIoLock by the CSQ 
    //  library... 
    // 
    InsertTailList(&devExt->IoQueue, &Irp->Tail.Overlay.ListEntry); 
 
#ifdef W2K3 
    return STATUS_SUCCESS; 
#else // W2K3 
    return; 
#endif // W2K3 
} 
 
 
/////////////////////////////////////////////////////////////////////////////// 
// 
// OsrCsqRemoveIoIrp 
// 
//  This routine is called by the cancel safe queue library 
//   when it wamts is to remove a Irp from our queue 
// 
// 
//  INPUTS: 
// 
//      Csq  -  Our cancel safe queue 
// 
//      Irp  -  The Irp to dequeue 
// 
// 
//  OUTPUTS: 
// 
//      None 
// 
//  RETURNS: 
// 
//      None 
// 
//  IRQL: 
// 
//      Because we're using a spinlcok for synchronization in 
//       OsrCsqAcquireIoLock/OsrCsqReleaseIoLock, this  
//       routine will be called at IRQL == DISPATCH_LEVEL..  
// 
//  CONTEXT: 
// 
//      Arbitrary 
// 
//  NOTES: 
// 
//      **Enters and exits with the CancelSafeIoLock held** 
// 
// 
/////////////////////////////////////////////////////////////////////////////// 
VOID OsrCsqRemoveIoIrp(PIO_CSQ Csq,PIRP Irp)  
{ 
 
    UNREFERENCED_PARAMETER(Csq); 
 
    // 
    // We should never be here and not at DISPATCH_LEVEL 
    // 
    ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); 
 
 
    OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_READWRITE,  
        ("OsrCsqRemoveIoIrp: Removing Irp 0x%p from the cancel safe queue...\n", 
                Irp)); 
 
    // 
    // Remove this entry from our write queue. No extra synchronization 
    //  needs to be done here since this call will be wrapped in calls 
    //  to OsrCsqAcquireWriteLock/OsrCsqReleaseWriteLock by the CSQ 
    //  library... 
    // 
    RemoveEntryList(&Irp->Tail.Overlay.ListEntry); 
 
    return; 
 
} 
 
 
/////////////////////////////////////////////////////////////////////////////// 
// 
// OsrCsqPeekNextIoIrp 
// 
//      We're called here when the CSQ library wants a pointer to the 
//      next Irp in the queue 
// 
//  INPUTS: 
// 
//      Csq         -  Our cancel safe queue 
// 
//      Irp         -  The Irp to dequeue 
// 
//      PeekContext -  The context parameter passed to IoCsqRemoveNextIrp, 
//                      in this driver it is not used 
// 
//  OUTPUTS: 
// 
//      None 
// 
//  RETURNS: 
// 
//      If there is another Irp in the queue, we return its address. 
//      Otherwise we return NULL 
// 
//  IRQL: 
// 
//      Since we're using a spinlcok for synchronization in 
//       OsrCsqAcquireIoLock/OsrCsqReleaseIoLock, this  
//       routine will be called at IRQL == DISPATCH_LEVEL..  
// 
//  CONTEXT: 
// 
//      Arbitrary 
// 
//  NOTES: 
// 
//      **Enters and exits with the CancelSafeIoLock held** 
// 
/////////////////////////////////////////////////////////////////////////////// 
PIRP OsrCsqPeekNextIoIrp(PIO_CSQ Csq,PIRP Irp,PVOID PeekContext) 
{ 
 
    PUSBFX2LK_EXT   devExt; 
    PIRP            nextIrp = NULL; 
    PLIST_ENTRY     nextEntry; 
    PLIST_ENTRY     listHead; 
 
    // 
    // We should never be here and not at DISPATCH_LEVEL 
    // 
    ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); 
 
    // 
    // Get a pointer to our device extension... 
    //  
    devExt = CONTAINING_RECORD(Csq,USBFX2LK_EXT,CancelSafeIoQueue); 
     
    listHead = &devExt->IoQueue; 
 
    // 
    // If the Irp parameter is NULL, we start with the first Irp 
    //  in the queue 
    // 
    if(Irp == NULL) {        
 
        OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_READWRITE,  
                    ("OsrCsqPeekNextIoIrp: Peeking next Irp from the head of the queue...\n")); 
 
        nextEntry = listHead->Flink; 
 
    } else { 
 
        // 
        // Otherwise we start with the Irp after the supplied Irp 
        // 
 
        OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_READWRITE,  
                    ("OsrCsqPeekNextIoIrp: Peeking next Irp starting at Irp 0x%p...\n", 
                    Irp)); 
 
        nextEntry = Irp->Tail.Overlay.ListEntry.Flink; 
 
    } 
     
    while(nextEntry != listHead) { 
         
        nextIrp = CONTAINING_RECORD(nextEntry, IRP, Tail.Overlay.ListEntry); 
 
        if(PeekContext) { 
 
            // 
            // If you passed a PeekContext value when you called 
            //  IoCsqRemoveNextIrp, you would do your driver 
            //  defined processing here to figure out if  
            //  nextIrp matches the Irp you were looking for 
            // 
 
        } else { 
 
            // 
            // We don't have any match criteria - just return the  
            // first one we found... 
            // 
            break; 
 
        } 
 
        nextIrp = NULL; 
         
        nextEntry = nextEntry->Flink; 
 
    } 
 
    OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_READWRITE,  
        ("OsrCsqPeekNextIoIrp: Next Irp is Irp 0x%p...\n",nextIrp)); 
 
    return nextIrp; 
     
} 
 
 
/////////////////////////////////////////////////////////////////////////////// 
// 
// OsrCsqAcquireIoLock 
// 
//      We're called here when the CSQ lib wants to synchronize 
//      access to our queue. 
// 
//  INPUTS: 
// 
//      Csq  -  Our cancel safe queue 
// 
//  OUTPUTS: 
// 
//      Irql -  We return the IRQL at which we want to drop 
//              back down to when called at our release routine 
//              in the Irql parameter 
// 
//  RETURNS: 
// 
//      None 
// 
//  IRQL: 
// 
//      This routine is called at IRQL <= DISPATCH_LEVEL 
// 
//  CONTEXT: 
// 
//      Arbitrary 
// 
//  NOTES: 
// 
// 
/////////////////////////////////////////////////////////////////////////////// 
VOID OsrCsqAcquireIoLock(PIO_CSQ Csq,PKIRQL Irql) 
{ 
 
    PUSBFX2LK_EXT devExt; 
 
    // 
    // We should never be here and not at <= DISPATCH_LEVEL 
    // 
    ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); 
 
    // 
    // Get a pointer to our device extension... 
    //  
    devExt = CONTAINING_RECORD(Csq, USBFX2LK_EXT, CancelSafeIoQueue); 
 
    OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_READWRITE,  
        ("OsrCsqAcquireIoLock: Acquiring the cancel safe queue lock...\n")); 
 
    // 
    // Simply acquire our spinlock. The current IRQL (which 
    //  is the IRQL we'll want to return to when dropping the lock) 
    //  will be returned in the Irql parameter. 
    // 
    KeAcquireSpinLock(&devExt->CancelSafeIoLock, Irql); 
 
} 
 
 
/////////////////////////////////////////////////////////////////////////////// 
// 
// OsrCsqReleaseIoLock 
// 
//      We're called here when the CSQ lib is finished accessing 
//      our queue 
// 
//  INPUTS: 
// 
//      Csq  -  Our cancel safe queue 
// 
//      Irql -  This is the IRQL value that we previously stored 
//              in OsrCsqAcquireIoLock 
// 
//  OUTPUTS: 
// 
//      None 
// 
//  RETURNS: 
// 
//      None 
// 
//  IRQL: 
// 
//      This routine is called at IRQL == DISPATCH_LEVEL (since 
//      we're holding the CancelSafeIoLock) 
// 
//  CONTEXT: 
// 
//      Arbitrary 
// 
//  NOTES: 
// 
// 
/////////////////////////////////////////////////////////////////////////////// 
VOID OsrCsqReleaseIoLock(PIO_CSQ Csq,KIRQL Irql)  
{ 
    PUSBFX2LK_EXT  devExt; 
 
    // 
    // We should never be here and not at DISPATCH_LEVEL 
    // 
    ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); 
 
    // 
    // Get a pointer to our device extension... 
    //  
    devExt = CONTAINING_RECORD(Csq,  
                               USBFX2LK_EXT,  
                               CancelSafeIoQueue); 
 
    OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_READWRITE,  
        ("OsrCsqReleaseIoLock: Releasing the cancel safe queue lock...\n")); 
 
    // 
    // Drop the lock, restoring the old Irql... 
    // 
    KeReleaseSpinLock(&devExt->CancelSafeIoLock, Irql); 
 
} 
 
 
 
/////////////////////////////////////////////////////////////////////////////// 
// 
// OsrCsqCompleteCancelledIoIrp 
// 
//      The CSQ library calls us here when it has a Irp that needs to be  
//      cancelled. 
// 
//  INPUTS: 
// 
//      Csq  -  Our cancel safe queue 
// 
//      Irp  -  The Irp to cancel 
// 
//  OUTPUTS: 
// 
//      None 
// 
//  RETURNS: 
// 
//      None 
// 
//  IRQL: 
// 
//      This routine is called at IRQL <= DISPATCH_LEVEL 
// 
//  CONTEXT: 
// 
//      Arbitrary 
// 
//  NOTES: 
// 
//      Note that while the Irp is in our Queue the  
//      Irp->Tail.Overlay.DriverContext[0], contains our IO Context for the 
//      operation.    
// 
/////////////////////////////////////////////////////////////////////////////// 
VOID OsrCsqCompleteCancelledIoIrp(PIO_CSQ Csq,PIRP Irp) 
{ 
    PUSBFX2LK_EXT        devExt; 
    PUSBFX2LK_IO_CONTEXT pFx2Context = NULL; 
    PURB                 ioctlUrb = NULL;  
 
    // 
    // We should never be here and not at <= DISPATCH_LEVEL 
    // 
    ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); 
 
    // 
    // Get a pointer to our device extension... 
    //  
    devExt = (PUSBFX2LK_EXT)CONTAINING_RECORD(Csq, USBFX2LK_EXT, CancelSafeIoQueue); 
 
    OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_READWRITE,  
        ("OsrCsqCompleteCancelledIoIrp: Cancelling Irp 0x%p!\n",  
                Irp)); 
 
    // 
    // See if we have a read/write context stored in the DriverContext field.   
    //  We can do this because we are not using system queuing.  Also  
    //  we can use DriverContext[0]. The IoCsq routines use DriverContext[3] 
    // 
    pFx2Context = (PUSBFX2LK_IO_CONTEXT) Irp->Tail.Overlay.DriverContext[0]; 
     
    if(pFx2Context) { 
        IoFreeMdl(pFx2Context->Mdl); 
        ExFreePool(pFx2Context->Urb); 
        IoFreeWorkItem(pFx2Context->PWorkItem); 
        ExFreePool(pFx2Context); 
    } 
 
    // 
    // For some IOCTLs, we queue them off and put the  
    //  URBs that we've allocated in the DriverContext[1]  
    //  pointer. Again, we can do this because these contexts 
    //  are ours while we own the IRP 
    // 
    ioctlUrb = (PURB)Irp->Tail.Overlay.DriverContext[1]; 
 
    if (ioctlUrb) { 
 
        ExFreePool(ioctlUrb); 
 
    } 
 
    // 
    // Just go ahead and cancel the Irp 
    // 
    Irp->IoStatus.Status      = STATUS_CANCELLED; 
    Irp->IoStatus.Information = 0; 
     
    IoCompleteRequest(Irp, IO_NO_INCREMENT); 
 
    // 
    // One less request, don't forget to decrement our outstanding 
    // IO count!  
    // 
    OsrDecrementOutstandingIoCount(devExt,__FILE__,__LINE__); 
 
} 
 
/////////////////////////////////////////////////////////////////////////////// 
// 
// OsrClearQueues 
// 
//    This routine is called to clear out all read and write requests 
//    that are either in progress or pending 
// 
//  INPUTS: 
// 
//      DevExt - The device extension for the device whose queues we want 
//               clear 
// 
//  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 OsrClearQueues(PUSBFX2LK_EXT DevExt) 
{ 
    PIRP irp; 
    PUSBFX2LK_IO_CONTEXT pFx2Context = NULL; 
    PURB ioctlUrb = NULL; ; 
 
    // 
    // We should never be here and not at <= DISPATCH_LEVEL 
    // 
    ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); 
 
    // 
    // Traverse the Io queue and fail any outstanding write  
    //  requests 
    // 
    while(irp = IoCsqRemoveNextIrp(&DevExt->CancelSafeIoQueue, NULL)) { 
 
        // 
        // See if we have a context stored in the DriverContext field.  We can do this 
        // because we are not using system queuing.  Also we can use DriverContext[0], 
        // The IoCsq routines use DriverContext[3]. 
        // 
        pFx2Context = (PUSBFX2LK_IO_CONTEXT) irp->Tail.Overlay.DriverContext[0]; 
        if(pFx2Context) { 
            IoFreeMdl(pFx2Context->Mdl); 
            ExFreePool(pFx2Context->Urb); 
            IoFreeWorkItem(pFx2Context->PWorkItem); 
            ExFreePool(pFx2Context); 
        } 
 
        // 
        // For some IOCTLs, we queue them off and put the  
        //  URBs that we've allocated in the DriverContext[1]  
        //  pointer. Again, we can do this because these contexts 
        //  are ours while we own the IRP 
        // 
        ioctlUrb = (PURB)irp->Tail.Overlay.DriverContext[1]; 
 
        if (ioctlUrb) { 
 
            ExFreePool(ioctlUrb); 
 
        } 
 
        // 
        // Mark the Irp as offline..... 
        // 
        irp->IoStatus.Status      = STATUS_DEVICE_OFF_LINE; 
        irp->IoStatus.Information = 0; 
     
        IoCompleteRequest(irp, IO_NO_INCREMENT); 
 
    } 
 
}