NT4/private/ntos/dd/digibrd/fep5/misc.c
2020-09-30 17:12:29 +02:00

771 lines
25 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
*****************************************************************************
* *
* This software contains proprietary and confidential information of *
* *
* Digi International Inc. *
* *
* By accepting transfer of this copy, Recipient agrees to retain this *
* software in confidence, to prevent disclosure to others, and to make *
* no use of this software other than that for which it was delivered. *
* This is an unpublished copyrighted work of Digi International Inc. *
* Except as permitted by federal law, 17 USC 117, copying is strictly *
* prohibited. *
* *
*****************************************************************************
Module Name:
misc.c
Abstract:
Revision History:
* $Log: /Components/Windows/NT/Async/FEP5/MISC.C $
*
* 4 3/05/96 6:27p Stana
* Bugfix: When DigiCancelIrpQueue cancels its first read irp, if another
* read irp is immediately issued by the app, it also gets cancelled.
* This can actually go on forever, but usually stops within a few hours.
* Now I have a spinlock (NewIrpLock) to prevent this.
*
* 1 3/04/96 12:18p Stana
* Misc. functions required to help with NT issues such as Multi-processor
* support, timing problems, and other such things.
*
* Revision 1.15.1.5 1995/11/28 12:48:26 dirkh
* Adopt common header file.
*
* Revision 1.15.1.4 1995/10/04 18:25:10 dirkh
* DevExt->XcPreview must be reset when pXoffCounter is cleared. (Not sure why...)
*
* Revision 1.15.1.3 1995/09/19 12:49:52 dirkh
* Add IOCTL_SERIAL_XOFF_COUNTER support:
* {
* DigiStartIrpRequest (if WRITE or XOFF_COUNTER is queued behind a *transmitted* XOFF_COUNTER, complete the transmitted XOFF_COUNTER).
* DigiTryToCompleteIrp (if IRP is XOFF_COUNTER, clear DevExt->pXoffCounter).
* }
* Simplify interface to DigiCancelIrpQueue.
*
* Revision 1.15.1.2 1995/09/05 16:59:38 dirkh
* DigiTryToCompleteIrp: Fix recovery from failed assertion.
*
* Revision 1.15.1.1 1995/09/05 14:28:18 dirkh
* General: Minimize IoCancel spin lock window.
* General: Eliminate special handling for "fast RAS" flush IRP. (It's now fully realized for IoCompleteRequest.)
* DigiStartIrpRequest queues IMMEDIATE_CHAR IRPs at the head of the queue, others at the tail.
* DigiCancelQueuedIrp holds lock to fix DevExt->TotalCharsQueued.
* DigiRundownIrpRefs kills the cancel routine only if that's the only reference left.
*
* Revision 1.15 1995/04/19 13:09:27 rik
* Added an undeclared local variable.
*
* Revision 1.14 1995/04/18 18:15:05 rik
* Fixed potential timing hole with canceling an Irp in the generic cancel
* routine.
*
* Revision 1.13 1995/04/12 14:42:04 rik
* Take into account self-inserted flush irp's being cancelled.
*
* Revision 1.12 1994/09/13 07:40:58 rik
* Added debug tracking output for cancel irps.
*
* Revision 1.11 1993/06/14 14:42:22 rik
* Tightened up some spinlock windows, and fixed a problem with how
* I was calling the startroutine in the DigiTryToCompleteIrp routine.
*
* Revision 1.10 1993/06/06 14:17:03 rik
* Tightened up windows in the code which were causing problems. Primarily,
* changes were in the functions DigiTryToCompleteIrp, and DigiCancelIrpQueue.
* I use Cancel spinlocks more rigoursly to help eliminate windows which were
* seen on multi-processor machines. The problem could also happen on
* uni-processor machines, depending on which IRQL level the requests were
* done at.
*
* Revision 1.9 1993/05/18 05:08:00 rik
* Fixed spinlock problems where the device extension wasn't being protected
* by its spinlock. As a result, on multi-processor machines, the device
* extension was being changed when it was being accessed by the other
* processor causing faults.
*
* Revision 1.8 1993/05/09 09:22:11 rik
* Added debugging output for completing IRP.
*
* Revision 1.7 1993/03/08 07:23:04 rik
* Changed how I handle read/write/wait IRPs now. Instead of always marking
* the IRP, I have changed it such that I only mark an IRP pending if the
* value from the start routine is STATUS_PENDING or if there is all ready
* and outstanding IRP(s) present on the appropriate queue.
*
* Revision 1.6 1993/02/25 19:09:58 rik
* Added debugging for tracing IRPs better.
*
* Revision 1.5 1993/02/04 12:23:40 rik
* ??
*
* Revision 1.4 1993/01/28 10:36:44 rik
* Updated function to always return STATUS_PENDING since I always IRP requests
* status pending. This is a new requirement for NT build 354.
*
* Revision 1.3 1993/01/22 12:36:10 rik
* *** empty log message ***
*
* Revision 1.2 1992/12/10 16:12:08 rik
* Reorganized function names to better reflect how they are used through out
* the driver.
*
* Revision 1.1 1992/11/12 12:50:59 rik
* Initial revision
*
--*/
#include "header.h"
#ifndef _MISC_DOT_C
# define _MISC_DOT_C
static char RCSInfo_MiscDotC[] = "$Header: /Components/Windows/NT/Async/FEP5/MISC.C 4 3/05/96 6:27p Stana $";
#endif
/****************************************************************************/
/* Local Prototypes */
/****************************************************************************/
void __inline
DigiRundownIrpRefs( IN PIRP Irp,
IN PKTIMER IntervalTimer OPTIONAL,
IN PKTIMER TotalTimer OPTIONAL );
VOID DigiCancelQueuedIrp( PDEVICE_OBJECT DeviceObject,
PIRP Irp );
NTSTATUS DigiStartIrpRequest( IN PDIGI_CONTROLLER_EXTENSION ControllerExt,
IN PDIGI_DEVICE_EXTENSION DeviceExt,
IN PLIST_ENTRY Queue,
IN PIRP Irp,
IN PDIGI_START_ROUTINE StartRoutine )
/*++
Routine Description:
Arguments:
ControllerExt - Pointer to the controller object extension associated
with this device.
DeviceExt - Pointer to the device object extension for this device.
Queue - The queue of Irp requests.
StartRoutine - The routine to call if the queue is empty.
( i.e. if this is the first request possibly ).
Return Value:
--*/
{
PIO_STACK_LOCATION IrpSp;
KIRQL OldIrql;
NTSTATUS Status;
BOOLEAN EmptyList;
DigiDump( DIGIFLOW, ("Entering DigiStartIrpRequest\n") );
KeAcquireSpinLock( &DeviceExt->NewIrpLock, &OldIrql );
KeReleaseSpinLock( &DeviceExt->NewIrpLock, OldIrql );
IrpSp = IoGetCurrentIrpStackLocation( Irp );
KeAcquireSpinLock( &DeviceExt->ControlAccess, &OldIrql);
// If we enqueue a WRITE or XOFF_COUNTER behind a transmitted XOFF_COUNTER,
// then the transmitted XOFF_COUNTER must be completed immediately.
if( Queue == &DeviceExt->WriteQueue
&& !IsListEmpty( Queue )
&& Queue->Flink->Flink == Queue // only one IRP on the queue
&& ( IrpSp->MajorFunction == IRP_MJ_WRITE
|| ( IrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_SERIAL_XOFF_COUNTER
&& IrpSp->MajorFunction == IRP_MJ_DEVICE_CONTROL
)
)
)
{
PIRP HeadIrp = CONTAINING_RECORD( Queue->Flink, IRP, Tail.Overlay.ListEntry );
if( HeadIrp->IoStatus.Information == 1 ) // XOFF_COUNTER has been transmitted
{
PIO_STACK_LOCATION HeadIrpSp = IoGetCurrentIrpStackLocation( HeadIrp );
if( HeadIrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_SERIAL_XOFF_COUNTER
&& HeadIrpSp->MajorFunction == IRP_MJ_DEVICE_CONTROL )
{
DigiDump( (DIGIWRITE|DIGIIRP|DIGIDIAG1), ("DigiStartIrpRequest is absorbing transmitted XOFF_COUNTER.\n") );
// Absorb the XOFF_COUNTER.
DigiTryToCompleteIrp( DeviceExt, &OldIrql, STATUS_SERIAL_MORE_WRITES,
Queue, NULL, &DeviceExt->WriteRequestTotalTimer, StartRoutine );
// It's possible that some other IRP sneaked in ahead of us...
KeAcquireSpinLock( &DeviceExt->ControlAccess, &OldIrql);
}
}
} // WRITE or XOFF_COUNTER is being added to non-empty WriteQueue
// IMMEDIATE_CHAR is queued at the head, all others at the tail of Queue.
if( IrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_SERIAL_IMMEDIATE_CHAR
&& IrpSp->MajorFunction == IRP_MJ_DEVICE_CONTROL )
{
ASSERT( Queue == &DeviceExt->WriteQueue );
DeviceExt->TotalCharsQueued++;
EmptyList = TRUE; // Force StartRoutine to be called.
// DH Change cancel routine on former head IRP, and avoid re-sending or starving IRP.
InsertHeadList( Queue, &Irp->Tail.Overlay.ListEntry );
}
else
{
if( IrpSp->MajorFunction == IRP_MJ_WRITE )
{
ASSERT( Queue == &DeviceExt->WriteQueue );
DeviceExt->TotalCharsQueued += IrpSp->Parameters.Write.Length;
}
else
if( IrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_SERIAL_XOFF_COUNTER
&& IrpSp->MajorFunction == IRP_MJ_DEVICE_CONTROL )
{
ASSERT( Queue == &DeviceExt->WriteQueue );
DeviceExt->TotalCharsQueued++;
}
EmptyList = IsListEmpty( Queue );
InsertTailList( Queue, &Irp->Tail.Overlay.ListEntry );
}
// Mark IRP as "never pending" to advise priority boost on IRP completion.
Irp->IoStatus.Status = STATUS_SUCCESS;
if( EmptyList )
{
DigiDump( DIGIFLOW, (" Calling Starter Routine\n") );
Status = StartRoutine( ControllerExt, DeviceExt, &OldIrql );
if( Status == STATUS_PENDING )
{
ASSERT( Irp->CancelRoutine != NULL ); // StartRoutine should have set this.
Irp->IoStatus.Status = Status; // STATUS_PENDING
DigiIoMarkIrpPending( Irp );
}
}
else // The IRP will be started later.
{
KIRQL OldCancelIrql;
DigiDump( DIGIFLOW, (" Queuing the Irp\n") );
Irp->IoStatus.Status = Status = STATUS_PENDING;
DigiIoMarkIrpPending( Irp );
IoAcquireCancelSpinLock( &OldCancelIrql );
IoSetCancelRoutine( Irp, DigiCancelQueuedIrp );
IoReleaseCancelSpinLock( OldCancelIrql );
}
DigiDump( DIGIFLOW, ("Exiting DigiStartIrpRequest\n") );
KeReleaseSpinLock( &DeviceExt->ControlAccess, OldIrql );
return( Status );
} // end DigiStartIrpRequest
VOID DigiCancelQueuedIrp( PDEVICE_OBJECT DeviceObject,
PIRP Irp )
/*++
Routine Description:
This routine is used to cancel Irps on the queue which are NOT the
head of the queue. I assume the head entry is the current Irp.
Arguments:
DeviceExt - Pointer to the device object for this device.
Irp - Pointer to the IRP to be cancelled.
Return Value:
None.
--*/
{
PIO_STACK_LOCATION IrpSp;
PDIGI_DEVICE_EXTENSION DeviceExt;
KIRQL OldIrql;
IoReleaseCancelSpinLock( Irp->CancelIrql );
DigiDump( (DIGIFLOW|DIGICANCELIRP), ("Canceling Queued Irp 0x%x\n",
Irp) );
IrpSp = IoGetCurrentIrpStackLocation(Irp);
DeviceExt = DeviceObject->DeviceExtension;
KeAcquireSpinLock( &DeviceExt->ControlAccess, &OldIrql );
RemoveEntryList( &Irp->Tail.Overlay.ListEntry );
if( IrpSp->MajorFunction == IRP_MJ_WRITE )
{
DeviceExt->TotalCharsQueued -= IrpSp->Parameters.Write.Length;
}
else
if( IrpSp->MajorFunction == IRP_MJ_DEVICE_CONTROL
&& ( IrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_SERIAL_IMMEDIATE_CHAR
|| IrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_SERIAL_XOFF_COUNTER
)
)
{
DeviceExt->TotalCharsQueued--;
}
KeReleaseSpinLock( &DeviceExt->ControlAccess, OldIrql );
Irp->IoStatus.Status = STATUS_CANCELLED;
Irp->IoStatus.Information = 0;
DigiIoCompleteRequest( Irp, IO_NO_INCREMENT );
DigiDump( DIGIFLOW, ("Exiting DigiCancelQueuedIrp\n") );
} // end DigiCancelQueuedIrp
VOID DigiTryToCompleteIrp( PDIGI_DEVICE_EXTENSION DeviceExt,
PKIRQL pOldIrql,
NTSTATUS StatusToUse,
PLIST_ENTRY Queue,
PKTIMER IntervalTimer,
PKTIMER TotalTimer,
PDIGI_START_ROUTINE StartRoutine )
/*++
Routine Description:
Arguments:
DeviceExt - Pointer to the device object for this device.
Irp - Pointer to the IRP to be cancelled.
Return Value:
None.
--*/
{
PIRP Irp;
DigiDump( DIGIFLOW, ("Entering DigiTryToCompleteIrp\n") );
if( IsListEmpty( Queue ) )
{
ASSERT( !IsListEmpty( Queue ) );
KeReleaseSpinLock( &DeviceExt->ControlAccess, *pOldIrql );
return;
}
Irp = CONTAINING_RECORD( Queue->Flink,
IRP,
Tail.Overlay.ListEntry );
//
// We can decrement the reference to "remove" the fact
// that the caller no longer will be accessing this irp.
//
DigiDump( DIGIREFERENCE, (" Dec Ref for entering\n") );
DIGI_DEC_REFERENCE( Irp );
//
// Try to run down all other references to this irp.
//
DigiRundownIrpRefs( Irp, IntervalTimer, TotalTimer );
//
// See if the ref count is zero after trying to kill everybody else.
//
if( !DIGI_REFERENCE_COUNT( Irp ) )
{
BOOLEAN discoveredIrp;
PIO_STACK_LOCATION IrpSp;
#if DBG
LONG Extra;
char const *IrpType,
ReadIrp[] = "read",
WriteIrp[] = "write",
FlushIrp[] = "flush",
IoctlIrp[] = "ioctl",
UnknownIrp[] = "unknown";
#endif
//
// The ref count was zero so we should complete this
// request.
//
DigiDump( DIGIREFERENCE, (" Completing Irp!\n") );
RemoveHeadList( Queue );
// Race to start IRPs: user mode (Serial*) vs. DPC routines
//
// When DigiStartIrpRequest adds an IRP to an empty queue, it starts the IRP.
// If we uncover/discover an IRP, DigiStartIrpRequest(s) will not see
// an empty queue while the lock is down, so it(they) will not start the IRP.
// Thus, if the queue is not empty now, we must start the IRP.
//
// We don't race ourselves because only one DigiTryToCompleteIrp wins (completes)
// and there never are any references to "buried" IRPs that would trigger
// completions and starts.
if( StartRoutine )
discoveredIrp = !IsListEmpty( Queue );
else
discoveredIrp = FALSE;
if( Queue == &DeviceExt->WriteQueue
&& DeviceExt->pXoffCounter )
{
ASSERT( DeviceExt->pXoffCounter == Irp->AssociatedIrp.SystemBuffer );
DeviceExt->pXoffCounter = NULL;
#if 1 // DBG DH necessary, but haven't figured out why
DeviceExt->XcPreview = 0; // Looks a little nicer...
#endif
}
KeReleaseSpinLock( &DeviceExt->ControlAccess, *pOldIrql );
Irp->IoStatus.Status = StatusToUse;
if( StatusToUse == STATUS_CANCELLED )
Irp->IoStatus.Information = 0;
#if DBG
IrpSp = IoGetCurrentIrpStackLocation( Irp );
switch ( IrpSp->MajorFunction )
{
case IRP_MJ_READ:
IrpType = ReadIrp;
Extra = IrpSp->Parameters.Read.Length;
if (Irp->IoStatus.Information>IrpSp->Parameters.Read.Length)
{
DbgPrint("Returning too much data! Asked for (%d) gave (%d).\n",
IrpSp->Parameters.Read.Length,
Irp->IoStatus.Information);
DbgBreakPoint();
}
break;
case IRP_MJ_WRITE:
IrpType = WriteIrp;
Extra = IrpSp->Parameters.Write.Length;
break;
case IRP_MJ_FLUSH_BUFFERS:
IrpType = FlushIrp;
Extra = -1;
break;
case IRP_MJ_DEVICE_CONTROL:
IrpType = IoctlIrp;
Extra = IrpSp->Parameters.DeviceIoControl.IoControlCode;
break;
default:
IrpType = UnknownIrp;
Extra = IrpSp->MajorFunction;
break;
}
DigiDump( (DIGIFLOW|DIGIREAD|DIGIWRITE|DIGIIRP|DIGIWAIT|DIGIREFERENCE),
("Completing %s(%d) IRP 0x%x, Status = 0x%.8x, Information = %u\n",
IrpType, Extra, Irp, Irp->IoStatus.Status, Irp->IoStatus.Information ) );
#endif
if (StatusToUse==STATUS_SUCCESS)
{
IrpSp = IoGetCurrentIrpStackLocation( Irp );
switch ( IrpSp->MajorFunction )
{
case IRP_MJ_READ:
ExInterlockedAddUlong(&DeviceExt->ParentControllerExt->PerfData.BytesRead,
Irp->IoStatus.Information,
&DeviceExt->ParentControllerExt->PerfLock);
ExInterlockedAddUlong(&DeviceExt->PerfData.BytesRead,
Irp->IoStatus.Information,
&DeviceExt->PerfLock);
break;
case IRP_MJ_WRITE:
ExInterlockedAddUlong(&DeviceExt->ParentControllerExt->PerfData.BytesWritten,
Irp->IoStatus.Information,
&DeviceExt->ParentControllerExt->PerfLock);
ExInterlockedAddUlong(&DeviceExt->PerfData.BytesWritten,
Irp->IoStatus.Information,
&DeviceExt->PerfLock);
break;
default:
break;
}
}
DigiIoCompleteRequest( Irp,
(char) ((StatusToUse == STATUS_SUCCESS) ? IO_SERIAL_INCREMENT : IO_NO_INCREMENT) );
if( discoveredIrp )
{
//
// We uncovered it, so we must start it.
// DH rare race: two IRPs, first completes, second cancels, a third is queued onto an empty queue -- will be started twice.
//
KeAcquireSpinLock( &DeviceExt->ControlAccess, pOldIrql );
// IRP may have timed out or have been cancelled while we dropped the lock.
if( !IsListEmpty( Queue ) )
StartRoutine( DeviceExt->ParentControllerExt, DeviceExt, pOldIrql );
KeReleaseSpinLock( &DeviceExt->ControlAccess, *pOldIrql );
}
}
else
{
KeReleaseSpinLock( &DeviceExt->ControlAccess, *pOldIrql );
}
//
// The expected behavior is for DigiTryToCompleteIrp to return
// with the passed in ControlAccess spinlock released.
//
DigiDump( DIGIFLOW, ("Exiting DigiTryToCompleteIrp\n") );
} // end DigiTryToCompleteIrp
void __inline
DigiRundownIrpRefs( IN PIRP Irp,
IN PKTIMER IntervalTimer OPTIONAL,
IN PKTIMER TotalTimer OPTIONAL )
/*++
Routine Description:
This routine runs through the various items that *could*
have a reference to the current read/write. It try's to kill
the reason. If it does succeed in killing the reason it
will decrement the reference count on the irp.
NOTE: This routine assumes that it is called with the ControlAccess
spin lock held.
Arguments:
Irp - Pointer to current irp for this particular operation.
IntervalTimer - Pointer to the interval timer for the operation.
NOTE: This could be null.
TotalTimer - Pointer to the total timer for the operation.
NOTE: This could be null.
Return Value:
None.
--*/
{
if( IntervalTimer )
{
//
// Try to cancel the operations interval timer. If the operation
// returns true then the timer did have a reference to the
// irp. Since we've canceled this timer that reference is
// no longer valid and we can decrement the reference count.
//
// If the cancel returns false then this means either of two things:
//
// a) The timer has already fired.
//
// b) There never was an interval timer.
//
// In the case of "b" there is no need to decrement the reference
// count since the "timer" never had a reference to it.
//
// In the case of "a", then the timer itself will be coming
// along and decrement it's reference. Note that the caller
// of this routine might actually be the this timer, but it
// has already decremented the reference.
//
if( KeCancelTimer( IntervalTimer ) )
{
DigiDump( DIGIREFERENCE, (" Dec Ref for interval timer\n") );
DIGI_DEC_REFERENCE( Irp );
}
}
if( TotalTimer )
{
//
// Try to cancel the operations total timer. If the operation
// returns true then the timer did have a reference to the
// irp. Since we've canceled this timer that reference is
// no longer valid and we can decrement the reference count.
//
// If the cancel returns false then this means either of two things:
//
// a) The timer has already fired.
//
// b) There never was an total timer.
//
// In the case of "b" there is no need to decrement the reference
// count since the "timer" never had a reference to it.
//
// In the case of "a", then the timer itself will be coming
// along and decrement it's reference. Note that the caller
// of this routine might actually be the this timer, but it
// has already decremented the reference.
//
if( KeCancelTimer( TotalTimer ) )
{
DigiDump( DIGIREFERENCE, (" Dec Ref for total timer\n") );
DIGI_DEC_REFERENCE( Irp );
}
}
//
// Don't kill the cancel routine until there's nothing else left.
//
if( DIGI_REFERENCE_COUNT( Irp ) == 1 )
{
KIRQL CancelIrql;
IoAcquireCancelSpinLock( &CancelIrql );
if( Irp->CancelRoutine )
{
DigiDump( DIGIREFERENCE, (" Dec Ref for cancel\n") );
DIGI_DEC_REFERENCE( Irp );
IoSetCancelRoutine( Irp, NULL );
IoReleaseCancelSpinLock( CancelIrql );
}
else
{
IoReleaseCancelSpinLock( CancelIrql );
}
}
} // end DigiRundownIrpRefs
void
DigiCancelIrpQueue( IN PDEVICE_OBJECT DeviceObject,
IN PLIST_ENTRY Queue )
/*++
Routine Description:
Arguments:
DeviceExt - Pointer to the device object extension for this device.
Queue - The queue of Irp requests.
Return Value:
--*/
{
KIRQL cancelIrql;
KIRQL OldIrql;
PDIGI_DEVICE_EXTENSION DeviceExt = DeviceObject->DeviceExtension;
DigiDump( DIGIFLOW, ("DigiBoard: Entering DigiCancelIrpQueue\n") );
KeAcquireSpinLock( &DeviceExt->NewIrpLock, &OldIrql );
KeAcquireSpinLockAtDpcLevel( &DeviceExt->ControlAccess );
//
// We acquire the cancel spin lock. This will prevent the
// irps from moving around.
//
IoAcquireCancelSpinLock( &cancelIrql );
while( !IsListEmpty( Queue ) )
{
PIRP currentLastIrp;
PDRIVER_CANCEL cancelRoutine;
currentLastIrp = CONTAINING_RECORD(
Queue->Blink,
IRP,
Tail.Overlay.ListEntry );
cancelRoutine = currentLastIrp->CancelRoutine;
currentLastIrp->Cancel = TRUE;
currentLastIrp->CancelRoutine = NULL;
IoReleaseCancelSpinLock( cancelIrql );
KeReleaseSpinLockFromDpcLevel( &DeviceExt->ControlAccess );
if( cancelRoutine )
{
IoAcquireCancelSpinLock( &cancelIrql );
currentLastIrp->CancelIrql = cancelIrql;
//
// This routine will release the cancel spin lock.
//
cancelRoutine( DeviceObject, currentLastIrp );
}
else
{
//
// Assume whoever nulled out the cancel routine
// is also going to complete the IRP.
//
#if DBG
DbgPrint( "DigiCancelIrpQueue(dev %s, ", DeviceExt->DeviceDbgString );
switch( (UCHAR *)Queue - (UCHAR *)DeviceExt )
{
case FIELD_OFFSET( DIGI_DEVICE_EXTENSION, ReadQueue ):
DbgPrint( "ReadQueue): " ); break;
case FIELD_OFFSET( DIGI_DEVICE_EXTENSION, WriteQueue ):
DbgPrint( "WriteQueue): " ); break;
case FIELD_OFFSET( DIGI_DEVICE_EXTENSION, WaitQueue ):
DbgPrint( "WaitQueue): " ); break;
default:
DbgPrint( "unknown queue at offset %d): ",
(UCHAR *)Queue - (UCHAR *)DeviceExt );
break;
}
DbgPrint( "no cancel routine for irp 0x%x!\n", currentLastIrp );
#endif // DBG
KeReleaseSpinLock( &DeviceExt->NewIrpLock, OldIrql );
return;
}
KeAcquireSpinLockAtDpcLevel( &DeviceExt->ControlAccess );
IoAcquireCancelSpinLock( &cancelIrql );
}
IoReleaseCancelSpinLock( cancelIrql );
KeReleaseSpinLockFromDpcLevel( &DeviceExt->ControlAccess );
KeReleaseSpinLock( &DeviceExt->NewIrpLock, OldIrql );
} // end DigiCancelIrpQueue