1 /*++ 2 3 Copyright (c) Microsoft Corporation 4 5 Module Name: 6 7 FxIoQueueApi.cpp 8 9 Abstract: 10 11 This module implements the FxIoQueue object C interfaces 12 13 Author: 14 15 16 17 18 Revision History: 19 20 21 --*/ 22 23 #include "ioprivshared.hpp" 24 #include "fxpkgio.hpp" 25 #include "fxioqueue.hpp" 26 27 extern "C" { 28 // #include "FxIoQueueApi.tmh" 29 } 30 31 // 32 // C Accessor methods 33 // 34 // These are the "public" API's used by driver writers for both 35 // C and C++. In the C++ case, a "wrapper" class is placed around these 36 // methods. This is to avoid exposing any internal details of our 37 // driver frameworks implementation class, which would cause 38 // binary coupling with the device driver. 39 // 40 // (thus causing drivers to rebuild for even small changes to this C++ object) 41 // 42 43 // 44 // extern all functions 45 // 46 extern "C" { 47 48 49 _Must_inspect_result_ 50 __drv_maxIRQL(DISPATCH_LEVEL) 51 NTSTATUS 52 STDCALL 53 WDFEXPORT(WdfIoQueueCreate)( 54 __in 55 PWDF_DRIVER_GLOBALS DriverGlobals, 56 __in 57 WDFDEVICE Device, 58 __in 59 PWDF_IO_QUEUE_CONFIG Config, 60 __in_opt 61 PWDF_OBJECT_ATTRIBUTES QueueAttributes, 62 __out_opt 63 WDFQUEUE* Queue 64 ) 65 66 /*++ 67 68 Routine Description: 69 70 Creates an IoQueue object and returns its handle to the caller. 71 72 The newly created IoQueue object is associated with the IoPackage 73 instance for the device. 74 75 The IoQueue object is automatically dereferenced when its 76 associated device is removed. This driver does not normally have 77 to manually manage IoQueue object reference counts. 78 79 An IoQueue object is created in the WdfIoQueuePause state, and is 80 configured for WdfIoQueueDispatchSynchronous; 81 82 Arguments: 83 84 Device - Handle to the Device the I/O Package registered with 85 at EvtDeviceFileCreate time. 86 87 Config - WDF_IO_QUEUE_CONFIG structure 88 89 pQueue - Pointer to location to store the returned IoQueue handle. 90 91 Return Value: 92 93 NTSTATUS 94 95 --*/ 96 97 { 98 DDI_ENTRY(); 99 100 PFX_DRIVER_GLOBALS pFxDriverGlobals; 101 CfxDevice* pDevice; 102 FxPkgIo* pPkgIo; 103 FxIoQueue* pQueue; 104 NTSTATUS status; 105 106 // 107 // Validate the I/O Package handle, and get the FxPkgIo* 108 // 109 FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), 110 Device, 111 FX_TYPE_DEVICE, 112 (PVOID*)&pDevice, 113 &pFxDriverGlobals); 114 115 pPkgIo = NULL; 116 pQueue = NULL; 117 118 FxPointerNotNull(pFxDriverGlobals, Config); 119 120 status = FxValidateObjectAttributes(pFxDriverGlobals, 121 QueueAttributes, 122 (FX_VALIDATE_OPTION_EXECUTION_LEVEL_ALLOWED | 123 FX_VALIDATE_OPTION_SYNCHRONIZATION_SCOPE_ALLOWED)); 124 if (!NT_SUCCESS(status)) { 125 return status; 126 } 127 128 // Validate Config structure 129 if (Config->Size != sizeof(WDF_IO_QUEUE_CONFIG) && 130 Config->Size != sizeof(WDF_IO_QUEUE_CONFIG_V1_9) && 131 Config->Size != sizeof(WDF_IO_QUEUE_CONFIG_V1_7)) { 132 status = STATUS_INFO_LENGTH_MISMATCH; 133 134 DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, 135 "WDF_IO_QUEUE_CONFIG Size 0x%x, " 136 "expected for v1.7 size 0x%x or v1.9 size 0x%x or " 137 "current version size 0x%x, %!STATUS!", 138 Config->Size, sizeof(WDF_IO_QUEUE_CONFIG_V1_7), 139 sizeof(WDF_IO_QUEUE_CONFIG_V1_9), 140 sizeof(WDF_IO_QUEUE_CONFIG), status); 141 return status; 142 } 143 144 // 145 // If the queue is not a default queue then the out parameter is not optional 146 // 147 if(!Config->DefaultQueue && Queue == NULL) { 148 status = STATUS_INVALID_PARAMETER_4; 149 150 DoTraceLevelMessage( 151 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, 152 "Parameter to receive WDFQUEUE handle is not optional " 153 "for non default queue %!STATUS!", status); 154 155 return status; 156 } 157 158 //pPkgIo = (FxPkgIo*)pDevice->m_PkgIo; 159 pPkgIo = pDevice->m_PkgIo; 160 161 // 162 // If the queue is a default queue, then we restrict the creation to happen 163 // a) before the device is started for pnp devices (FDO or PDO) 164 // b) before the call to WdfControlDeviceFinishInitializing for controldevices. 165 // This is done to prevent some unknown race conditions and reduce 166 // the test matrix. 167 // 168 if(Config->DefaultQueue) { 169 170 if(pDevice->IsLegacy()) { 171 // 172 // This is a controldevice. Make sure the create is called after the device 173 // is initialized and ready to accept I/O. 174 // 175 if((pDevice->GetDeviceObjectFlags() & DO_DEVICE_INITIALIZING) == FALSE) { 176 DoTraceLevelMessage( 177 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, 178 "Default queue can only be created before WdfControlDeviceFinishInitializing" 179 "on the WDFDEVICE %p is called %!STATUS!", 180 Device, 181 STATUS_INVALID_DEVICE_STATE); 182 return STATUS_INVALID_DEVICE_STATE; 183 } 184 185 } else { 186 // 187 // This is either FDO or PDO. Make sure it's not started yet. 188 // 189 if (pDevice->GetDevicePnpState() != WdfDevStatePnpInit) { 190 status = STATUS_INVALID_DEVICE_STATE; 191 DoTraceLevelMessage( 192 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, 193 "Default queue can only be created before the WDFDEVICE 0x%p " 194 "is started, %!STATUS!", Device, status); 195 return status; 196 } 197 } 198 } 199 200 // 201 // Create the Queue for the I/O package 202 // 203 status = pPkgIo->CreateQueue(Config, 204 QueueAttributes, 205 GetFxDriverGlobals(DriverGlobals)->Driver, 206 &pQueue); 207 if (!NT_SUCCESS(status)) { 208 DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, 209 "Queue Creation failed " 210 "for WDFDEVICE 0x%p, %!STATUS!", Device, status); 211 return status; 212 } 213 214 if(Config->DefaultQueue) { 215 216 // 217 // Make this a default queue. The default queue receives any 218 // I/O requests that have not been otherwise forwarded to another 219 // queue by WdfDeviceConfigureRequestDispatching . 220 // 221 222 status = pPkgIo->InitializeDefaultQueue( 223 pDevice, 224 pQueue 225 ); 226 227 if (!NT_SUCCESS(status)) { 228 DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, 229 "Create failed " 230 "for FxPkgIo 0x%p, WDFDEVICE 0x%p",pPkgIo, Device); 231 // 232 // Delete the queue *without* invoking driver defined callbacks 233 // 234 pQueue->DeleteFromFailedCreate(); 235 236 return status; 237 } 238 } 239 240 DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO, 241 "Created WDFQUEUE 0x%p", pQueue->GetObjectHandle()); 242 243 if(Queue != NULL) { 244 *Queue = (WDFQUEUE)pQueue->GetObjectHandle(); 245 } 246 247 return STATUS_SUCCESS; 248 } 249 250 251 __drv_maxIRQL(DISPATCH_LEVEL) 252 WDF_IO_QUEUE_STATE 253 STDCALL 254 WDFEXPORT(WdfIoQueueGetState)( 255 __in 256 PWDF_DRIVER_GLOBALS DriverGlobals, 257 __in 258 WDFQUEUE Queue, 259 __out_opt 260 PULONG QueueCount, 261 __out_opt 262 PULONG DriverCount 263 ) 264 265 /*++ 266 267 Routine Description: 268 269 Return the Queues status 270 271 Arguments: 272 273 Queue - Handle to Queue object 274 275 pQueueCount - Count of requests in the Queue not presented 276 to the driver. 277 278 pDriverCount - Count of requests the driver is operating 279 on that are associated with this queue. 280 281 Returns: 282 283 WDF_IO_QUEUE_STATE 284 285 --*/ 286 287 { 288 DDI_ENTRY(); 289 290 FxIoQueue* pQueue; 291 292 FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), 293 Queue, 294 FX_TYPE_QUEUE, 295 (PVOID*)&pQueue); 296 297 return pQueue->GetState(QueueCount, DriverCount); 298 } 299 300 __drv_maxIRQL(DISPATCH_LEVEL) 301 WDFDEVICE 302 STDCALL 303 WDFEXPORT(WdfIoQueueGetDevice)( 304 __in 305 PWDF_DRIVER_GLOBALS DriverGlobals, 306 __in 307 WDFQUEUE Queue 308 ) 309 310 /*++ 311 312 Routine Description: 313 Returns the device handle that the queue is associated with 314 315 Arguments: 316 Queue - Handle to queue object 317 318 Return Value: 319 WDFDEVICE handle 320 321 --*/ 322 323 { 324 DDI_ENTRY(); 325 326 FxIoQueue* pQueue; 327 328 FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), 329 Queue, 330 FX_TYPE_QUEUE, 331 (PVOID*) &pQueue); 332 333 return (WDFDEVICE) pQueue->GetDevice()->GetHandle(); 334 } 335 336 337 __drv_maxIRQL(DISPATCH_LEVEL) 338 VOID 339 STDCALL 340 WDFEXPORT(WdfIoQueueStart)( 341 __in 342 PWDF_DRIVER_GLOBALS DriverGlobals, 343 __in 344 WDFQUEUE Queue 345 ) 346 347 /*++ 348 349 Routine Description: 350 351 Set the Queues state to start accepting and dispatching new requests. 352 353 Arguments: 354 355 Queue - Handle to Queue object 356 357 A Queue may not go into a specific state right away, since it may have to 358 wait for requests to be completed or cancelled. This is reflected 359 in the status returned by WdfIoQueueGetState. 360 361 See the Queue event API's for asynchronous notification of 362 specific status states. 363 364 Returns: 365 366 NTSTATUS 367 --*/ 368 369 { 370 DDI_ENTRY(); 371 372 FxIoQueue* pQueue; 373 374 FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), 375 Queue, 376 FX_TYPE_QUEUE, 377 (PVOID*)&pQueue); 378 379 pQueue->QueueStart(); 380 381 return; 382 } 383 384 __drv_maxIRQL(DISPATCH_LEVEL) 385 VOID 386 STDCALL 387 WDFEXPORT(WdfIoQueueStop)( 388 __in 389 PWDF_DRIVER_GLOBALS DriverGlobals, 390 __in 391 WDFQUEUE Queue, 392 __drv_when(Context != 0, __in) 393 __drv_when(Context == 0, __in_opt) 394 PFN_WDF_IO_QUEUE_STATE StopComplete, 395 __drv_when(StopComplete != 0, __in) 396 __drv_when(StopComplete == 0, __in_opt) 397 WDFCONTEXT Context 398 ) 399 400 /*++ 401 402 Routine Description: 403 404 Set the Queue state to accept and queue (not dispatch) incoming new requests. 405 406 Arguments: 407 408 Queue - Handle to Queue object 409 410 A Queue may not go into a specific state right away, since it may have to 411 wait for requests to be completed or cancelled. This is reflected 412 in the status returned by WdfIoQueueGetState. 413 414 See the Queue event API's for asynchronous notification of 415 specific status states. 416 417 Returns: 418 419 --*/ 420 421 { 422 DDI_ENTRY(); 423 424 FxIoQueue* pQueue; 425 NTSTATUS status; 426 427 FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), 428 Queue, 429 FX_TYPE_QUEUE, 430 (PVOID*)&pQueue); 431 432 status = pQueue->QueueIdle(FALSE, StopComplete, Context); 433 if (!NT_SUCCESS(status)) { 434 pQueue->FatalError(status); 435 return; 436 } 437 438 return; 439 } 440 441 __drv_maxIRQL(PASSIVE_LEVEL) 442 VOID 443 STDCALL 444 WDFEXPORT(WdfIoQueueStopSynchronously)( 445 __in 446 PWDF_DRIVER_GLOBALS DriverGlobals, 447 __in 448 WDFQUEUE Queue 449 ) 450 451 /*++ 452 453 Routine Description: 454 455 Set the Queue state to accept and queue (not dispatch) incoming new requests and wait 456 for 1) all the dispatch callbacks to return and 2) all the driver-owned request to complete. 457 458 Arguments: 459 460 Queue - Handle to Queue object 461 462 Returns: 463 464 NTSTATUS 465 --*/ 466 467 { 468 DDI_ENTRY(); 469 470 PFX_DRIVER_GLOBALS pFxDriverGlobals; 471 FxIoQueue* pQueue; 472 NTSTATUS status; 473 474 FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), 475 Queue, 476 FX_TYPE_QUEUE, 477 (PVOID*)&pQueue, 478 &pFxDriverGlobals); 479 480 status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); 481 if (!NT_SUCCESS(status)) { 482 return; 483 } 484 485 status = pQueue->QueueIdleSynchronously(FALSE); 486 487 if (!NT_SUCCESS(status)) { 488 pQueue->FatalError(status); 489 return; 490 } 491 } 492 493 __drv_maxIRQL(DISPATCH_LEVEL) 494 VOID 495 STDCALL 496 WDFEXPORT(WdfIoQueueStopAndPurge)( 497 __in 498 PWDF_DRIVER_GLOBALS DriverGlobals, 499 __in 500 WDFQUEUE Queue, 501 __drv_when(Context != 0, __in) 502 __drv_when(Context == 0, __in_opt) 503 PFN_WDF_IO_QUEUE_STATE StopAndPurgeComplete, 504 __drv_when(StopAndPurgeComplete != 0, __in) 505 __drv_when(StopAndPurgeComplete == 0, __in_opt) 506 WDFCONTEXT Context 507 ) 508 509 /*++ 510 511 Routine Description: 512 513 This function does the following: 514 - sets the queue state to accept and queues (not dispatch) incoming new requests. 515 - cancels all current (at the time this function is called) queued requests. 516 - invokes, if present, the cancel callback of cancellable driver requests. 517 - Asynchronously if complete callback is specified, it waits until 518 1) all the dispatch callbacks to return and 519 2) all the driver-owned request to complete. 520 521 Arguments: 522 523 Queue - Handle to Queue object 524 525 A Queue may not go into a specific state right away, since it may have to 526 wait for requests to be completed or cancelled. This is reflected 527 in the status returned by WdfIoQueueGetState. 528 529 See the Queue event API's for asynchronous notification of 530 specific status states. 531 532 Returns: 533 534 --*/ 535 536 { 537 DDI_ENTRY(); 538 539 FxIoQueue* queue; 540 NTSTATUS status; 541 542 FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), 543 Queue, 544 FX_TYPE_QUEUE, 545 (PVOID*)&queue); 546 547 status = queue->QueueIdle(TRUE, StopAndPurgeComplete, Context); 548 if (!NT_SUCCESS(status)) { 549 queue->FatalError(status); 550 return; 551 } 552 553 return; 554 } 555 556 __drv_maxIRQL(PASSIVE_LEVEL) 557 VOID 558 STDCALL 559 WDFEXPORT(WdfIoQueueStopAndPurgeSynchronously)( 560 __in 561 PWDF_DRIVER_GLOBALS DriverGlobals, 562 __in 563 WDFQUEUE Queue 564 ) 565 566 /*++ 567 568 Routine Description: 569 570 This function does the following: 571 - sets the queue state to accept and queues (not dispatch) incoming new requests. 572 - cancels all current (at the time this function is called) queued requests. 573 - invokes, if present, the cancel callback of cancellable driver requests. 574 - before returning it waits until 575 1) all the dispatch callbacks to return and 576 2) all the driver-owned request to complete. 577 578 Arguments: 579 580 Queue - Handle to Queue object 581 582 Returns: 583 584 NTSTATUS 585 --*/ 586 587 { 588 DDI_ENTRY(); 589 590 PFX_DRIVER_GLOBALS fxDriverGlobals; 591 FxIoQueue* queue; 592 NTSTATUS status; 593 594 FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), 595 Queue, 596 FX_TYPE_QUEUE, 597 (PVOID*)&queue, 598 &fxDriverGlobals); 599 600 status = FxVerifierCheckIrqlLevel(fxDriverGlobals, PASSIVE_LEVEL); 601 if (!NT_SUCCESS(status)) { 602 return; 603 } 604 605 status = queue->QueueIdleSynchronously(TRUE); 606 607 if (!NT_SUCCESS(status)) { 608 queue->FatalError(status); 609 return; 610 } 611 } 612 613 _Must_inspect_result_ 614 __drv_maxIRQL(DISPATCH_LEVEL) 615 NTSTATUS 616 STDCALL 617 WDFEXPORT(WdfIoQueueRetrieveNextRequest)( 618 __in 619 PWDF_DRIVER_GLOBALS DriverGlobals, 620 __in 621 WDFQUEUE Queue, 622 __out 623 WDFREQUEST *OutRequest 624 ) 625 626 /*++ 627 628 WdfIoQueueRetrieveNextRequest: 629 630 Routine Description: 631 632 Returns a request from the head of the queue. 633 634 On successful return the driver owns the request, and must 635 eventually call WdfRequestComplete. 636 637 The driver does not need to release any extra reference counts, 638 other than calling WdfRequestComplete. 639 640 641 Arguments: 642 643 Queue - Queue handle 644 645 pOutRequest - Pointer to location to return new request handle 646 647 Returns: 648 649 650 STATUS_NO_MORE_ENTRIES - The queue is empty 651 652 STATUS_SUCCESS - A request was returned in pOutRequest 653 654 --*/ 655 656 { 657 DDI_ENTRY(); 658 659 FxIoQueue* pQueue; 660 FxRequest* pOutputRequest = NULL; 661 NTSTATUS status; 662 663 FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), 664 Queue, 665 FX_TYPE_QUEUE, 666 (PVOID*)&pQueue); 667 668 FxPointerNotNull(pQueue->GetDriverGlobals(), OutRequest); 669 670 status = pQueue->GetRequest(NULL, NULL, &pOutputRequest); 671 672 if (NT_SUCCESS(status)) { 673 *OutRequest = (WDFREQUEST)pOutputRequest->GetObjectHandle(); 674 } else { 675 *OutRequest = NULL; 676 ASSERT(status != STATUS_NOT_FOUND); 677 } 678 679 return status; 680 } 681 682 _Must_inspect_result_ 683 __drv_maxIRQL(DISPATCH_LEVEL) 684 NTSTATUS 685 STDCALL 686 WDFEXPORT(WdfIoQueueRetrieveRequestByFileObject)( 687 __in 688 PWDF_DRIVER_GLOBALS DriverGlobals, 689 __in 690 WDFQUEUE Queue, 691 __in 692 WDFFILEOBJECT FileObject, 693 __out 694 WDFREQUEST *OutRequest 695 ) 696 697 /*++ 698 699 WdfIoQueueRetrieveNextRequest: 700 701 Routine Description: 702 703 Returns a request from the queue that matches the fileobject. 704 705 Requests are dequeued in a first in, first out manner. 706 707 If there are no requests that match the selection criteria, 708 STATUS_NO_MORE_ENTRIES is returned. 709 710 On successful return the driver owns the request, and must 711 eventually call WdfRequestComplete. 712 713 The driver does not need to release any extra reference counts, 714 other than calling WdfRequestComplete. 715 716 Arguments: 717 718 Queue - Queue handle 719 720 FileObject - FileObject to match in the request 721 722 pOutRequest - Pointer to location to return new request handle 723 724 Returns: 725 726 727 STATUS_NO_MORE_ENTRIES - The queue is empty, or no more requests 728 match the selection criteria of TagRequest 729 and FileObject specified above. 730 731 STATUS_SUCCESS - A request context was returned in 732 pOutRequest 733 734 --*/ 735 736 { 737 DDI_ENTRY(); 738 739 FxIoQueue* pQueue; 740 FxRequest* pOutputRequest = NULL; 741 FxFileObject* pFO = NULL; 742 MdFileObject pWdmFO = NULL; 743 NTSTATUS status; 744 PFX_DRIVER_GLOBALS pFxDriverGlobals; 745 746 FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), 747 Queue, 748 FX_TYPE_QUEUE, 749 (PVOID*)&pQueue, 750 &pFxDriverGlobals); 751 752 FxPointerNotNull(pFxDriverGlobals, OutRequest); 753 754 FxObjectHandleGetPtr(pFxDriverGlobals, 755 FileObject, 756 FX_TYPE_FILEOBJECT, 757 (PVOID*)&pFO); 758 759 // Get the real WDM fileobject 760 pWdmFO = pFO->GetWdmFileObject(); 761 762 status = pQueue->GetRequest(pWdmFO, NULL, &pOutputRequest); 763 764 if (NT_SUCCESS(status)) { 765 766 // Copy out the handle to the new request 767 *OutRequest = (WDFREQUEST)pOutputRequest->GetObjectHandle(); 768 } else { 769 *OutRequest = NULL; 770 ASSERT(status != STATUS_NOT_FOUND); 771 } 772 773 return status; 774 } 775 776 _Must_inspect_result_ 777 __drv_maxIRQL(DISPATCH_LEVEL) 778 NTSTATUS 779 STDCALL 780 WDFEXPORT(WdfIoQueueRetrieveFoundRequest)( 781 __in 782 PWDF_DRIVER_GLOBALS DriverGlobals, 783 __in 784 WDFQUEUE Queue, 785 __in 786 WDFREQUEST TagRequest, 787 __out 788 WDFREQUEST * OutRequest 789 ) 790 791 /*++ 792 793 WdfIoQueueRetrieveNextRequest: 794 795 Routine Description: 796 797 Returns a request from the queue. 798 799 Requests are dequeued in a first in, first out manner. 800 801 The queue is searched for specific peeked 802 request, and if it is not found, STATUS_NOT_FOUND is 803 returned. A TagRequest value is returned 804 from WdfIoQueueFindRequest(). 805 806 If there are no requests that match the selection criteria, 807 STATUS_NO_MORE_ENTRIES is returned. 808 809 On successful return the driver owns the request, and must 810 eventually call WdfRequestComplete. 811 812 The driver does not need to release any extra reference counts, 813 other than calling WdfRequestComplete. 814 815 Arguments: 816 817 Queue - Queue handle 818 819 TagRequest - Request to look for in queue 820 821 pOutRequest - Pointer to location to return new request handle 822 823 Returns: 824 825 STATUS_NOT_FOUND - TagContext was specified, but not 826 found in the queue. This could be 827 because the request was cancelled, 828 or is part of an active queue and 829 the request was passed to the driver 830 or forwarded to another queue. 831 832 STATUS_NO_MORE_ENTRIES - The queue is empty, or no more requests 833 match the selection criteria of TagRequest 834 specified above. 835 836 STATUS_SUCCESS - A request context was returned in 837 pOutRequest 838 839 --*/ 840 841 { 842 DDI_ENTRY(); 843 844 FxIoQueue* pQueue; 845 FxRequest* pTagRequest = NULL; 846 FxRequest* pOutputRequest = NULL; 847 NTSTATUS status; 848 PFX_DRIVER_GLOBALS pFxDriverGlobals; 849 850 FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), 851 Queue, 852 FX_TYPE_QUEUE, 853 (PVOID*)&pQueue, 854 &pFxDriverGlobals); 855 856 FxPointerNotNull(pFxDriverGlobals, OutRequest); 857 858 FxObjectHandleGetPtr(pFxDriverGlobals, 859 TagRequest, 860 FX_TYPE_REQUEST, 861 (PVOID*)&pTagRequest); 862 863 status = pQueue->GetRequest(NULL, pTagRequest, &pOutputRequest); 864 865 if (NT_SUCCESS(status)) { 866 // Copy out the handle to the new request 867 *OutRequest = (WDFREQUEST)pOutputRequest->GetObjectHandle(); 868 } else { 869 *OutRequest = NULL; 870 } 871 872 return status; 873 } 874 875 _Must_inspect_result_ 876 __drv_maxIRQL(DISPATCH_LEVEL) 877 NTSTATUS 878 STDCALL 879 WDFEXPORT(WdfIoQueueFindRequest)( 880 __in 881 PWDF_DRIVER_GLOBALS DriverGlobals, 882 __in 883 WDFQUEUE Queue, 884 __in_opt 885 WDFREQUEST TagRequest, 886 __in_opt 887 WDFFILEOBJECT FileObject, 888 __inout_opt 889 PWDF_REQUEST_PARAMETERS Parameters, 890 __out 891 WDFREQUEST * OutRequest 892 ) 893 894 /*++ 895 896 WdfIoQueueFindRequest: 897 898 Routine Description: 899 900 PeekRequest allows a caller to enumerate through requests in 901 a queue, optionally only returning requests that match a specified 902 FileObject. 903 904 The first call specifies TagContext == NULL, and the first request 905 in the queue that matches the FileObject is returned. 906 907 Subsequent requests specify the previous request value as the 908 TagContext, and searching will continue at the request that follows. 909 910 If the queue is empty, there are no requests after TagContext, or no 911 requests match the FileObject, NULL is returned. 912 913 If FileObject == NULL, this matches any FileObject in a request. 914 915 If a WDF_REQUEST_PARAMETERS structure is supplied, the information 916 from the request is returned to allow the driver to further examine 917 the request to decide whether to service it. 918 919 If a TagRequest is specified, and it is not found, the return 920 status STATUS_NOT_FOUND means that the queue should 921 be re-scanned. This is because the TagRequest was cancelled from 922 the queue, or if the queue was active, delivered to the driver. 923 There may still be un-examined requests on the queue that match 924 the drivers search criteria, but the search marker has been lost. 925 926 Re-scanning the queue starting with TagRequest == NULL and 927 continuing until STATUS_NO_MORE_ENTRIES is returned will ensure 928 all requests have been examined. 929 930 Enumerating an active queue with this API could result in the 931 driver frequently having to re-scan. 932 933 If a successful return of a Request object handle occurs, the driver 934 *must* call WdfObjectDereference when done with it, otherwise an 935 object leak will result. 936 937 Returned request objects are not owned by the driver, and may not be 938 used by I/O or completed. The only valid operations are 939 WdfRequestGetParameters, passing it as the TagRequest parameter to 940 WdfIoQueueFindRequest, WdfIoQueueRetrieveFoundRequest, or calling 941 WdfObjectDereference. All other actions are undefined. 942 943 The request could be cancelled without a EvtIoCancel callback while the 944 driver has the handle. The request then becomes invalid, and 945 WdfObjectDereference must be called to release its resources. 946 947 The caller should not use any buffer pointers in the returned parameters 948 structure until it successfully receives ownership of the request by 949 calling WdfIoQueueRetrieveFoundRequest with the request tag. This is because 950 the I/O can be cancelled and completed at any time without the driver 951 being notified until it has received ownership, thus invalidating 952 the buffer pointers and releasing the memory, even if the request 953 object itself it still valid due to the reference. 954 955 The driver should hold the reference on the object until after 956 a call to WdfIoQueueFindRequest using it as the TagRequest 957 parameter, or WdfIoQueueRetrieveFoundtRequest. Otherwise, a race could 958 result in which the object is cancelled, its memory re-used for 959 a new request, and then an attempt to use it as a tag would result 960 in a different state than intended. The driver verifier will 961 catch this, but it is a rare race. 962 963 Calling this API on an operating Queue can lead to confusing results. This 964 is because the request could be presented to EvtIoDefault, causing it to be 965 invalid as a TagRequest in calls to WdfIoQueueFindRequest, and 966 WdfIoQueueRetrieveFoundRequest. The extra reference taken on the object by its return 967 from this call must still be released by WdfObjectDereference. 968 969 The intention of the API is to only hold onto the TagRequest long enough 970 for the driver to make a decision whether to service the request, or 971 to continue searching for requests. 972 973 Arguments: 974 975 Queue - Queue handle 976 977 TagRequest - If !NULL, request to begin search at 978 979 FileObject - If !NULL, FileObject to match in the request 980 981 Parameters - If !NULL, pointer to buffer to return the requests 982 parameters to aid in selection. 983 984 pOutRequest - Pointer to location to return request handle 985 986 Returns: 987 988 STATUS_NOT_FOUND - TagContext was specified, but not 989 found in the queue. This could be 990 because the request was cancelled, 991 or is part of an active queue and 992 the request was passed to the driver 993 or forwarded to another queue. 994 995 STATUS_NO_MORE_ENTRIES - The queue is empty, or no more requests 996 match the selection criteria of TagRequest 997 and FileObject specified above. 998 999 STATUS_SUCCESS - A request context was returned in 1000 pOutRequest 1001 1002 --*/ 1003 1004 { 1005 DDI_ENTRY(); 1006 1007 FxIoQueue* pQueue; 1008 FxRequest* pTagRequest = NULL; 1009 FxRequest* pOutputRequest = NULL; 1010 FxFileObject* pFO = NULL; 1011 MdFileObject pWdmFO = NULL; 1012 NTSTATUS status; 1013 PFX_DRIVER_GLOBALS pFxDriverGlobals; 1014 1015 FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), 1016 Queue, 1017 FX_TYPE_QUEUE, 1018 (PVOID*)&pQueue, 1019 &pFxDriverGlobals); 1020 1021 FxPointerNotNull(pFxDriverGlobals, OutRequest); 1022 1023 // 1024 // Validate tag request handle if supplied 1025 // 1026 if (TagRequest != NULL) { 1027 FxObjectHandleGetPtr(pFxDriverGlobals, 1028 TagRequest, 1029 FX_TYPE_REQUEST, 1030 (PVOID*)&pTagRequest); 1031 } 1032 1033 // 1034 // If present, validate the FileObject object handle, 1035 // and get its FxFileObject* 1036 // 1037 if (FileObject != NULL) { 1038 FxObjectHandleGetPtr(pFxDriverGlobals, 1039 FileObject, 1040 FX_TYPE_FILEOBJECT, 1041 (PVOID*)&pFO); 1042 // 1043 // Get the real WDM fileobject 1044 // 1045 pWdmFO = pFO->GetWdmFileObject(); 1046 } 1047 1048 // 1049 // If a parameters buffer is supplied, validate its length 1050 // 1051 if ((Parameters != NULL) && (Parameters->Size < sizeof(WDF_REQUEST_PARAMETERS))) { 1052 status = STATUS_INVALID_PARAMETER_4; 1053 DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, 1054 "Invalid WDF_REQUEST_PARAMETERS size %d %!STATUS!", 1055 Parameters->Size, status); 1056 return status; 1057 } 1058 1059 1060 status = pQueue->PeekRequest(pTagRequest, 1061 pWdmFO, 1062 Parameters, 1063 &pOutputRequest); 1064 1065 if (NT_SUCCESS(status)) { 1066 // 1067 // Copy out the handle to the new request 1068 // 1069 *OutRequest = (WDFREQUEST)pOutputRequest->GetObjectHandle(); 1070 } else { 1071 *OutRequest = NULL; 1072 } 1073 1074 return status; 1075 } 1076 1077 __drv_maxIRQL(DISPATCH_LEVEL) 1078 VOID 1079 STDCALL 1080 WDFEXPORT(WdfIoQueueDrain)( 1081 __in 1082 PWDF_DRIVER_GLOBALS DriverGlobals, 1083 __in 1084 WDFQUEUE Queue, 1085 __drv_when(Context != 0, __in) 1086 __drv_when(Context == 0, __in_opt) 1087 PFN_WDF_IO_QUEUE_STATE DrainComplete, 1088 __drv_when(DrainComplete != 0, __in) 1089 __drv_when(DrainComplete == 0, __in_opt) 1090 WDFCONTEXT Context 1091 ) 1092 1093 /*++ 1094 1095 Set the Queue to reject new requests, with newly arriving 1096 requests being completed with STATUS_CANCELLED. 1097 1098 If the optional DrainComplete callback is specified, the 1099 callback will be invoked with the supplied context when 1100 there are no requests owned by the driver and no request pending in the 1101 queue. 1102 1103 Only one callback registration for WdfIoQueueIdle, WdfIoQueuePurge, 1104 or WdfIoQueueDrain may be outstanding at a time. 1105 1106 --*/ 1107 1108 { 1109 DDI_ENTRY(); 1110 1111 FxIoQueue* pQueue; 1112 NTSTATUS status; 1113 1114 FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), 1115 Queue, 1116 FX_TYPE_QUEUE, 1117 (PVOID*)&pQueue); 1118 1119 status = pQueue->QueueDrain(DrainComplete, Context); 1120 1121 if (!NT_SUCCESS(status)) { 1122 pQueue->FatalError(status); 1123 return; 1124 } 1125 1126 return; 1127 } 1128 1129 __drv_maxIRQL(PASSIVE_LEVEL) 1130 VOID 1131 STDCALL 1132 WDFEXPORT(WdfIoQueueDrainSynchronously)( 1133 __in 1134 PWDF_DRIVER_GLOBALS DriverGlobals, 1135 __in 1136 WDFQUEUE Queue 1137 ) 1138 1139 /*++ 1140 1141 Set the Queue to fail new request with STATUS_CANCELLED, 1142 dispatches pending requests, and waits for the all the pending and 1143 inflight requests to complete before returning. 1144 1145 Should be called at PASSIVE_LEVEL. 1146 1147 --*/ 1148 1149 { 1150 DDI_ENTRY(); 1151 1152 PFX_DRIVER_GLOBALS pFxDriverGlobals; 1153 FxIoQueue* pQueue; 1154 NTSTATUS status; 1155 1156 FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), 1157 Queue, 1158 FX_TYPE_QUEUE, 1159 (PVOID*)&pQueue, 1160 &pFxDriverGlobals); 1161 1162 status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); 1163 if (!NT_SUCCESS(status)) { 1164 return; 1165 } 1166 1167 status = pQueue->QueueDrainSynchronously(); 1168 1169 if (!NT_SUCCESS(status)) { 1170 pQueue->FatalError(status); 1171 return; 1172 } 1173 } 1174 1175 __drv_maxIRQL(PASSIVE_LEVEL) 1176 VOID 1177 STDCALL 1178 WDFEXPORT(WdfIoQueuePurgeSynchronously)( 1179 __in 1180 PWDF_DRIVER_GLOBALS DriverGlobals, 1181 __in 1182 WDFQUEUE Queue 1183 ) 1184 1185 /*++ 1186 1187 Sets the queue state to fail incoming requests, 1188 cancels all the pending requests, cancels in-flights requests 1189 (if they are marked cancelable), and waits for all the requests 1190 to complete before returning. 1191 1192 Should be called at PASSIVE_LEVEL. 1193 1194 --*/ 1195 1196 { 1197 DDI_ENTRY(); 1198 1199 PFX_DRIVER_GLOBALS pFxDriverGlobals; 1200 FxIoQueue* pQueue; 1201 NTSTATUS status; 1202 1203 FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), 1204 Queue, 1205 FX_TYPE_QUEUE, 1206 (PVOID*)&pQueue, 1207 &pFxDriverGlobals); 1208 1209 status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); 1210 if (!NT_SUCCESS(status)) { 1211 return; 1212 } 1213 1214 status = pQueue->QueuePurgeSynchronously(); 1215 1216 if (!NT_SUCCESS(status)) { 1217 pQueue->FatalError(status); 1218 return; 1219 } 1220 1221 return; 1222 } 1223 1224 __drv_maxIRQL(DISPATCH_LEVEL) 1225 VOID 1226 STDCALL 1227 WDFEXPORT(WdfIoQueuePurge)( 1228 __in 1229 PWDF_DRIVER_GLOBALS DriverGlobals, 1230 __in 1231 WDFQUEUE Queue, 1232 __drv_when(Context != 0, __in) 1233 __drv_when(Context == 0, __in_opt) 1234 PFN_WDF_IO_QUEUE_STATE PurgeComplete, 1235 __drv_when(PurgeComplete != 0, __in) 1236 __drv_when(PurgeComplete == 0, __in_opt) 1237 WDFCONTEXT Context 1238 ) 1239 1240 /*++ 1241 1242 Set the Queue to reject new requests, with newly arriving 1243 requests being completed with STATUS_CANCELLED. 1244 1245 A Queue may not purge immediately, since the device driver 1246 could be operating on non-cancelable requests. 1247 1248 1249 If the optional PurgeComplete callback is specified, the 1250 callback will be invoked with the supplied context when 1251 the Queue is in the WDF_IO_QUEUE_PURGED state. 1252 (Reject new requests, no current requests in Queue or device driver) 1253 1254 Only one callback registration for WdfIoQueueIdle, WdfIoQueuePurge, 1255 or WdfIoQueueDrain may be outstanding at a time. 1256 1257 --*/ 1258 1259 { 1260 DDI_ENTRY(); 1261 1262 FxIoQueue* pQueue; 1263 NTSTATUS status; 1264 1265 FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), 1266 Queue, 1267 FX_TYPE_QUEUE, 1268 (PVOID*)&pQueue); 1269 1270 status = pQueue->QueuePurge( 1271 TRUE, 1272 TRUE, 1273 PurgeComplete, 1274 Context 1275 ); 1276 1277 if (!NT_SUCCESS(status)) { 1278 pQueue->FatalError(status); 1279 return; 1280 } 1281 1282 return; 1283 } 1284 1285 1286 _Must_inspect_result_ 1287 __drv_maxIRQL(DISPATCH_LEVEL) 1288 NTSTATUS 1289 STDCALL 1290 WDFEXPORT(WdfIoQueueReadyNotify)( 1291 __in 1292 PWDF_DRIVER_GLOBALS DriverGlobals, 1293 __in 1294 WDFQUEUE Queue, 1295 __in_opt 1296 PFN_WDF_IO_QUEUE_STATE QueueReady, 1297 __in_opt 1298 WDFCONTEXT Context 1299 ) 1300 1301 /*++ 1302 1303 This API notifies the device driver when the Queue 1304 has one or more requests that can be processed by 1305 the device driver. 1306 1307 This event registration continues until cancelled with 1308 by calling with NULL for QueueReady. 1309 1310 One event is generated for each transition from 1311 not ready, to ready. An event is not generated for each 1312 new request, only request arrival on an empty Queue. 1313 1314 --*/ 1315 1316 { 1317 DDI_ENTRY(); 1318 1319 FxIoQueue* pQueue; 1320 NTSTATUS status; 1321 1322 FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), 1323 Queue, 1324 FX_TYPE_QUEUE, 1325 (PVOID*)&pQueue); 1326 1327 status = pQueue->ReadyNotify( 1328 QueueReady, 1329 Context 1330 ); 1331 1332 return status; 1333 } 1334 1335 _Must_inspect_result_ 1336 __drv_maxIRQL(PASSIVE_LEVEL) 1337 NTSTATUS 1338 STDCALL 1339 WDFEXPORT(WdfIoQueueAssignForwardProgressPolicy)( 1340 __in 1341 PWDF_DRIVER_GLOBALS DriverGlobals, 1342 __in 1343 WDFQUEUE Queue, 1344 __in 1345 PWDF_IO_QUEUE_FORWARD_PROGRESS_POLICY ForwardProgressPolicy 1346 ) 1347 1348 /*++ 1349 1350 This DDI is used by the driver to configure a queue to have forward 1351 progress. 1352 --*/ 1353 { 1354 DDI_ENTRY(); 1355 1356 FxIoQueue* pQueue; 1357 NTSTATUS status; 1358 PFX_DRIVER_GLOBALS pFxDriverGlobals; 1359 1360 FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), 1361 Queue, 1362 FX_TYPE_QUEUE, 1363 (PVOID*)&pQueue, 1364 &pFxDriverGlobals); 1365 1366 FxPointerNotNull(pFxDriverGlobals, ForwardProgressPolicy); 1367 status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); 1368 if (!NT_SUCCESS(status)) { 1369 return status; 1370 } 1371 1372 if (pQueue->IsForwardProgressQueue()) { 1373 // 1374 // Queue is already configured for forward progress 1375 // 1376 status = STATUS_INVALID_PARAMETER; 1377 DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, 1378 "Queue is already configured for forward progress %!STATUS!", 1379 status); 1380 FxVerifierDbgBreakPoint(pFxDriverGlobals); 1381 return status; 1382 } 1383 1384 // 1385 // Validate Config structure 1386 // 1387 if (ForwardProgressPolicy->Size != sizeof(WDF_IO_QUEUE_FORWARD_PROGRESS_POLICY)) { 1388 status = STATUS_INFO_LENGTH_MISMATCH; 1389 DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, 1390 "WDF_IO_QUEUE_FORWARD_PROGRESS_POLICY Size 0x%x, " 1391 "expected 0x%x, %!STATUS!", 1392 ForwardProgressPolicy->Size, sizeof(WDF_IO_QUEUE_FORWARD_PROGRESS_POLICY), status); 1393 return status; 1394 } 1395 1396 // 1397 // Validate policy settings 1398 // 1399 switch (ForwardProgressPolicy->ForwardProgressReservedPolicy) { 1400 case WdfIoForwardProgressReservedPolicyUseExamine: 1401 if (ForwardProgressPolicy->ForwardProgressReservePolicySettings.Policy.ExaminePolicy.EvtIoWdmIrpForForwardProgress == NULL) { 1402 status = STATUS_INVALID_PARAMETER; 1403 DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, 1404 "Examine callback can't be null for WdfIoForwardProgressReservedPolicyUseExamine " 1405 " %!STATUS!", 1406 status); 1407 1408 return status; 1409 } 1410 break; 1411 1412 default: 1413 break; 1414 1415 } 1416 1417 // 1418 // Validate number of forward progress requests 1419 // 1420 if (ForwardProgressPolicy->TotalForwardProgressRequests == 0) { 1421 status = STATUS_INVALID_PARAMETER; 1422 DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, 1423 "Need to have more than 0 reserved Requests %!STATUS!", 1424 status); 1425 1426 return status; 1427 } 1428 1429 status = pQueue->AssignForwardProgressPolicy( 1430 ForwardProgressPolicy 1431 ); 1432 1433 return status; 1434 } 1435 1436 1437 1438 } // extern "C" 1439