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