[DRIVERS] Spelling fixes by Josh Soref. CORE-12286
[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 #include "private.hpp"
10
11 #ifndef YDEBUG
12 #define NDEBUG
13 #endif
14
15 #include <debug.h>
16
17 VOID
18 NTAPI
19 IServiceGroupDpc(
20 IN struct _KDPC *Dpc,
21 IN PVOID DeferredContext,
22 IN PVOID SystemArgument1,
23 IN PVOID SystemArgument2
24 );
25
26 typedef struct
27 {
28 LIST_ENTRY Entry;
29 IN PSERVICESINK pServiceSink;
30 }GROUP_ENTRY, *PGROUP_ENTRY;
31
32 class CServiceGroup : public IServiceGroup
33 {
34 public:
35 STDMETHODIMP QueryInterface( REFIID InterfaceId, PVOID* Interface);
36
37 STDMETHODIMP_(ULONG) AddRef()
38 {
39 InterlockedIncrement(&m_Ref);
40 return m_Ref;
41 }
42 STDMETHODIMP_(ULONG) Release()
43 {
44 InterlockedDecrement(&m_Ref);
45
46 if (!m_Ref)
47 {
48 delete this;
49 return 0;
50 }
51 return m_Ref;
52 }
53
54 IMP_IServiceGroup;
55 CServiceGroup(IUnknown * OuterUnknown);
56 virtual ~CServiceGroup() {}
57
58 protected:
59
60 LIST_ENTRY m_ServiceSinkHead;
61
62 BOOL m_TimerInitialized;
63 KTIMER m_Timer;
64 KDPC m_Dpc;
65 KSPIN_LOCK m_Lock;
66
67 friend VOID NTAPI IServiceGroupDpc(IN struct _KDPC *Dpc, IN PVOID DeferredContext, IN PVOID SystemArgument1, IN PVOID SystemArgument2);
68
69 LONG m_Ref;
70
71 };
72
73
74
75 //---------------------------------------------------------------
76 // IUnknown methods
77 //
78
79
80 NTSTATUS
81 NTAPI
82 CServiceGroup::QueryInterface(
83 IN REFIID refiid,
84 OUT PVOID* Output)
85 {
86 UNICODE_STRING GuidString;
87
88 if (IsEqualGUIDAligned(refiid, IID_IServiceGroup) ||
89 IsEqualGUIDAligned(refiid, IID_IServiceSink) ||
90 IsEqualGUIDAligned(refiid, IID_IUnknown))
91 {
92 *Output = PVOID(PSERVICEGROUP(this));
93 PUNKNOWN(*Output)->AddRef();
94 return STATUS_SUCCESS;
95 }
96
97 if (RtlStringFromGUID(refiid, &GuidString) == STATUS_SUCCESS)
98 {
99 DPRINT1("CServiceGroup::QueryInterface no interface!!! iface %S\n", GuidString.Buffer);
100 RtlFreeUnicodeString(&GuidString);
101 }
102
103 return STATUS_UNSUCCESSFUL;
104 }
105 //---------------------------------------------------------------
106 // IServiceSink methods
107 //
108
109 CServiceGroup::CServiceGroup(IUnknown * OuterUnknown)
110 {
111 // initialize dpc
112 KeInitializeDpc(&m_Dpc, IServiceGroupDpc, (PVOID)this);
113
114 // set highest importance
115 KeSetImportanceDpc(&m_Dpc, HighImportance);
116
117 // initialize service group list lock
118 KeInitializeSpinLock(&m_Lock);
119
120 // initialize service group list
121 InitializeListHead(&m_ServiceSinkHead);
122 }
123
124 VOID
125 NTAPI
126 CServiceGroup::RequestService()
127 {
128 KIRQL OldIrql;
129
130 DPRINT("CServiceGroup::RequestService() Dpc at Level %u\n", KeGetCurrentIrql());
131
132 if (m_TimerInitialized)
133 {
134 LARGE_INTEGER DueTime;
135
136 // no due time
137 DueTime.QuadPart = 0LL;
138
139 // delayed service requested
140 KeSetTimer(&m_Timer, DueTime, &m_Dpc);
141 }
142 else
143 {
144 // check current irql
145 if (KeGetCurrentIrql() > DISPATCH_LEVEL)
146 {
147 //insert dpc to queue
148 KeInsertQueueDpc(&m_Dpc, NULL, NULL);
149 }
150 else
151 {
152 // raise irql to dispatch level to make dpc fire immediately
153 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
154 // insert dpc to queue
155 KeInsertQueueDpc(&m_Dpc, NULL, NULL);
156 // lower irql to old level
157 KeLowerIrql(OldIrql);
158 }
159 }
160 }
161
162 //---------------------------------------------------------------
163 // IServiceGroup methods
164 //
165
166 NTSTATUS
167 NTAPI
168 CServiceGroup::AddMember(
169 IN PSERVICESINK pServiceSink)
170 {
171 PGROUP_ENTRY Entry;
172 KIRQL OldLevel;
173
174 // sanity check
175 PC_ASSERT_IRQL_EQUAL(PASSIVE_LEVEL);
176
177 // allocate service sink entry
178 Entry = (PGROUP_ENTRY)AllocateItem(NonPagedPool, sizeof(GROUP_ENTRY), TAG_PORTCLASS);
179 if (!Entry)
180 {
181 // out of memory
182 return STATUS_INSUFFICIENT_RESOURCES;
183 }
184
185 // initialize service sink entry
186 Entry->pServiceSink = pServiceSink;
187 // increment reference count
188 pServiceSink->AddRef();
189
190 // acquire service group list lock
191 KeAcquireSpinLock(&m_Lock, &OldLevel);
192
193 // insert into service sink list
194 InsertTailList(&m_ServiceSinkHead, &Entry->Entry);
195
196 // release service group list lock
197 KeReleaseSpinLock(&m_Lock, OldLevel);
198
199 return STATUS_SUCCESS;
200 }
201
202 VOID
203 NTAPI
204 CServiceGroup::RemoveMember(
205 IN PSERVICESINK pServiceSink)
206 {
207 PLIST_ENTRY CurEntry;
208 PGROUP_ENTRY Entry;
209 KIRQL OldLevel;
210
211 // sanity check
212 PC_ASSERT_IRQL_EQUAL(PASSIVE_LEVEL);
213
214 // acquire service group list lock
215 KeAcquireSpinLock(&m_Lock, &OldLevel);
216
217 // grab first entry
218 CurEntry = m_ServiceSinkHead.Flink;
219
220 // loop list until the passed entry is found
221 while (CurEntry != &m_ServiceSinkHead)
222 {
223 // grab entry
224 Entry = CONTAINING_RECORD(CurEntry, GROUP_ENTRY, Entry);
225
226 // check if it matches the passed entry
227 if (Entry->pServiceSink == pServiceSink)
228 {
229 // remove entry from list
230 RemoveEntryList(&Entry->Entry);
231
232 // release service sink reference
233 pServiceSink->Release();
234
235 // free service sink entry
236 FreeItem(Entry, TAG_PORTCLASS);
237
238 // leave loop
239 break;
240 }
241 // move to next entry
242 CurEntry = CurEntry->Flink;
243 }
244
245 // release service group list lock
246 KeReleaseSpinLock(&m_Lock, OldLevel);
247
248 }
249
250 VOID
251 NTAPI
252 IServiceGroupDpc(
253 IN struct _KDPC *Dpc,
254 IN PVOID DeferredContext,
255 IN PVOID SystemArgument1,
256 IN PVOID SystemArgument2
257 )
258 {
259 PLIST_ENTRY CurEntry;
260 PGROUP_ENTRY Entry;
261 CServiceGroup * This = (CServiceGroup*)DeferredContext;
262
263 // acquire service group list lock
264 KeAcquireSpinLockAtDpcLevel(&This->m_Lock);
265
266 // grab first entry
267 CurEntry = This->m_ServiceSinkHead.Flink;
268
269 // loop the list and call the attached service sink/group
270 while (CurEntry != &This->m_ServiceSinkHead)
271 {
272 //grab current entry
273 Entry = (PGROUP_ENTRY)CONTAINING_RECORD(CurEntry, GROUP_ENTRY, Entry);
274
275 // call service sink/group
276 Entry->pServiceSink->RequestService();
277
278 // move to next entry
279 CurEntry = CurEntry->Flink;
280 }
281
282 // release service group list lock
283 KeReleaseSpinLockFromDpcLevel(&This->m_Lock);
284 }
285
286 VOID
287 NTAPI
288 CServiceGroup::SupportDelayedService()
289 {
290 PC_ASSERT_IRQL(DISPATCH_LEVEL);
291
292 // initialize the timer
293 KeInitializeTimer(&m_Timer);
294
295 // use the timer to perform service requests
296 m_TimerInitialized = TRUE;
297 }
298
299 VOID
300 NTAPI
301 CServiceGroup::RequestDelayedService(
302 IN ULONGLONG ullDelay)
303 {
304 LARGE_INTEGER DueTime;
305
306 // sanity check
307 PC_ASSERT_IRQL(DISPATCH_LEVEL);
308 PC_ASSERT(m_TimerInitialized);
309
310 DueTime.QuadPart = ullDelay;
311
312 // set the timer
313 KeSetTimer(&m_Timer, DueTime, &m_Dpc);
314 }
315
316 VOID
317 NTAPI
318 CServiceGroup::CancelDelayedService()
319 {
320 PC_ASSERT_IRQL(DISPATCH_LEVEL);
321 PC_ASSERT(m_TimerInitialized);
322
323 // cancel the timer
324 KeCancelTimer(&m_Timer);
325 }
326
327 NTSTATUS
328 NTAPI
329 PcNewServiceGroup(
330 OUT PSERVICEGROUP* OutServiceGroup,
331 IN PUNKNOWN OuterUnknown OPTIONAL)
332 {
333 CServiceGroup * This;
334 NTSTATUS Status;
335
336 DPRINT("PcNewServiceGroup entered\n");
337
338 //FIXME support aggregation
339 PC_ASSERT(OuterUnknown == NULL);
340
341 // allocate a service group object
342 This = new(NonPagedPool, TAG_PORTCLASS)CServiceGroup(OuterUnknown);
343
344 if (!This)
345 {
346 // out of memory
347 return STATUS_INSUFFICIENT_RESOURCES;
348 }
349
350 // request IServiceSink interface
351 Status = This->QueryInterface(IID_IServiceSink, (PVOID*)OutServiceGroup);
352
353 if (!NT_SUCCESS(Status))
354 {
355 // failed to acquire service sink interface
356 delete This;
357 return Status;
358 }
359
360 // done
361 return Status;
362 }