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