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
15 IN PSERVICESINK pServiceSink
;
16 }GROUP_ENTRY
, *PGROUP_ENTRY
;
20 IServiceGroupVtbl
*lpVtbl
;
23 LIST_ENTRY ServiceSinkHead
;
35 //---------------------------------------------------------------
42 IServiceGroup_fnQueryInterface(
47 UNICODE_STRING GuidString
;
48 IServiceGroupImpl
* This
= (IServiceGroupImpl
*)iface
;
50 if (IsEqualGUIDAligned(refiid
, &IID_IServiceGroup
) ||
51 IsEqualGUIDAligned(refiid
, &IID_IServiceSink
) ||
52 IsEqualGUIDAligned(refiid
, &IID_IUnknown
))
54 *Output
= &This
->lpVtbl
;
55 InterlockedIncrement(&This
->ref
);
56 return STATUS_SUCCESS
;
59 if (RtlStringFromGUID(refiid
, &GuidString
) == STATUS_SUCCESS
)
61 DPRINT1("IServiceGroup_fnQueryInterface no interface!!! iface %S\n", GuidString
.Buffer
);
62 RtlFreeUnicodeString(&GuidString
);
65 return STATUS_UNSUCCESSFUL
;
70 IServiceGroup_fnAddRef(
73 IServiceGroupImpl
* This
= (IServiceGroupImpl
*)iface
;
75 return InterlockedIncrement(&This
->ref
);
80 IServiceGroup_fnRelease(
85 IServiceGroupImpl
* This
= (IServiceGroupImpl
*)iface
;
87 InterlockedDecrement(&This
->ref
);
91 while(!IsListEmpty(&This
->ServiceSinkHead
))
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
);
98 KeCancelTimer(&This
->Timer
);
99 if (This
->ThreadActive
)
101 KeSetEvent(&This
->Event
, 0, TRUE
);
103 FreeItem(This
, TAG_PORTCLASS
);
106 /* Return new reference count */
112 //---------------------------------------------------------------
113 // IServiceSink methods
118 IServiceGroup_fnRequestService(
119 IN IServiceGroup
* iface
)
122 IServiceGroupImpl
* This
= (IServiceGroupImpl
*)iface
;
124 if (KeGetCurrentIrql() > DISPATCH_LEVEL
)
126 KeInsertQueueDpc(&This
->Dpc
, NULL
, NULL
);
130 KeRaiseIrql(DISPATCH_LEVEL
, &OldIrql
);
131 KeInsertQueueDpc(&This
->Dpc
, NULL
, NULL
);
132 KeLowerIrql(OldIrql
);
135 //---------------------------------------------------------------
136 // IServiceGroup methods
141 IServiceGroup_fnAddMember(
142 IN IServiceGroup
* iface
,
143 IN PSERVICESINK pServiceSink
)
146 IServiceGroupImpl
* This
= (IServiceGroupImpl
*)iface
;
148 ASSERT_IRQL_EQUAL(PASSIVE_LEVEL
);
150 Entry
= AllocateItem(NonPagedPool
, sizeof(GROUP_ENTRY
), TAG_PORTCLASS
);
152 return STATUS_INSUFFICIENT_RESOURCES
;
154 Entry
->pServiceSink
= pServiceSink
;
155 pServiceSink
->lpVtbl
->AddRef(pServiceSink
);
157 InsertTailList(&This
->ServiceSinkHead
, &Entry
->Entry
);
159 return STATUS_SUCCESS
;
164 IServiceGroup_fnRemoveMember(
165 IN IServiceGroup
* iface
,
166 IN PSERVICESINK pServiceSink
)
168 PLIST_ENTRY CurEntry
;
170 IServiceGroupImpl
* This
= (IServiceGroupImpl
*)iface
;
172 ASSERT_IRQL_EQUAL(PASSIVE_LEVEL
);
174 CurEntry
= This
->ServiceSinkHead
.Flink
;
175 while (CurEntry
!= &This
->ServiceSinkHead
)
177 Entry
= CONTAINING_RECORD(CurEntry
, GROUP_ENTRY
, Entry
);
178 if (Entry
->pServiceSink
== pServiceSink
)
180 RemoveEntryList(&Entry
->Entry
);
181 pServiceSink
->lpVtbl
->Release(pServiceSink
);
182 FreeItem(Entry
, TAG_PORTCLASS
);
185 CurEntry
= CurEntry
->Flink
;
193 IN
struct _KDPC
*Dpc
,
194 IN PVOID DeferredContext
,
195 IN PVOID SystemArgument1
,
196 IN PVOID SystemArgument2
199 PLIST_ENTRY CurEntry
;
201 IServiceGroupImpl
* This
= (IServiceGroupImpl
*)DeferredContext
;
203 CurEntry
= This
->ServiceSinkHead
.Flink
;
204 while (CurEntry
!= &This
->ServiceSinkHead
)
206 Entry
= CONTAINING_RECORD(CurEntry
, GROUP_ENTRY
, Entry
);
207 Entry
->pServiceSink
->lpVtbl
->RequestService(Entry
->pServiceSink
);
208 CurEntry
= CurEntry
->Flink
;
215 ServiceGroupThread(IN PVOID StartContext
)
218 KWAIT_BLOCK WaitBlockArray
[2];
219 PVOID WaitObjects
[2];
220 IServiceGroupImpl
* This
= (IServiceGroupImpl
*)StartContext
;
222 /* Set thread state */
223 InterlockedIncrement(&This
->ThreadActive
);
225 /* Setup the wait objects */
226 WaitObjects
[0] = &This
->Timer
;
227 WaitObjects
[1] = &This
->Event
;
231 /* Wait on our objects */
232 Status
= KeWaitForMultipleObjects(2, WaitObjects
, WaitAny
, Executive
, KernelMode
, FALSE
, NULL
, WaitBlockArray
);
237 IServiceGroupDpc(&This
->Dpc
, (PVOID
)This
, NULL
, NULL
);
240 PsTerminateSystemThread(STATUS_SUCCESS
);
248 IServiceGroup_fnSupportDelayedService(
249 IN IServiceGroup
* iface
)
253 IServiceGroupImpl
* This
= (IServiceGroupImpl
*)iface
;
255 ASSERT_IRQL(DISPATCH_LEVEL
);
257 if (This
->Initialized
)
260 KeInitializeTimerEx(&This
->Timer
, NotificationTimer
);
262 Status
= PsCreateSystemThread(&ThreadHandle
, THREAD_ALL_ACCESS
, NULL
, 0, NULL
, ServiceGroupThread
, (PVOID
)This
);
263 if (NT_SUCCESS(Status
))
265 ZwClose(ThreadHandle
);
266 This
->Initialized
= TRUE
;
272 IServiceGroup_fnRequestDelayedService(
273 IN IServiceGroup
* iface
,
274 IN ULONGLONG ullDelay
)
276 LARGE_INTEGER DueTime
;
277 IServiceGroupImpl
* This
= (IServiceGroupImpl
*)iface
;
279 ASSERT_IRQL(DISPATCH_LEVEL
);
281 DueTime
.QuadPart
= ullDelay
;
283 if (This
->Initialized
)
285 if (KeGetCurrentIrql() <= DISPATCH_LEVEL
)
286 KeSetTimer(&This
->Timer
, DueTime
, &This
->Dpc
);
288 KeInsertQueueDpc(&This
->Dpc
, NULL
, NULL
);
294 IServiceGroup_fnCancelDelayedService(
295 IN IServiceGroup
* iface
)
297 IServiceGroupImpl
* This
= (IServiceGroupImpl
*)iface
;
299 ASSERT_IRQL(DISPATCH_LEVEL
);
301 if (This
->Initialized
)
303 KeCancelTimer(&This
->Timer
);
307 static IServiceGroupVtbl vt_IServiceGroup
=
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
326 OUT PSERVICEGROUP
* OutServiceGroup
,
327 IN PUNKNOWN OuterUnknown OPTIONAL
)
329 IServiceGroupImpl
* This
;
331 DPRINT("PcNewServiceGroup entered\n");
333 This
= AllocateItem(NonPagedPool
, sizeof(IServiceGroupImpl
), TAG_PORTCLASS
);
335 return STATUS_INSUFFICIENT_RESOURCES
;
337 This
->lpVtbl
= &vt_IServiceGroup
;
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
;
345 return STATUS_SUCCESS
;