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