1 //
2 //    Copyright (C) Microsoft.  All rights reserved.
3 //
4 #ifndef _FXDMATRANSACTION_HPP_
5 #define _FXDMATRANSACTION_HPP_
6 
7 extern "C" {
8 // #include "FxDmaTransaction.hpp.tmh"
9 }
10 
11 #include "fxdmatransactioncallbacks.hpp"
12 
13 //
14 // This type is used to allocate scatter-gather list of 1 element on the stack.
15 //
16 typedef DECLSPEC_ALIGN(MEMORY_ALLOCATION_ALIGNMENT) UCHAR UCHAR_MEMORY_ALIGNED;
17 
18 // begin_wpp enum
19 
20 //
21 // FxDmaTransactionStateCreated when the object is created.
22 // FxDmaTransactionStateInitialized when object is initialized using with
23 //    Mdl/VA/Length.
24 // FxDmaTransactionStateReserved when driver calls AllocateResources until
25 //    the adapter control routine returns
26 // FxDmaTransactionStateTransfer is called when the driver call Execute
27 //    to start the DMA transfer.
28 // FxDmaTransactionStateTransferCompleted is when transfer is completed or
29 //    aborted
30 // FxDmaTransactionStateTransferFailed is set if the framework is not able
31 //    to start the transfer due to error.
32 // FxDmaTransactionStateReleased is set when the object is reinitailized for reuse
33 // FxDmaTransactionStateDeleted is set in the Dipose due to WdfObjectDelete
34 //
35 enum FxDmaTransactionState {
36     FxDmaTransactionStateInvalid = 0,
37     FxDmaTransactionStateCreated,
38     FxDmaTransactionStateReserved,
39     FxDmaTransactionStateInitialized,
40     FxDmaTransactionStateTransfer,
41     FxDmaTransactionStateTransferCompleted,
42     FxDmaTransactionStateTransferFailed,
43     FxDmaTransactionStateReleased,
44     FxDmaTransactionStateDeleted,
45 };
46 
47 //
48 // FxDmaCompletionTypeFull is used when the driver calls WdfDmaTransactionDmaComplete
49 //      to indicate that last framgement has been transmitted fully and to initiate
50 //      the transfer of next fragment.
51 // FxDmaCompletionTypePartial is used when the driver completes the transfer and
52 //      specifies a amount of bytes it has transfered, and to initiate the next transfer
53 //      from the untransmitted portion of the buffer.
54 // FxDmaCompletionTypeAbort i used when the driver calls DmaCompleteFinal to indicate
55 //      that's the final transfer and not initiate anymore transfers for the remaining
56 //      data.
57 //
58 enum FxDmaCompletionType {
59     FxDmaCompletionTypeFull = 1,
60     FxDmaCompletionTypePartial,
61     FxDmaCompletionTypeAbort,
62 };
63 
64 // end_wpp
65 
66 //
67 // This tag is used to track whether the request pointer in the transaction
68 // has a reference taken on it.  Since the pointer is guaranteed to be
69 // 4-byte aligned this can be set and cleared without destroying the pointer.
70 //
71 #define FX_STRONG_REF_TAG               0x1
72 
73 //
74 // Simple set of macros to encode and decode tagged pointers.
75 //
76 #define FX_ENCODE_POINTER(T,p,tag)      ((T*) ((ULONG_PTR) p | (ULONG_PTR) tag))
77 #define FX_DECODE_POINTER(T,p,tag)      ((T*) ((ULONG_PTR) p & ~(ULONG_PTR) tag))
78 #define FX_IS_POINTER_ENCODED(p,tag)    ((((ULONG_PTR) p & (ULONG_PTR) tag) == tag) ? TRUE : FALSE)
79 
80 //
81 // An uninitialized value for Dma completion status
82 //
83 
84 #define UNDEFINED_DMA_COMPLETION_STATUS ((DMA_COMPLETION_STATUS) -1)
85 
86 class FxDmaTransactionBase : public FxNonPagedObject {
87 
88     friend class FxDmaEnabler;
89 
90 public:
91 
92     FxDmaTransactionBase(
93         __in PFX_DRIVER_GLOBALS FxDriverGlobals,
94         __in USHORT ObjectSize,
95         __in USHORT ExtraSize,
96         __in FxDmaEnabler *DmaEnabler
97         );
98 
99     static
100     VOID
101     _ComputeNextTransferAddress(
102         __in PMDL CurrentMdl,
103         __in size_t CurrentOffset,
104         __in ULONG Transferred,
105         __deref_out PMDL *NextMdl,
106         __out size_t *NextOffset
107         );
108 
109     _Must_inspect_result_
110     static
111     NTSTATUS
112     _CalculateRequiredMapRegisters(
113         __in PMDL Mdl,
114         __in size_t CurrentOffset,
115         __in ULONG Length,
116         __in ULONG AvailableMapRegisters,
117         __out_opt PULONG PossibleTransferLength,
118         __out PULONG MapRegistersRequired
119         );
120 
121     virtual
122     BOOLEAN
123     Dispose(
124         VOID
125         );
126 
127     _Must_inspect_result_
128     NTSTATUS
129     Initialize(
130         __in PFN_WDF_PROGRAM_DMA     ProgramDmaFunction,
131         __in WDF_DMA_DIRECTION       DmaDirection,
132         __in PMDL                    Mdl,
133         __in size_t                  Offset,
134         __in ULONG                   Length
135         );
136 
137     _Must_inspect_result_
138     virtual
139     NTSTATUS
140     InitializeResources(
141         VOID
142         )=0;
143 
144     _Must_inspect_result_
145     NTSTATUS
146     Execute(
147         __in PVOID   Context
148         );
149 
150     _Must_inspect_result_
151     virtual
152     NTSTATUS
153     StartTransfer(
154         VOID
155         )=0;
156 
157     _Must_inspect_result_
158     virtual
159     NTSTATUS
160     StageTransfer(
161         VOID
162         )=0;
163 
164     BOOLEAN
165     DmaCompleted(
166         __in  size_t      TransferredLength,
167         __out NTSTATUS  * ReturnStatus,
168         __in  FxDmaCompletionType CompletionType
169         );
170 
171     _Must_inspect_result_
172     virtual
173     NTSTATUS
174     TransferCompleted(
175         VOID
176         )=0;
177 
178     VOID
179     ReleaseForReuse(
180         __in BOOLEAN ForceRelease
181         );
182 
183     virtual
184     VOID
185     ReleaseResources(
186         __in BOOLEAN ForceRelease
187         )=0;
188 
189     VOID
190     GetTransferInfo(
191         __out_opt ULONG *MapRegisterCount,
192         __out_opt ULONG *ScatterGatherElementCount
193         );
194 
195     __forceinline
196     size_t
GetBytesTransferred(VOID)197     GetBytesTransferred(
198         VOID
199         )
200     {
201         return m_Transferred;
202     }
203 
204     __forceinline
205     FxDmaEnabler *
GetDmaEnabler(VOID)206     GetDmaEnabler(
207         VOID
208         )
209     {
210         return m_DmaEnabler;
211     }
212 
213     __forceinline
214     FxRequest *
GetRequest(VOID)215     GetRequest(
216         VOID
217         )
218     {
219         //
220         // Strip out the strong reference tag if it's set
221         //
222         return FX_DECODE_POINTER(FxRequest,
223                                  m_EncodedRequest,
224                                  FX_STRONG_REF_TAG);
225     }
226 
227     __forceinline
228     BOOLEAN
IsRequestReferenced(VOID)229     IsRequestReferenced(
230         VOID
231         )
232     {
233         return FX_IS_POINTER_ENCODED(m_EncodedRequest, FX_STRONG_REF_TAG);
234     }
235 
236     __forceinline
237     VOID
SetRequest(__in FxRequest * Request)238     SetRequest(
239         __in FxRequest* Request
240         )
241     {
242         ASSERT(m_EncodedRequest == NULL);
243 
244         //
245         // Make sure the pointer doesn't have the strong ref flag set already
246         //
247         ASSERT(FX_IS_POINTER_ENCODED(Request, FX_STRONG_REF_TAG) == FALSE);
248 
249         m_EncodedRequest = Request;
250     }
251 
252     __forceinline
253     VOID
ReferenceRequest(VOID)254     ReferenceRequest(
255         VOID
256         )
257     {
258         ASSERT(m_EncodedRequest != NULL);
259         ASSERT(IsRequestReferenced() == false);
260 
261         //
262         // Take a reference on the irp to catch completion of request
263         // when there is a pending DMA transaction.
264         // While there is no need to take a reference on request itself,
265         // I'm keeping it to avoid regression as we are so close to
266         // shipping this.
267         //
268         m_EncodedRequest->AddIrpReference();
269 
270         //
271         // Increment reference to this Request.
272         // See complementary section in WdfDmaTransactionDelete
273         // and WdfDmaTransactionRelease.
274         //
275         m_EncodedRequest->ADDREF( this );
276 
277         m_EncodedRequest = FX_ENCODE_POINTER(FxRequest,
278                                              m_EncodedRequest,
279                                              FX_STRONG_REF_TAG);
280     }
281 
282     __forceinline
283     VOID
ReleaseButRetainRequest(VOID)284     ReleaseButRetainRequest(
285         VOID
286         )
287     {
288         ASSERT(m_EncodedRequest != NULL);
289         ASSERT(IsRequestReferenced());
290 
291         //
292         // Clear the referenced bit on the encoded request.
293         //
294         m_EncodedRequest = FX_DECODE_POINTER(FxRequest,
295                                              m_EncodedRequest,
296                                              FX_STRONG_REF_TAG);
297 
298         //
299         // Release this reference to the Irp and FxRequest.
300         //
301         m_EncodedRequest->ReleaseIrpReference();
302 
303         m_EncodedRequest->RELEASE( this );
304     }
305 
306     __forceinline
307     VOID
ClearRequest(VOID)308     ClearRequest(
309         VOID
310         )
311     {
312         if (IsRequestReferenced()) {
313             ReleaseButRetainRequest();
314         }
315         m_EncodedRequest = NULL;
316     }
317 
318     __forceinline
319     size_t
GetMaximumFragmentLength(VOID)320     GetMaximumFragmentLength(
321         VOID
322         )
323     {
324         return m_MaxFragmentLength;
325     }
326 
327     __forceinline
328     VOID
SetMaximumFragmentLength(size_t MaximumFragmentLength)329     SetMaximumFragmentLength(
330         size_t  MaximumFragmentLength
331         )
332     {
333         if (MaximumFragmentLength < m_AdapterInfo->MaximumFragmentLength) {
334             m_MaxFragmentLength = MaximumFragmentLength;
335         }
336     }
337 
338     __forceinline
339     size_t
GetCurrentFragmentLength(VOID)340     GetCurrentFragmentLength(
341         VOID
342         )
343     {
344         return m_CurrentFragmentLength;
345     }
346 
347     __forceinline
348     WDFDMATRANSACTION
GetHandle(VOID)349     GetHandle(
350         VOID
351         )
352     {
353         return (WDFDMATRANSACTION) GetObjectHandle();
354     }
355 
356     PVOID
GetTransferContext(VOID)357     GetTransferContext(
358         VOID
359         )
360     {
361         return m_TransferContext;
362     }
363 
364     VOID
365     SetImmediateExecution(
366         __in BOOLEAN Value
367         );
368 
369     BOOLEAN
370     CancelResourceAllocation(
371         VOID
372         );
373 
374     FxDmaTransactionState
GetTransactionState(VOID)375     GetTransactionState(
376         VOID
377         )
378     {
379         return m_State;
380     }
381 
382 protected:
383 
384     FxDmaTransactionState         m_State;
385 
386     WDF_DMA_DIRECTION             m_DmaDirection;
387 
388     FxDmaEnabler*                 m_DmaEnabler;
389 
390     //
391     // Depending on the direction of the transfer, this one
392     // points to either m_ReadAdapterInfo or m_WriteAdapterInfo
393     // structure of the DMA enabler.
394     //
395     FxDmaDescription*             m_AdapterInfo;
396 
397     //
398     // Request associated with this transfer.  Encoding uses the
399     // FX_[EN|DE]CODE_POINTER macros with the FX_STRONG_REF_TAG
400     // to indicate whether the reference has been taken or not
401     //
402     FxRequest*                    m_EncodedRequest;
403 
404     //
405     // Callback and context for ProgramDma function
406     //
407     // The callback is overloaded to also hold the callback for
408     // Packet & System transfer's Reserve callback (to save space.)
409     // This is possible because the driver may not call execute
410     // and reserve in parallel on the same transaction.  Disambiguate
411     // using the state of the transaction.
412     //
413     FxDmaTransactionProgramOrReserveDma    m_DmaAcquiredFunction;
414     PVOID                                  m_DmaAcquiredContext;
415 
416     //
417     // The DMA transfer context (when using V3 DMA)
418     //
419     PVOID                         m_TransferContext;
420 
421     //
422     // This is the first MDL of the transaction.
423     //
424     PMDL                          m_StartMdl;
425 
426     //
427     // This is the MDL where the current transfer is being executed.
428     // If the data spans multiple MDL then this would be different
429     // from the startMDL when we stage large transfers and also
430     // if the driver performs partial transfers.
431     //
432     PMDL                          m_CurrentFragmentMdl;
433 
434     //
435     // Starting offset in the first m_StartMdl. This might be same as
436     // m_StartMdl->StartVA.
437     //
438     size_t                        m_StartOffset;
439 
440     //
441     // Points to address where the next transfer will begin.
442     //
443     size_t                        m_CurrentFragmentOffset;
444 
445     //
446     // This is maximum length of transfer that can be made. This is
447     // computed based on the available map registers and driver
448     // configuration.
449     //
450     size_t                        m_MaxFragmentLength;
451 
452     //
453     // Length of the whole transaction.
454     //
455     size_t                        m_TransactionLength;
456 
457     //
458     // Number of bytes pending to be transfered.
459     //
460     size_t                        m_Remaining;
461 
462     //
463     // Total number of bytes transfered.
464     //
465     size_t                        m_Transferred;
466 
467     //
468     // Number of bytes transfered in the last transaction.
469     //
470     size_t                        m_CurrentFragmentLength;
471 
472     //
473     // DMA flags for passing to GetScatterGatherListEx &
474     // AllocateAdapterChannelEx
475     //
476 
477     ULONG m_Flags;
478 
479     static
480     PVOID
GetStartVaFromOffset(__in PMDL Mdl,__in size_t Offset)481     GetStartVaFromOffset(
482         __in PMDL   Mdl,
483         __in size_t Offset
484         )
485     {
486         return ((PUCHAR) MmGetMdlVirtualAddress(Mdl)) + Offset;
487     }
488 
489     virtual
490     VOID
Reuse(VOID)491     Reuse(
492         VOID
493         )
494     {
495         return;
496     }
497 
498 };
499 
500 class FxDmaScatterGatherTransaction : public FxDmaTransactionBase {
501 
502 public:
503 
504     FxDmaScatterGatherTransaction(
505         __in PFX_DRIVER_GLOBALS FxDriverGlobals,
506         __in USHORT ExtraSize,
507         __in FxDmaEnabler *DmaEnabler
508         );
509 
510     virtual
511     BOOLEAN
512     Dispose(
513         VOID
514         );
515 
516     _Must_inspect_result_
517     virtual
518     NTSTATUS
519     InitializeResources(
520         VOID
521         );
522 
523     _Must_inspect_result_
524     virtual
525     NTSTATUS
526     StartTransfer(
527         VOID
528         );
529 
530     _Must_inspect_result_
531     virtual
532     NTSTATUS
533     TransferCompleted(
534         VOID
535         );
536 
537     _Must_inspect_result_
538     virtual
539     NTSTATUS
540     StageTransfer(
541         VOID
542         );
543 
544     virtual
545     VOID
546     ReleaseResources(
547         __in BOOLEAN ForceRelease
548         );
549 
550     _Must_inspect_result_
551     static
552     NTSTATUS
553     _Create(
554         __in  PFX_DRIVER_GLOBALS      FxDriverGlobals,
555         __in  PWDF_OBJECT_ATTRIBUTES  Attributes,
556         __in  FxDmaEnabler*           DmaEnabler,
557         __out WDFDMATRANSACTION*      Transaction
558         );
559 
560 protected:
561 
562     //
563     // Scatter-Gather list provided by the system.
564     //
565     PSCATTER_GATHER_LIST         m_SGList;
566 
567     //
568     // Preallocated memory from lookaside buffer for the
569     // scatter-gather list when running on XP and later OSes.
570     //
571     PVOID                        m_LookasideBuffer;
572 
573 
574 private:
575 
576     static
577     VOID
578     _AdapterListControl(
579         __in  DEVICE_OBJECT         * DeviceObject,
580         __in  IRP                   * Irp,
581         __in  SCATTER_GATHER_LIST   * SgList,
582         __in  VOID                  * Context
583         );
584 
585     _Must_inspect_result_
586     NTSTATUS
GetScatterGatherList(__in PMDL Mdl,__in size_t CurrentOffset,__in ULONG Length,__in PDRIVER_LIST_CONTROL ExecutionRoutine,__in PVOID Context)587     GetScatterGatherList (
588         __in PMDL  Mdl,
589         __in size_t CurrentOffset,
590         __in ULONG  Length,
591         __in PDRIVER_LIST_CONTROL  ExecutionRoutine,
592         __in PVOID  Context
593         )
594     {
595         NTSTATUS status;
596         KIRQL irql;
597 
598         KeRaiseIrql(DISPATCH_LEVEL, &irql);
599 
600         if (m_DmaEnabler->UsesDmaV3())
601         {
602             PDMA_OPERATIONS dmaOperations =
603                 m_AdapterInfo->AdapterObject->DmaOperations;
604 
605             status = dmaOperations->GetScatterGatherListEx(
606                                                m_AdapterInfo->AdapterObject,
607                                                m_DmaEnabler->m_FDO,
608                                                GetTransferContext(),
609                                                Mdl,
610                                                CurrentOffset,
611                                                Length,
612                                                m_Flags,
613                                                ExecutionRoutine,
614                                                Context,
615                                                (BOOLEAN) m_DmaDirection,
616                                                NULL,
617                                                NULL,
618                                                NULL
619                                                );
620         }
621         else
622         {
623             status = m_AdapterInfo->AdapterObject->DmaOperations->
624                         GetScatterGatherList(m_AdapterInfo->AdapterObject,
625                                              m_DmaEnabler->m_FDO,
626                                              Mdl,
627                                              GetStartVaFromOffset(Mdl, CurrentOffset),
628                                              Length,
629                                              ExecutionRoutine,
630                                              Context,
631                                              (BOOLEAN) m_DmaDirection);
632         }
633 
634         KeLowerIrql(irql);
635 
636         return status;
637     }
638 
639     VOID
PutScatterGatherList(__in PSCATTER_GATHER_LIST ScatterGather)640     PutScatterGatherList(
641         __in PSCATTER_GATHER_LIST  ScatterGather
642         )
643     {
644         KIRQL irql;
645 
646         KeRaiseIrql(DISPATCH_LEVEL, &irql);
647 
648         m_AdapterInfo->AdapterObject->DmaOperations->
649                 PutScatterGatherList(m_AdapterInfo->AdapterObject,
650                                      ScatterGather,
651                                      (BOOLEAN) m_DmaDirection);
652         KeLowerIrql(irql);
653 
654         return;
655     }
656 
657     _Must_inspect_result_
658     NTSTATUS
BuildScatterGatherList(__in PMDL Mdl,__in size_t CurrentOffset,__in ULONG Length,__in PDRIVER_LIST_CONTROL ExecutionRoutine,__in PVOID Context,__in PVOID ScatterGatherBuffer,__in ULONG ScatterGatherBufferLength)659     BuildScatterGatherList(
660         __in PMDL  Mdl,
661         __in size_t CurrentOffset,
662         __in ULONG  Length,
663         __in PDRIVER_LIST_CONTROL  ExecutionRoutine,
664         __in PVOID  Context,
665         __in PVOID  ScatterGatherBuffer,
666         __in ULONG  ScatterGatherBufferLength
667         )
668     {
669         NTSTATUS status;
670         KIRQL irql;
671 
672         KeRaiseIrql(DISPATCH_LEVEL, &irql);
673 
674         if (m_DmaEnabler->UsesDmaV3()) {
675 
676             PDMA_OPERATIONS dmaOperations =
677                 m_AdapterInfo->AdapterObject->DmaOperations;
678             ULONG flags = 0;
679 
680             if (GetDriverGlobals()->IsVersionGreaterThanOrEqualTo(1,15)) {
681                 //
682                 // Though the correct behavior is to pass the m_Flags to the
683                 // BuildScatterGatherListEx function, the code was not doing it
684                 // for versions <= 1.13. To reduce any chance of regression,
685                 // the m_Flags is honored for drivers that are 1.15
686                 // or newer.
687                 //
688                 flags = m_Flags;
689             }
690 
691             status = dmaOperations->BuildScatterGatherListEx(
692                                                  m_AdapterInfo->AdapterObject,
693                                                  m_DmaEnabler->m_FDO,
694                                                  GetTransferContext(),
695                                                  Mdl,
696                                                  CurrentOffset,
697                                                  Length,
698                                                  flags,
699                                                  ExecutionRoutine,
700                                                  Context,
701                                                  (BOOLEAN) m_DmaDirection,
702                                                  ScatterGatherBuffer,
703                                                  ScatterGatherBufferLength,
704                                                  NULL,
705                                                  NULL,
706                                                  NULL
707                                                  );
708         }
709         else {
710 
711             status = m_AdapterInfo->AdapterObject->DmaOperations->
712                         BuildScatterGatherList(m_AdapterInfo->AdapterObject,
713                                                m_DmaEnabler->m_FDO,
714                                                Mdl,
715                                                GetStartVaFromOffset(Mdl, CurrentOffset),
716                                                Length,
717                                                ExecutionRoutine,
718                                                Context,
719                                                (BOOLEAN) m_DmaDirection,
720                                                ScatterGatherBuffer,
721                                                ScatterGatherBufferLength);
722         }
723 
724 
725         KeLowerIrql(irql);
726 
727         return status;
728     }
729 };
730 
731 class FxDmaPacketTransaction : public FxDmaTransactionBase {
732 
733 protected:
734     FxDmaPacketTransaction(
735         __in PFX_DRIVER_GLOBALS FxDriverGlobals,
736         __in USHORT ObjectSize,
737         __in USHORT ExtraSize,
738         __in FxDmaEnabler *DmaEnabler
739         );
740 
741 public:
742 
743     _Must_inspect_result_
744     virtual
745     NTSTATUS
746     InitializeResources(
747         VOID
748         );
749 
750     _Must_inspect_result_
751     NTSTATUS
752     ReserveAdapter(
753         __in     ULONG               NumberOfMapRegisters,
754         __in     WDF_DMA_DIRECTION   Direction,
755         __in     PFN_WDF_RESERVE_DMA Callback,
756         __in_opt PVOID               Context
757         );
758 
759     VOID
760     ReleaseAdapter(
761         VOID
762         );
763 
764     _Must_inspect_result_
765     virtual
766     NTSTATUS
767     StartTransfer(
768         VOID
769         );
770 
771     _Must_inspect_result_
772     virtual
773     NTSTATUS
774     TransferCompleted(
775         VOID
776         );
777 
778     _Must_inspect_result_
779     virtual
780     NTSTATUS
781     StageTransfer(
782         VOID
783         );
784 
785     virtual
786     VOID
787     ReleaseResources(
788         __in BOOLEAN ForceRelease
789         );
790 
791     _Must_inspect_result_
792     static
793     NTSTATUS
794     _Create(
795         __in  PFX_DRIVER_GLOBALS      FxDriverGlobals,
796         __in  PWDF_OBJECT_ATTRIBUTES  Attributes,
797         __in  FxDmaEnabler*           DmaEnabler,
798         __out WDFDMATRANSACTION*      Transaction
799         );
800 
801     VOID
SetDeviceAddressOffset(__in ULONG Offset)802     SetDeviceAddressOffset(
803         __in ULONG Offset
804         )
805     {
806         m_DeviceAddressOffset = Offset;
807     }
808 
809 protected:
810 
811     //
812     // Number of map registers to be used in this transfer.
813     // This value is the least of the number of map registers
814     // needed to satisfy the current transfer request, and the
815     // number of available map registers returned by IoGetDmaAdapter.
816     //
817     ULONG                        m_MapRegistersNeeded;
818 
819     //
820     // Opaque-value represents the map registers that the system has
821     // assigned for this transfer operation. We pass this value in
822     // FlushAdapterBuffers, FreeMapRegisters, and MapTransfer.
823     //
824     PVOID                         m_MapRegisterBase;
825 
826     //
827     // TRUE when the map register base above is valid.  The HAL can give
828     // us a NULL map register base when double buffering isn't required,
829     // so we can't just do a NULL test on m_MapRegisterBase to know if
830     // the DMA channel is allocated.
831     //
832     BOOLEAN                       m_MapRegisterBaseSet;
833 
834     //
835     // For system-DMA this provides the offset from the original
836     // DeviceAddress used to compute the device register to or from which
837     // DMA should occur.
838     //
839     ULONG                         m_DeviceAddressOffset;
840 
841     //
842     // 0 if the transaction has not reserved the enabler.  Otherwise
843     // this is the number of map registers requested for the reservation.
844     // This value persists across a reuse and reinitialization of the
845     // transaction, and is only cleared when the enabler is released.
846     //
847     ULONG                         m_MapRegistersReserved;
848 
849     //
850     // These fields are used to defer completion or staging while another
851     // thread/CPU is already staging.  They are protected by the
852     // transfer state lock.
853     //
854     // These values are cleared when checked, not in InitializeResources.
855     // It's possible for a transaction being staged to complete on another
856     // CPU, get reused and reinitialized.  Clearing these values in
857     // InitializeResources would destroy the state the prior call to
858     // StageTransfer depends on.
859     //
860     struct {
861 
862         //
863         // Non-null when a staging operation is in progress on some CPU.
864         // When set any attempt to call the DMA completion routine or
865         // stage the transfer again (due to a call to TransferComplete)
866         // will be deferred to this thread.
867         //
868         PKTHREAD                      CurrentStagingThread;
869 
870         //
871         // Indicates that a nested or concurrent attempt to stage
872         // the transaction was deferred.  The CurrentStagingThread
873         // will restage the transaction.
874         //
875         BOOLEAN                       RerunStaging;
876 
877         //
878         // Indicates that a nested or concurrent attempt to call the
879         // DMA completion routine occurred.  The CurrentStagingThread
880         // will call the DMA completion routine when it unwinds providing
881         // the saved CompletionStatus
882         //
883         BOOLEAN                       RerunCompletion;
884         DMA_COMPLETION_STATUS         CompletionStatus;
885 
886     } m_TransferState;
887 
888     //
889     // Indicates that the DMA transfer has been cancelled.
890     // Set during StopTransfer and cleared during InitializeResources
891     // Checked during StageTransfer.  Stop and Initialize should never
892     // race (it's not valid for the driver to stop an uninitialized
893     // transaction).  Stop and Stage can race but in that case Stop
894     // will mark the transaction context such that MapTransfer fails
895     // (and that's protected by a HAL lock).
896     //
897     // So this field does not need to be volatile or interlocked, but
898     // it needs to be sized to allow atomic writes.
899     //
900     ULONG                           m_IsCancelled;
901 
902 
903     virtual
904     VOID
Reuse(VOID)905     Reuse(
906         VOID
907         )
908     {
909         return;
910     }
911 
912 protected:
913 
914     inline
915     void
SetMapRegisterBase(__in PVOID Value)916     SetMapRegisterBase(
917         __in PVOID Value
918         )
919     {
920         NT_ASSERTMSG("Map register base is already set",
921                      m_MapRegisterBaseSet == FALSE);
922 
923         m_MapRegisterBase = Value;
924         m_MapRegisterBaseSet = TRUE;
925     }
926 
927     inline
928     void
ClearMapRegisterBase(VOID)929     ClearMapRegisterBase(
930         VOID
931         )
932     {
933         NT_ASSERTMSG("Map register base was not set",
934                      m_MapRegisterBaseSet == TRUE);
935         m_MapRegisterBaseSet = FALSE;
936     }
937 
938     inline
939     BOOLEAN
IsMapRegisterBaseSet(VOID)940     IsMapRegisterBaseSet(
941         VOID
942         )
943     {
944         return m_MapRegisterBaseSet;
945     }
946 
947     inline
948     PVOID
GetMapRegisterBase(VOID)949     GetMapRegisterBase(
950         VOID
951         )
952     {
953         NT_ASSERTMSG("Map register base is not set",
954                      m_MapRegisterBaseSet == TRUE);
955         return m_MapRegisterBase;
956     }
957 
958     virtual
959     IO_ALLOCATION_ACTION
GetAdapterControlReturnValue(VOID)960     GetAdapterControlReturnValue(
961         VOID
962         )
963     {
964         return DeallocateObjectKeepRegisters;
965     }
966 
967     virtual
968     BOOLEAN
PreMapTransfer(VOID)969     PreMapTransfer(
970         VOID
971         )
972     {
973         return TRUE;
974     }
975 
_Acquires_lock_(this)976     _Acquires_lock_(this)
977     VOID
978     __drv_raisesIRQL(DISPATCH_LEVEL)
979 #pragma prefast(suppress:__WARNING_FAILING_TO_ACQUIRE_MEDIUM_CONFIDENCE, "transferring lock name to 'this->TransferStateLock'")
980 #pragma prefast(suppress:__WARNING_FAILING_TO_RELEASE_MEDIUM_CONFIDENCE, "transferring lock name to 'this->TransferStateLock'")
981     LockTransferState(
982         __out __drv_deref(__drv_savesIRQL) KIRQL *OldIrql
983         )
984     {
985         Lock(OldIrql);
986     }
987 
988     _Requires_lock_held_(this)
_Releases_lock_(this)989     _Releases_lock_(this)
990     VOID
991 #pragma prefast(suppress:__WARNING_FAILING_TO_RELEASE_MEDIUM_CONFIDENCE, "transferring lock name from 'this->TransferStateLock'")
992     UnlockTransferState(
993         __in __drv_restoresIRQL KIRQL OldIrql
994         )
995     {
996 #pragma prefast(suppress:__WARNING_CALLER_FAILING_TO_HOLD, "transferring lock name from 'this->TransferStateLock'")
997         Unlock(OldIrql);
998     }
999 
1000     virtual
1001     PDMA_COMPLETION_ROUTINE
GetTransferCompletionRoutine(VOID)1002     GetTransferCompletionRoutine(
1003         VOID
1004         )
1005     {
1006         return NULL;
1007     }
1008 
1009     static
1010     IO_ALLOCATION_ACTION
1011     STDCALL
1012     _AdapterControl(
1013         __in PDEVICE_OBJECT  DeviceObject,
1014         __in PIRP            Irp,
1015         __in PVOID           MapRegisterBase,
1016         __in PVOID           Context
1017         );
1018 
1019     _Must_inspect_result_
1020     NTSTATUS
AcquireDevice(VOID)1021     AcquireDevice(
1022         VOID
1023         )
1024     {
1025         if (m_DmaEnabler->UsesDmaV3() == FALSE)
1026         {
1027             return m_DmaEnabler->GetDevice()->AcquireDmaPacketTransaction();
1028         }
1029         else
1030         {
1031             return STATUS_SUCCESS;
1032         }
1033     }
1034 
1035     FORCEINLINE
1036     VOID
ReleaseDevice(VOID)1037     ReleaseDevice(
1038         VOID
1039         )
1040     {
1041         if (m_DmaEnabler->UsesDmaV3() == FALSE)
1042         {
1043             m_DmaEnabler->GetDevice()->ReleaseDmaPacketTransaction();
1044         }
1045     }
1046 
1047     _Must_inspect_result_
1048     NTSTATUS
AllocateAdapterChannel(__in BOOLEAN MapRegistersReserved)1049     AllocateAdapterChannel(
1050         __in BOOLEAN MapRegistersReserved
1051         )
1052     {
1053         NTSTATUS status;
1054         KIRQL irql;
1055 
1056         KeRaiseIrql(DISPATCH_LEVEL, &irql);
1057 
1058         if (GetDriverGlobals()->FxVerifierOn) {
1059 
1060             if (MapRegistersReserved == FALSE) {
1061                 DoTraceLevelMessage(
1062                     GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGDMA,
1063                     "Allocating %d map registers for "
1064                     "WDFDMATRANSACTION %p",
1065                     m_MapRegistersNeeded,
1066                     GetHandle()
1067                     );
1068             }
1069             else {
1070                 DoTraceLevelMessage(
1071                     GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGDMA,
1072                     "Using %d reserved map registers for "
1073                     "WDFDMATRANSACTION %p",
1074                     m_MapRegistersNeeded,
1075                     GetHandle()
1076                     );
1077             }
1078         }
1079 
1080         if (m_DmaEnabler->UsesDmaV3()) {
1081             PDMA_OPERATIONS dmaOperations =
1082                 m_AdapterInfo->AdapterObject->DmaOperations;
1083 
1084             if (MapRegistersReserved == FALSE)
1085             {
1086                 status = dmaOperations->AllocateAdapterChannelEx(
1087                                         m_AdapterInfo->AdapterObject,
1088                                         m_DmaEnabler->m_FDO,
1089                                         GetTransferContext(),
1090                                         m_MapRegistersNeeded,
1091                                         m_Flags,
1092 #pragma prefast(suppress: __WARNING_CLASS_MISMATCH_NONE, "This warning requires a wrapper class for the DRIVER_CONTROL type.")
1093                                         _AdapterControl,
1094                                         this,
1095                                         NULL
1096                                         );
1097             }
1098             else {
1099 #pragma prefast(suppress:__WARNING_PASSING_FUNCTION_UNEXPECTED_NULL, "_AdapterControl does not actually use the IRP parameter.");
1100                 _AdapterControl(m_DmaEnabler->m_FDO,
1101                                 NULL,
1102                                 GetMapRegisterBase(),
1103                                 this);
1104                 status = STATUS_SUCCESS;
1105             }
1106         }
1107         else {
1108 
1109             ASSERTMSG("Prereserved map registers are not compatible with DMA V2",
1110                       MapRegistersReserved == FALSE);
1111 
1112             status = m_AdapterInfo->AdapterObject->DmaOperations->
1113                         AllocateAdapterChannel(m_AdapterInfo->AdapterObject,
1114                                     m_DmaEnabler->m_FDO,
1115                                     m_MapRegistersNeeded,
1116 #pragma prefast(suppress: __WARNING_CLASS_MISMATCH_NONE, "This warning requires a wrapper class for the DRIVER_CONTROL type.")
1117                                     _AdapterControl,
1118                                     this);
1119         }
1120 
1121         KeLowerIrql(irql);
1122 
1123         if (!NT_SUCCESS(status))
1124         {
1125             DoTraceLevelMessage(
1126                 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGDMA,
1127                 "Allocating DMA resources (%d map registers) for WDFDMATRANSACTION %p "
1128                 "returned %!STATUS!",
1129                 m_MapRegistersNeeded,
1130                 GetHandle(),
1131                 status
1132                 );
1133         }
1134 
1135         return status;
1136     }
1137 
1138     FORCEINLINE
1139     NTSTATUS
MapTransfer(__out_bcount_opt (ScatterGatherListCb)PSCATTER_GATHER_LIST ScatterGatherList,__in ULONG ScatterGatherListCb,__in_opt PDMA_COMPLETION_ROUTINE CompletionRoutine,__in_opt PVOID CompletionContext,__out ULONG * TransferLength)1140     MapTransfer(
1141         __out_bcount_opt(ScatterGatherListCb)
1142                  PSCATTER_GATHER_LIST     ScatterGatherList,
1143         __in     ULONG                    ScatterGatherListCb,
1144         __in_opt PDMA_COMPLETION_ROUTINE  CompletionRoutine,
1145         __in_opt PVOID                    CompletionContext,
1146         __out    ULONG                   *TransferLength
1147         )
1148     {
1149         //
1150         // Cache globals & object handle since call to MapTransferEx could
1151         // result in a DmaComplete callback before returning.
1152         //
1153         PFX_DRIVER_GLOBALS pFxDriverGlobals = GetDriverGlobals();
1154         WDFDMATRANSACTION handle = GetHandle();
1155 #if DBG
1156         ULONG_PTR mapRegistersRequired;
1157 
1158         mapRegistersRequired = ADDRESS_AND_SIZE_TO_SPAN_PAGES(
1159                                     GetStartVaFromOffset(m_CurrentFragmentMdl,
1160                                                          m_CurrentFragmentOffset),
1161                                     m_CurrentFragmentLength
1162                                     );
1163         NT_ASSERTMSG("Mapping requires too many map registers",
1164                      mapRegistersRequired <= m_MapRegistersNeeded);
1165 #endif
1166 
1167         NTSTATUS status;
1168 
1169         //
1170         // Assume we're going to transfer the entire current fragment.
1171         // MapTransfer may say otherwise.
1172         //
1173 
1174         *TransferLength = (ULONG) m_CurrentFragmentLength;
1175 
1176         //
1177         // Map the transfer.
1178         //
1179 
1180         if (pFxDriverGlobals->FxVerifierOn) {
1181             DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGDMA,
1182                                 "Mapping transfer for WDFDMATRANSACTION %p.  "
1183                                 "MDL %p, Offset %I64x, Length %x, MapRegisterBase %p",
1184                                 handle,
1185                                 m_CurrentFragmentMdl,
1186                                 m_CurrentFragmentOffset,
1187                                 *TransferLength,
1188                                 GetMapRegisterBase());
1189         }
1190 
1191         if (m_DmaEnabler->UsesDmaV3()) {
1192 
1193             PDMA_OPERATIONS dmaOperations =
1194                 m_AdapterInfo->AdapterObject->DmaOperations;
1195 
1196             status = dmaOperations->MapTransferEx(
1197                                  m_AdapterInfo->AdapterObject,
1198                                  m_CurrentFragmentMdl,
1199                                  GetMapRegisterBase(),
1200                                  m_CurrentFragmentOffset,
1201                                  m_DeviceAddressOffset,
1202                                  TransferLength,
1203                                  (BOOLEAN) m_DmaDirection,
1204                                  ScatterGatherList,
1205                                  ScatterGatherListCb,
1206                                  CompletionRoutine,
1207                                  CompletionContext
1208                                  );
1209 
1210             NT_ASSERTMSG(
1211                 "With these parameters, MapTransferEx should never fail",
1212                 NT_SUCCESS(status) || status == STATUS_CANCELLED
1213                 );
1214         }
1215         else {
1216             NT_ASSERTMSG("cannot use DMA completion routine with DMAv2",
1217                          CompletionRoutine == NULL);
1218 
1219             NT_ASSERTMSG(
1220                 "scatter gather list length must be large enough for at least one element",
1221                 (ScatterGatherListCb >= (sizeof(SCATTER_GATHER_LIST) +
1222                                          sizeof(SCATTER_GATHER_ELEMENT)))
1223                 );
1224 
1225             //
1226             // This matches the assertion above.  There's no way to explain to
1227             // prefast that this code path requires the caller to provide a buffer
1228             // of sufficient size to store the SGL.  The only case which doesn't
1229             // provide any buffer is system-mode DMA and that uses DMA v3 and so
1230             // won't go through this path.
1231             //
1232 
1233             __assume((ScatterGatherListCb >= (sizeof(SCATTER_GATHER_LIST) +
1234                                               sizeof(SCATTER_GATHER_ELEMENT))));
1235 
1236             ScatterGatherList->NumberOfElements = 1;
1237             ScatterGatherList->Reserved = 0;
1238             ScatterGatherList->Elements[0].Address =
1239                 m_AdapterInfo->AdapterObject->DmaOperations->
1240                         MapTransfer(m_AdapterInfo->AdapterObject,
1241                                     m_CurrentFragmentMdl,
1242                                     GetMapRegisterBase(),
1243                                     GetStartVaFromOffset(m_CurrentFragmentMdl,
1244                                                          m_CurrentFragmentOffset),
1245                                     TransferLength,
1246                                     (BOOLEAN) m_DmaDirection);
1247             ScatterGatherList->Elements[0].Length = *TransferLength;
1248 
1249             status = STATUS_SUCCESS;
1250         }
1251 
1252         if (pFxDriverGlobals->FxVerifierOn) {
1253             DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGDMA,
1254                                 "MapTransfer mapped next %d bytes of "
1255                                 "WDFDMATRANSACTION %p - status %!STATUS!",
1256                                 *TransferLength,
1257                                 handle,
1258                                 status);
1259         }
1260 
1261         return status;
1262     }
1263 
1264     FORCEINLINE
1265     NTSTATUS
FlushAdapterBuffers(VOID)1266     FlushAdapterBuffers(
1267         VOID
1268         )
1269     {
1270         PDMA_OPERATIONS dmaOperations =
1271             m_AdapterInfo->AdapterObject->DmaOperations;
1272 
1273         NTSTATUS status;
1274 
1275 #if DBG
1276         ULONG_PTR mapRegistersRequired;
1277 
1278         mapRegistersRequired = ADDRESS_AND_SIZE_TO_SPAN_PAGES(
1279                                     GetStartVaFromOffset(m_CurrentFragmentMdl,
1280                                                          m_CurrentFragmentOffset),
1281                                     m_CurrentFragmentLength
1282                                     );
1283         NT_ASSERTMSG("Mapping requires too many map registers",
1284                      mapRegistersRequired <= m_MapRegistersNeeded);
1285 #endif
1286 
1287         if (GetDriverGlobals()->FxVerifierOn) {
1288             DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGDMA,
1289                                 "Flushing DMA buffers for WDFDMATRANSACTION %p.  "
1290                                 "MDL %p, Offset %I64x, Length %I64x",
1291                                 GetHandle(),
1292                                 m_CurrentFragmentMdl,
1293                                 m_CurrentFragmentOffset,
1294                                 m_CurrentFragmentLength);
1295         }
1296 
1297         if (m_DmaEnabler->UsesDmaV3()) {
1298             status = dmaOperations->FlushAdapterBuffersEx(
1299                                               m_AdapterInfo->AdapterObject,
1300                                               m_CurrentFragmentMdl,
1301                                               GetMapRegisterBase(),
1302                                               m_CurrentFragmentOffset,
1303                                               (ULONG) m_CurrentFragmentLength,
1304                                               (BOOLEAN) m_DmaDirection
1305                                               );
1306         }
1307         else if (dmaOperations->FlushAdapterBuffers(
1308                                 m_AdapterInfo->AdapterObject,
1309                                 m_CurrentFragmentMdl,
1310                                 GetMapRegisterBase(),
1311                                 GetStartVaFromOffset(m_CurrentFragmentMdl,
1312                                                      m_CurrentFragmentOffset),
1313                                 (ULONG) m_CurrentFragmentLength,
1314                                 (BOOLEAN) m_DmaDirection) == FALSE) {
1315                 status = STATUS_UNSUCCESSFUL;
1316         }
1317         else {
1318             status = STATUS_SUCCESS;
1319         }
1320 
1321         if (!NT_SUCCESS(status)) {
1322             DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGDMA,
1323                                 "Flushing DMA buffers for WDFDMATRANSACTION %p ("
1324                                 "MDL %p, Offset %I64x, Length %I64x)"
1325                                 "completed with %!STATUS!",
1326                                 GetHandle(),
1327                                 m_CurrentFragmentMdl,
1328                                 m_CurrentFragmentOffset,
1329                                 m_CurrentFragmentLength,
1330                                 status);
1331         }
1332 
1333         return status;
1334     }
1335 
1336     virtual
1337     VOID
FreeMapRegistersAndAdapter(VOID)1338     FreeMapRegistersAndAdapter(
1339         VOID
1340         )
1341     {
1342         KIRQL irql;
1343 
1344         PVOID mapRegisterBase = GetMapRegisterBase();
1345 
1346         //
1347         // It's illegal to free a NULL map register base, even if the HAL gave it
1348         // to us.
1349         //
1350         if (mapRegisterBase == NULL) {
1351             if (GetDriverGlobals()->FxVerifierOn) {
1352                 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGDMA,
1353                                     "Skipping free of %d map registers for WDFDMATRANSACTION %p "
1354                                     "because base was NULL",
1355                                     m_MapRegistersNeeded,
1356                                     GetHandle());
1357             }
1358 
1359             return;
1360         }
1361 
1362         //
1363         // Free the map registers
1364         //
1365         KeRaiseIrql(DISPATCH_LEVEL, &irql);
1366 
1367         if (GetDriverGlobals()->FxVerifierOn) {
1368             DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGDMA,
1369                                 "Freeing %d map registers for WDFDMATRANSACTION %p "
1370                                 "(base %p)",
1371                                 m_MapRegistersNeeded,
1372                                 GetHandle(),
1373                                 mapRegisterBase);
1374         }
1375 
1376         //
1377         // If we pre-reserved map registers then Reserved contains
1378         // the number to free.  Otherwise Needed is the number allocated
1379         // for the last transaction, which is the number to free.
1380         //
1381         m_AdapterInfo->AdapterObject->DmaOperations->
1382                     FreeMapRegisters(m_AdapterInfo->AdapterObject,
1383                                      mapRegisterBase,
1384                                      (m_MapRegistersReserved > 0 ?
1385                                         m_MapRegistersReserved :
1386                                         m_MapRegistersNeeded));
1387         KeLowerIrql(irql);
1388 
1389         return;
1390     }
1391 
1392     virtual
1393     VOID
CallEvtDmaCompleted(__in DMA_COMPLETION_STATUS)1394     CallEvtDmaCompleted(
1395         __in DMA_COMPLETION_STATUS /* Status */
1396         )
1397     {
1398         //
1399         // Packet mode DMA doesn't support cancellation or
1400         // completion routines.  So this should never run.
1401         //
1402         ASSERTMSG("EvtDmaCompleted is not a valid callback for "
1403                   "a packet-mode transaction",
1404                   FALSE);
1405         return;
1406     }
1407 
1408 };
1409 
1410 class FxDmaSystemTransaction: public FxDmaPacketTransaction {
1411 
1412     friend FxDmaPacketTransaction;
1413 
1414 public:
1415 
1416     FxDmaSystemTransaction(
1417         __in PFX_DRIVER_GLOBALS FxDriverGlobals,
1418         __in USHORT ExtraSize,
1419         __in FxDmaEnabler *DmaEnabler
1420         );
1421 
1422     _Must_inspect_result_
1423     static
1424     NTSTATUS
1425     _Create(
1426         __in  PFX_DRIVER_GLOBALS      FxDriverGlobals,
1427         __in  PWDF_OBJECT_ATTRIBUTES  Attributes,
1428         __in  FxDmaEnabler*           DmaEnabler,
1429         __out WDFDMATRANSACTION*      Transaction
1430         );
1431 
1432     VOID
SetConfigureChannelCallback(__in_opt PFN_WDF_DMA_TRANSACTION_CONFIGURE_DMA_CHANNEL Callback,__in_opt PVOID Context)1433     SetConfigureChannelCallback(
1434         __in_opt PFN_WDF_DMA_TRANSACTION_CONFIGURE_DMA_CHANNEL Callback,
1435         __in_opt PVOID Context
1436         )
1437     {
1438         m_ConfigureChannelFunction.Method = Callback;
1439         m_ConfigureChannelContext = Context;
1440     }
1441 
1442     VOID
SetTransferCompleteCallback(__in_opt PFN_WDF_DMA_TRANSACTION_DMA_TRANSFER_COMPLETE Callback,__in_opt PVOID Context)1443     SetTransferCompleteCallback(
1444         __in_opt PFN_WDF_DMA_TRANSACTION_DMA_TRANSFER_COMPLETE Callback,
1445         __in_opt PVOID Context
1446         )
1447     {
1448         m_TransferCompleteFunction.Method = Callback;
1449         m_TransferCompleteContext = Context;
1450     }
1451 
1452     VOID
1453     StopTransfer(
1454         VOID
1455         );
1456 
1457 protected:
1458 
1459     //
1460     // Callback and context for configure channel callback
1461     //
1462     FxDmaTransactionConfigureChannel m_ConfigureChannelFunction;
1463     PVOID                            m_ConfigureChannelContext;
1464 
1465     //
1466     // Callback and context for DMA completion callback
1467     //
1468     FxDmaTransactionTransferComplete m_TransferCompleteFunction;
1469     PVOID                            m_TransferCompleteContext;
1470 
1471     IO_ALLOCATION_ACTION
GetAdapterControlReturnValue(VOID)1472     GetAdapterControlReturnValue(
1473         VOID
1474         )
1475     {
1476         return KeepObject;
1477     }
1478 
1479     VOID
FreeMapRegistersAndAdapter(VOID)1480     FreeMapRegistersAndAdapter(
1481         VOID
1482         )
1483     {
1484         PFX_DRIVER_GLOBALS pFxDriverGlobals = GetDriverGlobals();
1485         KIRQL irql;
1486 
1487         KeRaiseIrql(DISPATCH_LEVEL, &irql);
1488 
1489         if (pFxDriverGlobals->FxVerifierOn) {
1490             DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGDMA,
1491                                 "Freeing adapter channel for WDFDMATRANSACTION %p",
1492                                 GetHandle());
1493         }
1494 
1495         m_AdapterInfo->AdapterObject->DmaOperations->
1496                     FreeAdapterChannel(m_AdapterInfo->AdapterObject);
1497         KeLowerIrql(irql);
1498 
1499         return;
1500     }
1501 
1502     BOOLEAN
CancelMappedTransfer(VOID)1503     CancelMappedTransfer(
1504         VOID
1505         )
1506     {
1507         NTSTATUS status;
1508 
1509         ASSERT(m_DmaEnabler->UsesDmaV3());
1510 
1511         //
1512         // Cancel the transfer.  if it's not yet mapped this will mark the
1513         // TC so that mapping will fail.  If it's running this will invoke the
1514         // DMA completion routine.
1515         //
1516         status =
1517             m_AdapterInfo->AdapterObject->DmaOperations->CancelMappedTransfer(
1518                 m_AdapterInfo->AdapterObject,
1519                 GetTransferContext()
1520                 );
1521 
1522         DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGDMA,
1523                             "Stopping WDFDMATRANSACTION %p returned status %!STATUS!",
1524                             GetHandle(),
1525                             status);
1526 
1527         return NT_SUCCESS(status);
1528     }
1529 
1530     VOID
Reuse(VOID)1531     Reuse(
1532         VOID
1533         )
1534     {
1535         FxDmaPacketTransaction::Reuse(); // __super call
1536         m_ConfigureChannelFunction.Method = NULL;
1537         m_ConfigureChannelContext = NULL;
1538 
1539         m_TransferCompleteFunction.Method = NULL;
1540         m_TransferCompleteContext = NULL;
1541     }
1542 
1543     VOID
1544     CallEvtDmaCompleted(
1545         __in DMA_COMPLETION_STATUS Status
1546         );
1547 
1548     virtual
1549     BOOLEAN
1550     PreMapTransfer(
1551         VOID
1552         );
1553 
1554     virtual
1555     PDMA_COMPLETION_ROUTINE
1556     GetTransferCompletionRoutine(
1557         VOID
1558         );
1559 
1560     static DMA_COMPLETION_ROUTINE _SystemDmaCompletion;
1561 };
1562 
1563 #endif // _FXDMATRANSACTION_HPP_
1564