[PORTCLS]
[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 #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 DPRINT("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->PartialResourceList.Count ||
442 !Parent->m_UntranslatedResourceList->List->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->PartialResourceList.Count = 0;
471 NewList->m_UntranslatedResourceList->List->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