[NTOSKRNL]
[reactos.git] / ntoskrnl / io / pnpmgr / pnpres.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * COPYRIGHT: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/io/pnpmgr/pnpres.c
5 * PURPOSE: Resource handling code
6 * PROGRAMMERS: Cameron Gutman (cameron.gutman@reactos.org)
7 * ReactOS Portable Systems Group
8 */
9
10 #include <ntoskrnl.h>
11
12 #define NDEBUG
13 #include <debug.h>
14
15 static
16 BOOLEAN
17 IopCheckDescriptorForConflict(PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc, OPTIONAL PCM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDescriptor)
18 {
19 CM_RESOURCE_LIST CmList;
20 NTSTATUS Status;
21
22 CmList.Count = 1;
23 CmList.List[0].InterfaceType = InterfaceTypeUndefined;
24 CmList.List[0].BusNumber = 0;
25 CmList.List[0].PartialResourceList.Version = 1;
26 CmList.List[0].PartialResourceList.Revision = 1;
27 CmList.List[0].PartialResourceList.Count = 1;
28 CmList.List[0].PartialResourceList.PartialDescriptors[0] = *CmDesc;
29
30 Status = IopDetectResourceConflict(&CmList, TRUE, ConflictingDescriptor);
31 if (Status == STATUS_CONFLICTING_ADDRESSES)
32 return TRUE;
33
34 return FALSE;
35 }
36
37 static
38 BOOLEAN
39 IopFindBusNumberResource(
40 IN PIO_RESOURCE_DESCRIPTOR IoDesc,
41 OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc)
42 {
43 ULONG Start;
44 CM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDesc;
45
46 ASSERT(IoDesc->Type == CmDesc->Type);
47 ASSERT(IoDesc->Type == CmResourceTypeBusNumber);
48
49 for (Start = IoDesc->u.BusNumber.MinBusNumber;
50 Start <= IoDesc->u.BusNumber.MaxBusNumber - IoDesc->u.BusNumber.Length + 1;
51 Start++)
52 {
53 CmDesc->u.BusNumber.Length = IoDesc->u.BusNumber.Length;
54 CmDesc->u.BusNumber.Start = Start;
55
56 if (IopCheckDescriptorForConflict(CmDesc, &ConflictingDesc))
57 {
58 Start += ConflictingDesc.u.BusNumber.Start + ConflictingDesc.u.BusNumber.Length;
59 }
60 else
61 {
62 DPRINT1("Satisfying bus number requirement with 0x%x (length: 0x%x)\n", Start, CmDesc->u.BusNumber.Length);
63 return TRUE;
64 }
65 }
66
67 return FALSE;
68 }
69
70 static
71 BOOLEAN
72 IopFindMemoryResource(
73 IN PIO_RESOURCE_DESCRIPTOR IoDesc,
74 OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc)
75 {
76 LONGLONG Start;
77 CM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDesc;
78
79 ASSERT(IoDesc->Type == CmDesc->Type);
80 ASSERT(IoDesc->Type == CmResourceTypeMemory);
81
82 /* HACK */
83 if (IoDesc->u.Memory.Alignment == 0) IoDesc->u.Memory.Alignment = 1;
84
85 for (Start = IoDesc->u.Memory.MinimumAddress.QuadPart;
86 Start <= IoDesc->u.Memory.MaximumAddress.QuadPart - IoDesc->u.Memory.Length + 1;
87 Start += IoDesc->u.Memory.Alignment)
88 {
89 CmDesc->u.Memory.Length = IoDesc->u.Memory.Length;
90 CmDesc->u.Memory.Start.QuadPart = Start;
91
92 if (IopCheckDescriptorForConflict(CmDesc, &ConflictingDesc))
93 {
94 Start += ConflictingDesc.u.Memory.Start.QuadPart +
95 ConflictingDesc.u.Memory.Length;
96 }
97 else
98 {
99 DPRINT1("Satisfying memory requirement with 0x%I64x (length: 0x%x)\n", Start, CmDesc->u.Memory.Length);
100 return TRUE;
101 }
102 }
103
104 return FALSE;
105 }
106
107 static
108 BOOLEAN
109 IopFindPortResource(
110 IN PIO_RESOURCE_DESCRIPTOR IoDesc,
111 OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc)
112 {
113 LONGLONG Start;
114 CM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDesc;
115
116 ASSERT(IoDesc->Type == CmDesc->Type);
117 ASSERT(IoDesc->Type == CmResourceTypePort);
118
119 /* HACK */
120 if (IoDesc->u.Port.Alignment == 0) IoDesc->u.Port.Alignment = 1;
121
122 for (Start = IoDesc->u.Port.MinimumAddress.QuadPart;
123 Start <= IoDesc->u.Port.MaximumAddress.QuadPart - IoDesc->u.Port.Length + 1;
124 Start += IoDesc->u.Port.Alignment)
125 {
126 CmDesc->u.Port.Length = IoDesc->u.Port.Length;
127 CmDesc->u.Port.Start.QuadPart = Start;
128
129 if (IopCheckDescriptorForConflict(CmDesc, &ConflictingDesc))
130 {
131 Start += ConflictingDesc.u.Port.Start.QuadPart + ConflictingDesc.u.Port.Length;
132 }
133 else
134 {
135 DPRINT1("Satisfying port requirement with 0x%I64x (length: 0x%x)\n", Start, CmDesc->u.Port.Length);
136 return TRUE;
137 }
138 }
139
140 return FALSE;
141 }
142
143 static
144 BOOLEAN
145 IopFindDmaResource(
146 IN PIO_RESOURCE_DESCRIPTOR IoDesc,
147 OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc)
148 {
149 ULONG Channel;
150
151 ASSERT(IoDesc->Type == CmDesc->Type);
152 ASSERT(IoDesc->Type == CmResourceTypeDma);
153
154 for (Channel = IoDesc->u.Dma.MinimumChannel;
155 Channel <= IoDesc->u.Dma.MaximumChannel;
156 Channel++)
157 {
158 CmDesc->u.Dma.Channel = Channel;
159 CmDesc->u.Dma.Port = 0;
160
161 if (!IopCheckDescriptorForConflict(CmDesc, NULL))
162 {
163 DPRINT1("Satisfying DMA requirement with channel 0x%x\n", Channel);
164 return TRUE;
165 }
166 }
167
168 return FALSE;
169 }
170
171 static
172 BOOLEAN
173 IopFindInterruptResource(
174 IN PIO_RESOURCE_DESCRIPTOR IoDesc,
175 OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc)
176 {
177 ULONG Vector;
178
179 ASSERT(IoDesc->Type == CmDesc->Type);
180 ASSERT(IoDesc->Type == CmResourceTypeInterrupt);
181
182 for (Vector = IoDesc->u.Interrupt.MinimumVector;
183 Vector <= IoDesc->u.Interrupt.MaximumVector;
184 Vector++)
185 {
186 CmDesc->u.Interrupt.Vector = Vector;
187 CmDesc->u.Interrupt.Level = Vector;
188 CmDesc->u.Interrupt.Affinity = (KAFFINITY)-1;
189
190 if (!IopCheckDescriptorForConflict(CmDesc, NULL))
191 {
192 DPRINT1("Satisfying interrupt requirement with IRQ 0x%x\n", Vector);
193 return TRUE;
194 }
195 }
196
197 return FALSE;
198 }
199
200 NTSTATUS NTAPI
201 IopFixupResourceListWithRequirements(
202 IN PIO_RESOURCE_REQUIREMENTS_LIST RequirementsList,
203 OUT PCM_RESOURCE_LIST *ResourceList)
204 {
205 ULONG i;
206 for (i = 0; i < RequirementsList->AlternativeLists; i++)
207 {
208 ULONG ii;
209 PIO_RESOURCE_LIST ResList = &RequirementsList->List[i];
210 BOOLEAN AlternateRequired = FALSE;
211
212 for (ii = 0; ii < ResList->Count; ii++)
213 {
214 ULONG iii;
215 PCM_PARTIAL_RESOURCE_LIST PartialList = (*ResourceList) ? &(*ResourceList)->List[0].PartialResourceList : NULL;
216 PIO_RESOURCE_DESCRIPTOR IoDesc = &ResList->Descriptors[ii];
217 BOOLEAN Matched = FALSE;
218
219 /* Skip alternates if we don't need one */
220 if (!AlternateRequired && (IoDesc->Option & IO_RESOURCE_ALTERNATIVE))
221 {
222 DPRINT("Skipping unneeded alternate\n");
223 continue;
224 }
225
226 /* Check if we couldn't satsify a requirement or its alternates */
227 if (AlternateRequired && !(IoDesc->Option & IO_RESOURCE_ALTERNATIVE))
228 {
229 DPRINT1("Unable to satisfy preferred resource or alternates\n");
230
231 if (*ResourceList)
232 {
233 ExFreePool(*ResourceList);
234 *ResourceList = NULL;
235 }
236 return STATUS_CONFLICTING_ADDRESSES;
237 }
238
239 for (iii = 0; PartialList && iii < PartialList->Count && !Matched; iii++)
240 {
241 PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc = &PartialList->PartialDescriptors[iii];
242
243 /* First check types */
244 if (IoDesc->Type != CmDesc->Type)
245 continue;
246
247 switch (IoDesc->Type)
248 {
249 case CmResourceTypeInterrupt:
250 /* Make sure it satisfies our vector range */
251 if (CmDesc->u.Interrupt.Vector >= IoDesc->u.Interrupt.MinimumVector &&
252 CmDesc->u.Interrupt.Vector <= IoDesc->u.Interrupt.MaximumVector)
253 {
254 /* Found it */
255 Matched = TRUE;
256 }
257 else
258 {
259 DPRINT("Interrupt - Not a match! 0x%x not inside 0x%x to 0x%x\n",
260 CmDesc->u.Interrupt.Vector,
261 IoDesc->u.Interrupt.MinimumVector,
262 IoDesc->u.Interrupt.MaximumVector);
263 }
264 break;
265
266 case CmResourceTypeMemory:
267 case CmResourceTypePort:
268 /* Make sure the length matches and it satisfies our address range */
269 if (CmDesc->u.Memory.Length == IoDesc->u.Memory.Length &&
270 CmDesc->u.Memory.Start.QuadPart >= IoDesc->u.Memory.MinimumAddress.QuadPart &&
271 CmDesc->u.Memory.Start.QuadPart + CmDesc->u.Memory.Length - 1 <= IoDesc->u.Memory.MaximumAddress.QuadPart)
272 {
273 /* Found it */
274 Matched = TRUE;
275 }
276 else
277 {
278 DPRINT("Memory/Port - Not a match! 0x%I64x with length 0x%x not inside 0x%I64x to 0x%I64x with length 0x%x\n",
279 CmDesc->u.Memory.Start.QuadPart,
280 CmDesc->u.Memory.Length,
281 IoDesc->u.Memory.MinimumAddress.QuadPart,
282 IoDesc->u.Memory.MaximumAddress.QuadPart,
283 IoDesc->u.Memory.Length);
284 }
285 break;
286
287 case CmResourceTypeBusNumber:
288 /* Make sure the length matches and it satisfies our bus number range */
289 if (CmDesc->u.BusNumber.Length == IoDesc->u.BusNumber.Length &&
290 CmDesc->u.BusNumber.Start >= IoDesc->u.BusNumber.MinBusNumber &&
291 CmDesc->u.BusNumber.Start + CmDesc->u.BusNumber.Length - 1 <= IoDesc->u.BusNumber.MaxBusNumber)
292 {
293 /* Found it */
294 Matched = TRUE;
295 }
296 else
297 {
298 DPRINT("Bus Number - Not a match! 0x%x with length 0x%x not inside 0x%x to 0x%x with length 0x%x\n",
299 CmDesc->u.BusNumber.Start,
300 CmDesc->u.BusNumber.Length,
301 IoDesc->u.BusNumber.MinBusNumber,
302 IoDesc->u.BusNumber.MaxBusNumber,
303 IoDesc->u.BusNumber.Length);
304 }
305 break;
306
307 case CmResourceTypeDma:
308 /* Make sure it fits in our channel range */
309 if (CmDesc->u.Dma.Channel >= IoDesc->u.Dma.MinimumChannel &&
310 CmDesc->u.Dma.Channel <= IoDesc->u.Dma.MaximumChannel)
311 {
312 /* Found it */
313 Matched = TRUE;
314 }
315 else
316 {
317 DPRINT("DMA - Not a match! 0x%x not inside 0x%x to 0x%x\n",
318 CmDesc->u.Dma.Channel,
319 IoDesc->u.Dma.MinimumChannel,
320 IoDesc->u.Dma.MaximumChannel);
321 }
322 break;
323
324 default:
325 /* Other stuff is fine */
326 Matched = TRUE;
327 break;
328 }
329 }
330
331 /* Check if we found a matching descriptor */
332 if (!Matched)
333 {
334 PCM_RESOURCE_LIST NewList;
335 CM_PARTIAL_RESOURCE_DESCRIPTOR NewDesc;
336 PCM_PARTIAL_RESOURCE_DESCRIPTOR DescPtr;
337 BOOLEAN FoundResource = TRUE;
338
339 /* Setup the new CM descriptor */
340 NewDesc.Type = IoDesc->Type;
341 NewDesc.Flags = IoDesc->Flags;
342 NewDesc.ShareDisposition = IoDesc->ShareDisposition;
343
344 /* Let'se see if we can find a resource to satisfy this */
345 switch (IoDesc->Type)
346 {
347 case CmResourceTypeInterrupt:
348 /* Find an available interrupt */
349 if (!IopFindInterruptResource(IoDesc, &NewDesc))
350 {
351 DPRINT1("Failed to find an available interrupt resource (0x%x to 0x%x)\n",
352 IoDesc->u.Interrupt.MinimumVector, IoDesc->u.Interrupt.MaximumVector);
353
354 FoundResource = FALSE;
355 }
356 break;
357
358 case CmResourceTypePort:
359 /* Find an available port range */
360 if (!IopFindPortResource(IoDesc, &NewDesc))
361 {
362 DPRINT1("Failed to find an available port resource (0x%I64x to 0x%I64x length: 0x%x)\n",
363 IoDesc->u.Port.MinimumAddress.QuadPart, IoDesc->u.Port.MaximumAddress.QuadPart,
364 IoDesc->u.Port.Length);
365
366 FoundResource = FALSE;
367 }
368 break;
369
370 case CmResourceTypeMemory:
371 /* Find an available memory range */
372 if (!IopFindMemoryResource(IoDesc, &NewDesc))
373 {
374 DPRINT1("Failed to find an available memory resource (0x%I64x to 0x%I64x length: 0x%x)\n",
375 IoDesc->u.Memory.MinimumAddress.QuadPart, IoDesc->u.Memory.MaximumAddress.QuadPart,
376 IoDesc->u.Memory.Length);
377
378 FoundResource = FALSE;
379 }
380 break;
381
382 case CmResourceTypeBusNumber:
383 /* Find an available bus address range */
384 if (!IopFindBusNumberResource(IoDesc, &NewDesc))
385 {
386 DPRINT1("Failed to find an available bus number resource (0x%x to 0x%x length: 0x%x)\n",
387 IoDesc->u.BusNumber.MinBusNumber, IoDesc->u.BusNumber.MaxBusNumber,
388 IoDesc->u.BusNumber.Length);
389
390 FoundResource = FALSE;
391 }
392 break;
393
394 case CmResourceTypeDma:
395 /* Find an available DMA channel */
396 if (!IopFindDmaResource(IoDesc, &NewDesc))
397 {
398 DPRINT1("Failed to find an available dma resource (0x%x to 0x%x)\n",
399 IoDesc->u.Dma.MinimumChannel, IoDesc->u.Dma.MaximumChannel);
400
401 FoundResource = FALSE;
402 }
403 break;
404
405 default:
406 DPRINT1("Unsupported resource type: %x\n", IoDesc->Type);
407 FoundResource = FALSE;
408 break;
409 }
410
411 /* Check if it's missing and required */
412 if (!FoundResource && IoDesc->Option == 0)
413 {
414 if (*ResourceList)
415 {
416 ExFreePool(*ResourceList);
417 *ResourceList = NULL;
418 }
419 return STATUS_CONFLICTING_ADDRESSES;
420 }
421 else if (!FoundResource)
422 {
423 /* Try an alternate for this preferred descriptor */
424 AlternateRequired = TRUE;
425 continue;
426 }
427 else
428 {
429 /* Move on to the next preferred or required descriptor after this one */
430 AlternateRequired = FALSE;
431 }
432
433 /* Figure out what we need */
434 if (PartialList == NULL)
435 {
436 /* We need a new list */
437 NewList = ExAllocatePool(PagedPool, sizeof(CM_RESOURCE_LIST));
438 if (!NewList)
439 return STATUS_NO_MEMORY;
440
441 /* Set it up */
442 NewList->Count = 1;
443 NewList->List[0].InterfaceType = RequirementsList->InterfaceType;
444 NewList->List[0].BusNumber = RequirementsList->BusNumber;
445 NewList->List[0].PartialResourceList.Version = 1;
446 NewList->List[0].PartialResourceList.Revision = 1;
447 NewList->List[0].PartialResourceList.Count = 1;
448
449 /* Set our pointer */
450 DescPtr = &NewList->List[0].PartialResourceList.PartialDescriptors[0];
451 }
452 else
453 {
454 /* Allocate the new larger list */
455 NewList = ExAllocatePool(PagedPool, PnpDetermineResourceListSize(*ResourceList) + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));
456 if (!NewList)
457 return STATUS_NO_MEMORY;
458
459 /* Copy the old stuff back */
460 RtlCopyMemory(NewList, *ResourceList, PnpDetermineResourceListSize(*ResourceList));
461
462 /* Set our pointer */
463 DescPtr = &NewList->List[0].PartialResourceList.PartialDescriptors[NewList->List[0].PartialResourceList.Count];
464
465 /* Increment the descriptor count */
466 NewList->List[0].PartialResourceList.Count++;
467
468 /* Free the old list */
469 ExFreePool(*ResourceList);
470 }
471
472 /* Copy the descriptor in */
473 *DescPtr = NewDesc;
474
475 /* Store the new list */
476 *ResourceList = NewList;
477 }
478 }
479 }
480
481 /* Done */
482 return STATUS_SUCCESS;
483 }
484
485 static
486 BOOLEAN
487 IopCheckResourceDescriptor(
488 IN PCM_PARTIAL_RESOURCE_DESCRIPTOR ResDesc,
489 IN PCM_RESOURCE_LIST ResourceList,
490 IN BOOLEAN Silent,
491 OUT OPTIONAL PCM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDescriptor)
492 {
493 ULONG i, ii;
494 BOOLEAN Result = FALSE;
495
496 for (i = 0; i < ResourceList->Count; i++)
497 {
498 PCM_PARTIAL_RESOURCE_LIST ResList = &ResourceList->List[i].PartialResourceList;
499 for (ii = 0; ii < ResList->Count; ii++)
500 {
501 PCM_PARTIAL_RESOURCE_DESCRIPTOR ResDesc2 = &ResList->PartialDescriptors[ii];
502
503 /* We don't care about shared resources */
504 if (ResDesc->ShareDisposition == CmResourceShareShared &&
505 ResDesc2->ShareDisposition == CmResourceShareShared)
506 continue;
507
508 /* Make sure we're comparing the same types */
509 if (ResDesc->Type != ResDesc2->Type)
510 continue;
511
512 switch (ResDesc->Type)
513 {
514 case CmResourceTypeMemory:
515 if ((ResDesc->u.Memory.Start.QuadPart < ResDesc2->u.Memory.Start.QuadPart &&
516 ResDesc->u.Memory.Start.QuadPart + ResDesc->u.Memory.Length >
517 ResDesc2->u.Memory.Start.QuadPart) || (ResDesc2->u.Memory.Start.QuadPart <
518 ResDesc->u.Memory.Start.QuadPart && ResDesc2->u.Memory.Start.QuadPart +
519 ResDesc2->u.Memory.Length > ResDesc->u.Memory.Start.QuadPart))
520 {
521 if (!Silent)
522 {
523 DPRINT1("Resource conflict: Memory (0x%I64x to 0x%I64x vs. 0x%I64x to 0x%I64x)\n",
524 ResDesc->u.Memory.Start.QuadPart, ResDesc->u.Memory.Start.QuadPart +
525 ResDesc->u.Memory.Length, ResDesc2->u.Memory.Start.QuadPart,
526 ResDesc2->u.Memory.Start.QuadPart + ResDesc2->u.Memory.Length);
527 }
528
529 Result = TRUE;
530
531 goto ByeBye;
532 }
533 break;
534
535 case CmResourceTypePort:
536 if ((ResDesc->u.Port.Start.QuadPart < ResDesc2->u.Port.Start.QuadPart &&
537 ResDesc->u.Port.Start.QuadPart + ResDesc->u.Port.Length >
538 ResDesc2->u.Port.Start.QuadPart) || (ResDesc2->u.Port.Start.QuadPart <
539 ResDesc->u.Port.Start.QuadPart && ResDesc2->u.Port.Start.QuadPart +
540 ResDesc2->u.Port.Length > ResDesc->u.Port.Start.QuadPart))
541 {
542 if (!Silent)
543 {
544 DPRINT1("Resource conflict: Port (0x%I64x to 0x%I64x vs. 0x%I64x to 0x%I64x)\n",
545 ResDesc->u.Port.Start.QuadPart, ResDesc->u.Port.Start.QuadPart +
546 ResDesc->u.Port.Length, ResDesc2->u.Port.Start.QuadPart,
547 ResDesc2->u.Port.Start.QuadPart + ResDesc2->u.Port.Length);
548 }
549
550 Result = TRUE;
551
552 goto ByeBye;
553 }
554 break;
555
556 case CmResourceTypeInterrupt:
557 if (ResDesc->u.Interrupt.Vector == ResDesc2->u.Interrupt.Vector)
558 {
559 if (!Silent)
560 {
561 DPRINT1("Resource conflict: IRQ (0x%x 0x%x vs. 0x%x 0x%x)\n",
562 ResDesc->u.Interrupt.Vector, ResDesc->u.Interrupt.Level,
563 ResDesc2->u.Interrupt.Vector, ResDesc2->u.Interrupt.Level);
564 }
565
566 Result = TRUE;
567
568 goto ByeBye;
569 }
570 break;
571
572 case CmResourceTypeBusNumber:
573 if ((ResDesc->u.BusNumber.Start < ResDesc2->u.BusNumber.Start &&
574 ResDesc->u.BusNumber.Start + ResDesc->u.BusNumber.Length >
575 ResDesc2->u.BusNumber.Start) || (ResDesc2->u.BusNumber.Start <
576 ResDesc->u.BusNumber.Start && ResDesc2->u.BusNumber.Start +
577 ResDesc2->u.BusNumber.Length > ResDesc->u.BusNumber.Start))
578 {
579 if (!Silent)
580 {
581 DPRINT1("Resource conflict: Bus number (0x%x to 0x%x vs. 0x%x to 0x%x)\n",
582 ResDesc->u.BusNumber.Start, ResDesc->u.BusNumber.Start +
583 ResDesc->u.BusNumber.Length, ResDesc2->u.BusNumber.Start,
584 ResDesc2->u.BusNumber.Start + ResDesc2->u.BusNumber.Length);
585 }
586
587 Result = TRUE;
588
589 goto ByeBye;
590 }
591 break;
592
593 case CmResourceTypeDma:
594 if (ResDesc->u.Dma.Channel == ResDesc2->u.Dma.Channel)
595 {
596 if (!Silent)
597 {
598 DPRINT1("Resource conflict: Dma (0x%x 0x%x vs. 0x%x 0x%x)\n",
599 ResDesc->u.Dma.Channel, ResDesc->u.Dma.Port,
600 ResDesc2->u.Dma.Channel, ResDesc2->u.Dma.Port);
601 }
602
603 Result = TRUE;
604
605 goto ByeBye;
606 }
607 break;
608 }
609 }
610 }
611
612 ByeBye:
613
614 if (Result && ConflictingDescriptor)
615 {
616 RtlCopyMemory(ConflictingDescriptor,
617 ResDesc,
618 sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));
619 }
620
621 return Result;
622 }
623
624 static
625 NTSTATUS
626 IopUpdateControlKeyWithResources(IN PDEVICE_NODE DeviceNode)
627 {
628 UNICODE_STRING EnumRoot = RTL_CONSTANT_STRING(ENUM_ROOT);
629 UNICODE_STRING Control = RTL_CONSTANT_STRING(L"Control");
630 UNICODE_STRING ValueName = RTL_CONSTANT_STRING(L"AllocConfig");
631 HANDLE EnumKey, InstanceKey, ControlKey;
632 NTSTATUS Status;
633 OBJECT_ATTRIBUTES ObjectAttributes;
634
635 /* Open the Enum key */
636 Status = IopOpenRegistryKeyEx(&EnumKey, NULL, &EnumRoot, KEY_ENUMERATE_SUB_KEYS);
637 if (!NT_SUCCESS(Status))
638 return Status;
639
640 /* Open the instance key (eg. Root\PNP0A03) */
641 Status = IopOpenRegistryKeyEx(&InstanceKey, EnumKey, &DeviceNode->InstancePath, KEY_ENUMERATE_SUB_KEYS);
642 ZwClose(EnumKey);
643
644 if (!NT_SUCCESS(Status))
645 return Status;
646
647 /* Create/Open the Control key */
648 InitializeObjectAttributes(&ObjectAttributes,
649 &Control,
650 OBJ_CASE_INSENSITIVE,
651 InstanceKey,
652 NULL);
653 Status = ZwCreateKey(&ControlKey,
654 KEY_SET_VALUE,
655 &ObjectAttributes,
656 0,
657 NULL,
658 REG_OPTION_VOLATILE,
659 NULL);
660 ZwClose(InstanceKey);
661
662 if (!NT_SUCCESS(Status))
663 return Status;
664
665 /* Write the resource list */
666 Status = ZwSetValueKey(ControlKey,
667 &ValueName,
668 0,
669 REG_RESOURCE_LIST,
670 DeviceNode->ResourceList,
671 PnpDetermineResourceListSize(DeviceNode->ResourceList));
672 ZwClose(ControlKey);
673
674 if (!NT_SUCCESS(Status))
675 return Status;
676
677 return STATUS_SUCCESS;
678 }
679
680 static
681 NTSTATUS
682 IopFilterResourceRequirements(IN PDEVICE_NODE DeviceNode)
683 {
684 IO_STACK_LOCATION Stack;
685 IO_STATUS_BLOCK IoStatusBlock;
686 NTSTATUS Status;
687
688 DPRINT("Sending IRP_MN_FILTER_RESOURCE_REQUIREMENTS to device stack\n");
689
690 Stack.Parameters.FilterResourceRequirements.IoResourceRequirementList = DeviceNode->ResourceRequirements;
691 Status = IopInitiatePnpIrp(
692 DeviceNode->PhysicalDeviceObject,
693 &IoStatusBlock,
694 IRP_MN_FILTER_RESOURCE_REQUIREMENTS,
695 &Stack);
696 if (!NT_SUCCESS(Status) && Status != STATUS_NOT_SUPPORTED)
697 {
698 DPRINT1("IopInitiatePnpIrp(IRP_MN_FILTER_RESOURCE_REQUIREMENTS) failed\n");
699 return Status;
700 }
701 else if (NT_SUCCESS(Status) && IoStatusBlock.Information)
702 {
703 DeviceNode->ResourceRequirements = (PIO_RESOURCE_REQUIREMENTS_LIST)IoStatusBlock.Information;
704 }
705
706 return STATUS_SUCCESS;
707 }
708
709
710 NTSTATUS
711 IopUpdateResourceMap(IN PDEVICE_NODE DeviceNode, PWCHAR Level1Key, PWCHAR Level2Key)
712 {
713 NTSTATUS Status;
714 ULONG Disposition;
715 HANDLE PnpMgrLevel1, PnpMgrLevel2, ResourceMapKey;
716 UNICODE_STRING KeyName;
717 OBJECT_ATTRIBUTES ObjectAttributes;
718
719 RtlInitUnicodeString(&KeyName,
720 L"\\Registry\\Machine\\HARDWARE\\RESOURCEMAP");
721 InitializeObjectAttributes(&ObjectAttributes,
722 &KeyName,
723 OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
724 0,
725 NULL);
726 Status = ZwCreateKey(&ResourceMapKey,
727 KEY_ALL_ACCESS,
728 &ObjectAttributes,
729 0,
730 NULL,
731 REG_OPTION_VOLATILE,
732 &Disposition);
733 if (!NT_SUCCESS(Status))
734 return Status;
735
736 RtlInitUnicodeString(&KeyName, Level1Key);
737 InitializeObjectAttributes(&ObjectAttributes,
738 &KeyName,
739 OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
740 ResourceMapKey,
741 NULL);
742 Status = ZwCreateKey(&PnpMgrLevel1,
743 KEY_ALL_ACCESS,
744 &ObjectAttributes,
745 0,
746 NULL,
747 REG_OPTION_VOLATILE,
748 &Disposition);
749 ZwClose(ResourceMapKey);
750 if (!NT_SUCCESS(Status))
751 return Status;
752
753 RtlInitUnicodeString(&KeyName, Level2Key);
754 InitializeObjectAttributes(&ObjectAttributes,
755 &KeyName,
756 OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
757 PnpMgrLevel1,
758 NULL);
759 Status = ZwCreateKey(&PnpMgrLevel2,
760 KEY_ALL_ACCESS,
761 &ObjectAttributes,
762 0,
763 NULL,
764 REG_OPTION_VOLATILE,
765 &Disposition);
766 ZwClose(PnpMgrLevel1);
767 if (!NT_SUCCESS(Status))
768 return Status;
769
770 if (DeviceNode->ResourceList)
771 {
772 UNICODE_STRING NameU;
773 UNICODE_STRING RawSuffix, TranslatedSuffix;
774 ULONG OldLength = 0;
775
776 ASSERT(DeviceNode->ResourceListTranslated);
777
778 RtlInitUnicodeString(&TranslatedSuffix, L".Translated");
779 RtlInitUnicodeString(&RawSuffix, L".Raw");
780
781 Status = IoGetDeviceProperty(DeviceNode->PhysicalDeviceObject,
782 DevicePropertyPhysicalDeviceObjectName,
783 0,
784 NULL,
785 &OldLength);
786 if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
787 {
788 ASSERT(OldLength);
789
790 NameU.Buffer = ExAllocatePool(PagedPool, OldLength + TranslatedSuffix.Length);
791 if (!NameU.Buffer)
792 {
793 ZwClose(PnpMgrLevel2);
794 return STATUS_INSUFFICIENT_RESOURCES;
795 }
796
797 NameU.Length = 0;
798 NameU.MaximumLength = (USHORT)OldLength + TranslatedSuffix.Length;
799
800 Status = IoGetDeviceProperty(DeviceNode->PhysicalDeviceObject,
801 DevicePropertyPhysicalDeviceObjectName,
802 NameU.MaximumLength,
803 NameU.Buffer,
804 &OldLength);
805 if (!NT_SUCCESS(Status))
806 {
807 ZwClose(PnpMgrLevel2);
808 ExFreePool(NameU.Buffer);
809 return Status;
810 }
811 }
812 else if (!NT_SUCCESS(Status))
813 {
814 /* Some failure */
815 ZwClose(PnpMgrLevel2);
816 return Status;
817 }
818 else
819 {
820 /* This should never happen */
821 ASSERT(FALSE);
822 }
823
824 NameU.Length = (USHORT)OldLength;
825
826 RtlAppendUnicodeStringToString(&NameU, &RawSuffix);
827
828 Status = ZwSetValueKey(PnpMgrLevel2,
829 &NameU,
830 0,
831 REG_RESOURCE_LIST,
832 DeviceNode->ResourceList,
833 PnpDetermineResourceListSize(DeviceNode->ResourceList));
834 if (!NT_SUCCESS(Status))
835 {
836 ZwClose(PnpMgrLevel2);
837 ExFreePool(NameU.Buffer);
838 return Status;
839 }
840
841 /* "Remove" the suffix by setting the length back to what it used to be */
842 NameU.Length = (USHORT)OldLength;
843
844 RtlAppendUnicodeStringToString(&NameU, &TranslatedSuffix);
845
846 Status = ZwSetValueKey(PnpMgrLevel2,
847 &NameU,
848 0,
849 REG_RESOURCE_LIST,
850 DeviceNode->ResourceListTranslated,
851 PnpDetermineResourceListSize(DeviceNode->ResourceListTranslated));
852 ZwClose(PnpMgrLevel2);
853 ExFreePool(NameU.Buffer);
854
855 if (!NT_SUCCESS(Status))
856 return Status;
857 }
858 else
859 {
860 ZwClose(PnpMgrLevel2);
861 }
862
863 return STATUS_SUCCESS;
864 }
865
866 NTSTATUS
867 IopUpdateResourceMapForPnPDevice(IN PDEVICE_NODE DeviceNode)
868 {
869 return IopUpdateResourceMap(DeviceNode, L"PnP Manager", L"PnpManager");
870 }
871
872 static
873 NTSTATUS
874 IopTranslateDeviceResources(
875 IN PDEVICE_NODE DeviceNode)
876 {
877 PCM_PARTIAL_RESOURCE_LIST pPartialResourceList;
878 PCM_PARTIAL_RESOURCE_DESCRIPTOR DescriptorRaw, DescriptorTranslated;
879 ULONG i, j, ListSize;
880 NTSTATUS Status;
881
882 if (!DeviceNode->ResourceList)
883 {
884 DeviceNode->ResourceListTranslated = NULL;
885 return STATUS_SUCCESS;
886 }
887
888 /* That's easy to translate a resource list. Just copy the
889 * untranslated one and change few fields in the copy
890 */
891 ListSize = PnpDetermineResourceListSize(DeviceNode->ResourceList);
892
893 DeviceNode->ResourceListTranslated = ExAllocatePool(PagedPool, ListSize);
894 if (!DeviceNode->ResourceListTranslated)
895 {
896 Status = STATUS_NO_MEMORY;
897 goto cleanup;
898 }
899 RtlCopyMemory(DeviceNode->ResourceListTranslated, DeviceNode->ResourceList, ListSize);
900
901 for (i = 0; i < DeviceNode->ResourceList->Count; i++)
902 {
903 pPartialResourceList = &DeviceNode->ResourceList->List[i].PartialResourceList;
904 for (j = 0; j < pPartialResourceList->Count; j++)
905 {
906 DescriptorRaw = &pPartialResourceList->PartialDescriptors[j];
907 DescriptorTranslated = &DeviceNode->ResourceListTranslated->List[i].PartialResourceList.PartialDescriptors[j];
908 switch (DescriptorRaw->Type)
909 {
910 case CmResourceTypePort:
911 {
912 ULONG AddressSpace = 1; /* IO space */
913 if (!HalTranslateBusAddress(
914 DeviceNode->ResourceList->List[i].InterfaceType,
915 DeviceNode->ResourceList->List[i].BusNumber,
916 DescriptorRaw->u.Port.Start,
917 &AddressSpace,
918 &DescriptorTranslated->u.Port.Start))
919 {
920 Status = STATUS_UNSUCCESSFUL;
921 DPRINT1("Failed to translate port resource (Start: 0x%I64x)\n", DescriptorRaw->u.Port.Start.QuadPart);
922 goto cleanup;
923 }
924
925 if (AddressSpace == 0)
926 {
927 DPRINT1("Guessed incorrect address space: 1 -> 0\n");
928
929 /* FIXME: I think all other CM_RESOURCE_PORT_XXX flags are
930 * invalid for this state but I'm not 100% sure */
931 DescriptorRaw->Flags =
932 DescriptorTranslated->Flags = CM_RESOURCE_PORT_MEMORY;
933 }
934 break;
935 }
936 case CmResourceTypeInterrupt:
937 {
938 DescriptorTranslated->u.Interrupt.Vector = HalGetInterruptVector(
939 DeviceNode->ResourceList->List[i].InterfaceType,
940 DeviceNode->ResourceList->List[i].BusNumber,
941 DescriptorRaw->u.Interrupt.Level,
942 DescriptorRaw->u.Interrupt.Vector,
943 (PKIRQL)&DescriptorTranslated->u.Interrupt.Level,
944 &DescriptorTranslated->u.Interrupt.Affinity);
945
946 if (!DescriptorTranslated->u.Interrupt.Vector)
947 {
948 Status = STATUS_UNSUCCESSFUL;
949 DPRINT1("Failed to translate interrupt resource (Vector: 0x%x | Level: 0x%x)\n", DescriptorRaw->u.Interrupt.Vector,
950 DescriptorRaw->u.Interrupt.Level);
951 goto cleanup;
952 }
953 break;
954 }
955 case CmResourceTypeMemory:
956 {
957 ULONG AddressSpace = 0; /* Memory space */
958 if (!HalTranslateBusAddress(
959 DeviceNode->ResourceList->List[i].InterfaceType,
960 DeviceNode->ResourceList->List[i].BusNumber,
961 DescriptorRaw->u.Memory.Start,
962 &AddressSpace,
963 &DescriptorTranslated->u.Memory.Start))
964 {
965 Status = STATUS_UNSUCCESSFUL;
966 DPRINT1("Failed to translate memory resource (Start: 0x%I64x)\n", DescriptorRaw->u.Memory.Start.QuadPart);
967 goto cleanup;
968 }
969
970 if (AddressSpace != 0)
971 {
972 DPRINT1("Guessed incorrect address space: 0 -> 1\n");
973
974 /* This should never happen for memory space */
975 ASSERT(FALSE);
976 }
977 }
978
979 case CmResourceTypeDma:
980 case CmResourceTypeBusNumber:
981 case CmResourceTypeDeviceSpecific:
982 /* Nothing to do */
983 break;
984 default:
985 DPRINT1("Unknown resource descriptor type 0x%x\n", DescriptorRaw->Type);
986 Status = STATUS_NOT_IMPLEMENTED;
987 goto cleanup;
988 }
989 }
990 }
991 return STATUS_SUCCESS;
992
993 cleanup:
994 /* Yes! Also delete ResourceList because ResourceList and
995 * ResourceListTranslated should be a pair! */
996 ExFreePool(DeviceNode->ResourceList);
997 DeviceNode->ResourceList = NULL;
998 if (DeviceNode->ResourceListTranslated)
999 {
1000 ExFreePool(DeviceNode->ResourceListTranslated);
1001 DeviceNode->ResourceList = NULL;
1002 }
1003 return Status;
1004 }
1005
1006 NTSTATUS
1007 NTAPI
1008 IopAssignDeviceResources(
1009 IN PDEVICE_NODE DeviceNode)
1010 {
1011 NTSTATUS Status;
1012 ULONG ListSize;
1013
1014 IopDeviceNodeSetFlag(DeviceNode, DNF_ASSIGNING_RESOURCES);
1015
1016 Status = IopFilterResourceRequirements(DeviceNode);
1017 if (!NT_SUCCESS(Status))
1018 goto ByeBye;
1019
1020 if (!DeviceNode->BootResources && !DeviceNode->ResourceRequirements)
1021 {
1022 DeviceNode->Flags |= DNF_NO_RESOURCE_REQUIRED;
1023 DeviceNode->Flags &= ~DNF_ASSIGNING_RESOURCES;
1024
1025 /* No resource needed for this device */
1026 DeviceNode->ResourceList = NULL;
1027 DeviceNode->ResourceListTranslated = NULL;
1028
1029 return STATUS_SUCCESS;
1030 }
1031
1032 if (DeviceNode->BootResources)
1033 {
1034 ListSize = PnpDetermineResourceListSize(DeviceNode->BootResources);
1035
1036 DeviceNode->ResourceList = ExAllocatePool(PagedPool, ListSize);
1037 if (!DeviceNode->ResourceList)
1038 {
1039 Status = STATUS_NO_MEMORY;
1040 goto ByeBye;
1041 }
1042
1043 RtlCopyMemory(DeviceNode->ResourceList, DeviceNode->BootResources, ListSize);
1044
1045 Status = IopDetectResourceConflict(DeviceNode->ResourceList, FALSE, NULL);
1046 if (!NT_SUCCESS(Status))
1047 {
1048 DPRINT1("Boot resources for %wZ cause a resource conflict!\n", &DeviceNode->InstancePath);
1049 ExFreePool(DeviceNode->ResourceList);
1050 DeviceNode->ResourceList = NULL;
1051 }
1052 }
1053 else
1054 {
1055 /* We'll make this from the requirements */
1056 DeviceNode->ResourceList = NULL;
1057 }
1058
1059 /* No resources requirements */
1060 if (!DeviceNode->ResourceRequirements)
1061 goto Finish;
1062
1063 /* Call HAL to fixup our resource requirements list */
1064 HalAdjustResourceList(&DeviceNode->ResourceRequirements);
1065
1066 /* Add resource requirements that aren't in the list we already got */
1067 Status = IopFixupResourceListWithRequirements(DeviceNode->ResourceRequirements,
1068 &DeviceNode->ResourceList);
1069 if (!NT_SUCCESS(Status))
1070 {
1071 DPRINT1("Failed to fixup a resource list from supplied resources for %wZ\n", &DeviceNode->InstancePath);
1072 goto ByeBye;
1073 }
1074
1075 /* IopFixupResourceListWithRequirements should NEVER give us a conflicting list */
1076 ASSERT(IopDetectResourceConflict(DeviceNode->ResourceList, FALSE, NULL) != STATUS_CONFLICTING_ADDRESSES);
1077
1078 Finish:
1079 Status = IopTranslateDeviceResources(DeviceNode);
1080 if (!NT_SUCCESS(Status))
1081 {
1082 DPRINT1("Failed to translate resources for %wZ\n", &DeviceNode->InstancePath);
1083 goto ByeBye;
1084 }
1085
1086 Status = IopUpdateResourceMapForPnPDevice(DeviceNode);
1087 if (!NT_SUCCESS(Status))
1088 goto ByeBye;
1089
1090 Status = IopUpdateControlKeyWithResources(DeviceNode);
1091 if (!NT_SUCCESS(Status))
1092 goto ByeBye;
1093
1094 IopDeviceNodeSetFlag(DeviceNode, DNF_RESOURCE_ASSIGNED);
1095
1096 IopDeviceNodeClearFlag(DeviceNode, DNF_ASSIGNING_RESOURCES);
1097
1098 return STATUS_SUCCESS;
1099
1100 ByeBye:
1101 if (DeviceNode->ResourceList)
1102 {
1103 ExFreePool(DeviceNode->ResourceList);
1104 DeviceNode->ResourceList = NULL;
1105 }
1106
1107 DeviceNode->ResourceListTranslated = NULL;
1108
1109 IopDeviceNodeClearFlag(DeviceNode, DNF_ASSIGNING_RESOURCES);
1110
1111 return Status;
1112 }
1113
1114 static
1115 BOOLEAN
1116 IopCheckForResourceConflict(
1117 IN PCM_RESOURCE_LIST ResourceList1,
1118 IN PCM_RESOURCE_LIST ResourceList2,
1119 IN BOOLEAN Silent,
1120 OUT OPTIONAL PCM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDescriptor)
1121 {
1122 ULONG i, ii;
1123 BOOLEAN Result = FALSE;
1124
1125 for (i = 0; i < ResourceList1->Count; i++)
1126 {
1127 PCM_PARTIAL_RESOURCE_LIST ResList = &ResourceList1->List[i].PartialResourceList;
1128 for (ii = 0; ii < ResList->Count; ii++)
1129 {
1130 PCM_PARTIAL_RESOURCE_DESCRIPTOR ResDesc = &ResList->PartialDescriptors[ii];
1131
1132 Result = IopCheckResourceDescriptor(ResDesc,
1133 ResourceList2,
1134 Silent,
1135 ConflictingDescriptor);
1136 if (Result) goto ByeBye;
1137 }
1138 }
1139
1140 ByeBye:
1141
1142 return Result;
1143 }
1144
1145 NTSTATUS NTAPI
1146 IopDetectResourceConflict(
1147 IN PCM_RESOURCE_LIST ResourceList,
1148 IN BOOLEAN Silent,
1149 OUT OPTIONAL PCM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDescriptor)
1150 {
1151 OBJECT_ATTRIBUTES ObjectAttributes;
1152 UNICODE_STRING KeyName;
1153 HANDLE ResourceMapKey = INVALID_HANDLE_VALUE, ChildKey2 = INVALID_HANDLE_VALUE, ChildKey3 = INVALID_HANDLE_VALUE;
1154 ULONG KeyInformationLength, RequiredLength, KeyValueInformationLength, KeyNameInformationLength;
1155 PKEY_BASIC_INFORMATION KeyInformation;
1156 PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation;
1157 PKEY_VALUE_BASIC_INFORMATION KeyNameInformation;
1158 ULONG ChildKeyIndex1 = 0, ChildKeyIndex2 = 0, ChildKeyIndex3 = 0;
1159 NTSTATUS Status;
1160
1161 RtlInitUnicodeString(&KeyName, L"\\Registry\\Machine\\HARDWARE\\RESOURCEMAP");
1162 InitializeObjectAttributes(&ObjectAttributes, &KeyName, OBJ_CASE_INSENSITIVE, 0, NULL);
1163 Status = ZwOpenKey(&ResourceMapKey, KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE, &ObjectAttributes);
1164 if (!NT_SUCCESS(Status))
1165 {
1166 /* The key is missing which means we are the first device */
1167 return STATUS_SUCCESS;
1168 }
1169
1170 while (TRUE)
1171 {
1172 Status = ZwEnumerateKey(ResourceMapKey,
1173 ChildKeyIndex1,
1174 KeyBasicInformation,
1175 NULL,
1176 0,
1177 &RequiredLength);
1178 if (Status == STATUS_NO_MORE_ENTRIES)
1179 break;
1180 else if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
1181 {
1182 KeyInformationLength = RequiredLength;
1183 KeyInformation = ExAllocatePool(PagedPool, KeyInformationLength);
1184 if (!KeyInformation)
1185 {
1186 Status = STATUS_INSUFFICIENT_RESOURCES;
1187 goto cleanup;
1188 }
1189
1190 Status = ZwEnumerateKey(ResourceMapKey,
1191 ChildKeyIndex1,
1192 KeyBasicInformation,
1193 KeyInformation,
1194 KeyInformationLength,
1195 &RequiredLength);
1196 }
1197 else
1198 goto cleanup;
1199 ChildKeyIndex1++;
1200 if (!NT_SUCCESS(Status))
1201 goto cleanup;
1202
1203 KeyName.Buffer = KeyInformation->Name;
1204 KeyName.MaximumLength = KeyName.Length = (USHORT)KeyInformation->NameLength;
1205 InitializeObjectAttributes(&ObjectAttributes,
1206 &KeyName,
1207 OBJ_CASE_INSENSITIVE,
1208 ResourceMapKey,
1209 NULL);
1210 Status = ZwOpenKey(&ChildKey2, KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE, &ObjectAttributes);
1211 ExFreePool(KeyInformation);
1212 if (!NT_SUCCESS(Status))
1213 goto cleanup;
1214
1215 while (TRUE)
1216 {
1217 Status = ZwEnumerateKey(ChildKey2,
1218 ChildKeyIndex2,
1219 KeyBasicInformation,
1220 NULL,
1221 0,
1222 &RequiredLength);
1223 if (Status == STATUS_NO_MORE_ENTRIES)
1224 break;
1225 else if (Status == STATUS_BUFFER_TOO_SMALL)
1226 {
1227 KeyInformationLength = RequiredLength;
1228 KeyInformation = ExAllocatePool(PagedPool, KeyInformationLength);
1229 if (!KeyInformation)
1230 {
1231 Status = STATUS_INSUFFICIENT_RESOURCES;
1232 goto cleanup;
1233 }
1234
1235 Status = ZwEnumerateKey(ChildKey2,
1236 ChildKeyIndex2,
1237 KeyBasicInformation,
1238 KeyInformation,
1239 KeyInformationLength,
1240 &RequiredLength);
1241 }
1242 else
1243 goto cleanup;
1244 ChildKeyIndex2++;
1245 if (!NT_SUCCESS(Status))
1246 goto cleanup;
1247
1248 KeyName.Buffer = KeyInformation->Name;
1249 KeyName.MaximumLength = KeyName.Length = (USHORT)KeyInformation->NameLength;
1250 InitializeObjectAttributes(&ObjectAttributes,
1251 &KeyName,
1252 OBJ_CASE_INSENSITIVE,
1253 ChildKey2,
1254 NULL);
1255 Status = ZwOpenKey(&ChildKey3, KEY_QUERY_VALUE, &ObjectAttributes);
1256 ExFreePool(KeyInformation);
1257 if (!NT_SUCCESS(Status))
1258 goto cleanup;
1259
1260 while (TRUE)
1261 {
1262 Status = ZwEnumerateValueKey(ChildKey3,
1263 ChildKeyIndex3,
1264 KeyValuePartialInformation,
1265 NULL,
1266 0,
1267 &RequiredLength);
1268 if (Status == STATUS_NO_MORE_ENTRIES)
1269 break;
1270 else if (Status == STATUS_BUFFER_TOO_SMALL)
1271 {
1272 KeyValueInformationLength = RequiredLength;
1273 KeyValueInformation = ExAllocatePool(PagedPool, KeyValueInformationLength);
1274 if (!KeyValueInformation)
1275 {
1276 Status = STATUS_INSUFFICIENT_RESOURCES;
1277 goto cleanup;
1278 }
1279
1280 Status = ZwEnumerateValueKey(ChildKey3,
1281 ChildKeyIndex3,
1282 KeyValuePartialInformation,
1283 KeyValueInformation,
1284 KeyValueInformationLength,
1285 &RequiredLength);
1286 }
1287 else
1288 goto cleanup;
1289 if (!NT_SUCCESS(Status))
1290 goto cleanup;
1291
1292 Status = ZwEnumerateValueKey(ChildKey3,
1293 ChildKeyIndex3,
1294 KeyValueBasicInformation,
1295 NULL,
1296 0,
1297 &RequiredLength);
1298 if (Status == STATUS_BUFFER_TOO_SMALL)
1299 {
1300 KeyNameInformationLength = RequiredLength;
1301 KeyNameInformation = ExAllocatePool(PagedPool, KeyNameInformationLength + sizeof(WCHAR));
1302 if (!KeyNameInformation)
1303 {
1304 Status = STATUS_INSUFFICIENT_RESOURCES;
1305 goto cleanup;
1306 }
1307
1308 Status = ZwEnumerateValueKey(ChildKey3,
1309 ChildKeyIndex3,
1310 KeyValueBasicInformation,
1311 KeyNameInformation,
1312 KeyNameInformationLength,
1313 &RequiredLength);
1314 }
1315 else
1316 goto cleanup;
1317
1318 ChildKeyIndex3++;
1319
1320 if (!NT_SUCCESS(Status))
1321 goto cleanup;
1322
1323 KeyNameInformation->Name[KeyNameInformation->NameLength / sizeof(WCHAR)] = UNICODE_NULL;
1324
1325 /* Skip translated entries */
1326 if (wcsstr(KeyNameInformation->Name, L".Translated"))
1327 {
1328 ExFreePool(KeyNameInformation);
1329 continue;
1330 }
1331
1332 ExFreePool(KeyNameInformation);
1333
1334 if (IopCheckForResourceConflict(ResourceList,
1335 (PCM_RESOURCE_LIST)KeyValueInformation->Data,
1336 Silent,
1337 ConflictingDescriptor))
1338 {
1339 ExFreePool(KeyValueInformation);
1340 Status = STATUS_CONFLICTING_ADDRESSES;
1341 goto cleanup;
1342 }
1343
1344 ExFreePool(KeyValueInformation);
1345 }
1346 }
1347 }
1348
1349 cleanup:
1350 if (ResourceMapKey != INVALID_HANDLE_VALUE)
1351 ZwClose(ResourceMapKey);
1352 if (ChildKey2 != INVALID_HANDLE_VALUE)
1353 ZwClose(ChildKey2);
1354 if (ChildKey3 != INVALID_HANDLE_VALUE)
1355 ZwClose(ChildKey3);
1356
1357 if (Status == STATUS_NO_MORE_ENTRIES)
1358 Status = STATUS_SUCCESS;
1359
1360 return Status;
1361 }
1362