- Convert portcls to a C++ driver
[reactos.git] / reactos / drivers / wdm / audio / backpln / portcls / resource.cpp
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS
4 * FILE: drivers/wdm/audio/backpln/portcls/resource.cpp
5 * PURPOSE: Port Class driver / ResourceList implementation
6 * PROGRAMMER: Andrew Greenwood
7 * Johannes Anderwald
8 * HISTORY:
9 * 27 Jan 07 Created
10 */
11
12 #include "private.hpp"
13
14 class CResourceList : public IResourceList
15 {
16 public:
17 STDMETHODIMP QueryInterface( REFIID InterfaceId, PVOID* Interface);
18
19 STDMETHODIMP_(ULONG) AddRef()
20 {
21 InterlockedIncrement(&m_Ref);
22 return m_Ref;
23 }
24 STDMETHODIMP_(ULONG) Release()
25 {
26 InterlockedDecrement(&m_Ref);
27
28 if (!m_Ref)
29 {
30 delete this;
31 return 0;
32 }
33 return m_Ref;
34 }
35
36 IMP_IResourceList;
37 CResourceList(IUnknown * OuterUnknown) {}
38 virtual ~CResourceList() {}
39
40 public:
41 PUNKNOWN m_OuterUnknown;
42 POOL_TYPE m_PoolType;
43 PCM_RESOURCE_LIST m_TranslatedResourceList;
44 PCM_RESOURCE_LIST m_UntranslatedResourceList;
45 ULONG m_NumberOfEntries;
46
47 LONG m_Ref;
48 };
49
50
51 NTSTATUS
52 NTAPI
53 CResourceList::QueryInterface(
54 IN REFIID refiid,
55 OUT PVOID* Output)
56 {
57 UNICODE_STRING GuidString;
58
59 if (IsEqualGUIDAligned(refiid, IID_IResourceList) ||
60 IsEqualGUIDAligned(refiid, IID_IUnknown))
61 {
62 *Output = PVOID(PRESOURCELIST(this));
63 PUNKNOWN(*Output)->AddRef();
64 return STATUS_SUCCESS;
65 }
66
67 if (RtlStringFromGUID(refiid, &GuidString) == STATUS_SUCCESS)
68 {
69 DPRINT1("IResourceList_QueryInterface no interface!!! iface %S\n", GuidString.Buffer);
70 RtlFreeUnicodeString(&GuidString);
71 }
72
73 return STATUS_UNSUCCESSFUL;
74 }
75
76 ULONG
77 NTAPI
78 CResourceList::NumberOfEntries()
79 {
80 // ASSERT_IRQL_EQUAL(PASSIVE_LEVEL);
81
82 return m_NumberOfEntries;
83 }
84
85 ULONG
86 NTAPI
87 CResourceList::NumberOfEntriesOfType(
88 IN CM_RESOURCE_TYPE Type)
89 {
90 ULONG Index, Count = 0;
91 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor;
92
93 PC_ASSERT_IRQL_EQUAL(PASSIVE_LEVEL);
94
95 if (!m_TranslatedResourceList)
96 {
97 // no resource list
98 return 0;
99 }
100
101 // I guess the translated and untranslated lists will be same length?
102 for (Index = 0; Index < m_TranslatedResourceList->List[0].PartialResourceList.Count; Index ++ )
103 {
104 PartialDescriptor = &m_TranslatedResourceList->List[0].PartialResourceList.PartialDescriptors[Index];
105 DPRINT("Descriptor Type %u\n", PartialDescriptor->Type);
106 if (PartialDescriptor->Type == Type)
107 {
108 // Yay! Finally found one that matches!
109 Count++;
110 }
111 }
112
113 DPRINT("Found %d type %d\n", Count, Type);
114 return Count;
115 }
116
117 PCM_PARTIAL_RESOURCE_DESCRIPTOR
118 NTAPI
119 CResourceList::FindTranslatedEntry(
120 IN CM_RESOURCE_TYPE Type,
121 IN ULONG Index)
122 {
123 ULONG DescIndex, Count = 0;
124 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor;
125
126 PC_ASSERT_IRQL_EQUAL(PASSIVE_LEVEL);
127
128 if (!m_TranslatedResourceList)
129 {
130 // no resource list
131 return NULL;
132 }
133
134 for (DescIndex = 0; DescIndex < m_TranslatedResourceList->List[0].PartialResourceList.Count; DescIndex ++ )
135 {
136 PartialDescriptor = &m_TranslatedResourceList->List[0].PartialResourceList.PartialDescriptors[DescIndex];
137
138 if (PartialDescriptor->Type == Type)
139 {
140 // Yay! Finally found one that matches!
141 if (Index == Count)
142 {
143 return PartialDescriptor;
144 }
145 Count++;
146 }
147 }
148
149 return NULL;
150 }
151
152 PCM_PARTIAL_RESOURCE_DESCRIPTOR
153 NTAPI
154 CResourceList::FindUntranslatedEntry(
155 IN CM_RESOURCE_TYPE Type,
156 IN ULONG Index)
157 {
158 ULONG DescIndex, Count = 0;
159 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor;
160
161 PC_ASSERT_IRQL_EQUAL(PASSIVE_LEVEL);
162
163 if (!m_UntranslatedResourceList)
164 {
165 // no resource list
166 return NULL;
167 }
168
169 for (DescIndex = 0; DescIndex < m_UntranslatedResourceList->List[0].PartialResourceList.Count; DescIndex ++ )
170 {
171 PartialDescriptor = &m_UntranslatedResourceList->List[0].PartialResourceList.PartialDescriptors[DescIndex];
172
173 if (PartialDescriptor->Type == Type)
174 {
175 // Yay! Finally found one that matches!
176 if (Index == Count)
177 {
178 return PartialDescriptor;
179 }
180 Count++;
181 }
182 }
183 return NULL;
184 }
185
186 NTSTATUS
187 NTAPI
188 CResourceList::AddEntry(
189 IN PCM_PARTIAL_RESOURCE_DESCRIPTOR Translated,
190 IN PCM_PARTIAL_RESOURCE_DESCRIPTOR Untranslated)
191 {
192 PCM_RESOURCE_LIST NewUntranslatedResources, NewTranslatedResources;
193 ULONG NewTranslatedSize, NewUntranslatedSize, TranslatedSize, UntranslatedSize, ResourceCount;
194
195 PC_ASSERT_IRQL_EQUAL(PASSIVE_LEVEL);
196
197 // calculate translated resource list size
198 ResourceCount = m_TranslatedResourceList->List[0].PartialResourceList.Count;
199 #ifdef _MSC_VER
200 NewTranslatedSize = FIELD_OFFSET(CM_RESOURCE_LIST, List[0].PartialResourceList.PartialDescriptors[ResourceCount+1]);
201 TranslatedSize = FIELD_OFFSET(CM_RESOURCE_LIST, List[0].PartialResourceList.PartialDescriptors[ResourceCount]);
202 #else
203 NewTranslatedSize = sizeof(CM_RESOURCE_LIST) + (ResourceCount > 0 ? (ResourceCount+1) * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) : 0);
204 TranslatedSize = sizeof(CM_RESOURCE_LIST) + (ResourceCount > 0 ? (ResourceCount) * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) : 0);
205
206 #endif
207 NewTranslatedResources = (PCM_RESOURCE_LIST)AllocateItem(m_PoolType, NewTranslatedSize, TAG_PORTCLASS);
208 if (!NewTranslatedResources)
209 return STATUS_INSUFFICIENT_RESOURCES;
210
211
212 // calculate untranslated resouce list size
213 ResourceCount = m_UntranslatedResourceList->List[0].PartialResourceList.Count;
214
215 #ifdef _MSC_VER
216 NewUntranslatedSize = FIELD_OFFSET(CM_RESOURCE_LIST, List[0].PartialResourceList.PartialDescriptors[ResourceCount+1]);
217 UntranslatedSize = FIELD_OFFSET(CM_RESOURCE_LIST, List[0].PartialResourceList.PartialDescriptors[ResourceCount]);
218 #else
219 NewUntranslatedSize = sizeof(CM_RESOURCE_LIST) + (ResourceCount > 0 ? (ResourceCount+1) * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) : 0);
220 UntranslatedSize = sizeof(CM_RESOURCE_LIST) + (ResourceCount > 0 ? (ResourceCount) * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) : 0);
221
222 #endif
223
224
225 // allocate untranslated resource list size
226 NewUntranslatedResources = (PCM_RESOURCE_LIST)AllocateItem(m_PoolType, NewUntranslatedSize, TAG_PORTCLASS);
227 if (!NewUntranslatedResources)
228 {
229 FreeItem(NewTranslatedResources, TAG_PORTCLASS);
230 return STATUS_INSUFFICIENT_RESOURCES;
231 }
232
233 // now copy translated resource list
234 RtlMoveMemory(NewTranslatedResources, m_TranslatedResourceList, TranslatedSize);
235 RtlMoveMemory((PUCHAR)NewTranslatedResources + TranslatedSize, Translated, sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));
236
237 // now copy untranslated resource list
238 RtlMoveMemory(NewUntranslatedResources, m_UntranslatedResourceList, UntranslatedSize);
239 RtlMoveMemory((PUCHAR)NewUntranslatedResources + UntranslatedSize, Untranslated, sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));
240
241 // free old lists
242 FreeItem(m_TranslatedResourceList, TAG_PORTCLASS);
243 FreeItem(m_UntranslatedResourceList, TAG_PORTCLASS);
244
245 // store new lists
246 m_UntranslatedResourceList = NewUntranslatedResources;
247 m_TranslatedResourceList = NewTranslatedResources;
248
249 // increment descriptor count
250 NewUntranslatedResources->List[0].PartialResourceList.Count++;
251 NewTranslatedResources->List[0].PartialResourceList.Count++;
252
253 // add entry count
254 m_NumberOfEntries++;
255
256 return STATUS_SUCCESS;
257 }
258
259 NTSTATUS
260 NTAPI
261 CResourceList::AddEntryFromParent(
262 IN IResourceList* Parent,
263 IN CM_RESOURCE_TYPE Type,
264 IN ULONG Index)
265 {
266 PCM_PARTIAL_RESOURCE_DESCRIPTOR Translated, Untranslated;
267
268 PC_ASSERT_IRQL_EQUAL(PASSIVE_LEVEL);
269
270 Translated = Parent->FindTranslatedEntry(Type, Index);
271 Untranslated = Parent->FindUntranslatedEntry(Type, Index);
272
273 if (Translated && Untranslated)
274 {
275 // add entry from parent
276 return AddEntry(Translated, Untranslated);
277 }
278
279 // entry not found
280 return STATUS_INVALID_PARAMETER;
281 }
282
283 PCM_RESOURCE_LIST
284 NTAPI
285 CResourceList::TranslatedList()
286 {
287 PC_ASSERT_IRQL_EQUAL(PASSIVE_LEVEL);
288
289 return m_TranslatedResourceList;
290 }
291
292 PCM_RESOURCE_LIST
293 NTAPI
294 CResourceList::UntranslatedList()
295 {
296 PC_ASSERT_IRQL_EQUAL(PASSIVE_LEVEL);
297
298 return m_UntranslatedResourceList;
299 }
300
301
302 PORTCLASSAPI
303 NTSTATUS
304 NTAPI
305 PcNewResourceList(
306 OUT PRESOURCELIST* OutResourceList,
307 IN PUNKNOWN OuterUnknown OPTIONAL,
308 IN POOL_TYPE PoolType,
309 IN PCM_RESOURCE_LIST TranslatedResourceList,
310 IN PCM_RESOURCE_LIST UntranslatedResourceList)
311 {
312 PCM_RESOURCE_LIST NewUntranslatedResources, NewTranslatedResources;
313 ULONG NewTranslatedSize, NewUntranslatedSize, ResourceCount;
314 CResourceList* NewList;
315 NTSTATUS Status;
316
317 if (!TranslatedResourceList)
318 {
319 //
320 // if the untranslated resource list is also not provided, it becomes an empty resource list
321 //
322 if (UntranslatedResourceList)
323 {
324 // invalid parameter mix
325 return STATUS_INVALID_PARAMETER;
326 }
327 }
328 else
329 {
330 //
331 // if the translated resource list is also not provided, it becomes an empty resource list
332 //
333 if (!UntranslatedResourceList)
334 {
335 // invalid parameter mix
336 return STATUS_INVALID_PARAMETER;
337 }
338 }
339
340 NewList = new(PoolType, TAG_PORTCLASS)CResourceList(OuterUnknown);
341 if (!NewList)
342 return STATUS_INSUFFICIENT_RESOURCES;
343
344 Status = NewList->QueryInterface(IID_IResourceList, (PVOID*)OutResourceList);
345
346 if (!NT_SUCCESS(Status))
347 {
348 delete NewList;
349 }
350
351 // calculate translated resource list size
352 ResourceCount = TranslatedResourceList->List[0].PartialResourceList.Count;
353 #ifdef _MSC_VER
354 NewTranslatedSize = FIELD_OFFSET(CM_RESOURCE_LIST, List[0].PartialResourceList.PartialDescriptors[ResourceCount]);
355 #else
356 NewTranslatedSize = sizeof(CM_RESOURCE_LIST) + (ResourceCount > 0 ? (ResourceCount-1) * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) : 0);
357 #endif
358
359 // store resource count
360 NewList->m_NumberOfEntries = ResourceCount;
361
362 // calculate untranslated resouce list size
363 ResourceCount = UntranslatedResourceList->List[0].PartialResourceList.Count;
364 #ifdef _MSC_VER
365 NewUntranslatedSize = FIELD_OFFSET(CM_RESOURCE_LIST, List[0].PartialResourceList.PartialDescriptors[ResourceCount]);
366 #else
367 NewUntranslatedSize = sizeof(CM_RESOURCE_LIST) + (ResourceCount > 0 ? (ResourceCount-1) * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) : 0);
368 #endif
369
370 // allocate translated resource list
371 NewTranslatedResources = (PCM_RESOURCE_LIST)AllocateItem(PoolType, NewTranslatedSize, TAG_PORTCLASS);
372 if (!NewTranslatedResources)
373 {
374 FreeItem(NewList, TAG_PORTCLASS);
375 return STATUS_INSUFFICIENT_RESOURCES;
376 }
377
378 // allocate untranslated resource list
379 NewUntranslatedResources = (PCM_RESOURCE_LIST)AllocateItem(PoolType, NewUntranslatedSize, TAG_PORTCLASS);
380 if (!NewUntranslatedResources)
381 {
382 FreeItem(NewList, TAG_PORTCLASS);
383 FreeItem(NewTranslatedResources, TAG_PORTCLASS);
384 return STATUS_INSUFFICIENT_RESOURCES;
385 }
386
387 // copy resource lists
388 RtlCopyMemory(NewTranslatedResources, TranslatedResourceList, NewTranslatedSize);
389 RtlCopyMemory(NewUntranslatedResources, UntranslatedResourceList, NewUntranslatedSize);
390
391 // store resource lists
392 NewList->m_TranslatedResourceList= NewTranslatedResources;
393 NewList->m_UntranslatedResourceList = NewUntranslatedResources;
394
395 return STATUS_SUCCESS;
396 }
397
398 PORTCLASSAPI
399 NTSTATUS
400 NTAPI
401 PcNewResourceSublist(
402 OUT PRESOURCELIST* OutResourceList,
403 IN PUNKNOWN OuterUnknown OPTIONAL,
404 IN POOL_TYPE PoolType,
405 IN PRESOURCELIST ParentList,
406 IN ULONG MaximumEntries)
407 {
408 CResourceList* NewList, *Parent;
409
410 if (!OutResourceList || !ParentList || !MaximumEntries)
411 return STATUS_INVALID_PARAMETER;
412
413 Parent = (CResourceList*)ParentList;
414
415 if (!Parent->m_TranslatedResourceList->List->PartialResourceList.Count ||
416 !Parent->m_UntranslatedResourceList->List->PartialResourceList.Count)
417 {
418 // parent list can't be empty
419 return STATUS_INVALID_PARAMETER;
420 }
421
422 NewList = new(PoolType, TAG_PORTCLASS) CResourceList(OuterUnknown);
423 if (!NewList)
424 return STATUS_INSUFFICIENT_RESOURCES;
425
426 NewList->m_TranslatedResourceList = (PCM_RESOURCE_LIST)AllocateItem(PoolType, sizeof(CM_RESOURCE_LIST), TAG_PORTCLASS);
427 if (!NewList->m_TranslatedResourceList)
428 {
429 delete NewList;
430 return STATUS_INSUFFICIENT_RESOURCES;
431 }
432
433 NewList->m_UntranslatedResourceList = (PCM_RESOURCE_LIST)AllocateItem(PoolType, sizeof(CM_RESOURCE_LIST), TAG_PORTCLASS);
434 if (!NewList->m_UntranslatedResourceList)
435 {
436 delete NewList;
437 return STATUS_INSUFFICIENT_RESOURCES;
438 }
439
440 RtlCopyMemory(NewList->m_TranslatedResourceList, Parent->m_TranslatedResourceList, sizeof(CM_RESOURCE_LIST));
441 RtlCopyMemory(NewList->m_UntranslatedResourceList, Parent->m_UntranslatedResourceList, sizeof(CM_RESOURCE_LIST));
442
443 // mark list as empty
444 NewList->m_TranslatedResourceList->List->PartialResourceList.Count = 0;
445 NewList->m_UntranslatedResourceList->List->PartialResourceList.Count = 0;
446 // store members
447 NewList->m_OuterUnknown = OuterUnknown;
448 NewList->m_PoolType = PoolType;
449 NewList->m_Ref = 1;
450
451 *OutResourceList = (IResourceList*)NewList;
452
453 DPRINT("PcNewResourceSublist OutResourceList %p OuterUnknown %p ParentList %p\n", *OutResourceList, OuterUnknown, ParentList);
454 return STATUS_SUCCESS;
455 }
456