1 /*++
2 
3 Copyright (c) Microsoft Corporation
4 
5 Module Name:
6 
7     FxDmaTransactionAPI.cpp
8 
9 Abstract:
10 
11     Base for WDF DMA Transaction APIs
12 
13 Environment:
14 
15     Kernel mode only.
16 
17 Notes:
18 
19 
20 Revision History:
21 
22 --*/
23 
24 #include "FxDmaPCH.hpp"
25 
26 extern "C" {
27 #include "FxDmaTransactionAPI.tmh"
28 }
29 
30 //
31 // Extern "C" the entire file
32 //
33 extern "C" {
34 
35 _Must_inspect_result_
36 __drv_maxIRQL(DISPATCH_LEVEL)
37 NTSTATUS
38 WDFEXPORT(WdfDmaTransactionCreate)(
39     __in
40     PWDF_DRIVER_GLOBALS DriverGlobals,
41     __in
42     WDFDMAENABLER DmaEnabler,
43     __in_opt
44     WDF_OBJECT_ATTRIBUTES * Attributes,
45     __out
46     WDFDMATRANSACTION * DmaTransactionHandle
47     )
48 {
49     NTSTATUS status;
50     FxDmaEnabler* pDmaEnabler;
51     PFX_DRIVER_GLOBALS pFxDriverGlobals;
52 
53     FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
54                                    DmaEnabler,
55                                    FX_TYPE_DMA_ENABLER,
56                                    (PVOID *) &pDmaEnabler,
57                                    &pFxDriverGlobals);
58 
59     FxPointerNotNull(pFxDriverGlobals, DmaTransactionHandle);
60 
61     *DmaTransactionHandle = NULL;
62 
63     status = FxValidateObjectAttributes(pFxDriverGlobals,
64                                         Attributes,
65                                         FX_VALIDATE_OPTION_PARENT_NOT_ALLOWED
66                                         );
67     if (!NT_SUCCESS(status)) {
68         return status;
69     }
70 
71     switch (pDmaEnabler->GetProfile())
72     {
73         case WdfDmaProfilePacket:
74         case WdfDmaProfilePacket64:
75             status = FxDmaPacketTransaction::_Create(pFxDriverGlobals,
76                                                      Attributes,
77                                                      pDmaEnabler,
78                                                      DmaTransactionHandle);
79             break;
80 
81         case WdfDmaProfileScatterGather:
82         case WdfDmaProfileScatterGather64:
83         case WdfDmaProfileScatterGatherDuplex:
84         case WdfDmaProfileScatterGather64Duplex:
85             status = FxDmaScatterGatherTransaction::_Create(
86                                                         pFxDriverGlobals,
87                                                         Attributes,
88                                                         pDmaEnabler,
89                                                         DmaTransactionHandle
90                                                         );
91             break;
92 
93         case WdfDmaProfileSystem:
94         case WdfDmaProfileSystemDuplex:
95             status = FxDmaSystemTransaction::_Create(pFxDriverGlobals,
96                                                      Attributes,
97                                                      pDmaEnabler,
98                                                      DmaTransactionHandle);
99             break;
100 
101         default:
102             NT_ASSERTMSG("Unknown profile for DMA enabler", FALSE);
103             status = STATUS_UNSUCCESSFUL;
104             break;
105     }
106 
107     return status;
108 }
109 
110 _Must_inspect_result_
111 __drv_maxIRQL(DISPATCH_LEVEL)
112 NTSTATUS
113 WDFEXPORT(WdfDmaTransactionInitializeUsingRequest)(
114     __in
115     PWDF_DRIVER_GLOBALS DriverGlobals,
116     __in
117     WDFDMATRANSACTION DmaTransaction,
118     __in
119     WDFREQUEST Request,
120     __in
121     PFN_WDF_PROGRAM_DMA EvtProgramDmaFunction,
122     __in
123     WDF_DMA_DIRECTION DmaDirection
124     )
125 {
126     NTSTATUS status;
127     FxDmaTransactionBase* pDmaTrans;
128     FxRequest* pReqObj;
129     MDL* mdl = NULL;
130     PIO_STACK_LOCATION stack;
131     ULONG reqLength;
132     PFX_DRIVER_GLOBALS  pFxDriverGlobals;
133 
134     FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
135                                    DmaTransaction,
136                                    FX_TYPE_DMA_TRANSACTION,
137                                    (PVOID *) &pDmaTrans,
138                                    &pFxDriverGlobals);
139 
140     FxPointerNotNull(pFxDriverGlobals, EvtProgramDmaFunction);
141 
142     if (DmaDirection != WdfDmaDirectionReadFromDevice &&
143         DmaDirection != WdfDmaDirectionWriteToDevice) {
144         status = STATUS_INVALID_PARAMETER;
145         DoTraceLevelMessage(
146             pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA,
147             "Initialization of WDFDMATRANSACTION 0x%p using WDFREQUEST %p, "
148             "DmaDirection 0x%x is an invalid value, %!STATUS!",
149             DmaTransaction, Request, DmaDirection, status);
150         return status;
151     }
152 
153     FxObjectHandleGetPtr(pFxDriverGlobals,
154                          Request,
155                          FX_TYPE_REQUEST,
156                          (PVOID *) &pReqObj);
157 
158     reqLength = 0;
159 
160     stack = pReqObj->GetFxIrp()->GetCurrentIrpStackLocation();
161 
162     //
163     // Get the MDL and Length from the request.
164     //
165     switch (stack->MajorFunction) {
166 
167     case IRP_MJ_READ:
168 
169         if (DmaDirection != WdfDmaDirectionReadFromDevice) {
170             status = STATUS_INVALID_DEVICE_REQUEST;
171 
172             DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA,
173                                 "Dma direction %!WDF_DMA_DIRECTION! of WDFTRANSACTION "
174                                 "0x%p doesn't match with the WDFREQUEST 0x%p type "
175                                 "%!WDF_REQUEST_TYPE! %!STATUS!",
176                                 DmaDirection, DmaTransaction, Request,
177                                 stack->MajorFunction, status);
178 
179             return status;
180         }
181 
182         reqLength = stack->Parameters.Read.Length;
183 
184         status = pReqObj->GetMdl(&mdl);
185         break;
186 
187     case IRP_MJ_WRITE:
188 
189         if (DmaDirection != WdfDmaDirectionWriteToDevice) {
190             status = STATUS_INVALID_DEVICE_REQUEST;
191 
192             DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA,
193                                 "Dma direction %!WDF_DMA_DIRECTION! of WDFTRANSACTION "
194                                 "0x%p doesn't match with the WDFREQUEST 0x%p type "
195                                 "%!WDF_REQUEST_TYPE! %!STATUS!",
196                                 DmaDirection, DmaTransaction, Request,
197                                 stack->MajorFunction, status);
198 
199             return status;
200         }
201 
202         reqLength = stack->Parameters.Write.Length;
203 
204         status = pReqObj->GetMdl(&mdl);
205         break;
206 
207     case IRP_MJ_DEVICE_CONTROL:
208     case IRP_MJ_INTERNAL_DEVICE_CONTROL:
209 
210         switch (METHOD_FROM_CTL_CODE(stack->Parameters.DeviceIoControl.IoControlCode)) {
211             case METHOD_BUFFERED:
212 
213                 if (DmaDirection == WdfDmaDirectionWriteToDevice) {
214                     reqLength = stack->Parameters.DeviceIoControl.InputBufferLength;
215                 } else {
216                     reqLength = stack->Parameters.DeviceIoControl.OutputBufferLength;
217                 }
218 
219                 //
220                 // In this case both input buffer and output buffer map
221                 // to the same MDL and it's probed for read & write access.
222                 // So it's okay for DMA transfer in either direction.
223                 //
224                 status = pReqObj->GetMdl(&mdl);
225                 break;
226 
227             case METHOD_IN_DIRECT:
228                 //
229                 // For this type, the output buffer is probed for read access.
230                 // So the direction of DMA transfer is WdfDmaDirectionWriteToDevice.
231                 //
232                 if (DmaDirection != WdfDmaDirectionWriteToDevice) {
233 
234                     status = STATUS_INVALID_DEVICE_REQUEST;
235 
236                     DoTraceLevelMessage(pFxDriverGlobals,
237                                         TRACE_LEVEL_ERROR, TRACINGDMA,
238                                         "Dma direction %!WDF_DMA_DIRECTION! of WDFTRANSACTION "
239                                         "0x%p doesn't match with WDFREQUEST 0x%p ioctl type "
240                                         "METHOD_IN_DIRECT %!STATUS!",
241                                         DmaDirection, DmaTransaction, Request, status);
242                     return status;
243                 }
244 
245                 reqLength = stack->Parameters.DeviceIoControl.OutputBufferLength;
246 
247                 status = pReqObj->GetDeviceControlOutputMdl(&mdl);
248 
249                 break;
250 
251             case METHOD_OUT_DIRECT:
252                 //
253                 // For this type, the output buffer is probed for write access.
254                 // So the direction of DMA transfer is WdfDmaDirectionReadFromDevice.
255                 //
256                 if (DmaDirection != WdfDmaDirectionReadFromDevice) {
257 
258                     status = STATUS_INVALID_DEVICE_REQUEST;
259 
260                     DoTraceLevelMessage(pFxDriverGlobals,
261                                         TRACE_LEVEL_ERROR, TRACINGDMA,
262                                         "Dma direction %!WDF_DMA_DIRECTION! of WDFTRANSACTION "
263                                         "0x%p doesn't match with WDFREQUEST 0x%p ioctl type "
264                                         "METHOD_OUT_DIRECT %!STATUS!",
265                                         DmaDirection, DmaTransaction, Request, status);
266 
267                     return status;
268                 }
269 
270                 reqLength = stack->Parameters.DeviceIoControl.OutputBufferLength;
271 
272                 status = pReqObj->GetDeviceControlOutputMdl(&mdl);
273 
274                 break;
275             default:
276 
277                 status = STATUS_INVALID_DEVICE_REQUEST;
278 
279                 DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA,
280                                     "Invalid ioctl code in WDFREQUEST 0x%p %!STATUS!",
281                                     Request, status);
282 
283                 FxVerifierDbgBreakPoint(pFxDriverGlobals);
284                 break;
285 
286         }// End of switch(ioctType)
287         break;
288 
289     default:
290         status = STATUS_INVALID_DEVICE_REQUEST;
291         break;
292 
293     }
294 
295     if (!NT_SUCCESS(status)) {
296         DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA,
297                             "Couldn't retrieve mdl from WDFREQUEST 0x%p for "
298                             "WDFTRANSACTION 0x%p %!STATUS!",
299                             Request, DmaTransaction, status);
300         return status;
301     }
302 
303     if (reqLength == 0) {
304         status = STATUS_INVALID_DEVICE_REQUEST;
305         DoTraceLevelMessage(
306             pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA,
307             "Zero length request, %!STATUS!", status);
308         return status;
309     }
310 
311     //
312     // If the DMA enabler is packet based, make sure the virtual address and
313     // the length of transfer are within bounds. Basically, we are checking
314     // to see if the length of data to be transferred doesn't span multiple
315     // MDLs, because packet based DMA doesn't support chained MDLs.
316     //
317     if (pDmaTrans->GetDmaEnabler()->SupportsChainedMdls() == FALSE) {
318         ULONG  length;
319 
320         length = MmGetMdlByteCount(mdl);
321 
322         if (reqLength > length) {
323             status = STATUS_INVALID_PARAMETER;
324             DoTraceLevelMessage(
325                 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA,
326                 "WDFREQUEST %p transfer length (%d) is out of bounds of MDL "
327                 "Byte count (%d), %!STATUS!",
328                 Request, reqLength, length, status);
329 
330             return status;
331         }
332     }
333 
334     //
335     // Parms appear OK, so initialize this instance.
336     //
337     status = pDmaTrans->Initialize(EvtProgramDmaFunction,
338                                    DmaDirection,
339                                    mdl,
340                                    0,
341                                    reqLength);
342 
343     if (!NT_SUCCESS(status)) {
344         DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA,
345                             "WDFTANSACTION 0x%p initialization failed: "
346                             "%!STATUS!", DmaTransaction, status);
347         return status;
348     }
349 
350     //
351     // Set this Request in the new DmaTransaction.  The request will
352     // take a reference on this request when it starts executing.
353     //
354     pDmaTrans->SetRequest(pReqObj);
355 
356     return STATUS_SUCCESS;
357 }
358 
359 
360 _Must_inspect_result_
361 __drv_maxIRQL(DISPATCH_LEVEL)
362 NTSTATUS
363 WDFEXPORT(WdfDmaTransactionInitializeUsingOffset)(
364     __in
365     PWDF_DRIVER_GLOBALS DriverGlobals,
366     __in
367     WDFDMATRANSACTION DmaTransaction,
368     __in
369     PFN_WDF_PROGRAM_DMA EvtProgramDmaFunction,
370     __in
371     WDF_DMA_DIRECTION DmaDirection,
372     __in
373     PMDL Mdl,
374     __in
375     size_t Offset,
376     __in
377     __drv_when(Length == 0, __drv_reportError(Length cannot be zero))
378     size_t Length
379     )
380 {
381     //
382     // Stub this out by calling the regular initialize method.  Eventually
383     // the regular initialize method will call this instead.
384     //
385 
386     return WDFEXPORT(WdfDmaTransactionInitialize)(
387             DriverGlobals,
388             DmaTransaction,
389             EvtProgramDmaFunction,
390             DmaDirection,
391             Mdl,
392             (PVOID) (((ULONG_PTR) MmGetMdlVirtualAddress(Mdl)) + Offset),
393             Length
394             );
395 }
396 
397 _Must_inspect_result_
398 __drv_maxIRQL(DISPATCH_LEVEL)
399 NTSTATUS
400 WDFEXPORT(WdfDmaTransactionInitialize)(
401     __in
402     PWDF_DRIVER_GLOBALS DriverGlobals,
403     __in
404     WDFDMATRANSACTION DmaTransaction,
405     __in
406     PFN_WDF_PROGRAM_DMA EvtProgramDmaFunction,
407     __in
408     WDF_DMA_DIRECTION DmaDirection,
409     __in
410     PMDL Mdl,
411 
412     //__drv_when(DmaDirection == WdfDmaDirectionReadFromDevice, __out_bcount(Length))
413     //__drv_when(DmaDirection == WdfDmaDirectionWriteToDevice, __in_bcount(Length))
414     __in
415     PVOID VirtualAddress,
416     __in
417     __drv_when(Length == 0, __drv_reportError(Length cannot be zero))
418     size_t Length
419     )
420 {
421     NTSTATUS           status;
422     FxDmaTransactionBase * pDmaTrans;
423     PUCHAR pVA;
424     ULONG  mdlLength;
425     PFX_DRIVER_GLOBALS pFxDriverGlobals;
426 
427     FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
428                                    DmaTransaction,
429                                    FX_TYPE_DMA_TRANSACTION,
430                                    (PVOID *) &pDmaTrans,
431                                    &pFxDriverGlobals);
432 
433     FxPointerNotNull(pFxDriverGlobals, EvtProgramDmaFunction);
434     FxPointerNotNull(pFxDriverGlobals, Mdl);
435 
436     if (Length == 0) {
437         status = STATUS_INVALID_PARAMETER;
438         DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA,
439                             "Can't initialize WDFDMATRANSACTION 0x%p with "
440                             "zero length transfer", DmaTransaction);
441         return status;
442     }
443 
444     if (DmaDirection != WdfDmaDirectionReadFromDevice &&
445         DmaDirection != WdfDmaDirectionWriteToDevice) {
446         status = STATUS_INVALID_PARAMETER;
447         DoTraceLevelMessage(
448             pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA,
449             "Initialization of WDFDMATRANSACTION 0x%p,DmaDirection 0x%x is an "
450             "invalid value, %!STATUS!", DmaTransaction, DmaDirection, status);
451         return status;
452     }
453 
454     //
455     // Make sure the VirtualAddress is within the first MDL bounds.
456     //
457     pVA  = (PUCHAR) MmGetMdlVirtualAddress(Mdl);
458     mdlLength = MmGetMdlByteCount(Mdl);
459 
460     if (VirtualAddress < pVA ||
461         VirtualAddress >= WDF_PTR_ADD_OFFSET(pVA, mdlLength)) {
462         status = STATUS_INVALID_PARAMETER;
463         DoTraceLevelMessage(
464             pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA,
465             "VirtualAddress %p is not within the Mdl bounds, StartVA (%p) + "
466             "ByteCount (0x%x), %!STATUS! ",
467             VirtualAddress, pVA, mdlLength, status);
468 
469         return status;
470     }
471 
472     //
473     // Get the DmaEnabler
474     //
475     FxObjectHandleGetPtr(pFxDriverGlobals,
476                          DmaTransaction,
477                          FX_TYPE_DMA_TRANSACTION,
478                          (PVOID *) &pDmaTrans);
479 
480     if (pDmaTrans->GetDmaEnabler()->SupportsChainedMdls() == FALSE) {
481         //
482         // Make sure the MDL is not a chained MDL by checking
483         // to see if the virtual address and the length
484         // are within bounds.
485         //
486         if (WDF_PTR_ADD_OFFSET(VirtualAddress, Length) >
487             WDF_PTR_ADD_OFFSET(pVA, mdlLength)) {
488             status = STATUS_INVALID_PARAMETER;
489             DoTraceLevelMessage(
490                 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA,
491                 "VirtualAddress+Length (%p+%I64d) is out of bounds of MDL VA + MDL "
492                 "Byte count (max address is %p). "
493                 "Possibly a chained MDL, %!STATUS!",
494                 VirtualAddress, Length,
495                 WDF_PTR_ADD_OFFSET(pVA, mdlLength), status);
496 
497             return status;
498         }
499     }
500 
501     status = pDmaTrans->Initialize(EvtProgramDmaFunction,
502                                    DmaDirection,
503                                    Mdl,
504                                    WDF_PTR_GET_OFFSET(
505                                     MmGetMdlVirtualAddress(Mdl),
506                                     VirtualAddress
507                                     ),
508                                    (ULONG) Length);
509 
510     if (!NT_SUCCESS(status)) {
511         DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA,
512                             "WDFTANSACTION 0x%p initialization failed: "
513                             "%!STATUS!", DmaTransaction, status);
514     }
515 
516     return status;
517 }
518 
519 
520 _Must_inspect_result_
521 __drv_maxIRQL(DISPATCH_LEVEL)
522 NTSTATUS
523 WDFEXPORT(WdfDmaTransactionExecute)(
524     __in
525     PWDF_DRIVER_GLOBALS DriverGlobals,
526     __in
527     WDFDMATRANSACTION DmaTransaction,
528     __in_opt
529     WDFCONTEXT Context
530     )
531 {
532     FxDmaTransactionBase* pDmaTrans;
533 
534     FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
535                          DmaTransaction,
536                          FX_TYPE_DMA_TRANSACTION,
537                          (PVOID *) &pDmaTrans);
538 
539     return pDmaTrans->Execute(Context);
540 }
541 
542 __success(TRUE)
543 __drv_maxIRQL(DISPATCH_LEVEL)
544 NTSTATUS
545 WDFEXPORT(WdfDmaTransactionRelease)(
546     __in
547     PWDF_DRIVER_GLOBALS DriverGlobals,
548     __in
549     WDFDMATRANSACTION  DmaTransaction
550     )
551 {
552     FxDmaTransactionBase* pDmaTrans;
553 
554     FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
555                          DmaTransaction,
556                          FX_TYPE_DMA_TRANSACTION,
557                          (PVOID *) &pDmaTrans);
558 
559     //
560     // Release map registers allocated for this specific transaction,
561     // but not map registers which were allocated through
562     // AllocateResources.
563     //
564     pDmaTrans->ReleaseForReuse(FALSE);
565     return STATUS_SUCCESS;
566 }
567 
568 
569 __drv_maxIRQL(DISPATCH_LEVEL)
570 BOOLEAN
571 WDFEXPORT(WdfDmaTransactionDmaCompleted)(
572     __in
573     PWDF_DRIVER_GLOBALS DriverGlobals,
574     __in
575     WDFDMATRANSACTION DmaTransaction,
576     __out
577     NTSTATUS * pStatus
578     )
579 {
580     FxDmaTransactionBase    * pDmaTrans;
581 
582     FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
583                          DmaTransaction,
584                          FX_TYPE_DMA_TRANSACTION,
585                          (PVOID *) &pDmaTrans);
586 
587     FxPointerNotNull(pDmaTrans->GetDriverGlobals(), pStatus);
588 
589 
590     //
591     // Indicate this DMA has been completed.
592     //
593     return pDmaTrans->DmaCompleted(0, pStatus, FxDmaCompletionTypeFull);
594 }
595 
596 __drv_maxIRQL(DISPATCH_LEVEL)
597 BOOLEAN
598 WDFEXPORT(WdfDmaTransactionDmaCompletedWithLength)(
599     __in
600     PWDF_DRIVER_GLOBALS DriverGlobals,
601     __in
602     WDFDMATRANSACTION DmaTransaction,
603     __in
604     size_t TransferredLength,
605     __out
606     NTSTATUS * pStatus
607     )
608 {
609     FxDmaTransactionBase* pDmaTrans;
610 
611     FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
612                          DmaTransaction,
613                          FX_TYPE_DMA_TRANSACTION,
614                          (PVOID *) &pDmaTrans);
615 
616     FxPointerNotNull(pDmaTrans->GetDriverGlobals(), pStatus);
617 
618     //
619     // Indicate this DMA transfer has been completed.
620     //
621     return pDmaTrans->DmaCompleted(TransferredLength,
622                                    pStatus,
623                                    FxDmaCompletionTypePartial);
624 }
625 
626 __drv_maxIRQL(DISPATCH_LEVEL)
627 BOOLEAN
628 WDFEXPORT(WdfDmaTransactionDmaCompletedFinal)(
629     __in
630     PWDF_DRIVER_GLOBALS DriverGlobals,
631     __in
632     WDFDMATRANSACTION DmaTransaction,
633     __in
634     size_t FinalTransferredLength,
635     __out
636     NTSTATUS * pStatus
637     )
638 {
639     FxDmaTransactionBase* pDmaTrans;
640 
641     FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
642                          DmaTransaction,
643                          FX_TYPE_DMA_TRANSACTION,
644                          (PVOID *) &pDmaTrans);
645 
646     FxPointerNotNull(pDmaTrans->GetDriverGlobals(), pStatus);
647 
648     //
649     // Indicate this DMA FinalLength has completed.
650     //
651     return pDmaTrans->DmaCompleted(FinalTransferredLength,
652                                    pStatus,
653                                    FxDmaCompletionTypeAbort);
654 }
655 
656 
657 __drv_maxIRQL(DISPATCH_LEVEL)
658 size_t
659 WDFEXPORT(WdfDmaTransactionGetBytesTransferred)(
660     __in
661     PWDF_DRIVER_GLOBALS DriverGlobals,
662     __in
663     WDFDMATRANSACTION DmaTransaction
664     )
665 {
666     FxDmaTransactionBase* pDmaTrans;
667 
668     FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
669                          DmaTransaction,
670                          FX_TYPE_DMA_TRANSACTION,
671                          (PVOID *) &pDmaTrans);
672 
673     return pDmaTrans->GetBytesTransferred();
674 }
675 
676 __drv_maxIRQL(DISPATCH_LEVEL)
677 VOID
678 WDFEXPORT(WdfDmaTransactionSetMaximumLength)(
679     __in
680     PWDF_DRIVER_GLOBALS DriverGlobals,
681     __in
682     WDFDMATRANSACTION DmaTransaction,
683     __in
684     size_t MaximumLength
685     )
686 {
687     FxDmaTransactionBase* pDmaTrans;
688 
689     FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
690                          DmaTransaction,
691                          FX_TYPE_DMA_TRANSACTION,
692                          (PVOID *) &pDmaTrans);
693 
694     pDmaTrans->SetMaximumFragmentLength(MaximumLength);
695 }
696 
697 __drv_maxIRQL(DISPATCH_LEVEL)
698 WDFREQUEST
699 WDFEXPORT(WdfDmaTransactionGetRequest)(
700     __in
701     PWDF_DRIVER_GLOBALS DriverGlobals,
702     __in
703     WDFDMATRANSACTION DmaTransaction
704     )
705 {
706     FxDmaTransactionBase* pDmaTrans;
707     FxRequest* pRequest;
708 
709     FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
710                          DmaTransaction,
711                          FX_TYPE_DMA_TRANSACTION,
712                          (PVOID *) &pDmaTrans);
713 
714     pRequest = pDmaTrans->GetRequest();
715 
716     if (pRequest != NULL) {
717         return pRequest->GetHandle();
718     }
719     else {
720         return NULL;
721     }
722 }
723 
724 __drv_maxIRQL(DISPATCH_LEVEL)
725 size_t
726 WDFEXPORT(WdfDmaTransactionGetCurrentDmaTransferLength)(
727     __in
728     PWDF_DRIVER_GLOBALS DriverGlobals,
729     __in
730     WDFDMATRANSACTION DmaTransaction
731     )
732 {
733     FxDmaTransactionBase* pDmaTrans;
734 
735     FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
736                          DmaTransaction,
737                          FX_TYPE_DMA_TRANSACTION,
738                          (PVOID *) &pDmaTrans);
739 
740     return pDmaTrans->GetCurrentFragmentLength();
741 }
742 
743 
744 __drv_maxIRQL(DISPATCH_LEVEL)
745 WDFDEVICE
746 WDFEXPORT(WdfDmaTransactionGetDevice)(
747     __in
748     PWDF_DRIVER_GLOBALS DriverGlobals,
749     __in
750     WDFDMATRANSACTION DmaTransaction
751     )
752 {
753     FxDmaTransactionBase* pDmaTrans;
754 
755     FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
756                          DmaTransaction,
757                          FX_TYPE_DMA_TRANSACTION,
758                          (PVOID *) &pDmaTrans);
759 
760     return pDmaTrans->GetDmaEnabler()->GetDeviceHandle();
761 }
762 
763 __drv_maxIRQL(DISPATCH_LEVEL)
764 VOID
765 WDFEXPORT(WdfDmaTransactionSetChannelConfigurationCallback)(
766     __in
767     PWDF_DRIVER_GLOBALS DriverGlobals,
768     __in
769     WDFDMATRANSACTION DmaTransaction,
770     __in_opt
771     PFN_WDF_DMA_TRANSACTION_CONFIGURE_DMA_CHANNEL ConfigureRoutine,
772     __in_opt
773     PVOID ConfigureContext
774     )
775 {
776     FxDmaTransactionBase* pDmaTrans;
777     PFX_DRIVER_GLOBALS pFxDriverGlobals;
778 
779     FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
780                                    DmaTransaction,
781                                    FX_TYPE_DMA_TRANSACTION,
782                                    (PVOID *) &pDmaTrans,
783                                    &pFxDriverGlobals);
784 
785     //
786     // Verify that the transaction belongs to a system profile enabler.
787     //
788 
789     WDF_DMA_PROFILE profile = pDmaTrans->GetDmaEnabler()->GetProfile();
790     if ((profile != WdfDmaProfileSystem) &&
791         (profile != WdfDmaProfileSystemDuplex)) {
792         DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA,
793                             "Cannot call %!FUNC! on non-system-profile "
794                             "WDFDMATRANSACTION (%p) (transaction profile "
795                             "is %!WDF_DMA_PROFILE!).",
796                             DmaTransaction,
797                             profile);
798         FxVerifierDbgBreakPoint(pFxDriverGlobals);
799         return;
800     }
801 
802     //
803     // Cast the transaction to the right sub-type now that we've verified the
804     // profile.
805     //
806 
807     FxDmaSystemTransaction* systemTransaction = (FxDmaSystemTransaction*) pDmaTrans;
808     systemTransaction->SetConfigureChannelCallback(ConfigureRoutine,
809                                                    ConfigureContext);
810 }
811 
812 __drv_maxIRQL(DISPATCH_LEVEL)
813 VOID
814 WDFEXPORT(WdfDmaTransactionSetTransferCompleteCallback)(
815     __in
816     PWDF_DRIVER_GLOBALS DriverGlobals,
817     __in
818     WDFDMATRANSACTION DmaTransaction,
819     __in_opt
820     PFN_WDF_DMA_TRANSACTION_DMA_TRANSFER_COMPLETE DmaCompletionRoutine,
821     __in_opt
822     PVOID DmaCompletionContext
823     )
824 {
825     FxDmaTransactionBase* pDmaTrans;
826     PFX_DRIVER_GLOBALS pFxDriverGlobals;
827 
828     FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
829                                    DmaTransaction,
830                                    FX_TYPE_DMA_TRANSACTION,
831                                    (PVOID *) &pDmaTrans,
832                                    &pFxDriverGlobals);
833 
834     //
835     // Verify that the transaction belongs to a system profile enabler.
836     //
837 
838     WDF_DMA_PROFILE profile = pDmaTrans->GetDmaEnabler()->GetProfile();
839     if ((profile != WdfDmaProfileSystem) &&
840         (profile != WdfDmaProfileSystemDuplex)) {
841         DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA,
842                             "Cannot call %!FUNC! on non-system-profile "
843                             "WDFDMATRANSACTION (%p) (transaction profile "
844                             "is %!WDF_DMA_PROFILE!).",
845                             DmaTransaction,
846                             profile);
847         FxVerifierDbgBreakPoint(pFxDriverGlobals);
848         return;
849     }
850 
851     //
852     // Cast the transaction to the right sub-type now that we've verified the
853     // profile.
854     //
855 
856     FxDmaSystemTransaction* systemTransaction = (FxDmaSystemTransaction*) pDmaTrans;
857     systemTransaction->SetTransferCompleteCallback(DmaCompletionRoutine,
858                                                    DmaCompletionContext);
859 
860 }
861 
862 __drv_maxIRQL(DISPATCH_LEVEL)
863 VOID
864 WDFEXPORT(WdfDmaTransactionSetDeviceAddressOffset)(
865     __in
866     PWDF_DRIVER_GLOBALS DriverGlobals,
867     __in
868     WDFDMATRANSACTION DmaTransaction,
869     __in
870     ULONG Offset
871     )
872 {
873     FxDmaTransactionBase* pDmaTrans;
874     PFX_DRIVER_GLOBALS pFxDriverGlobals;
875 
876     FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
877                                    DmaTransaction,
878                                    FX_TYPE_DMA_TRANSACTION,
879                                    (PVOID *) &pDmaTrans,
880                                    &pFxDriverGlobals);
881 
882     //
883     // Verify that the transaction belongs to a system profile enabler.
884     //
885 
886     WDF_DMA_PROFILE profile = pDmaTrans->GetDmaEnabler()->GetProfile();
887     if ((profile != WdfDmaProfileSystem) &&
888         (profile != WdfDmaProfileSystemDuplex)) {
889         DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA,
890                             "Cannot call %!FUNC! on non-system-profile "
891                             "WDFDMATRANSACTION (%p) (transaction profile "
892                             "is %!WDF_DMA_PROFILE!).",
893                             DmaTransaction,
894                             profile);
895         FxVerifierDbgBreakPoint(pFxDriverGlobals);
896         return;
897     }
898 
899     //
900     // Cast the transaction to the right sub-type now that we've verified the
901     // profile.
902     //
903 
904     FxDmaSystemTransaction* systemTransaction = (FxDmaSystemTransaction*) pDmaTrans;
905     systemTransaction->SetDeviceAddressOffset(Offset);
906 }
907 
908 __drv_maxIRQL(DISPATCH_LEVEL)
909 PVOID
910 WDFEXPORT(WdfDmaTransactionWdmGetTransferContext)(
911     __in
912     PWDF_DRIVER_GLOBALS DriverGlobals,
913     __in
914     WDFDMATRANSACTION DmaTransaction
915     )
916 {
917     FxDmaTransactionBase* pDmaTrans;
918     PFX_DRIVER_GLOBALS pFxDriverGlobals;
919 
920     FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
921                                    DmaTransaction,
922                                    FX_TYPE_DMA_TRANSACTION,
923                                    (PVOID *) &pDmaTrans,
924                                    &pFxDriverGlobals);
925 
926     if (pDmaTrans->GetDmaEnabler()->UsesDmaV3() == FALSE) {
927         DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA,
928                             "Cannot call %!FUNC! for WDFDMATRANSACTION %p "
929                             "because the parent WDFDMAENABLER (%p) is not "
930                             "configured to use DMA version 3.",
931                             DmaTransaction,
932                             pDmaTrans->GetDmaEnabler()->GetHandle());
933         FxVerifierDbgBreakPoint(pFxDriverGlobals);
934         return NULL;
935     }
936 
937     FxDmaTransactionState state = pDmaTrans->GetTransactionState();
938 
939     if ((state == FxDmaTransactionStateInvalid) ||
940         (state == FxDmaTransactionStateCreated) ||
941         (state == FxDmaTransactionStateReleased) ||
942         (state == FxDmaTransactionStateDeleted)) {
943         DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA,
944                             "Cannot call %!FUNC! on WDFDMATRANSACTION %p "
945                             "becuase it is uninitialized, reused, deleted "
946                             "(state is %!FxDmaTransactionState!).",
947                             DmaTransaction,
948                             state
949                             );
950         FxVerifierDbgBreakPoint(pFxDriverGlobals);
951         return NULL;
952     }
953 
954     return pDmaTrans->GetTransferContext();
955 }
956 
957 __drv_maxIRQL(DISPATCH_LEVEL)
958 VOID
959 WDFEXPORT(WdfDmaTransactionGetTransferInfo)(
960     __in
961     PWDF_DRIVER_GLOBALS DriverGlobals,
962     __in
963     WDFDMATRANSACTION DmaTransaction,
964     __out_opt
965     ULONG* MapRegisterCount,
966     __out_opt
967     ULONG* ScatterGatherElementCount
968     )
969 {
970     FxDmaTransactionBase* pDmaTrans;
971     PFX_DRIVER_GLOBALS pFxDriverGlobals;
972 
973     FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
974                                    DmaTransaction,
975                                    FX_TYPE_DMA_TRANSACTION,
976                                    (PVOID *) &pDmaTrans,
977                                    &pFxDriverGlobals);
978 
979     pDmaTrans->GetTransferInfo(MapRegisterCount, ScatterGatherElementCount);
980 }
981 
982 //
983 // Stubbed WDF 1.11 DMA DDIs start here.
984 //
985 
986 __drv_maxIRQL(DISPATCH_LEVEL)
987 VOID
988 WDFEXPORT(WdfDmaTransactionSetImmediateExecution)(
989     __in
990     PWDF_DRIVER_GLOBALS DriverGlobals,
991     __in
992     WDFDMATRANSACTION DmaTransaction,
993     __in
994     BOOLEAN UseImmediateExecution
995     )
996 {
997     FxDmaTransactionBase* pDmaTrans;
998     PFX_DRIVER_GLOBALS pFxDriverGlobals;
999 
1000     FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
1001                                    DmaTransaction,
1002                                    FX_TYPE_DMA_TRANSACTION,
1003                                    (PVOID *) &pDmaTrans,
1004                                    &pFxDriverGlobals);
1005 
1006     if (pDmaTrans->GetDmaEnabler()->UsesDmaV3() == FALSE)
1007     {
1008         DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA,
1009                             "Cannot call %!FUNC! for WDFDMATRANSACTION %p "
1010                             "because the parent WDFDMAENABLER (%p) is not "
1011                             "configured to use DMA version 3.",
1012                             DmaTransaction,
1013                             pDmaTrans->GetDmaEnabler()->GetHandle());
1014         FxVerifierDbgBreakPoint(pFxDriverGlobals);
1015         return;
1016     }
1017 
1018     pDmaTrans->SetImmediateExecution(UseImmediateExecution);
1019 }
1020 
1021 __drv_maxIRQL(DISPATCH_LEVEL)
1022 NTSTATUS
1023 WDFEXPORT(WdfDmaTransactionAllocateResources)(
1024     __in
1025     PWDF_DRIVER_GLOBALS DriverGlobals,
1026     __in
1027     WDFDMATRANSACTION DmaTransaction,
1028     __in
1029     WDF_DMA_DIRECTION DmaDirection,
1030     __in
1031     ULONG RequiredMapRegisters,
1032     __in
1033     PFN_WDF_RESERVE_DMA EvtReserveDmaFunction,
1034     __in
1035     PVOID EvtReserveDmaContext
1036     )
1037 {
1038     FxDmaPacketTransaction* pDmaTrans;
1039     PFX_DRIVER_GLOBALS pFxDriverGlobals;
1040 
1041     NTSTATUS status;
1042 
1043     FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
1044                                    DmaTransaction,
1045                                    FX_TYPE_DMA_TRANSACTION,
1046                                    (PVOID *) &pDmaTrans,
1047                                    &pFxDriverGlobals);
1048 
1049     //
1050     // Only valid if DMA V3 is enabled.
1051     //
1052 
1053     if (pDmaTrans->GetDmaEnabler()->UsesDmaV3() == FALSE)
1054     {
1055         status = STATUS_INVALID_DEVICE_REQUEST;
1056 
1057         DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA,
1058                             "Cannot call %!FUNC! on WDFDMATRANSACTION %p "
1059                             "because WDFDMAENABLER %p was not configured "
1060                             "for DMA version 3 - %!STATUS!.",
1061                             DmaTransaction,
1062                             pDmaTrans->GetDmaEnabler()->GetHandle(),
1063                             status);
1064         FxVerifierDbgBreakPoint(pFxDriverGlobals);
1065         return status;
1066     }
1067 
1068     //
1069     // Only valid for packet or system profile transactions.
1070     //
1071     WDF_DMA_PROFILE profile = pDmaTrans->GetDmaEnabler()->GetProfile();
1072     if ((profile != WdfDmaProfilePacket) &&
1073         (profile != WdfDmaProfilePacket64) &&
1074         (profile != WdfDmaProfileSystem) &&
1075         (profile != WdfDmaProfileSystemDuplex)) {
1076 
1077         status = STATUS_INVALID_DEVICE_REQUEST;
1078 
1079         DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA,
1080                             "Cannot call %!FUNC! on non packet or system "
1081                             "profile WDFDMATRANSACTION (%p) (transaction "
1082                             "profile is %!WDF_DMA_PROFILE!) - %!STATUS!.",
1083                             DmaTransaction,
1084                             profile,
1085                             status);
1086         FxVerifierDbgBreakPoint(pFxDriverGlobals);
1087         return status;
1088     }
1089 
1090     //
1091     // Validate the direction value.
1092     //
1093     if (DmaDirection != WdfDmaDirectionReadFromDevice &&
1094         DmaDirection != WdfDmaDirectionWriteToDevice) {
1095         status = STATUS_INVALID_PARAMETER;
1096         DoTraceLevelMessage(
1097             pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA,
1098             "Allocation of DMA adapter for WDFDMATRANSACTION 0x%p, "
1099             "DmaDirection 0x%x is an invalid value, %!STATUS!",
1100             DmaTransaction, DmaDirection, status);
1101         FxVerifierDbgBreakPoint(pFxDriverGlobals);
1102         return status;
1103     }
1104 
1105     FxPointerNotNull(pFxDriverGlobals, EvtReserveDmaFunction);
1106 
1107     status = pDmaTrans->ReserveAdapter(RequiredMapRegisters,
1108                                        DmaDirection,
1109                                        EvtReserveDmaFunction,
1110                                        EvtReserveDmaContext);
1111 
1112     return status;
1113 }
1114 __drv_maxIRQL(DISPATCH_LEVEL)
1115 VOID
1116 WDFEXPORT(WdfDmaTransactionFreeResources)(
1117     __in
1118     PWDF_DRIVER_GLOBALS DriverGlobals,
1119     __in
1120     WDFDMATRANSACTION DmaTransaction
1121     )
1122 {
1123     FxDmaPacketTransaction* pDmaTrans;
1124     PFX_DRIVER_GLOBALS pFxDriverGlobals;
1125 
1126     FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
1127                                    DmaTransaction,
1128                                    FX_TYPE_DMA_TRANSACTION,
1129                                    (PVOID *) &pDmaTrans,
1130                                    &pFxDriverGlobals);
1131 
1132     //
1133     // Only valid for packet or system profile transactions.
1134     //
1135     WDF_DMA_PROFILE profile = pDmaTrans->GetDmaEnabler()->GetProfile();
1136     if ((profile != WdfDmaProfilePacket) &&
1137         (profile != WdfDmaProfilePacket64) &&
1138         (profile != WdfDmaProfileSystem) &&
1139         (profile != WdfDmaProfileSystemDuplex)) {
1140         DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA,
1141                             "Cannot call %!FUNC! on non packet or system "
1142                             "profile WDFDMATRANSACTION (%p) (transaction "
1143                             "profile is %!WDF_DMA_PROFILE!).",
1144                             DmaTransaction,
1145                             profile);
1146         FxVerifierDbgBreakPoint(pFxDriverGlobals);
1147         return;
1148     }
1149 
1150     //
1151     // Only valid if DMA V3 is enabled.
1152     //
1153 
1154     if (pDmaTrans->GetDmaEnabler()->UsesDmaV3() == FALSE)
1155     {
1156         DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA,
1157                             "Cannot call %!FUNC! on WDFDMATRANSACTION %p "
1158                             "because WDFDMAENABLER %p was not configured "
1159                             "for DMA version 3",
1160                             DmaTransaction,
1161                             pDmaTrans->GetDmaEnabler()->GetHandle());
1162         FxVerifierDbgBreakPoint(pFxDriverGlobals);
1163         return;
1164     }
1165 
1166     pDmaTrans->ReleaseAdapter();
1167 
1168     return;
1169 }
1170 __drv_maxIRQL(DISPATCH_LEVEL)
1171 BOOLEAN
1172 WDFEXPORT(WdfDmaTransactionCancel)(
1173     __in
1174     PWDF_DRIVER_GLOBALS DriverGlobals,
1175     __in
1176     WDFDMATRANSACTION DmaTransaction
1177     )
1178 {
1179     FxDmaTransactionBase* pDmaTrans;
1180     PFX_DRIVER_GLOBALS pFxDriverGlobals;
1181 
1182     FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
1183                                    DmaTransaction,
1184                                    FX_TYPE_DMA_TRANSACTION,
1185                                    (PVOID *) &pDmaTrans,
1186                                    &pFxDriverGlobals);
1187 
1188     //
1189     // Only valid if the enabler uses DMA v3
1190     //
1191 
1192     if (pDmaTrans->GetDmaEnabler()->UsesDmaV3() == FALSE) {
1193         DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA,
1194                             "Cannot call %!FUNC! WDFDMATRANSACTION (%p) "
1195                             "because enabler is not using DMA version 3",
1196                             DmaTransaction);
1197         FxVerifierDbgBreakPoint(pFxDriverGlobals);
1198         return FALSE;
1199     }
1200 
1201     return pDmaTrans->CancelResourceAllocation();
1202 }
1203 
1204 __drv_maxIRQL(DISPATCH_LEVEL)
1205 VOID
1206 WDFEXPORT(WdfDmaTransactionStopSystemTransfer)(
1207     __in
1208     PWDF_DRIVER_GLOBALS DriverGlobals,
1209     __in
1210     WDFDMATRANSACTION DmaTransaction
1211     )
1212 {
1213     FxDmaTransactionBase* pDmaTrans;
1214     PFX_DRIVER_GLOBALS pFxDriverGlobals;
1215 
1216     FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
1217                                    DmaTransaction,
1218                                    FX_TYPE_DMA_TRANSACTION,
1219                                    (PVOID *) &pDmaTrans,
1220                                    &pFxDriverGlobals);
1221 
1222     //
1223     // Verify that the transaction belongs to a system profile enabler.
1224     //
1225 
1226     WDF_DMA_PROFILE profile = pDmaTrans->GetDmaEnabler()->GetProfile();
1227     if ((profile != WdfDmaProfileSystem) &&
1228         (profile != WdfDmaProfileSystemDuplex)) {
1229         DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA,
1230                             "Cannot call %!FUNC! on non-system-profile "
1231                             "WDFDMATRANSACTION (%p) (transaction profile "
1232                             "is %!WDF_DMA_PROFILE!).",
1233                             DmaTransaction,
1234                             profile);
1235         FxVerifierDbgBreakPoint(pFxDriverGlobals);
1236         return;
1237     }
1238 
1239     //
1240     // Cast the transaction to the right sub-type now that we've verified the
1241     // profile.
1242     //
1243 
1244     FxDmaSystemTransaction* systemTransaction = (FxDmaSystemTransaction*) pDmaTrans;
1245     systemTransaction->StopTransfer();
1246     return;
1247 }
1248 
1249 
1250 
1251 } // extern "C"
1252