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