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