1 /*++
2
3 Copyright (c) Microsoft Corporation
4
5 Module Name:
6
7 InterruptObjectUm.cpp
8
9 Abstract:
10
11 This module implements a frameworks managed interrupt object
12
13 Author:
14
15 Environment:
16
17 User mode only
18
19 Revision History:
20
21
22
23 --*/
24
25 #include "fxmin.hpp"
26 #include "FxInterruptThreadpoolUm.hpp"
27
28 extern "C" {
29 #include "InterruptObjectUm.tmh"
30 }
31
32 #define STRSAFE_LIB
33 #include <strsafe.h>
34
35 _Must_inspect_result_
36 NTSTATUS
InitializeInternal(__in FxObject * Parent,__in PWDF_INTERRUPT_CONFIG Configuration)37 FxInterrupt::InitializeInternal(
38 __in FxObject* Parent,
39 __in PWDF_INTERRUPT_CONFIG Configuration
40 )
41 {
42 IWudfDeviceStack *deviceStack;
43 HRESULT hr;
44 NTSTATUS status = STATUS_SUCCESS;
45 FxInterruptThreadpool* pool = NULL;
46 CM_SHARE_DISPOSITION shareVector;
47
48 UNREFERENCED_PARAMETER(Parent);
49
50 deviceStack = m_Device->GetDeviceStack();
51
52 switch (m_ShareVector) {
53 case WdfTrue:
54 //
55 // Override the bus driver's value, explicitly sharing this interrupt.
56 //
57 shareVector = CmResourceShareShared;
58 break;
59
60 case WdfFalse:
61 //
62 // Override the bus driver's value, explicitly claiming this interrupt
63 // as non-shared.
64 //
65 shareVector = CmResourceShareDeviceExclusive;
66 break;
67
68 case WdfUseDefault:
69 default:
70 //
71 // Leave the bus driver's value alone.
72 //
73 shareVector = CmResourceShareUndetermined;
74 break;
75 }
76
77 //
78 // Create a thread pool if not already created. An interrupt is created in
79 // one of the pnp callbacks (OnAddDevice, OnPrepareHarwdare etc) so there is
80 // no race in getting and setting the theradpool pointer.
81 //
82 pool = m_Device->GetInterruptThreadpool();
83 if (pool == NULL) {
84 hr = FxInterruptThreadpool::_CreateAndInit(GetDriverGlobals(),
85 &pool);
86 if (FAILED(hr))
87 {
88 goto exit;
89 }
90
91 m_Device->SetInterruptThreadpool(pool);
92 }
93
94 //
95 // create an instance of interruypt wait block
96 //
97 hr = FxInterruptWaitblock::_CreateAndInit(pool,
98 this,
99 FxInterrupt::_InterruptThunk,
100 &m_InterruptWaitblock);
101 if (FAILED(hr)) {
102 DoTraceLevelMessage(GetDriverGlobals(),
103 TRACE_LEVEL_ERROR, TRACINGPNP,
104 "Waitblock creation failed for CWdfInterrupt object"
105 " %!hresult!", hr);
106 goto exit;
107 }
108
109 //
110 // Send an IOCTL to redirector to create and initialize an interrupt object
111 //
112 deviceStack = m_Device->GetDeviceStack();
113
114 hr = deviceStack->InitializeInterrupt((WUDF_INTERRUPT_CONTEXT) this,
115 m_InterruptWaitblock->GetEventHandle(),
116 shareVector,
117 &m_RdInterruptContext
118 );
119
120 if (SUCCEEDED(hr))
121 {
122 status = STATUS_SUCCESS;
123 }
124 else
125 {
126 PUMDF_VERSION_DATA driverVersion = deviceStack->GetMinDriverVersion();
127
128 BOOL preserveCompat =
129 deviceStack->ShouldPreserveIrpCompletionStatusCompatibility();
130
131 status = CHostFxUtil::NtStatusFromHr(
132 hr,
133 driverVersion->MajorNumber,
134 driverVersion->MinorNumber,
135 preserveCompat
136 );
137 }
138
139 if (!NT_SUCCESS(status)) {
140 DoTraceLevelMessage(GetDriverGlobals(),
141 TRACE_LEVEL_ERROR, TRACINGPNP,
142 "failed to initialize interrupt "
143 "%!STATUS!", status);
144
145 goto exit;
146 }
147
148 exit:
149
150 //
151 // Dispose will do cleanup. No need to cleanup here.
152 //
153
154 return status;
155 }
156
157 NTSTATUS
ConnectInternal(VOID)158 FxInterrupt::ConnectInternal(
159 VOID
160 )
161 {
162 HRESULT hr;
163 NTSTATUS status;
164 IWudfDeviceStack2 *deviceStack;
165 PFX_DRIVER_GLOBALS pFxDriverGlobals;
166 BOOLEAN isRdConnectingOrConnected = FALSE;
167
168 pFxDriverGlobals = GetDriverGlobals();
169 deviceStack = m_Device->GetDeviceStack2();
170
171 //
172 // reset the interrupt event to non-signaled state to start with a
173 // clean slate.
174 //
175 m_InterruptWaitblock->ResetEvent();
176
177 //
178 // Open the queue and enqueue an interrupt event wait to the threadpool
179 // before connecting the interrupt in the reflector. This minimizes the
180 // processing delay for interrupts that fire as soon as they are connected,
181 // like GPIO button devices that have no means to explicitly enable and
182 // disable interrupts at the hardware level.
183 //
184 StartThreadpoolWaitQueue();
185
186 //
187 // Tell the PnP Manager to connect the interrupt. Send a message to
188 // redirector to do so. When ConnectInterrupt returns a failure code,
189 // we use isRdConnectingOrConnected to check if the failure was due
190 // to an already connected or currently connecting interrupt.
191 //
192 hr = deviceStack->ConnectInterrupt(m_RdInterruptContext,
193 &isRdConnectingOrConnected);
194 if (FAILED(hr))
195 {
196 if (isRdConnectingOrConnected) {
197 //
198 // The connect call failed because we asked the Reflector to connect
199 // an already connected or currently connecting interrupt. Perhaps the
200 // client made a redundant call to WdfInterruptEnable. In this case,
201 // we want to keep the threadpool active so that we continue to receive
202 // and acknowledge interrupts - otherwise RdIsrPassiveLevel may time out.
203 //
204 DoTraceLevelMessage(pFxDriverGlobals,
205 TRACE_LEVEL_ERROR, TRACINGPNP,
206 "Multiple connection attempts for !WDFINTERRUPT 0x%p",
207 GetHandle());
208
209 if (pFxDriverGlobals->IsVersionGreaterThanOrEqualTo(2, 19)) {
210 FX_VERIFY_WITH_NAME(DRIVER(BadArgument, TODO),
211 CHECK("Multiple interrupt connection attempts", FALSE),
212 pFxDriverGlobals->Public.DriverName);
213 }
214 }
215 else {
216 //
217 // Connecting the interrupt in the reflector failed, which means
218 // that IoConnectInterruptEx either failed or was not called at all.
219 // All we need to do in this case is revert the actions done by
220 // StartThreadpoolWaitQueue above, which are closing the queue
221 // and removing the enqueued interrupt event wait.
222 //
223 StopAndFlushThreadpoolWaitQueue();
224 }
225
226 PUMDF_VERSION_DATA driverVersion = deviceStack->GetMinDriverVersion();
227 BOOL preserveCompat =
228 deviceStack->ShouldPreserveIrpCompletionStatusCompatibility();
229
230 status = CHostFxUtil::NtStatusFromHr(
231 hr,
232 driverVersion->MajorNumber,
233 driverVersion->MinorNumber,
234 preserveCompat
235 );
236
237 DoTraceLevelMessage(pFxDriverGlobals,
238 TRACE_LEVEL_ERROR, TRACINGPNP,
239 "Connect message to reflector returned failure "
240 "%!hresult!", hr);
241
242 return status;
243 }
244
245 status = STATUS_SUCCESS;
246
247 return status;
248 }
249
250 VOID
DisconnectInternal(VOID)251 FxInterrupt::DisconnectInternal(
252 VOID
253 )
254 {
255 IWudfDeviceStack *deviceStack;
256 HRESULT hr;
257 InterruptControlType controlType;
258
259 //
260 // Tell the PnP Manager to disconnect the interrupt.
261 // Send a message to redirector to do so.
262 //
263 deviceStack = m_Device->GetDeviceStack();
264
265 controlType = InterruptControlTypeDisconnect;
266 hr = deviceStack->ControlInterrupt(m_RdInterruptContext, controlType);
267 if (FAILED(hr))
268 {
269 DoTraceLevelMessage(GetDriverGlobals(),
270 TRACE_LEVEL_ERROR, TRACINGPNP,
271 "Disconnect message to reflector returned failure "
272 "%!hresult!", hr);
273
274 FX_VERIFY_WITH_NAME(INTERNAL, TRAPMSG("Disconnect message to reflector returned failure. "),
275 GetDriverGlobals()->Public.DriverName);
276 }
277
278 //
279 // Now that interrupt has been disconnected, flush the threadpool. Note that
280 // we need to do this after disconnect because if we did it before disconnect,
281 // we might drop any spurious interrupts that were generated after
282 // the driver disabled interrupt generation in its Disable callback,
283 // and after the DPCs were flushed. Fx can't drop spurious interrupt
284 // because if the interrupt is level-triggered then refelctor would be waiting
285 // for acknowledgement. The fact that disconnect command to reflector has
286 // returned to fx guarantees that there are no more interrupts pending in
287 // reflector.
288 //
289 StopAndFlushThreadpoolWaitQueue();
290
291 //
292 // There might still be WorkItemForIsr running as a result of
293 // the handling of spurious interrupt by driver, so we need to flush the
294 // workitem as well.
295 //
296 FlushQueuedWorkitem();
297
298 return;
299 }
300
301 VOID
SetPolicyInternal(__in WDF_INTERRUPT_POLICY Policy,__in WDF_INTERRUPT_PRIORITY Priority,__in PGROUP_AFFINITY TargetProcessorSet)302 FxInterrupt::SetPolicyInternal(
303 __in WDF_INTERRUPT_POLICY Policy,
304 __in WDF_INTERRUPT_PRIORITY Priority,
305 __in PGROUP_AFFINITY TargetProcessorSet
306 )
307 {
308 IWudfDeviceStack *deviceStack;
309 HRESULT hr;
310
311 deviceStack = m_Device->GetDeviceStack();
312
313 //
314 // Tell reflector to set the policy of interrupt.
315 //
316 hr = deviceStack->SetInterruptPolicy(m_RdInterruptContext,
317 Policy,
318 Priority,
319 TargetProcessorSet);
320 if (FAILED(hr))
321 {
322 DoTraceLevelMessage(GetDriverGlobals(),
323 TRACE_LEVEL_ERROR, TRACINGPNP,
324 "SetPolicy message to reflector returned failure "
325 "%!hresult!", hr);
326 }
327
328 FX_VERIFY_WITH_NAME(INTERNAL, CHECK_HR(hr), GetDriverGlobals()->Public.DriverName);
329
330 return;
331 }
332
333 VOID
FilterResourceRequirements(__inout PIO_RESOURCE_DESCRIPTOR IoResourceDescriptor)334 FxInterrupt::FilterResourceRequirements(
335 __inout PIO_RESOURCE_DESCRIPTOR IoResourceDescriptor
336 )
337 /*++
338
339 Routine Description:
340
341 This function allows an interrupt object to change the
342 IoResourceRequirementsList that the PnP Manager sends during
343 IRP_MN_FILTER_RESOURCE_REQUIREMENTS. This function takes a single
344 IoResourceDescriptor and applies default or user specified policy.
345
346 Arguments:
347
348 IoResourceDescriptor - Pointer to descriptor that matches this interrupt object
349
350 Return Value:
351
352 VOID
353
354 --*/
355 {
356 UNREFERENCED_PARAMETER(IoResourceDescriptor);
357
358 ASSERTMSG("Not implemented for UMDF\n", FALSE);
359 }
360
361 VOID
ResetInternal(VOID)362 FxInterrupt::ResetInternal(
363 VOID
364 )
365 {
366 IWudfDeviceStack *deviceStack;
367 InterruptControlType controlType;
368 HRESULT hr;
369
370 if (m_RdInterruptContext == NULL) {
371 //
372 // Reflector hasn't yet created a partner interrupt object so nothing
373 // to do.
374 //
375 return;
376 }
377
378 //
379 // Send a message to redirector to reset interrupt info.
380 //
381 deviceStack = m_Device->GetDeviceStack();
382
383 controlType = InterruptControlTypeResetInterruptInfo;
384 hr = deviceStack->ControlInterrupt(m_RdInterruptContext, controlType);
385 if (FAILED(hr))
386 {
387 DoTraceLevelMessage(GetDriverGlobals(),
388 TRACE_LEVEL_ERROR, TRACINGPNP,
389 "ResetInterruptInfo message to reflector returned failure "
390 "%!hresult!", hr);
391 }
392
393 FX_VERIFY_WITH_NAME(INTERNAL, CHECK_HR(hr), GetDriverGlobals()->Public.DriverName);
394
395 return;
396 }
397
398 VOID
RevokeResourcesInternal(VOID)399 FxInterrupt::RevokeResourcesInternal(
400 VOID
401 )
402 {
403 IWudfDeviceStack *deviceStack;
404 InterruptControlType controlType;
405 HRESULT hr;
406
407 if (m_RdInterruptContext == NULL) {
408 //
409 // Reflector hasn't yet created a partner interrupt object so nothing
410 // to do.
411 //
412 return;
413 }
414
415 //
416 // Send a message to redirector to revoke interrupt resources.
417 //
418 deviceStack = m_Device->GetDeviceStack();
419
420 controlType = InterruptControlTypeRevokeResources;
421 hr = deviceStack->ControlInterrupt(m_RdInterruptContext, controlType);
422 if (FAILED(hr))
423 {
424 DoTraceLevelMessage(GetDriverGlobals(),
425 TRACE_LEVEL_ERROR, TRACINGPNP,
426 "RevokeResources message to reflector returned failure "
427 "%!hresult!", hr);
428 }
429
430 FX_VERIFY_WITH_NAME(INTERNAL, CHECK_HR(hr), GetDriverGlobals()->Public.DriverName);
431
432 return;
433 }
434
435 VOID
FlushQueuedDpcs(VOID)436 FxInterrupt::FlushQueuedDpcs(
437 VOID
438 )
439 {
440 IWudfDeviceStack *deviceStack;
441 HRESULT hr;
442
443 //
444 // Send a message to redirector to flush DPCs.
445 //
446 deviceStack = m_Device->GetDeviceStack();
447 hr = deviceStack->ControlInterrupt(m_RdInterruptContext,
448 InterruptControlTypeFlushQueuedDpcs);
449 if (FAILED(hr))
450 {
451 DoTraceLevelMessage(GetDriverGlobals(),
452 TRACE_LEVEL_ERROR, TRACINGPNP,
453 "FlushQueuedDpcs message to reflector returned failure "
454 "%!hresult!", hr);
455
456 FX_VERIFY_WITH_NAME(INTERNAL,
457 TRAPMSG("FlushQueuedDpcs message to reflector returned failure"),
458 GetDriverGlobals()->Public.DriverName);
459 }
460
461 return;
462 }
463
464 VOID
AssignResourcesInternal(__in PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDescRaw,__in PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDescTrans,__in PWDF_INTERRUPT_INFO InterruptInfo)465 FxInterrupt::AssignResourcesInternal(
466 __in PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDescRaw,
467 __in PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDescTrans,
468 __in PWDF_INTERRUPT_INFO InterruptInfo
469 )
470 {
471 IWudfDeviceStack *deviceStack;
472 HRESULT hr;
473
474 //
475 // level-triggered interrupt handling is supported only on win8 and newer.
476 //
477 if (IsLevelTriggered(CmDescTrans->Flags) &&
478 FxIsPassiveLevelInterruptSupported() == FALSE) {
479 hr = E_INVALIDARG;
480 DoTraceLevelMessage(GetDriverGlobals(),
481 TRACE_LEVEL_ERROR, TRACINGPNP,
482 "Failed to assign interrupt resource to interrupt object"
483 "because interrupt resource is for level-triggered interrupt"
484 "which is not supported on this platform. See the docs for info on"
485 "supported platforms. %!hresult!\n", hr);
486
487 FX_VERIFY_WITH_NAME(DRIVER(BadArgument, TODO), TRAPMSG(
488 "Failed to assign interrupt resource to interrupt object"
489 "because interrupt resource is for level-triggered interrupt"
490 "which is not supported on this platform. See the docs for info on"
491 "supported platforms."),
492 GetDriverGlobals()->Public.DriverName);
493 }
494
495 //
496 // Sharing is only supported for level-triggered interrupts. We allow
497 // shared latched interrupts in order to accomodate incorrect device
498 // firmwares that mistakenly declare their exclusive resources as shared.
499 // Genuinely shared edge-triggered interrupts will cause a deadlock
500 // because of how the OS handles non-passive latched interrupts with
501 // multiple registered handlers. See RdInterrupt::AssignResources
502 // for details.
503 //
504 if (IsLevelTriggered(CmDescTrans->Flags) == FALSE &&
505 CmDescTrans->ShareDisposition != CmResourceShareDeviceExclusive) {
506
507 DoTraceLevelMessage(GetDriverGlobals(),
508 TRACE_LEVEL_WARNING, TRACINGPNP,
509 "The resource descriptor indicates that this is a shared "
510 "edge-triggered interrupt. UMDF only supports sharing of "
511 "level-triggered interrupts. Please check if your device "
512 "firmware mistakenly declares this resource as shared "
513 "instead of device exclusive. If the resource is in fact "
514 "shared, then UMDF does not support this device.\n");
515 }
516
517 //
518 // Tell the PnP Manager to assign resources to the interrupt.
519 // Send a message to redirector to do so.
520 //
521 deviceStack = m_Device->GetDeviceStack();
522
523 hr = deviceStack->AssignInterruptResources(m_RdInterruptContext,
524 CmDescRaw,
525 CmDescTrans,
526 InterruptInfo,
527 m_PassiveHandlingByRedirector);
528 if (FAILED(hr))
529 {
530 DoTraceLevelMessage(GetDriverGlobals(),
531 TRACE_LEVEL_ERROR, TRACINGPNP,
532 "AssignResources message to reflector returned failure "
533 "%!hresult!\n", hr);
534 }
535
536 FX_VERIFY_WITH_NAME(INTERNAL, CHECK_HR(hr),
537 GetDriverGlobals()->Public.DriverName);
538
539 }
540
541 VOID
ThreadpoolWaitCallback(VOID)542 FxInterrupt::ThreadpoolWaitCallback(
543 VOID
544 )
545 {
546 BOOLEAN claimed;
547
548 //
549 // ETW event for performance measurement
550 //
551 EventWriteEVENT_UMDF_FX_INTERRUPT_NOTIFICATION_RECEIVED(
552 m_InterruptInfo.MessageNumber
553 );
554
555 //
556 // Invoke the ISR callback under interrupt lock.
557 //
558 if (IsWakeCapable()) {
559 //
560 // if it is a wake capable interrupt, we will hand it off
561 // to the state machine so that it can power up the device
562 // if required and then invoke the ISR callback
563 //
564 claimed = WakeInterruptIsr();
565 } else {
566 AcquireLock();
567 claimed = m_EvtInterruptIsr(GetHandle(),
568 m_InterruptInfo.MessageNumber
569 );
570 ReleaseLock();
571 }
572
573 //
574 // Queue another wait. MSDN: You must re-register the event with the
575 // wait object before signaling it each time to trigger the wait callback.
576 //
577 if (m_CanQueue) {
578 QueueSingleWaitOnInterruptEvent();
579 }
580
581 //
582 // Return acknowledgement to reflector if it's handled at passive level
583 // by reflector.
584 //
585 if (m_PassiveHandlingByRedirector) {
586 IWudfDeviceStack *deviceStack;
587 HRESULT hr;
588
589 deviceStack = m_Device->GetDeviceStack();
590
591 hr = deviceStack->AcknowledgeInterrupt(m_RdInterruptContext, claimed);
592
593 if (FAILED(hr)) {
594 DoTraceLevelMessage(GetDriverGlobals(),
595 TRACE_LEVEL_ERROR, TRACINGPNP,
596 "AcknowledgeInterrupt message to reflector returned "
597 "failure. Check UMDF log for failure reason. %!hresult!", hr);
598
599 FX_VERIFY_WITH_NAME(INTERNAL, TRAPMSG("AcknowledgeInterrupt message to "
600 "reflector returned failure. Check UMDF log for failure reason. "),
601 GetDriverGlobals()->Public.DriverName);
602 }
603 }
604
605 return;
606 }
607
608 VOID
QueueSingleWaitOnInterruptEvent(VOID)609 FxInterrupt::QueueSingleWaitOnInterruptEvent(
610 VOID
611 )
612 {
613 m_InterruptWaitblock->SetThreadpoolWait();
614 }
615
616 VOID
StartThreadpoolWaitQueue(VOID)617 FxInterrupt::StartThreadpoolWaitQueue(
618 VOID
619 )
620 {
621 m_CanQueue = TRUE;
622
623 QueueSingleWaitOnInterruptEvent();
624 }
625
626 VOID
StopAndFlushThreadpoolWaitQueue(VOID)627 FxInterrupt::StopAndFlushThreadpoolWaitQueue(
628 VOID
629 )
630 {
631 //
632 // We need to stop the threadpool wait queue and accomplish the following:
633 // 1) Prevent any new waits from being queued.
634 // 2) Removed any waits already queued.
635 // 3) Wait for interrupt isr callback to complete.
636 //
637
638 //
639 // Prevent any more enquing now that interrupt has been disconnected.
640 //
641 m_CanQueue = FALSE;
642
643 //
644 // wait for isr callback
645 //
646 m_InterruptWaitblock->WaitForOutstandingCallbackToComplete();
647
648 //
649 // remove any waits already queued
650 //
651 m_InterruptWaitblock->ClearThreadpoolWait();
652
653 //
654 // wait for callback. This additional wait for callback is needed to
655 // handle the follwoing race:
656 // - CanQueue is set to false in this thread
657 // - Callback is executing at statement after CanQueue check so it did not
658 // see false.
659 // - this thread waits for callback
660 // - callback thread queues a wait and returns
661 // - the wait earlier queued is satisfied and callback runs
662 // - this thread clears the queue (there is nothing to clear) but there is
663 // still a callback runnning and this thread needs to wait.
664 //
665 m_InterruptWaitblock->WaitForOutstandingCallbackToComplete();
666 }
667
668 VOID
669 CALLBACK
_InterruptThunk(PTP_CALLBACK_INSTANCE Instance,PVOID Parameter,PTP_WAIT Wait,TP_WAIT_RESULT WaitResult)670 FxInterrupt::_InterruptThunk(
671 PTP_CALLBACK_INSTANCE Instance,
672 PVOID Parameter,
673 PTP_WAIT Wait,
674 TP_WAIT_RESULT WaitResult
675 )
676 {
677 FxInterrupt* fxInterrupt = (FxInterrupt*) Parameter;
678
679 UNREFERENCED_PARAMETER(Instance);
680 UNREFERENCED_PARAMETER(Wait);
681 UNREFERENCED_PARAMETER(WaitResult);
682
683 fxInterrupt->ThreadpoolWaitCallback();
684
685 return;
686 }
687
688 VOID
FlushAndRundownInternal(VOID)689 FxInterrupt::FlushAndRundownInternal(
690 VOID
691 )
692 {
693 //
694 // flush the threadpool callbacks
695 //
696 StopAndFlushThreadpoolWaitQueue();
697
698 //
699 // Rundown the workitem.
700 //
701 if (m_SystemWorkItem != NULL) {
702 m_SystemWorkItem->DeleteObject();
703 m_SystemWorkItem = NULL;
704 }
705
706 //
707 // If present, delete the default passive-lock.
708 //
709 if (m_DisposeWaitLock) {
710 ASSERT(m_WaitLock != NULL);
711 m_WaitLock->DeleteObject();
712 m_WaitLock = NULL;
713 m_DisposeWaitLock = FALSE;
714 }
715
716 //
717 // waitblock destructor will ensure event and waitblock cleanup.
718 //
719 if (m_InterruptWaitblock != NULL) {
720 delete m_InterruptWaitblock;
721 m_InterruptWaitblock = NULL;
722 }
723
724 //
725 // No need to explicitly delete the COM wrapper (CWdfInterrupt).
726 // The COM wrapper will get deleted in fxInterrupt's destroy callback when
727 // the object tree reference taken during creation will be released.
728 //
729 }
730
731 BOOLEAN
QueueDpcForIsr(VOID)732 FxInterrupt::QueueDpcForIsr(
733 VOID
734 )
735 {
736 FX_VERIFY_WITH_NAME(INTERNAL, TRAPMSG("Not implemented"),
737 GetDriverGlobals()->Public.DriverName);
738 return FALSE;
739 }
740
741 VOID
WorkItemHandler(VOID)742 FxInterrupt::WorkItemHandler(
743 VOID
744 )
745 {
746 //
747 // For UMDF, we allow drivers to call WdfInterruptQueueDpcdForIsr, and
748 // internally we queue a workitem and invoke EvtInterruptDpc. Only
749 // one of the callbacks EvtInterruptDpc or EvtInterruptWorkitem is
750 // allowed.
751 //
752 ASSERT(m_EvtInterruptWorkItem != NULL || m_EvtInterruptDpc != NULL);
753 ASSERT((m_EvtInterruptWorkItem != NULL && m_EvtInterruptDpc != NULL) == FALSE);
754
755 FX_TRACK_DRIVER(GetDriverGlobals());
756
757 //
758 // Call the drivers registered WorkItemForIsr event callback
759 //
760 if (m_CallbackLock != NULL) {
761 KIRQL irql = 0;
762
763 m_CallbackLock->Lock(&irql);
764 if (m_EvtInterruptWorkItem != NULL) {
765 m_EvtInterruptWorkItem(GetHandle(), m_Device->GetHandle());
766 }
767 else {
768 m_EvtInterruptDpc(GetHandle(), m_Device->GetHandle());
769 }
770 m_CallbackLock->Unlock(irql);
771 }
772 else {
773 if (m_EvtInterruptWorkItem != NULL) {
774 m_EvtInterruptWorkItem(GetHandle(), m_Device->GetHandle());
775 }
776 else {
777 m_EvtInterruptDpc(GetHandle(), m_Device->GetHandle());
778 }
779 }
780
781 return;
782 }
783
784 BOOLEAN
_SynchronizeExecution(__in MdInterrupt Interrupt,__in MdInterruptSynchronizeRoutine SynchronizeRoutine,__in PVOID SynchronizeContext)785 _SynchronizeExecution(
786 __in MdInterrupt Interrupt,
787 __in MdInterruptSynchronizeRoutine SynchronizeRoutine,
788 __in PVOID SynchronizeContext
789 )
790 {
791 FxInterruptEnableParameters* pParams;
792 BOOLEAN isPassive;
793
794 UNREFERENCED_PARAMETER(Interrupt);
795
796 pParams = (FxInterruptEnableParameters*) SynchronizeContext;
797 isPassive = pParams->Interrupt->IsPassiveHandling();
798 FX_VERIFY(INTERNAL, CHECK("Must be Passive Interrupt", isPassive));
799
800 //
801 // The internal synchronize routine will call the routine under lock
802 //
803 return SynchronizeRoutine(SynchronizeContext);
804 }
805