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