- Check for valid DeviceExtensionSize
[reactos.git] / reactos / drivers / wdm / audio / backpln / portcls / interrupt.c
1 #include "private.h"
2
3 typedef struct
4 {
5 LIST_ENTRY ListEntry;
6 PINTERRUPTSYNCROUTINE SyncRoutine;
7 PVOID DynamicContext;
8 }SYNC_ENTRY, *PSYNC_ENTRY;
9
10 typedef struct
11 {
12 IInterruptSyncVtbl *lpVtbl;
13
14 LONG ref;
15 KSPIN_LOCK Lock;
16 LIST_ENTRY ServiceRoutines;
17 PKINTERRUPT Interrupt;
18 INTERRUPTSYNCMODE Mode;
19 PRESOURCELIST ResourceList;
20 ULONG ResourceIndex;
21
22 PINTERRUPTSYNCROUTINE SyncRoutine;
23 PVOID DynamicContext;
24 }IInterruptSyncImpl;
25
26
27 //---------------------------------------------------------------
28 // IUnknown methods
29 //
30
31
32
33 NTSTATUS
34 NTAPI
35 IInterruptSync_fnQueryInterface(
36 IInterruptSync * iface,
37 IN REFIID refiid,
38 OUT PVOID* Output)
39 {
40 IInterruptSyncImpl * This = (IInterruptSyncImpl*)iface;
41
42 DPRINT1("IInterruptSync_fnQueryInterface: This %p\n", This);
43
44 if (IsEqualGUIDAligned(refiid, &IID_IInterruptSync))
45 {
46 *Output = &This->lpVtbl;
47 _InterlockedIncrement(&This->ref);
48 return STATUS_SUCCESS;
49 }
50 DPRINT1("IInterruptSync_fnQueryInterface: This %p UNKNOWN interface requested\n", This);
51 return STATUS_UNSUCCESSFUL;
52 }
53
54 ULONG
55 NTAPI
56 IInterruptSync_fnAddRef(
57 IInterruptSync * iface)
58 {
59 IInterruptSyncImpl * This = (IInterruptSyncImpl*)iface;
60
61 DPRINT1("IInterruptSync_AddRef: This %p\n", This);
62
63 return _InterlockedIncrement(&This->ref);
64 }
65
66 ULONG
67 NTAPI
68 IInterruptSync_fnRelease(
69 IInterruptSync* iface)
70 {
71 PLIST_ENTRY CurEntry;
72 PSYNC_ENTRY Entry;
73 IInterruptSyncImpl * This = (IInterruptSyncImpl*)iface;
74
75 _InterlockedDecrement(&This->ref);
76
77 DPRINT1("IInterruptSync_Release: This %p new ref %u\n", This, This->ref);
78
79 if (This->ref == 0)
80 {
81 while(!IsListEmpty(&This->ServiceRoutines))
82 {
83 CurEntry = RemoveHeadList(&This->ServiceRoutines);
84 Entry = CONTAINING_RECORD(CurEntry, SYNC_ENTRY, ListEntry);
85 FreeItem(Entry, TAG_PORTCLASS);
86 }
87
88 //This->ResourceList->lpVtbl->Release(This->ResourceList);
89 //FreeItem(This, TAG_PORTCLASS);
90 DPRINT1("IInterruptSync_Release: complete\n");
91 return 0;
92 }
93 /* Return new reference count */
94 return This->ref;
95 }
96
97 //---------------------------------------------------------------
98 // IInterruptSync methods
99 //
100
101
102 BOOLEAN
103 NTAPI
104 IInterruptSynchronizedRoutine(
105 IN PVOID ServiceContext)
106 {
107 IInterruptSyncImpl * This = (IInterruptSyncImpl*)ServiceContext;
108 DPRINT1("IInterruptSynchronizedRoutine This %p SyncRoutine%p\n", This, This->SyncRoutine);
109 return This->SyncRoutine((IInterruptSync*)&This->lpVtbl, This->DynamicContext);
110 }
111
112 NTSTATUS
113 NTAPI
114 IInterruptSync_fnCallSynchronizedRoutine(
115 IN IInterruptSync * iface,
116 IN PINTERRUPTSYNCROUTINE Routine,
117 IN PVOID DynamicContext)
118 {
119 KIRQL OldIrql;
120 IInterruptSyncImpl * This = (IInterruptSyncImpl*)iface;
121
122 DPRINT1("IInterruptSync_fnCallSynchronizedRoutine This %p Routine %p DynamicContext %p\n", This, Routine, DynamicContext);
123
124 if (!This->Interrupt)
125 {
126 DPRINT("IInterruptSync_CallSynchronizedRoutine %p no interrupt connected\n", This);
127 if (KeGetCurrentIrql() > DISPATCH_LEVEL)
128 return STATUS_UNSUCCESSFUL;
129
130 KeAcquireSpinLock(&This->Lock, &OldIrql);
131 This->SyncRoutine = Routine;
132 This->DynamicContext = DynamicContext;
133 IInterruptSynchronizedRoutine((PVOID)This);
134 KeReleaseSpinLock(&This->Lock, OldIrql);
135
136 return STATUS_SUCCESS;
137 }
138
139 This->SyncRoutine = Routine;
140 This->DynamicContext = DynamicContext;
141
142 return KeSynchronizeExecution(This->Interrupt, IInterruptSynchronizedRoutine, (PVOID)This);
143 }
144
145 NTAPI
146 PKINTERRUPT
147 IInterruptSync_fnGetKInterrupt(
148 IN IInterruptSync * iface)
149 {
150 IInterruptSyncImpl * This = (IInterruptSyncImpl*)iface;
151 DPRINT1("IInterruptSynchronizedRoutine\n");
152
153 return This->Interrupt;
154 }
155
156 BOOLEAN
157 NTAPI
158 IInterruptServiceRoutine(
159 IN PKINTERRUPT Interrupt,
160 IN PVOID ServiceContext)
161 {
162 PLIST_ENTRY CurEntry;
163 PSYNC_ENTRY Entry;
164 NTSTATUS Status;
165 BOOL Success;
166 IInterruptSyncImpl * This = (IInterruptSyncImpl*)ServiceContext;
167
168 DPRINT1("IInterruptServiceRoutine\n");
169
170 if (This->Mode == InterruptSyncModeNormal)
171 {
172 CurEntry = This->ServiceRoutines.Flink;
173 while (CurEntry != &This->ServiceRoutines)
174 {
175 Entry = CONTAINING_RECORD(CurEntry, SYNC_ENTRY, ListEntry);
176 Status = Entry->SyncRoutine((IInterruptSync*)This, Entry->DynamicContext);
177 if (NT_SUCCESS(Status))
178 {
179 return TRUE;
180 }
181 CurEntry = CurEntry->Flink;
182 }
183 return FALSE;
184 }
185 else if (This->Mode == InterruptSyncModeAll)
186 {
187 CurEntry = This->ServiceRoutines.Flink;
188 while (CurEntry != &This->ServiceRoutines)
189 {
190 Entry = CONTAINING_RECORD(CurEntry, SYNC_ENTRY, ListEntry);
191 Status = Entry->SyncRoutine((IInterruptSync*)This, Entry->DynamicContext);
192 CurEntry = CurEntry->Flink;
193 }
194 DPRINT("Returning TRUE with mode InterruptSyncModeAll\n");
195 return TRUE; //FIXME
196 }
197 else if (This->Mode == InterruptSyncModeRepeat)
198 {
199 do
200 {
201 Success = FALSE;
202 CurEntry = This->ServiceRoutines.Flink;
203 while (CurEntry != &This->ServiceRoutines)
204 {
205 Entry = CONTAINING_RECORD(CurEntry, SYNC_ENTRY, ListEntry);
206 Status = Entry->SyncRoutine((IInterruptSync*)This, Entry->DynamicContext);
207 if (NT_SUCCESS(Status))
208 Success = TRUE;
209 CurEntry = CurEntry->Flink;
210 }
211 }while(Success);
212 DPRINT("Returning TRUE with mode InterruptSyncModeRepeat\n");
213 return TRUE; //FIXME
214 }
215 else
216 {
217 DPRINT("Unknown mode %u\n", This->Mode);
218 return FALSE; //FIXME
219 }
220 }
221
222
223 NTSTATUS
224 NTAPI
225 IInterruptSync_fnConnect(
226 IN IInterruptSync * iface)
227 {
228 IInterruptSyncImpl * This = (IInterruptSyncImpl*)iface;
229 NTSTATUS Status;
230 PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor;
231
232 DPRINT1("IInterruptSync_fnConnect\n");
233
234 Descriptor = This->ResourceList->lpVtbl->FindTranslatedEntry(This->ResourceList, CmResourceTypeInterrupt, This->ResourceIndex);
235 if (!Descriptor)
236 return STATUS_UNSUCCESSFUL;
237
238 if (IsListEmpty(&This->ServiceRoutines))
239 return STATUS_UNSUCCESSFUL;
240
241 Status = IoConnectInterrupt(&This->Interrupt,
242 IInterruptServiceRoutine,
243 (PVOID)This,
244 &This->Lock, Descriptor->u.Interrupt.Vector,
245 Descriptor->u.Interrupt.Level,
246 Descriptor->u.Interrupt.Level, //FIXME
247 LevelSensitive, //FIXME
248 TRUE, //FIXME
249 Descriptor->u.Interrupt.Affinity,
250 FALSE);
251
252 return Status;
253 }
254
255
256 VOID
257 NTAPI
258 IInterruptSync_fnDisconnect(
259 IN IInterruptSync * iface)
260 {
261 IInterruptSyncImpl * This = (IInterruptSyncImpl*)iface;
262 DPRINT1("IInterruptSync_fnDisconnect\n");
263
264 if (!This->Interrupt)
265 {
266 DPRINT("IInterruptSync_Disconnect %p no interrupt connected\n", This);
267 return;
268 }
269
270 IoDisconnectInterrupt(This->Interrupt);
271 This->Interrupt = NULL;
272 }
273
274 NTSTATUS
275 NTAPI
276 IInterruptSync_fnRegisterServiceRoutine(
277 IN IInterruptSync * iface,
278 IN PINTERRUPTSYNCROUTINE Routine,
279 IN PVOID DynamicContext,
280 IN BOOLEAN First)
281 {
282 PSYNC_ENTRY NewEntry;
283 IInterruptSyncImpl * This = (IInterruptSyncImpl*)iface;
284
285 DPRINT1("IInterruptSync_fnRegisterServiceRoutine\n");
286
287 NewEntry = AllocateItem(NonPagedPool, sizeof(SYNC_ENTRY), TAG_PORTCLASS);
288 if (!NewEntry)
289 return STATUS_INSUFFICIENT_RESOURCES;
290
291 NewEntry->SyncRoutine = Routine;
292 NewEntry->DynamicContext = DynamicContext;
293
294 if (First)
295 InsertHeadList(&This->ServiceRoutines, &NewEntry->ListEntry);
296 else
297 InsertTailList(&This->ServiceRoutines, &NewEntry->ListEntry);
298
299 return STATUS_SUCCESS;
300 }
301
302 static IInterruptSyncVtbl vt_IInterruptSyncVtbl =
303 {
304 /* IUnknown methods */
305 IInterruptSync_fnQueryInterface,
306 IInterruptSync_fnAddRef,
307 IInterruptSync_fnRelease,
308 /* IInterruptSync methods */
309 IInterruptSync_fnCallSynchronizedRoutine,
310 IInterruptSync_fnGetKInterrupt,
311 IInterruptSync_fnConnect,
312 IInterruptSync_fnDisconnect,
313 IInterruptSync_fnRegisterServiceRoutine
314 };
315
316 /*
317 * @unimplemented
318 */
319 NTSTATUS NTAPI
320 PcNewInterruptSync(
321 OUT PINTERRUPTSYNC* OutInterruptSync,
322 IN PUNKNOWN OuterUnknown OPTIONAL,
323 IN PRESOURCELIST ResourceList,
324 IN ULONG ResourceIndex,
325 IN INTERRUPTSYNCMODE Mode)
326 {
327 IInterruptSyncImpl * This;
328
329 DPRINT1("PcNewInterruptSync entered\n");
330
331 if (!OutInterruptSync || !ResourceList || Mode > InterruptSyncModeRepeat || Mode < 0)
332 return STATUS_INVALID_PARAMETER;
333
334 if (ResourceIndex > ResourceList->lpVtbl->NumberOfEntriesOfType(ResourceList, CmResourceTypeInterrupt))
335 return STATUS_INVALID_PARAMETER;
336
337
338 ResourceList->lpVtbl->AddRef(ResourceList);
339
340 This = AllocateItem(NonPagedPool, sizeof(IInterruptSyncImpl), TAG_PORTCLASS);
341 if (!This)
342 return STATUS_INSUFFICIENT_RESOURCES;
343
344 /* initialize object */
345 This->lpVtbl = &vt_IInterruptSyncVtbl;
346 This->ref = 1;
347 This->Mode = Mode;
348 This->ResourceIndex = ResourceIndex;
349 This->ResourceList = ResourceList;
350 InitializeListHead(&This->ServiceRoutines);
351 KeInitializeSpinLock(&This->Lock);
352
353 *OutInterruptSync = (PINTERRUPTSYNC)&This->lpVtbl;
354 DPRINT1("PcNewInterruptSync success %p\n", *OutInterruptSync);
355 return STATUS_SUCCESS;
356 }
357