// // -------------------------------------------------------------------------- // define Global Async Request tracking resources // #define MAX_ASYNC_REQUESTS 60 // bitmap of active Async Requests ULARGE_INTEGER gAsyncRequestMask; // current Async Requests index ( 0 to MAX_ASYNC_REQUESTS ) ULONG gAsyncRequestIndex; // spinlock to protect modification of // Async Request tracking resources KSPIN_LOCK gAsyncRequestIndexLock; // // -------------------------------------------------------------------------- // declare Global Async Request tracking routines // BOOLEAN GetNextAsyncRequestIndex( OUT PULONG AsyncReqIdx ); VOID FreeAsyncRequestIndex( IN ULONG AsyncReqIdx ); VOID InitAsyncRequestIndex(); // // -------------------------------------------------------------------------- // implement Global Async Request tracking routines //
BOOLEAN GetNextAsyncRequestIndex( OUT PULONG AsyncReqIdx ) /*++ Routine Description: Checks whether the previous Async Request that would use the same Transaction Label as the current Async Request has completed. If so, returns TRUE, and sets the Async Request Index (0-63) for the current Async Request (to be used later in a call to FreeAsyncRequestIndex, to mark this Async Request as completed. If not, returns FALSE. Arguments: AsyncReqIdx - Pointer to the Async Request Index for this new request. Return Value: TRUE is returned (and AsyncReqIdx is set) if there are no pending Async Requests that would be using the same TLabel value as the current Async Request, and the current Async Request can be submitted to the 1394 stack immediately. FALSE is returned (and AsyncReqIdx is not set) if there is an Async Request still pending that would use the same TLabel value as the current Async Request. In this case, further Async Requests must be held/queued until this pending Async Request has completed. --*/ { ULARGE_INTEGER SetMask = 0; KIRQL Irql = KeGetCurrentIrql(); BOOLEAN bCanProceed = TRUE; // global value check ASSERT(gAsyncRequestIndex < MAX_ASYNC_REQUESTS); // acquire spinlock KeAcquireSpinLock(&gAsyncRequestIndexLock, &Irql); // set the bit mask SetMask.QuadPart = ( 1 << gAsyncRequestIndex ); // check whether the previous Async Request // (that would use this same TLabel value) // has completed if ( gAsyncRequestMask.QuadPart | SetMask.QuadPart ) { // The previous Async Request (that would use // this same TLabel value) has NOT completed yet. // We need to wait (and possibly initiate recovery // for a failed Async Request) before proceeding // with further Async Requests. bCanProceed = FALSE; } else { // The previous Async Request (that would use // this same TLabel value) HAS completed. // Full speed ahead. // set the bit to mark this Async Request as pending gAsyncRequestMask.QuadPart |= SetMask.QuadPart; // return index value for this Async Request *AsyncReqIdx = gAsyncRequestIndex; // advance to next Async Request index gAsyncRequestIndex++; // wrap back to 0 as needed if (gAsyncRequestIndex == MAX_ASYNC_REQUESTS) { gAsyncRequestIndex = 0; } } // release spinlock KeReleaseSpinLock(&gAsyncRequestIndexLock, Irql); return bCanProceed; } VOID FreeAsyncRequestIndex( IN ULONG AsyncReqIdx ) /*++ Routine Description: Marks the indicated Async Request Index as completed to that further Async Requests can proceed. Arguments: AsyncReqIdx - Async Request Index for this completed request. Return Value: None. --*/ { ULARGE_INTEGER ClearMask = 0; KIRQL Irql = KeGetCurrentIrql(); // parameter check ASSERT(gAsyncRequestIndex < MAX_ASYNC_REQUESTS); // acquire spinlock KeAcquireSpinLock(&gAsyncRequestIndexLock, &Irql); // set the bit mask ClearMask.QuadPart = ~( 1 << AsyncReqIdx ); // clear the bit to mark this Async Request as completed gAsyncRequestMask.QuadPart &= ClearMask.QuadPart; // release spinlock KeReleaseSpinLock(&gAsyncRequestIndexLock, Irql); return; } VOID InitAsyncRequestIndex() /*++
Routine Description: Initializes the Global Async Request tracking resources. This should be called on Start Device (or Driver Entry) and Bus Reset events. Arguments: None. Return Value: None. --*/ { // initialize bitmap of active Async Requests gAsyncRequestMask = 0; // initialize current Async Requests index (0-63) gAsyncRequestIndex = 0; // initialize spinlock KeInitializeSpinLock(&gAsyncRequestIndexLock); return; } // // -------------------------------------------------------------------------- // check whether you can proceed with the next Async Request before submitting the Irp // NTSTATUS YourAsyncRequestSubmissionRoutine() {
... while ( !GetNextAsyncRequestIndex(&YourAsyncReqContext->AsyncReqIdx) ) {
... // Wait, retry, etc. // Do not proceed with additional Async Requests // (pause your queue, etc.) until the current oldest // Async Request completes, and GetNextAsyncRequestIndex // returns TRUE.
... } ... // ensure that AsyncReqIdx value returned by GetNextAsyncRequestIndex // is preserved in the context associated with this Async Request, // and is accessible in the completion routine for this IRP. IoSetCompletionRoutine( Irp, YourAsyncRequestCompletionRoutine, YourAsyncReqContext, TRUE, TRUE, TRUE ); ... status = IoCallDriver( TargetDeviceObject, Irp ); ... } NTSTATUS YourAsyncRequestCompletionRoutine( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context ) { ... PYOUR_ASYNC_REQ_CONTEXT YourAsyncReqContext = (PYOUR_ASYNC_REQ_CONTEXT)Context; ... FreeAsyncRequestIndex(YourAsyncReqContext->AsyncReqIdx); ... } |