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