2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Kernel Streaming
4 * FILE: drivers/wdm/audio/backpln/portcls/interrupt.cpp
5 * PURPOSE: portcls interrupt object
6 * PROGRAMMER: Johannes Anderwald
10 #include "private.hpp"
15 PINTERRUPTSYNCROUTINE SyncRoutine
;
17 }SYNC_ENTRY
, *PSYNC_ENTRY
;
19 class CInterruptSync
: public IInterruptSync
22 STDMETHODIMP
QueryInterface( REFIID InterfaceId
, PVOID
* Interface
);
24 STDMETHODIMP_(ULONG
) AddRef()
26 InterlockedIncrement(&m_Ref
);
29 STDMETHODIMP_(ULONG
) Release()
31 InterlockedDecrement(&m_Ref
);
41 CInterruptSync(IUnknown
*OuterUnknown
){}
42 virtual ~CInterruptSync(){}
47 LIST_ENTRY m_ServiceRoutines
;
48 PKINTERRUPT m_Interrupt
;
49 INTERRUPTSYNCMODE m_Mode
;
50 PRESOURCELIST m_ResourceList
;
51 ULONG m_ResourceIndex
;
53 PINTERRUPTSYNCROUTINE m_SyncRoutine
;
54 PVOID m_DynamicContext
;
58 friend BOOLEAN NTAPI
CInterruptSynchronizedRoutine(IN PVOID ServiceContext
);
59 friend BOOLEAN NTAPI
IInterruptServiceRoutine(IN PKINTERRUPT Interrupt
, IN PVOID ServiceContext
);
63 //---------------------------------------------------------------
71 CInterruptSync::QueryInterface(
75 DPRINT("CInterruptSync::QueryInterface: this %p\n", this);
77 if (IsEqualGUIDAligned(refiid
, IID_IInterruptSync
) ||
78 IsEqualGUIDAligned(refiid
, IID_IUnknown
))
80 *Output
= PVOID(PUNKNOWN(this));
81 PUNKNOWN(*Output
)->AddRef();
82 return STATUS_SUCCESS
;
85 DPRINT("CInterruptSync::QueryInterface: this %p UNKNOWN interface requested\n", this);
86 return STATUS_UNSUCCESSFUL
;
89 //---------------------------------------------------------------
90 // CInterruptSync methods
96 CInterruptSynchronizedRoutine(
97 IN PVOID ServiceContext
)
99 CInterruptSync
* This
= (CInterruptSync
*)ServiceContext
;
100 NTSTATUS Status
= This
->m_SyncRoutine(This
, This
->m_DynamicContext
);
102 DPRINT("CInterruptSynchronizedRoutine this %p SyncRoutine %p Context %p Status %x\n", This
, This
->m_SyncRoutine
, This
->m_DynamicContext
, Status
);
103 return NT_SUCCESS(Status
);
108 CInterruptSync::CallSynchronizedRoutine(
109 IN PINTERRUPTSYNCROUTINE Routine
,
110 IN PVOID DynamicContext
)
114 DPRINT("CInterruptSync::CallSynchronizedRoutine this %p Routine %p DynamicContext %p Irql %x Interrupt %p\n", this, Routine
, DynamicContext
, KeGetCurrentIrql(), m_Interrupt
);
118 DPRINT("CInterruptSync_CallSynchronizedRoutine %p no interrupt connected\n", this);
119 if (KeGetCurrentIrql() > DISPATCH_LEVEL
)
120 return STATUS_UNSUCCESSFUL
;
122 KeAcquireSpinLock(&m_Lock
, &OldIrql
);
123 m_SyncRoutine
= Routine
;
124 m_DynamicContext
= DynamicContext
;
125 CInterruptSynchronizedRoutine((PVOID
)this);
126 KeReleaseSpinLock(&m_Lock
, OldIrql
);
128 return STATUS_SUCCESS
;
131 m_SyncRoutine
= Routine
;
132 m_DynamicContext
= DynamicContext
;
134 if (KeSynchronizeExecution(m_Interrupt
, CInterruptSynchronizedRoutine
, (PVOID
)this))
135 return STATUS_SUCCESS
;
137 return STATUS_UNSUCCESSFUL
;
142 CInterruptSync::GetKInterrupt()
144 DPRINT("CInterruptSynchronizedRoutine\n");
151 IInterruptServiceRoutine(
152 IN PKINTERRUPT Interrupt
,
153 IN PVOID ServiceContext
)
155 PLIST_ENTRY CurEntry
;
160 CInterruptSync
* This
= (CInterruptSync
*)ServiceContext
;
162 DPRINT("IInterruptServiceRoutine Mode %u\n", This
->m_Mode
);
164 if (This
->m_Mode
== InterruptSyncModeNormal
)
166 CurEntry
= This
->m_ServiceRoutines
.Flink
;
167 while (CurEntry
!= &This
->m_ServiceRoutines
)
169 Entry
= CONTAINING_RECORD(CurEntry
, SYNC_ENTRY
, ListEntry
);
170 Status
= Entry
->SyncRoutine((CInterruptSync
*)This
, Entry
->DynamicContext
);
171 if (NT_SUCCESS(Status
))
175 CurEntry
= CurEntry
->Flink
;
179 else if (This
->m_Mode
== InterruptSyncModeAll
)
181 CurEntry
= This
->m_ServiceRoutines
.Flink
;
182 while (CurEntry
!= &This
->m_ServiceRoutines
)
184 Entry
= CONTAINING_RECORD(CurEntry
, SYNC_ENTRY
, ListEntry
);
185 Entry
->SyncRoutine((CInterruptSync
*)This
, Entry
->DynamicContext
);
186 CurEntry
= CurEntry
->Flink
;
188 DPRINT("Returning TRUE with mode InterruptSyncModeAll\n");
191 else if (This
->m_Mode
== InterruptSyncModeRepeat
)
196 CurEntry
= This
->m_ServiceRoutines
.Flink
;
197 while (CurEntry
!= &This
->m_ServiceRoutines
)
199 Entry
= CONTAINING_RECORD(CurEntry
, SYNC_ENTRY
, ListEntry
);
200 Status
= Entry
->SyncRoutine((CInterruptSync
*)This
, Entry
->DynamicContext
);
201 if (NT_SUCCESS(Status
))
203 CurEntry
= CurEntry
->Flink
;
206 DPRINT("Returning TRUE with mode InterruptSyncModeRepeat\n");
211 DPRINT("Unknown mode %u\n", This
->m_Mode
);
212 return FALSE
; //FIXME
219 CInterruptSync::Connect()
222 PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor
;
224 DPRINT("CInterruptSync::Connect\n");
225 PC_ASSERT_IRQL_EQUAL(PASSIVE_LEVEL
);
227 Descriptor
= m_ResourceList
->FindTranslatedEntry(CmResourceTypeInterrupt
, m_ResourceIndex
);
229 return STATUS_UNSUCCESSFUL
;
231 if (IsListEmpty(&m_ServiceRoutines
))
232 return STATUS_UNSUCCESSFUL
;
234 DPRINT("Vector %u Level %u Flags %x Affinity %x\n", Descriptor
->u
.Interrupt
.Vector
, Descriptor
->u
.Interrupt
.Level
, Descriptor
->Flags
, Descriptor
->u
.Interrupt
.Affinity
);
236 Status
= IoConnectInterrupt(&m_Interrupt
,
237 IInterruptServiceRoutine
,
240 Descriptor
->u
.Interrupt
.Vector
,
241 (KIRQL
)Descriptor
->u
.Interrupt
.Level
,
242 (KIRQL
)Descriptor
->u
.Interrupt
.Level
,
243 (KINTERRUPT_MODE
)(Descriptor
->Flags
& CM_RESOURCE_INTERRUPT_LATCHED
),
244 (Descriptor
->Flags
!= CM_RESOURCE_INTERRUPT_LATCHED
),
245 Descriptor
->u
.Interrupt
.Affinity
,
248 DPRINT("CInterruptSync::Connect result %x\n", Status
);
255 CInterruptSync::Disconnect()
257 DPRINT("CInterruptSync::Disconnect\n");
258 PC_ASSERT_IRQL_EQUAL(PASSIVE_LEVEL
);
262 DPRINT("CInterruptSync_Disconnect %p no interrupt connected\n", this);
266 IoDisconnectInterrupt(m_Interrupt
);
272 CInterruptSync::RegisterServiceRoutine(
273 IN PINTERRUPTSYNCROUTINE Routine
,
274 IN PVOID DynamicContext
,
277 PSYNC_ENTRY NewEntry
;
279 DPRINT("CInterruptSync::RegisterServiceRoutine\n");
280 PC_ASSERT_IRQL_EQUAL(PASSIVE_LEVEL
);
282 NewEntry
= (PSYNC_ENTRY
)AllocateItem(NonPagedPool
, sizeof(SYNC_ENTRY
), TAG_PORTCLASS
);
284 return STATUS_INSUFFICIENT_RESOURCES
;
286 NewEntry
->SyncRoutine
= Routine
;
287 NewEntry
->DynamicContext
= DynamicContext
;
290 InsertHeadList(&m_ServiceRoutines
, &NewEntry
->ListEntry
);
292 InsertTailList(&m_ServiceRoutines
, &NewEntry
->ListEntry
);
294 return STATUS_SUCCESS
;
300 OUT PINTERRUPTSYNC
* OutInterruptSync
,
301 IN PUNKNOWN OuterUnknown OPTIONAL
,
302 IN PRESOURCELIST ResourceList
,
303 IN ULONG ResourceIndex
,
304 IN INTERRUPTSYNCMODE Mode
)
306 CInterruptSync
* This
;
309 DPRINT("PcNewInterruptSync entered OutInterruptSync %p OuterUnknown %p ResourceList %p ResourceIndex %u Mode %d\n",
310 OutInterruptSync
, OuterUnknown
, ResourceList
, ResourceIndex
, Mode
);
312 if (!OutInterruptSync
|| !ResourceList
|| Mode
< InterruptSyncModeNormal
|| Mode
> InterruptSyncModeRepeat
)
313 return STATUS_INVALID_PARAMETER
;
315 if (ResourceIndex
> ResourceList
->NumberOfEntriesOfType(CmResourceTypeInterrupt
))
316 return STATUS_INVALID_PARAMETER
;
318 This
= new(NonPagedPool
, TAG_PORTCLASS
)CInterruptSync(OuterUnknown
);
320 return STATUS_INSUFFICIENT_RESOURCES
;
322 Status
= This
->QueryInterface(IID_IInterruptSync
, (PVOID
*)OutInterruptSync
);
324 if (!NT_SUCCESS(Status
))
330 ResourceList
->AddRef();
336 This
->m_ResourceIndex
= ResourceIndex
;
337 This
->m_ResourceList
= ResourceList
;
338 InitializeListHead(&This
->m_ServiceRoutines
);
339 KeInitializeSpinLock(&This
->m_Lock
);