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
;
59 friend BOOLEAN NTAPI
CInterruptSynchronizedRoutine(IN PVOID ServiceContext
);
60 friend BOOLEAN NTAPI
IInterruptServiceRoutine(IN PKINTERRUPT Interrupt
, IN PVOID ServiceContext
);
64 //---------------------------------------------------------------
72 CInterruptSync::QueryInterface(
76 DPRINT("CInterruptSync::QueryInterface: this %p\n", this);
78 if (IsEqualGUIDAligned(refiid
, IID_IInterruptSync
) ||
79 IsEqualGUIDAligned(refiid
, IID_IUnknown
))
81 *Output
= PVOID(PUNKNOWN(this));
82 PUNKNOWN(*Output
)->AddRef();
83 return STATUS_SUCCESS
;
86 DPRINT("CInterruptSync::QueryInterface: this %p UNKNOWN interface requested\n", this);
87 return STATUS_UNSUCCESSFUL
;
90 //---------------------------------------------------------------
91 // CInterruptSync methods
97 CInterruptSynchronizedRoutine(
98 IN PVOID ServiceContext
)
100 CInterruptSync
* This
= (CInterruptSync
*)ServiceContext
;
101 This
->m_Status
= This
->m_SyncRoutine(This
, This
->m_DynamicContext
);
103 DPRINT("CInterruptSynchronizedRoutine this %p SyncRoutine %p Context %p Status %x\n", This
, This
->m_SyncRoutine
, This
->m_DynamicContext
, This
->m_Status
);
109 CInterruptSync::CallSynchronizedRoutine(
110 IN PINTERRUPTSYNCROUTINE Routine
,
111 IN PVOID DynamicContext
)
115 DPRINT("CInterruptSync::CallSynchronizedRoutine this %p Routine %p DynamicContext %p Irql %x Interrupt %p\n", this, Routine
, DynamicContext
, KeGetCurrentIrql(), m_Interrupt
);
119 DPRINT("CInterruptSync_CallSynchronizedRoutine %p no interrupt connected\n", this);
120 if (KeGetCurrentIrql() > DISPATCH_LEVEL
)
121 return STATUS_UNSUCCESSFUL
;
123 KeAcquireSpinLock(&m_Lock
, &OldIrql
);
124 m_SyncRoutine
= Routine
;
125 m_DynamicContext
= DynamicContext
;
126 CInterruptSynchronizedRoutine((PVOID
)this);
127 KeReleaseSpinLock(&m_Lock
, OldIrql
);
132 m_SyncRoutine
= Routine
;
133 m_DynamicContext
= DynamicContext
;
135 if (KeSynchronizeExecution(m_Interrupt
, CInterruptSynchronizedRoutine
, (PVOID
)this))
138 return STATUS_UNSUCCESSFUL
;
143 CInterruptSync::GetKInterrupt()
145 DPRINT("CInterruptSynchronizedRoutine\n");
152 IInterruptServiceRoutine(
153 IN PKINTERRUPT Interrupt
,
154 IN PVOID ServiceContext
)
156 PLIST_ENTRY CurEntry
;
161 CInterruptSync
* This
= (CInterruptSync
*)ServiceContext
;
163 DPRINT("IInterruptServiceRoutine Mode %u\n", This
->m_Mode
);
165 if (This
->m_Mode
== InterruptSyncModeNormal
)
167 CurEntry
= This
->m_ServiceRoutines
.Flink
;
168 while (CurEntry
!= &This
->m_ServiceRoutines
)
170 Entry
= CONTAINING_RECORD(CurEntry
, SYNC_ENTRY
, ListEntry
);
171 Status
= Entry
->SyncRoutine((CInterruptSync
*)This
, Entry
->DynamicContext
);
172 if (NT_SUCCESS(Status
))
176 CurEntry
= CurEntry
->Flink
;
180 else if (This
->m_Mode
== InterruptSyncModeAll
)
182 CurEntry
= This
->m_ServiceRoutines
.Flink
;
183 while (CurEntry
!= &This
->m_ServiceRoutines
)
185 Entry
= CONTAINING_RECORD(CurEntry
, SYNC_ENTRY
, ListEntry
);
186 Entry
->SyncRoutine((CInterruptSync
*)This
, Entry
->DynamicContext
);
187 CurEntry
= CurEntry
->Flink
;
189 DPRINT("Returning TRUE with mode InterruptSyncModeAll\n");
192 else if (This
->m_Mode
== InterruptSyncModeRepeat
)
197 CurEntry
= This
->m_ServiceRoutines
.Flink
;
198 while (CurEntry
!= &This
->m_ServiceRoutines
)
200 Entry
= CONTAINING_RECORD(CurEntry
, SYNC_ENTRY
, ListEntry
);
201 Status
= Entry
->SyncRoutine((CInterruptSync
*)This
, Entry
->DynamicContext
);
202 if (NT_SUCCESS(Status
))
204 CurEntry
= CurEntry
->Flink
;
207 DPRINT("Returning TRUE with mode InterruptSyncModeRepeat\n");
212 DPRINT("Unknown mode %u\n", This
->m_Mode
);
213 return FALSE
; //FIXME
220 CInterruptSync::Connect()
223 PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor
;
225 DPRINT("CInterruptSync::Connect\n");
226 PC_ASSERT_IRQL_EQUAL(PASSIVE_LEVEL
);
228 Descriptor
= m_ResourceList
->FindTranslatedEntry(CmResourceTypeInterrupt
, m_ResourceIndex
);
230 return STATUS_UNSUCCESSFUL
;
232 if (IsListEmpty(&m_ServiceRoutines
))
233 return STATUS_UNSUCCESSFUL
;
235 DPRINT1("Vector %u Level %u Flags %x Affinity %x\n", Descriptor
->u
.Interrupt
.Vector
, Descriptor
->u
.Interrupt
.Level
, Descriptor
->Flags
, Descriptor
->u
.Interrupt
.Affinity
);
237 Status
= IoConnectInterrupt(&m_Interrupt
,
238 IInterruptServiceRoutine
,
241 Descriptor
->u
.Interrupt
.Vector
,
242 (KIRQL
)Descriptor
->u
.Interrupt
.Level
,
243 (KIRQL
)Descriptor
->u
.Interrupt
.Level
,
244 (KINTERRUPT_MODE
)(Descriptor
->Flags
& CM_RESOURCE_INTERRUPT_LATCHED
),
245 (Descriptor
->ShareDisposition
!= CmResourceShareDeviceExclusive
),
246 Descriptor
->u
.Interrupt
.Affinity
,
249 DPRINT1("CInterruptSync::Connect result %x\n", Status
);
256 CInterruptSync::Disconnect()
258 DPRINT("CInterruptSync::Disconnect\n");
259 PC_ASSERT_IRQL_EQUAL(PASSIVE_LEVEL
);
263 DPRINT("CInterruptSync_Disconnect %p no interrupt connected\n", this);
267 IoDisconnectInterrupt(m_Interrupt
);
273 CInterruptSync::RegisterServiceRoutine(
274 IN PINTERRUPTSYNCROUTINE Routine
,
275 IN PVOID DynamicContext
,
278 PSYNC_ENTRY NewEntry
;
280 DPRINT("CInterruptSync::RegisterServiceRoutine\n");
281 PC_ASSERT_IRQL_EQUAL(PASSIVE_LEVEL
);
283 NewEntry
= (PSYNC_ENTRY
)AllocateItem(NonPagedPool
, sizeof(SYNC_ENTRY
), TAG_PORTCLASS
);
285 return STATUS_INSUFFICIENT_RESOURCES
;
287 NewEntry
->SyncRoutine
= Routine
;
288 NewEntry
->DynamicContext
= DynamicContext
;
291 InsertHeadList(&m_ServiceRoutines
, &NewEntry
->ListEntry
);
293 InsertTailList(&m_ServiceRoutines
, &NewEntry
->ListEntry
);
295 return STATUS_SUCCESS
;
301 OUT PINTERRUPTSYNC
* OutInterruptSync
,
302 IN PUNKNOWN OuterUnknown OPTIONAL
,
303 IN PRESOURCELIST ResourceList
,
304 IN ULONG ResourceIndex
,
305 IN INTERRUPTSYNCMODE Mode
)
307 CInterruptSync
* This
;
310 DPRINT("PcNewInterruptSync entered OutInterruptSync %p OuterUnknown %p ResourceList %p ResourceIndex %u Mode %d\n",
311 OutInterruptSync
, OuterUnknown
, ResourceList
, ResourceIndex
, Mode
);
313 if (!OutInterruptSync
|| !ResourceList
|| Mode
< InterruptSyncModeNormal
|| Mode
> InterruptSyncModeRepeat
)
314 return STATUS_INVALID_PARAMETER
;
316 if (ResourceIndex
> ResourceList
->NumberOfEntriesOfType(CmResourceTypeInterrupt
))
317 return STATUS_INVALID_PARAMETER
;
319 This
= new(NonPagedPool
, TAG_PORTCLASS
)CInterruptSync(OuterUnknown
);
321 return STATUS_INSUFFICIENT_RESOURCES
;
323 Status
= This
->QueryInterface(IID_IInterruptSync
, (PVOID
*)OutInterruptSync
);
325 if (!NT_SUCCESS(Status
))
331 ResourceList
->AddRef();
337 This
->m_ResourceIndex
= ResourceIndex
;
338 This
->m_ResourceList
= ResourceList
;
339 InitializeListHead(&This
->m_ServiceRoutines
);
340 KeInitializeSpinLock(&This
->m_Lock
);