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