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