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