- Fix various bugs such as wrong function definitions, using of uninitialized variables
[reactos.git] / reactos / drivers / wdm / audio / backpln / portcls / service_group.cpp
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Kernel Streaming
4 * FILE: drivers/wdm/audio/backpln/portcls/service_group.cpp
5 * PURPOSE: ServiceGroup object implementation
6 * PROGRAMMER: Johannes Anderwald
7 */
8
9
10 #include "private.hpp"
11
12 VOID
13 NTAPI
14 IServiceGroupDpc(
15 IN struct _KDPC *Dpc,
16 IN PVOID DeferredContext,
17 IN PVOID SystemArgument1,
18 IN PVOID SystemArgument2
19 );
20
21 typedef struct
22 {
23 LIST_ENTRY Entry;
24 IN PSERVICESINK pServiceSink;
25 }GROUP_ENTRY, *PGROUP_ENTRY;
26
27 class CServiceGroup : public IServiceGroup
28 {
29 public:
30 STDMETHODIMP QueryInterface( REFIID InterfaceId, PVOID* Interface);
31
32 STDMETHODIMP_(ULONG) AddRef()
33 {
34 InterlockedIncrement(&m_Ref);
35 return m_Ref;
36 }
37 STDMETHODIMP_(ULONG) Release()
38 {
39 InterlockedDecrement(&m_Ref);
40
41 if (!m_Ref)
42 {
43 delete this;
44 return 0;
45 }
46 return m_Ref;
47 }
48
49 IMP_IServiceGroup;
50 CServiceGroup(IUnknown * OuterUnknown);
51 virtual ~CServiceGroup() {}
52
53 protected:
54
55 LIST_ENTRY m_ServiceSinkHead;
56
57 BOOL m_Initialized;
58 BOOL m_TimerActive;
59 KTIMER m_Timer;
60 KDPC m_Dpc;
61 KEVENT m_Event;
62 LONG m_ThreadActive;
63
64 friend VOID NTAPI IServiceGroupDpc(IN struct _KDPC *Dpc, IN PVOID DeferredContext, IN PVOID SystemArgument1, IN PVOID SystemArgument2);
65
66 LONG m_Ref;
67
68 };
69
70
71
72 //---------------------------------------------------------------
73 // IUnknown methods
74 //
75
76
77 NTSTATUS
78 NTAPI
79 CServiceGroup::QueryInterface(
80 IN REFIID refiid,
81 OUT PVOID* Output)
82 {
83 UNICODE_STRING GuidString;
84
85 if (IsEqualGUIDAligned(refiid, IID_IServiceGroup) ||
86 IsEqualGUIDAligned(refiid, IID_IServiceSink) ||
87 IsEqualGUIDAligned(refiid, IID_IUnknown))
88 {
89 *Output = PVOID(PSERVICEGROUP(this));
90 PUNKNOWN(*Output)->AddRef();
91 return STATUS_SUCCESS;
92 }
93
94 if (RtlStringFromGUID(refiid, &GuidString) == STATUS_SUCCESS)
95 {
96 DPRINT1("CServiceGroup::QueryInterface no interface!!! iface %S\n", GuidString.Buffer);
97 RtlFreeUnicodeString(&GuidString);
98 }
99
100 return STATUS_UNSUCCESSFUL;
101 }
102 //---------------------------------------------------------------
103 // IServiceSink methods
104 //
105
106 CServiceGroup::CServiceGroup(IUnknown * OuterUnknown)
107 {
108 KeInitializeDpc(&m_Dpc, IServiceGroupDpc, (PVOID)this);
109 KeSetImportanceDpc(&m_Dpc, HighImportance);
110 KeInitializeEvent(&m_Event, NotificationEvent, FALSE);
111 InitializeListHead(&m_ServiceSinkHead);
112 }
113
114 VOID
115 NTAPI
116 CServiceGroup::RequestService()
117 {
118 KIRQL OldIrql;
119
120 DPRINT("CServiceGroup::RequestService() Dpc at Level %u\n", KeGetCurrentIrql());
121
122 if (KeGetCurrentIrql() > DISPATCH_LEVEL)
123 {
124 KeInsertQueueDpc(&m_Dpc, NULL, NULL);
125 return;
126 }
127
128 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
129 KeInsertQueueDpc(&m_Dpc, NULL, NULL);
130 KeLowerIrql(OldIrql);
131 }
132
133 //---------------------------------------------------------------
134 // IServiceGroup methods
135 //
136
137 NTSTATUS
138 NTAPI
139 CServiceGroup::AddMember(
140 IN PSERVICESINK pServiceSink)
141 {
142 PGROUP_ENTRY Entry;
143
144 PC_ASSERT_IRQL_EQUAL(PASSIVE_LEVEL);
145
146 Entry = (PGROUP_ENTRY)AllocateItem(NonPagedPool, sizeof(GROUP_ENTRY), TAG_PORTCLASS);
147 if (!Entry)
148 return STATUS_INSUFFICIENT_RESOURCES;
149
150 Entry->pServiceSink = pServiceSink;
151 pServiceSink->AddRef();
152
153 InsertTailList(&m_ServiceSinkHead, &Entry->Entry);
154
155 return STATUS_SUCCESS;
156 }
157
158 VOID
159 NTAPI
160 CServiceGroup::RemoveMember(
161 IN PSERVICESINK pServiceSink)
162 {
163 PLIST_ENTRY CurEntry;
164 PGROUP_ENTRY Entry;
165
166 PC_ASSERT_IRQL_EQUAL(PASSIVE_LEVEL);
167
168 CurEntry = m_ServiceSinkHead.Flink;
169 while (CurEntry != &m_ServiceSinkHead)
170 {
171 Entry = CONTAINING_RECORD(CurEntry, GROUP_ENTRY, Entry);
172 if (Entry->pServiceSink == pServiceSink)
173 {
174 RemoveEntryList(&Entry->Entry);
175 pServiceSink->Release();
176 FreeItem(Entry, TAG_PORTCLASS);
177 return;
178 }
179 CurEntry = CurEntry->Flink;
180 }
181
182 }
183
184 VOID
185 NTAPI
186 IServiceGroupDpc(
187 IN struct _KDPC *Dpc,
188 IN PVOID DeferredContext,
189 IN PVOID SystemArgument1,
190 IN PVOID SystemArgument2
191 )
192 {
193 PLIST_ENTRY CurEntry;
194 PGROUP_ENTRY Entry;
195 CServiceGroup * This = (CServiceGroup*)DeferredContext;
196
197 CurEntry = This->m_ServiceSinkHead.Flink;
198 while (CurEntry != &This->m_ServiceSinkHead)
199 {
200 Entry = (PGROUP_ENTRY)CONTAINING_RECORD(CurEntry, GROUP_ENTRY, Entry);
201 Entry->pServiceSink->RequestService();
202 CurEntry = CurEntry->Flink;
203 }
204 }
205
206
207 #if 0
208 VOID
209 NTAPI
210 ServiceGroupThread(IN PVOID StartContext)
211 {
212 NTSTATUS Status;
213 KWAIT_BLOCK WaitBlockArray[2];
214 PVOID WaitObjects[2];
215 CServiceGroup * This = (CServiceGroup*)StartContext;
216
217 // Set thread state
218 InterlockedIncrement(&This->m_ThreadActive);
219
220 // Setup the wait objects
221 WaitObjects[0] = &m_Timer;
222 WaitObjects[1] = &m_Event;
223
224 do
225 {
226 // Wait on our objects
227 Status = KeWaitForMultipleObjects(2, WaitObjects, WaitAny, Executive, KernelMode, FALSE, NULL, WaitBlockArray);
228
229 switch(Status)
230 {
231 case STATUS_WAIT_0:
232 IServiceGroupDpc(&This->m_Dpc, (PVOID)This, NULL, NULL);
233 break;
234 case STATUS_WAIT_1:
235 PsTerminateSystemThread(STATUS_SUCCESS);
236 return;
237 }
238 }while(TRUE);
239 }
240
241 #endif
242 VOID
243 NTAPI
244 CServiceGroup::SupportDelayedService()
245 {
246 //NTSTATUS Status;
247 //HANDLE ThreadHandle;
248
249 PC_ASSERT_IRQL(DISPATCH_LEVEL);
250
251 if (m_Initialized)
252 return;
253
254 KeInitializeTimerEx(&m_Timer, NotificationTimer);
255
256 #if 0
257 Status = PsCreateSystemThread(&ThreadHandle, THREAD_ALL_ACCESS, NULL, 0, NULL, ServiceGroupThread, (PVOID)This);
258 if (NT_SUCCESS(Status))
259 {
260 ZwClose(ThreadHandle);
261 m_Initialized = TRUE;
262 }
263 #endif
264 }
265
266 VOID
267 NTAPI
268 CServiceGroup::RequestDelayedService(
269 IN ULONGLONG ullDelay)
270 {
271 LARGE_INTEGER DueTime;
272
273 PC_ASSERT_IRQL(DISPATCH_LEVEL);
274
275 DueTime.QuadPart = ullDelay;
276
277 if (m_Initialized)
278 {
279 if (KeGetCurrentIrql() <= DISPATCH_LEVEL)
280 KeSetTimer(&m_Timer, DueTime, &m_Dpc);
281 else
282 KeInsertQueueDpc(&m_Dpc, NULL, NULL);
283 }
284 }
285
286 VOID
287 NTAPI
288 CServiceGroup::CancelDelayedService()
289 {
290 PC_ASSERT_IRQL(DISPATCH_LEVEL);
291
292 if (m_Initialized)
293 {
294 KeCancelTimer(&m_Timer);
295 }
296 }
297
298 NTSTATUS
299 NTAPI
300 PcNewServiceGroup(
301 OUT PSERVICEGROUP* OutServiceGroup,
302 IN PUNKNOWN OuterUnknown OPTIONAL)
303 {
304 CServiceGroup * This;
305 NTSTATUS Status;
306 DPRINT("PcNewServiceGroup entered\n");
307
308 This = new(NonPagedPool, TAG_PORTCLASS)CServiceGroup(OuterUnknown);
309 if (!This)
310 return STATUS_INSUFFICIENT_RESOURCES;
311
312 Status = This->QueryInterface(IID_IServiceSink, (PVOID*)OutServiceGroup);
313
314 if (!NT_SUCCESS(Status))
315 {
316 delete This;
317 return Status;
318 }
319
320 return Status;
321 }