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