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_
__drv_maxIRQL(DISPATCH_LEVEL)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_
__drv_maxIRQL(DISPATCH_LEVEL)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_
__drv_maxIRQL(DISPATCH_LEVEL)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_
__drv_maxIRQL(DISPATCH_LEVEL)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_
__drv_maxIRQL(DISPATCH_LEVEL)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)
__drv_maxIRQL(DISPATCH_LEVEL)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
__drv_maxIRQL(DISPATCH_LEVEL)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
__drv_maxIRQL(DISPATCH_LEVEL)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
__drv_maxIRQL(DISPATCH_LEVEL)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
__drv_maxIRQL(DISPATCH_LEVEL)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
__drv_maxIRQL(DISPATCH_LEVEL)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
__drv_maxIRQL(DISPATCH_LEVEL)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
__drv_maxIRQL(DISPATCH_LEVEL)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
__drv_maxIRQL(DISPATCH_LEVEL)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
__drv_maxIRQL(DISPATCH_LEVEL)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
__drv_maxIRQL(DISPATCH_LEVEL)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
__drv_maxIRQL(DISPATCH_LEVEL)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
__drv_maxIRQL(DISPATCH_LEVEL)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
__drv_maxIRQL(DISPATCH_LEVEL)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
__drv_maxIRQL(DISPATCH_LEVEL)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
__drv_maxIRQL(DISPATCH_LEVEL)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 }
__drv_maxIRQL(DISPATCH_LEVEL)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 }
__drv_maxIRQL(DISPATCH_LEVEL)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
__drv_maxIRQL(DISPATCH_LEVEL)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