2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Kernel Streaming
4 * FILE: drivers/wdm/audio/backpln/portcls/interrupt.c
5 * PURPOSE: portcls interrupt object
6 * PROGRAMMER: Johannes Anderwald
15 PINTERRUPTSYNCROUTINE SyncRoutine
;
17 }SYNC_ENTRY
, *PSYNC_ENTRY
;
21 IInterruptSyncVtbl
*lpVtbl
;
25 LIST_ENTRY ServiceRoutines
;
26 PKINTERRUPT Interrupt
;
27 INTERRUPTSYNCMODE Mode
;
28 PRESOURCELIST ResourceList
;
31 PINTERRUPTSYNCROUTINE SyncRoutine
;
36 //---------------------------------------------------------------
44 IInterruptSync_fnQueryInterface(
45 IInterruptSync
* iface
,
49 IInterruptSyncImpl
* This
= (IInterruptSyncImpl
*)iface
;
51 DPRINT("IInterruptSync_fnQueryInterface: This %p\n", This
);
53 if (IsEqualGUIDAligned(refiid
, &IID_IInterruptSync
) ||
54 IsEqualGUIDAligned(refiid
, &IID_IUnknown
))
56 *Output
= &This
->lpVtbl
;
57 InterlockedIncrement(&This
->ref
);
58 return STATUS_SUCCESS
;
60 DPRINT1("IInterruptSync_fnQueryInterface: This %p UNKNOWN interface requested\n", This
);
61 return STATUS_UNSUCCESSFUL
;
66 IInterruptSync_fnAddRef(
67 IInterruptSync
* iface
)
69 IInterruptSyncImpl
* This
= (IInterruptSyncImpl
*)iface
;
71 DPRINT("IInterruptSync_AddRef: This %p\n", This
);
73 return InterlockedIncrement(&This
->ref
);
78 IInterruptSync_fnRelease(
79 IInterruptSync
* iface
)
83 IInterruptSyncImpl
* This
= (IInterruptSyncImpl
*)iface
;
85 InterlockedDecrement(&This
->ref
);
87 DPRINT("IInterruptSync_Release: This %p new ref %u\n", This
, This
->ref
);
91 while(!IsListEmpty(&This
->ServiceRoutines
))
93 CurEntry
= RemoveHeadList(&This
->ServiceRoutines
);
94 Entry
= CONTAINING_RECORD(CurEntry
, SYNC_ENTRY
, ListEntry
);
95 FreeItem(Entry
, TAG_PORTCLASS
);
98 This
->ResourceList
->lpVtbl
->Release(This
->ResourceList
);
99 FreeItem(This
, TAG_PORTCLASS
);
102 /* Return new reference count */
106 //---------------------------------------------------------------
107 // IInterruptSync methods
113 IInterruptSynchronizedRoutine(
114 IN PVOID ServiceContext
)
116 IInterruptSyncImpl
* This
= (IInterruptSyncImpl
*)ServiceContext
;
117 DPRINT("IInterruptSynchronizedRoutine This %p SyncRoutine %p Context %p\n", This
, This
->SyncRoutine
, This
->DynamicContext
);
118 return This
->SyncRoutine((IInterruptSync
*)&This
->lpVtbl
, This
->DynamicContext
);
123 IInterruptSync_fnCallSynchronizedRoutine(
124 IN IInterruptSync
* iface
,
125 IN PINTERRUPTSYNCROUTINE Routine
,
126 IN PVOID DynamicContext
)
129 IInterruptSyncImpl
* This
= (IInterruptSyncImpl
*)iface
;
131 DPRINT("IInterruptSync_fnCallSynchronizedRoutine This %p Routine %p DynamicContext %p Irql %x Interrupt %p\n", This
, Routine
, DynamicContext
, KeGetCurrentIrql(), This
->Interrupt
);
133 if (!This
->Interrupt
)
135 DPRINT("IInterruptSync_CallSynchronizedRoutine %p no interrupt connected\n", This
);
136 if (KeGetCurrentIrql() > DISPATCH_LEVEL
)
137 return STATUS_UNSUCCESSFUL
;
139 KeAcquireSpinLock(&This
->Lock
, &OldIrql
);
140 This
->SyncRoutine
= Routine
;
141 This
->DynamicContext
= DynamicContext
;
142 IInterruptSynchronizedRoutine((PVOID
)This
);
143 KeReleaseSpinLock(&This
->Lock
, OldIrql
);
145 return STATUS_SUCCESS
;
148 This
->SyncRoutine
= Routine
;
149 This
->DynamicContext
= DynamicContext
;
151 if (KeSynchronizeExecution(This
->Interrupt
, IInterruptSynchronizedRoutine
, (PVOID
)This
))
152 return STATUS_SUCCESS
;
154 return STATUS_UNSUCCESSFUL
;
159 IInterruptSync_fnGetKInterrupt(
160 IN IInterruptSync
* iface
)
162 IInterruptSyncImpl
* This
= (IInterruptSyncImpl
*)iface
;
163 DPRINT("IInterruptSynchronizedRoutine\n");
165 return This
->Interrupt
;
170 IInterruptServiceRoutine(
171 IN PKINTERRUPT Interrupt
,
172 IN PVOID ServiceContext
)
174 PLIST_ENTRY CurEntry
;
178 IInterruptSyncImpl
* This
= (IInterruptSyncImpl
*)ServiceContext
;
180 //DPRINT("IInterruptServiceRoutine Mode %u\n", This->Mode);
182 if (This
->Mode
== InterruptSyncModeNormal
)
184 CurEntry
= This
->ServiceRoutines
.Flink
;
185 while (CurEntry
!= &This
->ServiceRoutines
)
187 Entry
= CONTAINING_RECORD(CurEntry
, SYNC_ENTRY
, ListEntry
);
188 Status
= Entry
->SyncRoutine((IInterruptSync
*)This
, Entry
->DynamicContext
);
189 if (NT_SUCCESS(Status
))
193 CurEntry
= CurEntry
->Flink
;
197 else if (This
->Mode
== InterruptSyncModeAll
)
199 CurEntry
= This
->ServiceRoutines
.Flink
;
200 while (CurEntry
!= &This
->ServiceRoutines
)
202 Entry
= CONTAINING_RECORD(CurEntry
, SYNC_ENTRY
, ListEntry
);
203 Status
= Entry
->SyncRoutine((IInterruptSync
*)This
, Entry
->DynamicContext
);
204 CurEntry
= CurEntry
->Flink
;
206 DPRINT("Returning TRUE with mode InterruptSyncModeAll\n");
209 else if (This
->Mode
== InterruptSyncModeRepeat
)
214 CurEntry
= This
->ServiceRoutines
.Flink
;
215 while (CurEntry
!= &This
->ServiceRoutines
)
217 Entry
= CONTAINING_RECORD(CurEntry
, SYNC_ENTRY
, ListEntry
);
218 Status
= Entry
->SyncRoutine((IInterruptSync
*)This
, Entry
->DynamicContext
);
219 if (NT_SUCCESS(Status
))
221 CurEntry
= CurEntry
->Flink
;
224 DPRINT("Returning TRUE with mode InterruptSyncModeRepeat\n");
229 DPRINT("Unknown mode %u\n", This
->Mode
);
230 return FALSE
; //FIXME
237 IInterruptSync_fnConnect(
238 IN IInterruptSync
* iface
)
240 IInterruptSyncImpl
* This
= (IInterruptSyncImpl
*)iface
;
242 PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor
;
244 DPRINT("IInterruptSync_fnConnect\n");
245 ASSERT_IRQL_EQUAL(PASSIVE_LEVEL
);
247 Descriptor
= This
->ResourceList
->lpVtbl
->FindTranslatedEntry(This
->ResourceList
, CmResourceTypeInterrupt
, This
->ResourceIndex
);
249 return STATUS_UNSUCCESSFUL
;
251 if (IsListEmpty(&This
->ServiceRoutines
))
252 return STATUS_UNSUCCESSFUL
;
254 Status
= IoConnectInterrupt(&This
->Interrupt
,
255 IInterruptServiceRoutine
,
258 Descriptor
->u
.Interrupt
.Vector
,
259 Descriptor
->u
.Interrupt
.Level
,
260 Descriptor
->u
.Interrupt
.Level
,
261 (Descriptor
->Flags
& CM_RESOURCE_INTERRUPT_LATCHED
),
262 (Descriptor
->Flags
!= CM_RESOURCE_INTERRUPT_LATCHED
),
263 Descriptor
->u
.Interrupt
.Affinity
,
266 DPRINT("IInterruptSync_fnConnect result %x\n", Status
);
273 IInterruptSync_fnDisconnect(
274 IN IInterruptSync
* iface
)
276 IInterruptSyncImpl
* This
= (IInterruptSyncImpl
*)iface
;
278 DPRINT("IInterruptSync_fnDisconnect\n");
279 ASSERT_IRQL_EQUAL(PASSIVE_LEVEL
);
281 if (!This
->Interrupt
)
283 DPRINT("IInterruptSync_Disconnect %p no interrupt connected\n", This
);
287 IoDisconnectInterrupt(This
->Interrupt
);
288 This
->Interrupt
= NULL
;
293 IInterruptSync_fnRegisterServiceRoutine(
294 IN IInterruptSync
* iface
,
295 IN PINTERRUPTSYNCROUTINE Routine
,
296 IN PVOID DynamicContext
,
299 PSYNC_ENTRY NewEntry
;
300 IInterruptSyncImpl
* This
= (IInterruptSyncImpl
*)iface
;
302 DPRINT("IInterruptSync_fnRegisterServiceRoutine\n");
303 ASSERT_IRQL_EQUAL(PASSIVE_LEVEL
);
305 NewEntry
= AllocateItem(NonPagedPool
, sizeof(SYNC_ENTRY
), TAG_PORTCLASS
);
307 return STATUS_INSUFFICIENT_RESOURCES
;
309 NewEntry
->SyncRoutine
= Routine
;
310 NewEntry
->DynamicContext
= DynamicContext
;
313 InsertHeadList(&This
->ServiceRoutines
, &NewEntry
->ListEntry
);
315 InsertTailList(&This
->ServiceRoutines
, &NewEntry
->ListEntry
);
317 return STATUS_SUCCESS
;
320 static IInterruptSyncVtbl vt_IInterruptSyncVtbl
=
322 /* IUnknown methods */
323 IInterruptSync_fnQueryInterface
,
324 IInterruptSync_fnAddRef
,
325 IInterruptSync_fnRelease
,
326 /* IInterruptSync methods */
327 IInterruptSync_fnCallSynchronizedRoutine
,
328 IInterruptSync_fnGetKInterrupt
,
329 IInterruptSync_fnConnect
,
330 IInterruptSync_fnDisconnect
,
331 IInterruptSync_fnRegisterServiceRoutine
339 OUT PINTERRUPTSYNC
* OutInterruptSync
,
340 IN PUNKNOWN OuterUnknown OPTIONAL
,
341 IN PRESOURCELIST ResourceList
,
342 IN ULONG ResourceIndex
,
343 IN INTERRUPTSYNCMODE Mode
)
345 IInterruptSyncImpl
* This
;
347 DPRINT("PcNewInterruptSync entered OutInterruptSync %p OuterUnknown %p ResourceList %p ResourceIndex %u Mode %d\n",
348 OutInterruptSync
, OuterUnknown
, ResourceList
, ResourceIndex
, Mode
);
350 if (!OutInterruptSync
|| !ResourceList
|| Mode
< InterruptSyncModeNormal
|| Mode
> InterruptSyncModeRepeat
)
351 return STATUS_INVALID_PARAMETER
;
353 if (ResourceIndex
> ResourceList
->lpVtbl
->NumberOfEntriesOfType(ResourceList
, CmResourceTypeInterrupt
))
354 return STATUS_INVALID_PARAMETER
;
357 ResourceList
->lpVtbl
->AddRef(ResourceList
);
359 This
= AllocateItem(NonPagedPool
, sizeof(IInterruptSyncImpl
), TAG_PORTCLASS
);
361 return STATUS_INSUFFICIENT_RESOURCES
;
363 /* initialize object */
364 This
->lpVtbl
= &vt_IInterruptSyncVtbl
;
367 This
->ResourceIndex
= ResourceIndex
;
368 This
->ResourceList
= ResourceList
;
369 InitializeListHead(&This
->ServiceRoutines
);
370 KeInitializeSpinLock(&This
->Lock
);
372 *OutInterruptSync
= (PINTERRUPTSYNC
)&This
->lpVtbl
;
373 DPRINT("PcNewInterruptSync success %p\n", *OutInterruptSync
);
374 return STATUS_SUCCESS
;