1 /*++
2
3 Copyright (c) Microsoft Corporation
4
5 Module Name:
6
7 FxInterruptApi.cpp
8
9 Abstract:
10
11 This implements the WDFINTERRUPT API's
12
13 Author:
14
15
16
17
18 Environment:
19
20 Both kernel and user mode
21
22 Revision History:
23
24
25 --*/
26
27 #include "pnppriv.hpp"
28
29 extern "C" {
30 // #include "FxInterruptApi.tmh"
31 }
32
33 //
34 // At this time we are unable to include wdf19.h in the share code, thus for
35 // now we simply cut and paste the needed structures.
36 //
37 typedef struct _WDF_INTERRUPT_CONFIG_V1_9 {
38 ULONG Size;
39
40 //
41 // If this interrupt is to be synchronized with other interrupt(s) assigned
42 // to the same WDFDEVICE, create a WDFSPINLOCK and assign it to each of the
43 // WDFINTERRUPTs config.
44 //
45 WDFSPINLOCK SpinLock;
46
47 WDF_TRI_STATE ShareVector;
48
49 BOOLEAN FloatingSave;
50
51 //
52 // Automatic Serialization of the DpcForIsr
53 //
54 BOOLEAN AutomaticSerialization;
55
56 // Event Callbacks
57 PFN_WDF_INTERRUPT_ISR EvtInterruptIsr;
58
59 PFN_WDF_INTERRUPT_DPC EvtInterruptDpc;
60
61 PFN_WDF_INTERRUPT_ENABLE EvtInterruptEnable;
62
63 PFN_WDF_INTERRUPT_DISABLE EvtInterruptDisable;
64
65 } WDF_INTERRUPT_CONFIG_V1_9, *PWDF_INTERRUPT_CONFIG_V1_9;
66
67 //
68 // The interrupt config structure has changed post win8-Beta. This is a
69 // temporary definition to allow beta drivers to load on post-beta builds.
70 // Note that size of win8-beta and win8-postbeta structure is different only on
71 // non-x64 platforms, but the fact that size is same on amd64 is harmless because
72 // the struture gets zero'out by init macro, and the default value of the new
73 // field is 0 on amd64.
74 //
75 typedef struct _WDF_INTERRUPT_CONFIG_V1_11_BETA {
76 ULONG Size;
77
78 //
79 // If this interrupt is to be synchronized with other interrupt(s) assigned
80 // to the same WDFDEVICE, create a WDFSPINLOCK and assign it to each of the
81 // WDFINTERRUPTs config.
82 //
83 WDFSPINLOCK SpinLock;
84
85 WDF_TRI_STATE ShareVector;
86
87 BOOLEAN FloatingSave;
88
89 //
90 // DIRQL handling: automatic serialization of the DpcForIsr/WaitItemForIsr.
91 // Passive-level handling: automatic serialization of all callbacks.
92 //
93 BOOLEAN AutomaticSerialization;
94
95 //
96 // Event Callbacks
97 //
98 PFN_WDF_INTERRUPT_ISR EvtInterruptIsr;
99 PFN_WDF_INTERRUPT_DPC EvtInterruptDpc;
100 PFN_WDF_INTERRUPT_ENABLE EvtInterruptEnable;
101 PFN_WDF_INTERRUPT_DISABLE EvtInterruptDisable;
102 PFN_WDF_INTERRUPT_WORKITEM EvtInterruptWorkItem;
103
104 //
105 // These fields are only used when interrupt is created in
106 // EvtDevicePrepareHardware callback.
107 //
108 PCM_PARTIAL_RESOURCE_DESCRIPTOR InterruptRaw;
109 PCM_PARTIAL_RESOURCE_DESCRIPTOR InterruptTranslated;
110
111 //
112 // Optional passive lock for handling interrupts at passive-level.
113 //
114 WDFWAITLOCK WaitLock;
115
116 //
117 // TRUE: handle interrupt at passive-level.
118 // FALSE: handle interrupt at DIRQL level. This is the default.
119 //
120 BOOLEAN PassiveHandling;
121
122 } WDF_INTERRUPT_CONFIG_V1_11_BETA, *PWDF_INTERRUPT_CONFIG_V1_11_BETA;
123
124 //
125 // Interrupt Configuration Structure
126 //
127 typedef struct _WDF_INTERRUPT_CONFIG_V1_11 {
128 ULONG Size;
129
130 //
131 // If this interrupt is to be synchronized with other interrupt(s) assigned
132 // to the same WDFDEVICE, create a WDFSPINLOCK and assign it to each of the
133 // WDFINTERRUPTs config.
134 //
135 WDFSPINLOCK SpinLock;
136
137 WDF_TRI_STATE ShareVector;
138
139 BOOLEAN FloatingSave;
140
141 //
142 // DIRQL handling: automatic serialization of the DpcForIsr/WaitItemForIsr.
143 // Passive-level handling: automatic serialization of all callbacks.
144 //
145 BOOLEAN AutomaticSerialization;
146
147 //
148 // Event Callbacks
149 //
150 PFN_WDF_INTERRUPT_ISR EvtInterruptIsr;
151 PFN_WDF_INTERRUPT_DPC EvtInterruptDpc;
152 PFN_WDF_INTERRUPT_ENABLE EvtInterruptEnable;
153 PFN_WDF_INTERRUPT_DISABLE EvtInterruptDisable;
154 PFN_WDF_INTERRUPT_WORKITEM EvtInterruptWorkItem;
155
156 //
157 // These fields are only used when interrupt is created in
158 // EvtDevicePrepareHardware callback.
159 //
160 PCM_PARTIAL_RESOURCE_DESCRIPTOR InterruptRaw;
161 PCM_PARTIAL_RESOURCE_DESCRIPTOR InterruptTranslated;
162
163 //
164 // Optional passive lock for handling interrupts at passive-level.
165 //
166 WDFWAITLOCK WaitLock;
167
168 //
169 // TRUE: handle interrupt at passive-level.
170 // FALSE: handle interrupt at DIRQL level. This is the default.
171 //
172 BOOLEAN PassiveHandling;
173
174 //
175 // TRUE: Interrupt is reported inactive on explicit power down
176 // instead of disconnecting it.
177 // FALSE: Interrupt is disconnected instead of reporting inactive
178 // on explicit power down.
179 // DEFAULT: Framework decides the right value.
180 //
181 WDF_TRI_STATE ReportInactiveOnPowerDown;
182
183 } WDF_INTERRUPT_CONFIG_V1_11, *PWDF_INTERRUPT_CONFIG_V1_11;
184
185 //
186 // extern "C" the entire file
187 //
188 extern "C" {
189
190 _Must_inspect_result_
__drv_maxIRQL(DISPATCH_LEVEL)191 __drv_maxIRQL(DISPATCH_LEVEL)
192 NTSTATUS
193 STDCALL
194 WDFEXPORT(WdfInterruptCreate)(
195 __in
196 PWDF_DRIVER_GLOBALS DriverGlobals,
197 __in
198 WDFDEVICE Device,
199 __in
200 PWDF_INTERRUPT_CONFIG Configuration,
201 __in_opt
202 PWDF_OBJECT_ATTRIBUTES Attributes,
203 __out
204 WDFINTERRUPT* Interrupt
205 )
206
207 /*++
208
209 Routine Description:
210
211 Create an Interrupt object along with its associated DpcForIsr.
212
213 Arguments:
214
215 Object - Handle to a WDFDEVICE or WDFQUEUE to associate the interrupt with.
216
217 pConfiguration - WDF_INTERRUPT_CONFIG structure.
218
219 pAttributes - Optional WDF_OBJECT_ATTRIBUTES to request a context
220 memory allocation, and a DestroyCallback.
221
222 pInterrupt - Pointer to location to return the resulting WDFINTERRUPT handle.
223
224 Returns:
225
226 STATUS_SUCCESS - A WDFINTERRUPT handle has been created.
227
228 --*/
229
230 {
231 DDI_ENTRY();
232
233 PFX_DRIVER_GLOBALS pFxDriverGlobals;
234 FxInterrupt* pFxInterrupt;
235 FxDevice* pDevice;
236 FxObject* pParent;
237 NTSTATUS status;
238 WDF_DEVICE_PNP_STATE devicePnpState;
239 ULONG expectedConfigSize;
240 WDF_INTERRUPT_CONFIG intConfig;
241
242 FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
243 Device,
244 FX_TYPE_DEVICE,
245 (PVOID*)&pDevice,
246 &pFxDriverGlobals);
247
248 FxPointerNotNull(pFxDriverGlobals, Configuration);
249 FxPointerNotNull(pFxDriverGlobals, Interrupt);
250
251 if (pFxDriverGlobals->IsVersionGreaterThanOrEqualTo(1,13)) {
252 expectedConfigSize = sizeof(WDF_INTERRUPT_CONFIG);
253 } else if (pFxDriverGlobals->IsVersionGreaterThanOrEqualTo(1,11)) {
254 expectedConfigSize = sizeof(WDF_INTERRUPT_CONFIG_V1_11);
255 } else {
256 expectedConfigSize = sizeof(WDF_INTERRUPT_CONFIG_V1_9);
257 }
258
259
260 //
261 // We could check if Configuration->Size != expectedConfigSize, but
262 // logic below allows me to installing old WDF drivers v1.11 on new WDF.
263 //
264 if (Configuration->Size != sizeof(WDF_INTERRUPT_CONFIG) &&
265 Configuration->Size != sizeof(WDF_INTERRUPT_CONFIG_V1_11) &&
266 Configuration->Size != sizeof(WDF_INTERRUPT_CONFIG_V1_11_BETA) &&
267 Configuration->Size != sizeof(WDF_INTERRUPT_CONFIG_V1_9)) {
268
269 DoTraceLevelMessage(
270 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
271 "WDF_INTERRUPT_CONFIG size 0x%x incorrect, expected 0x%x",
272 Configuration->Size, expectedConfigSize);
273
274 return STATUS_INFO_LENGTH_MISMATCH;
275 }
276
277 //
278 // Normalize WDF_INTERRUPT_CONFIG structure.
279 //
280 if (Configuration->Size < sizeof(WDF_INTERRUPT_CONFIG)) {
281 //
282 // Init new fields to default values.
283 //
284 WDF_INTERRUPT_CONFIG_INIT(&intConfig,
285 Configuration->EvtInterruptIsr,
286 Configuration->EvtInterruptDpc);
287 //
288 // Copy over existing fields and readjust the struct size.
289 //
290 RtlCopyMemory(&intConfig, Configuration, Configuration->Size);
291 intConfig.Size = sizeof(intConfig);
292
293 //
294 // Use new config structure from now on.
295 //
296 Configuration = &intConfig;
297 }
298
299 //
300 // Parameter validation.
301 //
302
303 #if (FX_CORE_MODE == FX_CORE_USER_MODE)
304 //
305 // Ensure access to interrupts is allowed
306 //
307 FX_VERIFY_WITH_NAME(DRIVER(BadArgument, TODO),
308 CHECK(ERROR_STRING_HW_ACCESS_NOT_ALLOWED,
309 (pDevice->IsInterruptAccessAllowed() == TRUE)),
310 DriverGlobals->DriverName);
311
312 //
313 // PassiveHandling member must be set to TRUE. INIT macro does that for
314 // UMDF. This check ensures the field is not overriden by caller.
315 //
316 FX_VERIFY_WITH_NAME(DRIVER(BadArgument, TODO),
317 CHECK("PassiveHandling not set to TRUE in WDF_INTERRUPT_CONFIG structure",
318 (Configuration->PassiveHandling == TRUE)),
319 DriverGlobals->DriverName);
320 #endif
321
322 if (Configuration->EvtInterruptIsr == NULL) {
323 DoTraceLevelMessage(
324 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
325 "NULL EvtInterruptIsr in WDF_INTERRUPT_CONFIG structure 0x%p"
326 " passed", Configuration);
327 return STATUS_INVALID_PARAMETER;
328 }
329
330 //
331 // Driver can specify a parent only in the AutomaticSerialization case.
332 //
333 status = FxValidateObjectAttributes(
334 pFxDriverGlobals,
335 Attributes,
336 Configuration->AutomaticSerialization ?
337 FX_VALIDATE_OPTION_NONE_SPECIFIED :
338 FX_VALIDATE_OPTION_PARENT_NOT_ALLOWED);
339 if (!NT_SUCCESS(status)) {
340 return status;
341 }
342
343 if (Attributes != NULL && Attributes->ParentObject != NULL) {
344 FxObjectHandleGetPtr(pFxDriverGlobals,
345 Attributes->ParentObject,
346 FX_TYPE_OBJECT,
347 (PVOID*)&pParent);
348 }
349 else {
350 pParent = (FxObject*)pDevice;
351 }
352
353 devicePnpState = pDevice->GetDevicePnpState();
354
355 if (devicePnpState != WdfDevStatePnpInit &&
356 0x0 == (pDevice->GetCallbackFlags() &
357 FXDEVICE_CALLBACK_IN_PREPARE_HARDWARE)) {
358
359 status = STATUS_INVALID_DEVICE_STATE;
360
361 DoTraceLevelMessage(
362 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
363 "WDFINTERRUPTs can only be created during: "
364 "(1) EvtDriverDeviceAdd when the WDFDEVICE %p is initially created, or "
365 "(2) EvtDevicePrepareHardware, %!STATUS!", Device, status);
366
367 return status;
368 }
369
370 //
371 // Interrupts created in EvtDriverDeviceAdd must not specify any
372 // CM resources b/c driver doesn't known them yet.
373 //
374 if (devicePnpState == WdfDevStatePnpInit) {
375
376 if (Configuration->InterruptRaw != NULL ||
377 Configuration->InterruptTranslated != NULL) {
378
379 status = STATUS_INVALID_PARAMETER;
380
381 DoTraceLevelMessage(
382 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
383 "Not NULL InterruptRaw or InterruptTranslated in "
384 "WDF_INTERRUPT_CONFIG structure 0x%p passed, %!STATUS!",
385 Configuration, status);
386
387 return status;
388 }
389
390 //
391 // Wake Interrupts can not be created in AddDevice as it is
392 // not known if they are actually marked as wake capable
393 //
394 if (Configuration->CanWakeDevice) {
395 status = STATUS_INVALID_PARAMETER;
396
397 DoTraceLevelMessage(
398 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
399 "CanWakeDevice set in WDF_INTERRUPT_CONFIG structure 0x%p"
400 "during EvtDriverDeviceAdd, %!STATUS!",
401 Configuration, status);
402
403 return status;
404 }
405 }
406
407 //
408 // Checks for interrupt created in EvtDevicePrepareHardware.
409 //
410 if (devicePnpState != WdfDevStatePnpInit) {
411 //
412 // CM resources must be specified.
413 //
414 if (Configuration->InterruptRaw == NULL ||
415 Configuration->InterruptTranslated == NULL) {
416
417 status = STATUS_INVALID_DEVICE_STATE;
418
419 DoTraceLevelMessage(
420 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
421 "NULL InterruptRaw or InterruptTranslated in "
422 "WDF_INTERRUPT_CONFIG structure 0x%p passed, %!STATUS!",
423 Configuration, status);
424
425 return status;
426 }
427
428 //
429 // Share vector must be default.
430 //
431 if (Configuration->ShareVector != WdfUseDefault) {
432 status = STATUS_INVALID_DEVICE_STATE;
433
434 DoTraceLevelMessage(
435 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
436 "Driver cannot specify ShareVector different from "
437 "WdfUseDefault in EvtDevicePrepareHardware callback,"
438 "WDF_INTERRUPT_CONFIG structure 0x%p passed, %!STATUS!",
439 Configuration, status);
440
441 return status;
442 }
443
444 }
445
446 if (Configuration->CanWakeDevice) {
447 if (FxInterrupt::_IsWakeHintedInterrupt(
448 Configuration->InterruptTranslated->Flags) == FALSE) {
449
450 status = STATUS_INVALID_PARAMETER;
451 DoTraceLevelMessage(
452 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
453 "Driver cannot specify an interrupt as CanWakeDevice if "
454 "the CM_RESOURCE_INTERRUPT_WAKE_HINT is not present."
455 "WDF_INTERRUPT_CONFIG structure 0x%p passed, %!STATUS!",
456 Configuration, status);
457
458 return status;
459 }
460
461 //
462 // Driver is allowed to create wake interrupt only if it
463 // is the power policy owner so that the we can wake the
464 // stack when the interrupt fires
465 //
466 if (pDevice->m_PkgPnp->IsPowerPolicyOwner() == FALSE) {
467 status = STATUS_INVALID_PARAMETER;
468 DoTraceLevelMessage(
469 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
470 "Driver cannot specify an interrupt as CanWakeDevice if "
471 "it is not power policy powner. WDF_INTERRUPT_CONFIG "
472 "structure 0x%p passed, %!STATUS!",
473 Configuration, status);
474
475 return status;
476 }
477
478 //
479 // Declaring an interrupt as wake capable allows it to
480 // take ownership of interrupt from ACPI. It does not
481 // make sense for a PDO
482 //
483 if (pDevice->IsPdo()) {
484 status = STATUS_INVALID_PARAMETER;
485 DoTraceLevelMessage(
486 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
487 "Driver cannot specify an interrupt as CanWakeDevice for a PDO "
488 "WDF_INTERRUPT_CONFIG structure 0x%p passed, %!STATUS!",
489 Configuration, status);
490
491 return status;
492 }
493 }
494
495 if (Configuration->EvtInterruptDpc != NULL &&
496 Configuration->EvtInterruptWorkItem != NULL) {
497 status = STATUS_INVALID_PARAMETER;
498 DoTraceLevelMessage(
499 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
500 "Driver can provide either EvtInterruptDpc or "
501 "EvtInterruptWorkItem callback but not both. "
502 "WDF_INTERRUPT_CONFIG structure 0x%p passed, %!STATUS!",
503 Configuration, status);
504
505 return status;
506 }
507
508 if (Configuration->PassiveHandling == FALSE) {
509 //
510 // DIRQL handling validations.
511 //
512 if (Configuration->WaitLock) {
513 status = STATUS_INVALID_PARAMETER;
514 DoTraceLevelMessage(
515 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
516 "Driver cannot specify WaitLock when handling interrupts at "
517 "DIRQL, WDF_INTERRUPT_CONFIG structure 0x%p passed, %!STATUS!",
518 Configuration, status);
519
520 return status;
521 }
522 //
523 // Wake interrupts should be passive level so that the stack
524 // can be sychronously bring the device back to D0 form within
525 // the ISR
526 //
527 if (Configuration->CanWakeDevice) {
528 status = STATUS_INVALID_PARAMETER;
529
530 DoTraceLevelMessage(
531 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
532 "CanWakeDevice set in WDF_INTERRUPT_CONFIG structure for an"
533 "interrupt not marked as passive 0x%p, %!STATUS!",
534 Configuration, status);
535
536 return status;
537 }
538 }
539 else {
540 //
541 // Passive-level handling validations.
542 //
543 if (FxIsPassiveLevelInterruptSupported() == FALSE) {
544 status = STATUS_NOT_SUPPORTED;
545 DoTraceLevelMessage(
546 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
547 "The current version of Windows does not support the handling "
548 "of interrupts at passive-level, WDF_INTERRUPT_CONFIG "
549 "structure 0x%p passed, %!STATUS!", Configuration, status);
550
551 return status;
552 }
553
554 if (Configuration->SpinLock) {
555 status = STATUS_INVALID_PARAMETER;
556 DoTraceLevelMessage(
557 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
558 "Driver cannot specify SpinLock when handling interrupts at "
559 "passive-level, WDF_INTERRUPT_CONFIG structure 0x%p passed, "
560 "%!STATUS!", Configuration, status);
561
562 return status;
563 }
564
565
566 //
567 // For UMDF reflector decides whether to handle the interrupt
568 // at passive or DIRQL. Driver has no choice. Therefore this check
569 // is applicable only for KMDF.
570 //
571 #if (FX_CORE_MODE == FX_CORE_KERNEL_MODE)
572 if (Configuration->InterruptTranslated != NULL &&
573 FxInterrupt::_IsMessageInterrupt(
574 Configuration->InterruptTranslated->Flags)) {
575 status = STATUS_INVALID_PARAMETER;
576 DoTraceLevelMessage(
577 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
578 "Driver cannot specify PassiveHandling for MSI interrupts, "
579 "WDF_INTERRUPT_CONFIG structure 0x%p passed, %!STATUS!",
580 Configuration, status);
581
582 return status;
583 }
584 #endif
585 }
586
587 //
588 // Make sure the specified resources are valid.
589 // Do this check only under verifier b/c if the driver has a lot of
590 // interrupts/resources, this verification can slow down power up.
591 // Note that if InterruptRaw is != NULL, it implies that
592 // InterruptTranslated is != NULL from the checks above.
593 //
594 if (pFxDriverGlobals->FxVerifierOn) {
595 if (Configuration->InterruptRaw != NULL ) {
596 status = pDevice->m_PkgPnp->ValidateInterruptResourceCm(
597 Configuration->InterruptRaw,
598 Configuration->InterruptTranslated,
599 Configuration);
600 if (!NT_SUCCESS(status)) {
601 return status;
602 }
603 }
604 }
605
606 status = FxInterrupt::_CreateAndInit(
607 pFxDriverGlobals,
608 pDevice,
609 pParent,
610 Attributes,
611 Configuration,
612 &pFxInterrupt);
613
614 if (NT_SUCCESS(status)) {
615 *Interrupt = (WDFINTERRUPT) pFxInterrupt->GetObjectHandle();
616 }
617
618 return status;
619 }
620
621 BOOLEAN
622 STDCALL
WDFEXPORT(WdfInterruptQueueDpcForIsr)623 WDFEXPORT(WdfInterruptQueueDpcForIsr)(
624 __in
625 PWDF_DRIVER_GLOBALS DriverGlobals,
626 __in
627 WDFINTERRUPT Interrupt
628 )
629
630 /*++
631
632 Routine Description:
633
634 Queue the DPC for the ISR
635
636 Arguments:
637
638 Interrupt - Handle to WDFINTERUPT object created with WdfInterruptCreate.
639
640 Returns:
641
642 TRUE - If the DPC has been enqueued.
643
644 FALSE - If the DPC has already been enqueued.
645
646 --*/
647
648 {
649 DDI_ENTRY();
650
651 FxInterrupt* pFxInterrupt;
652
653 FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
654 Interrupt,
655 FX_TYPE_INTERRUPT,
656 (PVOID*)&pFxInterrupt);
657
658 return pFxInterrupt->QueueDeferredRoutineForIsr();
659 }
660
661 BOOLEAN
662 STDCALL
WDFEXPORT(WdfInterruptQueueWorkItemForIsr)663 WDFEXPORT(WdfInterruptQueueWorkItemForIsr)(
664 __in
665 PWDF_DRIVER_GLOBALS DriverGlobals,
666 __in
667 WDFINTERRUPT Interrupt
668 )
669
670 /*++
671
672 Routine Description:
673
674 Queue the interrupt's work-item for the ISR.
675
676 Arguments:
677
678 Interrupt - Handle to WDFINTERUPT object created with WdfInterruptCreate.
679
680 Returns:
681
682 TRUE - If the work-item has been enqueued.
683
684 FALSE - If the work-item has already been enqueued.
685
686
687 --*/
688
689 {
690 DDI_ENTRY();
691
692 FxInterrupt* pFxInterrupt;
693
694 FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
695 Interrupt,
696 FX_TYPE_INTERRUPT,
697 (PVOID*)&pFxInterrupt);
698
699 return pFxInterrupt->QueueWorkItemForIsr();
700 }
701
__drv_maxIRQL(DISPATCH_LEVEL)702 __drv_maxIRQL(DISPATCH_LEVEL)
703 BOOLEAN
704 STDCALL
705 WDFEXPORT(WdfInterruptSynchronize)(
706 __in
707 PWDF_DRIVER_GLOBALS DriverGlobals,
708 __in
709 WDFINTERRUPT Interrupt,
710 __in
711 PFN_WDF_INTERRUPT_SYNCHRONIZE Callback,
712 __in
713 WDFCONTEXT Context
714 )
715
716 /*++
717
718 Routine Description:
719
720 Synchronize execution with the interrupt handler
721
722 Arguments:
723
724 Interrupt - Handle to WDFINTERUPT object created with WdfInterruptCreate.
725
726 Callback - PWDF_INTERRUPT_SYNCHRONIZE callback function to invoke
727
728 Context - Context to pass to the PFN_WDF_INTERRUPT_SYNCHRONIZE callback
729
730 Returns:
731
732 BOOLEAN result from user PFN_WDF_INTERRUPT_SYNCHRONIZE callback
733
734 --*/
735
736 {
737 DDI_ENTRY();
738
739 FxInterrupt* pFxInterrupt;
740 NTSTATUS status;
741
742 FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
743 Interrupt,
744 FX_TYPE_INTERRUPT,
745 (PVOID*)&pFxInterrupt);
746
747 if (pFxInterrupt->IsPassiveHandling()) {
748 status = FxVerifierCheckIrqlLevel(pFxInterrupt->GetDriverGlobals(),
749 PASSIVE_LEVEL);
750 if (!NT_SUCCESS(status)) {
751 return FALSE;
752 }
753 }
754
755 FxPointerNotNull(pFxInterrupt->GetDriverGlobals(), Callback);
756
757 return pFxInterrupt->Synchronize(Callback, Context);
758 }
759
__drv_maxIRQL(DISPATCH_LEVEL)760 __drv_maxIRQL(DISPATCH_LEVEL)
761 VOID
762 STDCALL
763 WDFEXPORT(WdfInterruptAcquireLock)(
764 __in
765 PWDF_DRIVER_GLOBALS DriverGlobals,
766 __in
767 _Requires_lock_not_held_(_Curr_)
768 _Acquires_lock_(_Curr_)
769 WDFINTERRUPT Interrupt
770 )
771
772 /*++
773
774 Routine Description:
775
776 Begin synchronization to the interrupts IRQL level
777
778 Arguments:
779
780 Interrupt - Handle to WDFINTERUPT object created with WdfInterruptCreate.
781
782 Returns:
783
784 --*/
785
786 {
787 DDI_ENTRY();
788
789 FxInterrupt* pFxInterrupt;
790 NTSTATUS status;
791
792 FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
793 Interrupt,
794 FX_TYPE_INTERRUPT,
795 (PVOID*)&pFxInterrupt);
796
797 if (pFxInterrupt->IsPassiveHandling()) {
798 status = FxVerifierCheckIrqlLevel(pFxInterrupt->GetDriverGlobals(),
799 PASSIVE_LEVEL);
800 if (!NT_SUCCESS(status)) {
801 return;
802 }
803 }
804
805 pFxInterrupt->AcquireLock();
806 }
807
808 __drv_maxIRQL(DISPATCH_LEVEL + 1)
809 VOID
810 STDCALL
WDFEXPORT(WdfInterruptReleaseLock)811 WDFEXPORT(WdfInterruptReleaseLock)(
812 __in
813 PWDF_DRIVER_GLOBALS DriverGlobals,
814 __in
815 _Requires_lock_held_(_Curr_)
816 _Releases_lock_(_Curr_)
817 WDFINTERRUPT Interrupt
818 )
819
820 /*++
821
822 Routine Description:
823
824 End synchronization to the interrupts IRQL level
825
826 Arguments:
827
828 Interrupt - Handle to WDFINTERUPT object created with WdfInterruptCreate.
829
830 Returns:
831
832 --*/
833
834 {
835 DDI_ENTRY();
836
837 FxInterrupt* pFxInterrupt;
838 NTSTATUS status;
839
840 FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
841 Interrupt,
842 FX_TYPE_INTERRUPT,
843 (PVOID*)&pFxInterrupt);
844
845 if (pFxInterrupt->IsPassiveHandling()) {
846 status = FxVerifierCheckIrqlLevel(pFxInterrupt->GetDriverGlobals(),
847 PASSIVE_LEVEL);
848 if (!NT_SUCCESS(status)) {
849 return;
850 }
851 }
852
853 pFxInterrupt->ReleaseLock();
854 }
855
__drv_maxIRQL(PASSIVE_LEVEL)856 __drv_maxIRQL(PASSIVE_LEVEL)
857 VOID
858 STDCALL
859 WDFEXPORT(WdfInterruptEnable)(
860 __in
861 PWDF_DRIVER_GLOBALS DriverGlobals,
862 __in
863 WDFINTERRUPT Interrupt
864 )
865
866 /*++
867
868 Routine Description:
869
870 Request that the interrupt be enabled in the hardware.
871
872 Arguments:
873
874 Interrupt - Handle to WDFINTERUPT object created with WdfInterruptCreate.
875
876 Returns:
877
878 --*/
879
880 {
881 DDI_ENTRY();
882
883 FxInterrupt* pFxInterrupt;
884 NTSTATUS status;
885
886 FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
887 Interrupt,
888 FX_TYPE_INTERRUPT,
889 (PVOID*)&pFxInterrupt);
890
891 status = FxVerifierCheckIrqlLevel(pFxInterrupt->GetDriverGlobals(),
892 PASSIVE_LEVEL);
893 if (!NT_SUCCESS(status)) {
894 return;
895 }
896
897 //
898 // Okay to ignore error status. Called function prints error messages.
899 //
900 (VOID) pFxInterrupt->ForceReconnect();
901 }
902
__drv_maxIRQL(PASSIVE_LEVEL)903 __drv_maxIRQL(PASSIVE_LEVEL)
904 VOID
905 STDCALL
906 WDFEXPORT(WdfInterruptDisable)(
907 __in
908 PWDF_DRIVER_GLOBALS DriverGlobals,
909 __in
910 WDFINTERRUPT Interrupt
911 )
912
913 /*++
914
915 Routine Description:
916
917 Request that the interrupt be disabled in the hardware.
918
919 Arguments:
920
921 Interrupt - Handle to WDFINTERUPT object created with WdfInterruptCreate.
922
923 Returns:
924
925 --*/
926
927 {
928 DDI_ENTRY();
929
930 FxInterrupt* pFxInterrupt;
931 NTSTATUS status;
932
933 FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
934 Interrupt,
935 FX_TYPE_INTERRUPT,
936 (PVOID*)&pFxInterrupt);
937
938 status = FxVerifierCheckIrqlLevel(pFxInterrupt->GetDriverGlobals(),
939 PASSIVE_LEVEL);
940 if (!NT_SUCCESS(status)) {
941 return;
942 }
943
944 //
945 // Okay to ignore error status. Called function prints error messages.
946 //
947 (VOID) pFxInterrupt->ForceDisconnect();
948 }
949
950 _Must_inspect_result_
951 struct _KINTERRUPT*
952 STDCALL
WDFEXPORT(WdfInterruptWdmGetInterrupt)953 WDFEXPORT(WdfInterruptWdmGetInterrupt)(
954 __in
955 PWDF_DRIVER_GLOBALS DriverGlobals,
956 __in
957 WDFINTERRUPT Interrupt
958 )
959
960 /*++
961
962 Routine Description:
963
964 Return the WDM _KINTERRUPT*
965
966 Arguments:
967
968 Interrupt - Handle to WDFINTERUPT object created with WdfInterruptCreate.
969
970 Returns:
971
972 --*/
973
974 {
975 DDI_ENTRY();
976
977 FxInterrupt* pFxInterrupt;
978
979 FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
980 Interrupt,
981 FX_TYPE_INTERRUPT,
982 (PVOID*)&pFxInterrupt);
983
984 return pFxInterrupt->GetInterruptPtr();
985 }
986
__drv_maxIRQL(DISPATCH_LEVEL)987 __drv_maxIRQL(DISPATCH_LEVEL)
988 VOID
989 STDCALL
990 WDFEXPORT(WdfInterruptGetInfo)(
991 __in
992 PWDF_DRIVER_GLOBALS DriverGlobals,
993 __in
994 WDFINTERRUPT Interrupt,
995 __out
996 PWDF_INTERRUPT_INFO Info
997 )
998
999 /*++
1000
1001 Routine Description:
1002
1003 Return the WDF_INTERRUPT_INFO that describes this
1004 particular Message Signaled Interrupt MessageID.
1005
1006 Arguments:
1007
1008 Interrupt - Handle to WDFINTERUPT object created with WdfInterruptCreate.
1009
1010 Returns:
1011 Nothing
1012
1013 --*/
1014 {
1015 DDI_ENTRY();
1016
1017 PFX_DRIVER_GLOBALS pFxDriverGlobals = NULL;
1018 FxInterrupt* pFxInterrupt = NULL;
1019 ULONG size = 0;
1020
1021 FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
1022 Interrupt,
1023 FX_TYPE_INTERRUPT,
1024 (PVOID*)&pFxInterrupt,
1025 &pFxDriverGlobals);
1026
1027 FxPointerNotNull(pFxDriverGlobals, Info);
1028
1029 if (sizeof(WDF_INTERRUPT_INFO_V1_7) == Info->Size) {
1030 size = sizeof(WDF_INTERRUPT_INFO_V1_7);
1031 }
1032 else if (sizeof(WDF_INTERRUPT_INFO) == Info->Size) {
1033 size = sizeof(WDF_INTERRUPT_INFO);
1034 }
1035 else {
1036 DoTraceLevelMessage(
1037 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
1038 "WDF_INTERRUPT_INFO %p Size %d invalid, expected %d",
1039 Interrupt, Info->Size, sizeof(WDF_INTERRUPT_INFO));
1040 FxVerifierDbgBreakPoint(pFxDriverGlobals);
1041 return;
1042 }
1043
1044 RtlCopyMemory(Info, pFxInterrupt->GetInfo(), size);
1045
1046 Info->Size = size;
1047 }
1048
1049 WDFDEVICE
1050 STDCALL
WDFEXPORT(WdfInterruptGetDevice)1051 WDFEXPORT(WdfInterruptGetDevice)(
1052 __in
1053 PWDF_DRIVER_GLOBALS DriverGlobals,
1054 __in
1055 WDFINTERRUPT Interrupt
1056 )
1057
1058 /*++
1059
1060 Routine Description:
1061
1062 Get the device that the interrupt is related to.
1063
1064 Arguments:
1065
1066 Interrupt - Handle to WDFINTERUPT object created with WdfInterruptCreate.
1067
1068 Returns:
1069
1070 WDFDEVICE
1071
1072 --*/
1073
1074 {
1075 DDI_ENTRY();
1076
1077 FxInterrupt* pFxInterrupt;
1078
1079 FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
1080 Interrupt,
1081 FX_TYPE_INTERRUPT,
1082 (PVOID*)&pFxInterrupt);
1083
1084 return pFxInterrupt->GetDevice()->GetHandle();
1085 }
1086
__drv_maxIRQL(DISPATCH_LEVEL)1087 __drv_maxIRQL(DISPATCH_LEVEL)
1088 VOID
1089 STDCALL
1090 WDFEXPORT(WdfInterruptSetPolicy)(
1091 __in
1092 PWDF_DRIVER_GLOBALS DriverGlobals,
1093 __in
1094 WDFINTERRUPT Interrupt,
1095 __in
1096 WDF_INTERRUPT_POLICY Policy,
1097 __in
1098 WDF_INTERRUPT_PRIORITY Priority,
1099 __in
1100 KAFFINITY TargetProcessorSet
1101 )
1102
1103 /*++
1104
1105 Routine Description:
1106
1107 Interrupts have attributes that a driver might want to influence. This
1108 routine tells the Framework to tell the PnP manager what the driver would
1109 prefer.
1110
1111 Arguments:
1112
1113 Interrupt - Handle to WDFINTERUPT object created with WdfInterruptCreate.
1114
1115 Returns:
1116
1117 NTSTATUS
1118
1119 --*/
1120
1121 {
1122 DDI_ENTRY();
1123
1124 PFX_DRIVER_GLOBALS pFxDriverGlobals = NULL;
1125 FxInterrupt* pFxInterrupt = NULL;
1126 GROUP_AFFINITY processorSet;
1127
1128 FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
1129 Interrupt,
1130 FX_TYPE_INTERRUPT,
1131 (PVOID*)&pFxInterrupt,
1132 &pFxDriverGlobals);
1133
1134 if (Policy < WdfIrqPolicyMachineDefault ||
1135 Policy > WdfIrqPolicySpreadMessagesAcrossAllProcessors) {
1136 DoTraceLevelMessage(
1137 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
1138 "Policy %d is out of range", Policy);
1139 FxVerifierDbgBreakPoint(pFxDriverGlobals);
1140 return;
1141 }
1142
1143 if (Priority < WdfIrqPriorityLow || Priority > WdfIrqPriorityHigh) {
1144 DoTraceLevelMessage(
1145 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
1146 "Priority %d is out of range", Priority);
1147 FxVerifierDbgBreakPoint(pFxDriverGlobals);
1148 return;
1149 }
1150
1151 RtlZeroMemory(&processorSet, sizeof(processorSet));
1152 processorSet.Mask = TargetProcessorSet;
1153
1154 pFxInterrupt->SetPolicy(Policy, Priority, &processorSet);
1155 }
1156
__drv_maxIRQL(DISPATCH_LEVEL)1157 __drv_maxIRQL(DISPATCH_LEVEL)
1158 VOID
1159 STDCALL
1160 WDFEXPORT(WdfInterruptSetExtendedPolicy)(
1161 __in
1162 PWDF_DRIVER_GLOBALS DriverGlobals,
1163 __in
1164 WDFINTERRUPT Interrupt,
1165 __in
1166 PWDF_INTERRUPT_EXTENDED_POLICY PolicyAndGroup
1167 )
1168
1169 /*++
1170
1171 Routine Description:
1172
1173 Interrupts have attributes that a driver might want to influence. This
1174 routine tells the Framework to tell the PnP manager what the driver would
1175 prefer.
1176
1177 Arguments:
1178
1179 Interrupt - Handle to WDFINTERUPT object created with WdfInterruptCreate.
1180
1181 PolicyAndGroup - Driver preference for policy, priority and group affinity.
1182
1183 Returns:
1184
1185 NTSTATUS
1186
1187 --*/
1188
1189 {
1190 DDI_ENTRY();
1191
1192 PFX_DRIVER_GLOBALS pFxDriverGlobals = NULL;
1193 FxInterrupt* pFxInterrupt = NULL;
1194 PGROUP_AFFINITY processorSet = NULL;
1195 WDF_INTERRUPT_POLICY policy;
1196 WDF_INTERRUPT_PRIORITY priority;
1197
1198 FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
1199 Interrupt,
1200 FX_TYPE_INTERRUPT,
1201 (PVOID*)&pFxInterrupt,
1202 &pFxDriverGlobals);
1203
1204 if (PolicyAndGroup->Size != sizeof(WDF_INTERRUPT_EXTENDED_POLICY)) {
1205 DoTraceLevelMessage(
1206 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
1207 "WDF_INTERRUPT_EXTENDED_POLICY %p Size %d invalid, expected %d",
1208 PolicyAndGroup,
1209 PolicyAndGroup->Size,
1210 sizeof(WDF_INTERRUPT_EXTENDED_POLICY));
1211 FxVerifierDbgBreakPoint(pFxDriverGlobals);
1212 return;
1213 }
1214
1215 policy = PolicyAndGroup->Policy;
1216 priority = PolicyAndGroup->Priority;
1217 processorSet = &PolicyAndGroup->TargetProcessorSetAndGroup;
1218
1219 if (policy < WdfIrqPolicyMachineDefault ||
1220 policy > WdfIrqPolicySpreadMessagesAcrossAllProcessors) {
1221 DoTraceLevelMessage(
1222 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
1223 "Policy %d is out of range", policy);
1224 FxVerifierDbgBreakPoint(pFxDriverGlobals);
1225 return;
1226 }
1227
1228 if (priority < WdfIrqPriorityLow || priority > WdfIrqPriorityHigh) {
1229 DoTraceLevelMessage(
1230 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
1231 "Priority %d is out of range", priority);
1232 FxVerifierDbgBreakPoint(pFxDriverGlobals);
1233 return;
1234 }
1235
1236 if (processorSet->Reserved[0] != 0 || processorSet->Reserved[1] != 0 ||
1237 processorSet->Reserved[2] != 0) {
1238 DoTraceLevelMessage(
1239 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
1240 "TargetProcessorSet's reserved fields are not zero");
1241 FxVerifierDbgBreakPoint(pFxDriverGlobals);
1242 return;
1243 }
1244
1245 pFxInterrupt->SetPolicy(policy, priority, processorSet);
1246 }
1247
1248 _Must_inspect_result_
_IRQL_requires_max_(PASSIVE_LEVEL)1249 _IRQL_requires_max_(PASSIVE_LEVEL)
1250 _Post_satisfies_(return == 1 || return == 0)
1251 BOOLEAN
1252 STDCALL
1253 WDFEXPORT(WdfInterruptTryToAcquireLock)(
1254 __in
1255 PWDF_DRIVER_GLOBALS DriverGlobals,
1256 __in
1257 _Requires_lock_not_held_(_Curr_)
1258 _When_(return!=0, _Acquires_lock_(_Curr_))
1259 WDFINTERRUPT Interrupt
1260 )
1261
1262 /*++
1263
1264 Routine Description:
1265
1266 Try to acquire the interrupt's passive-lock.
1267
1268 Arguments:
1269
1270 Interrupt - Handle to WDFINTERUPT object created with WdfInterruptCreate.
1271
1272 Returns:
1273
1274 TRUE: function was able to successfully acquire the lock.
1275
1276 FALSE: function was unable to acquire the lock.
1277
1278 --*/
1279
1280 {
1281 DDI_ENTRY();
1282
1283 FxInterrupt* pFxInterrupt;
1284 NTSTATUS status;
1285
1286 FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
1287 Interrupt,
1288 FX_TYPE_INTERRUPT,
1289 (PVOID*)&pFxInterrupt);
1290
1291 if (pFxInterrupt->GetDriverGlobals()->FxVerifierOn) {
1292 if (pFxInterrupt->IsPassiveHandling() == FALSE) {
1293 DoTraceLevelMessage(
1294 pFxInterrupt->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
1295 "WDFINTERRUPT %p is handled at DIRQL. This API is not "
1296 "available for DIQRL interrupt handling.",
1297 Interrupt);
1298 FxVerifierDbgBreakPoint(pFxInterrupt->GetDriverGlobals());
1299 return FALSE;
1300 }
1301
1302 status = FxVerifierCheckIrqlLevel(pFxInterrupt->GetDriverGlobals(),
1303 PASSIVE_LEVEL);
1304 if (!NT_SUCCESS(status)) {
1305 return FALSE;
1306 }
1307 }
1308
1309 return pFxInterrupt->TryToAcquireLock();
1310 }
1311
__drv_maxIRQL(DISPATCH_LEVEL)1312 __drv_maxIRQL(DISPATCH_LEVEL)
1313 VOID
1314 STDCALL
1315 WDFEXPORT(WdfInterruptReportActive)(
1316 _In_
1317 PWDF_DRIVER_GLOBALS DriverGlobals,
1318 _In_
1319 WDFINTERRUPT Interrupt
1320 )
1321
1322 /*++
1323
1324 Routine Description:
1325
1326 This DDI informs the system that the interrupt is active and expecting
1327 interrupt requests on the associated lines. This is typically called after
1328 having reported the lines as inactive via WdfInterruptReportInactive.
1329 The DDI doesn't do anything if this DDI is called before
1330 WdfInterruptReportInactive while the interrupt is connected.
1331
1332 Arguments:
1333
1334 Interrupt - Handle to WDFINTERUPT object created with WdfInterruptCreate.
1335
1336 Returns:
1337
1338 VOID
1339
1340 --*/
1341 {
1342 DDI_ENTRY();
1343
1344 PFX_DRIVER_GLOBALS pFxDriverGlobals = NULL;
1345 FxInterrupt* pFxInterrupt = NULL;
1346
1347 FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
1348 Interrupt,
1349 FX_TYPE_INTERRUPT,
1350 (PVOID*)&pFxInterrupt,
1351 &pFxDriverGlobals);
1352
1353 pFxInterrupt->ReportActive();
1354
1355 return;
1356 }
1357
__drv_maxIRQL(DISPATCH_LEVEL)1358 __drv_maxIRQL(DISPATCH_LEVEL)
1359 VOID
1360 STDCALL
1361 WDFEXPORT(WdfInterruptReportInactive)(
1362 _In_
1363 PWDF_DRIVER_GLOBALS DriverGlobals,
1364 _In_
1365 WDFINTERRUPT Interrupt
1366 )
1367
1368 /*++
1369
1370 Routine Description:
1371
1372 This DDI informs the system that the the interrupt is no longer active
1373 and is not expecting interrupt requests on the associated lines.
1374
1375 Arguments:
1376
1377 Interrupt - Handle to WDFINTERUPT object created with WdfInterruptCreate.
1378
1379 Returns:
1380
1381 VOID
1382
1383 --*/
1384 {
1385 DDI_ENTRY();
1386
1387 PFX_DRIVER_GLOBALS pFxDriverGlobals = NULL;
1388 FxInterrupt* pFxInterrupt = NULL;
1389
1390 FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
1391 Interrupt,
1392 FX_TYPE_INTERRUPT,
1393 (PVOID*)&pFxInterrupt,
1394 &pFxDriverGlobals);
1395
1396 pFxInterrupt->ReportInactive();
1397
1398 return;
1399 }
1400
1401 } // extern "C"
1402