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