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