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