[TCPIP]
[reactos.git] / reactos / ntoskrnl / io / pnpmgr / pnpres.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * COPYRIGHT: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/io/pnpmgr/pnpres.c
5 * PURPOSE: Resource handling code
6 * PROGRAMMERS: Cameron Gutman (cameron.gutman@reactos.org)
7 * ReactOS Portable Systems Group
8 */
9
10 #include <ntoskrnl.h>
11
12 #define NDEBUG
13 #include <debug.h>
14
15 static
16 BOOLEAN
17 IopCheckDescriptorForConflict(PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc, OPTIONAL PCM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDescriptor)
18 {
19 CM_RESOURCE_LIST CmList;
20 NTSTATUS Status;
21
22 CmList.Count = 1;
23 CmList.List[0].InterfaceType = InterfaceTypeUndefined;
24 CmList.List[0].BusNumber = 0;
25 CmList.List[0].PartialResourceList.Version = 1;
26 CmList.List[0].PartialResourceList.Revision = 1;
27 CmList.List[0].PartialResourceList.Count = 1;
28 CmList.List[0].PartialResourceList.PartialDescriptors[0] = *CmDesc;
29
30 Status = IopDetectResourceConflict(&CmList, TRUE, ConflictingDescriptor);
31 if (Status == STATUS_CONFLICTING_ADDRESSES)
32 return TRUE;
33
34 return FALSE;
35 }
36
37 static
38 BOOLEAN
39 IopFindBusNumberResource(
40 IN PIO_RESOURCE_DESCRIPTOR IoDesc,
41 OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc)
42 {
43 ULONG Start;
44 CM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDesc;
45
46 ASSERT(IoDesc->Type == CmDesc->Type);
47 ASSERT(IoDesc->Type == CmResourceTypeBusNumber);
48
49 for (Start = IoDesc->u.BusNumber.MinBusNumber;
50 Start < IoDesc->u.BusNumber.MaxBusNumber;
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
762 if (AddressSpace == 0)
763 {
764 /* This is actually a memory resource */
765 DescriptorRaw->Type = CmResourceTypeMemory;
766 DescriptorTranslated->Type = CmResourceTypeMemory;
767 }
768 break;
769 }
770 case CmResourceTypeInterrupt:
771 {
772 DescriptorTranslated->u.Interrupt.Vector = HalGetInterruptVector(
773 DeviceNode->ResourceList->List[i].InterfaceType,
774 DeviceNode->ResourceList->List[i].BusNumber,
775 DescriptorRaw->u.Interrupt.Level,
776 DescriptorRaw->u.Interrupt.Vector,
777 (PKIRQL)&DescriptorTranslated->u.Interrupt.Level,
778 &DescriptorTranslated->u.Interrupt.Affinity);
779
780 if (!DescriptorTranslated->u.Interrupt.Vector)
781 {
782 Status = STATUS_UNSUCCESSFUL;
783 DPRINT1("Failed to translate interrupt resource (Vector: 0x%x | Level: 0x%x)\n", DescriptorRaw->u.Interrupt.Vector,
784 DescriptorRaw->u.Interrupt.Level);
785 goto cleanup;
786 }
787 break;
788 }
789 case CmResourceTypeMemory:
790 {
791 ULONG AddressSpace = 0; /* Memory space */
792 if (!HalTranslateBusAddress(
793 DeviceNode->ResourceList->List[i].InterfaceType,
794 DeviceNode->ResourceList->List[i].BusNumber,
795 DescriptorRaw->u.Memory.Start,
796 &AddressSpace,
797 &DescriptorTranslated->u.Memory.Start))
798 {
799 Status = STATUS_UNSUCCESSFUL;
800 DPRINT1("Failed to translate memory resource (Start: 0xI64x)\n", DescriptorRaw->u.Memory.Start.QuadPart);
801 goto cleanup;
802 }
803
804 if (AddressSpace != 0)
805 {
806 /* This is actually an I/O port resource */
807 DescriptorRaw->Type = CmResourceTypePort;
808 DescriptorTranslated->Type = CmResourceTypePort;
809 }
810 }
811
812 case CmResourceTypeDma:
813 case CmResourceTypeBusNumber:
814 case CmResourceTypeDeviceSpecific:
815 /* Nothing to do */
816 break;
817 default:
818 DPRINT1("Unknown resource descriptor type 0x%x\n", DescriptorRaw->Type);
819 Status = STATUS_NOT_IMPLEMENTED;
820 goto cleanup;
821 }
822 }
823 }
824 return STATUS_SUCCESS;
825
826 cleanup:
827 /* Yes! Also delete ResourceList because ResourceList and
828 * ResourceListTranslated should be a pair! */
829 ExFreePool(DeviceNode->ResourceList);
830 DeviceNode->ResourceList = NULL;
831 if (DeviceNode->ResourceListTranslated)
832 {
833 ExFreePool(DeviceNode->ResourceListTranslated);
834 DeviceNode->ResourceList = NULL;
835 }
836 return Status;
837 }
838
839 NTSTATUS
840 NTAPI
841 IopAssignDeviceResources(
842 IN PDEVICE_NODE DeviceNode)
843 {
844 NTSTATUS Status;
845 ULONG ListSize;
846
847 IopDeviceNodeSetFlag(DeviceNode, DNF_ASSIGNING_RESOURCES);
848
849 Status = IopFilterResourceRequirements(DeviceNode);
850 if (!NT_SUCCESS(Status))
851 goto ByeBye;
852
853 if (!DeviceNode->BootResources && !DeviceNode->ResourceRequirements)
854 {
855 DeviceNode->Flags |= DNF_NO_RESOURCE_REQUIRED;
856 DeviceNode->Flags &= ~DNF_ASSIGNING_RESOURCES;
857
858 /* No resource needed for this device */
859 DeviceNode->ResourceList = NULL;
860 DeviceNode->ResourceListTranslated = NULL;
861
862 return STATUS_SUCCESS;
863 }
864
865 /* Fill DeviceNode->ResourceList
866 * FIXME: the PnP arbiter should go there!
867 * Actually, use the BootResources if provided, else the resource requirements
868 */
869
870 if (DeviceNode->BootResources)
871 {
872 ListSize = PnpDetermineResourceListSize(DeviceNode->BootResources);
873
874 DeviceNode->ResourceList = ExAllocatePool(PagedPool, ListSize);
875 if (!DeviceNode->ResourceList)
876 {
877 Status = STATUS_NO_MEMORY;
878 goto ByeBye;
879 }
880 RtlCopyMemory(DeviceNode->ResourceList, DeviceNode->BootResources, ListSize);
881
882 Status = IopDetectResourceConflict(DeviceNode->ResourceList, FALSE, NULL);
883 if (NT_SUCCESS(Status) || !DeviceNode->ResourceRequirements)
884 {
885 if (!NT_SUCCESS(Status) && !DeviceNode->ResourceRequirements)
886 {
887 DPRINT1("Using conflicting boot resources because no requirements were supplied!\n");
888 }
889
890 goto Finish;
891 }
892 else
893 {
894 DPRINT1("Boot resources for %wZ cause a resource conflict!\n", &DeviceNode->InstancePath);
895 ExFreePool(DeviceNode->ResourceList);
896 DeviceNode->ResourceList = NULL;
897 }
898 }
899
900 Status = IopCreateResourceListFromRequirements(DeviceNode->ResourceRequirements,
901 &DeviceNode->ResourceList);
902 if (!NT_SUCCESS(Status))
903 {
904 DPRINT1("Failed to create a resource list from supplied resources for %wZ\n", &DeviceNode->InstancePath);
905 goto ByeBye;
906 }
907
908 /* IopCreateResourceListFromRequirements should NEVER succeed with a conflicting list */
909 ASSERT(IopDetectResourceConflict(DeviceNode->ResourceList, FALSE, NULL) != STATUS_CONFLICTING_ADDRESSES);
910
911 Finish:
912 Status = IopTranslateDeviceResources(DeviceNode);
913 if (!NT_SUCCESS(Status))
914 {
915 DPRINT1("Failed to translate resources for %wZ\n", &DeviceNode->InstancePath);
916 goto ByeBye;
917 }
918
919 Status = IopUpdateResourceMapForPnPDevice(DeviceNode);
920 if (!NT_SUCCESS(Status))
921 goto ByeBye;
922
923 Status = IopUpdateControlKeyWithResources(DeviceNode);
924 if (!NT_SUCCESS(Status))
925 goto ByeBye;
926
927 IopDeviceNodeSetFlag(DeviceNode, DNF_RESOURCE_ASSIGNED);
928
929 IopDeviceNodeClearFlag(DeviceNode, DNF_ASSIGNING_RESOURCES);
930
931 return STATUS_SUCCESS;
932
933 ByeBye:
934 if (DeviceNode->ResourceList)
935 {
936 ExFreePool(DeviceNode->ResourceList);
937 DeviceNode->ResourceList = NULL;
938 }
939
940 DeviceNode->ResourceListTranslated = NULL;
941
942 IopDeviceNodeClearFlag(DeviceNode, DNF_ASSIGNING_RESOURCES);
943
944 return Status;
945 }
946
947 static
948 BOOLEAN
949 IopCheckForResourceConflict(
950 IN PCM_RESOURCE_LIST ResourceList1,
951 IN PCM_RESOURCE_LIST ResourceList2,
952 IN BOOLEAN Silent,
953 OUT OPTIONAL PCM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDescriptor)
954 {
955 ULONG i, ii;
956 BOOLEAN Result = FALSE;
957
958 for (i = 0; i < ResourceList1->Count; i++)
959 {
960 PCM_PARTIAL_RESOURCE_LIST ResList = &ResourceList1->List[i].PartialResourceList;
961 for (ii = 0; ii < ResList->Count; ii++)
962 {
963 PCM_PARTIAL_RESOURCE_DESCRIPTOR ResDesc = &ResList->PartialDescriptors[ii];
964
965 Result = IopCheckResourceDescriptor(ResDesc,
966 ResourceList2,
967 Silent,
968 ConflictingDescriptor);
969 if (Result) goto ByeBye;
970 }
971 }
972
973
974 ByeBye:
975
976 return Result;
977 }
978
979 NTSTATUS NTAPI
980 IopDetectResourceConflict(
981 IN PCM_RESOURCE_LIST ResourceList,
982 IN BOOLEAN Silent,
983 OUT OPTIONAL PCM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDescriptor)
984 {
985 OBJECT_ATTRIBUTES ObjectAttributes;
986 UNICODE_STRING KeyName;
987 HANDLE ResourceMapKey = INVALID_HANDLE_VALUE, ChildKey2 = INVALID_HANDLE_VALUE, ChildKey3 = INVALID_HANDLE_VALUE;
988 ULONG KeyInformationLength, RequiredLength, KeyValueInformationLength, KeyNameInformationLength;
989 PKEY_BASIC_INFORMATION KeyInformation;
990 PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation;
991 PKEY_VALUE_BASIC_INFORMATION KeyNameInformation;
992 ULONG ChildKeyIndex1 = 0, ChildKeyIndex2 = 0, ChildKeyIndex3 = 0;
993 NTSTATUS Status;
994
995 RtlInitUnicodeString(&KeyName, L"\\Registry\\Machine\\HARDWARE\\RESOURCEMAP");
996 InitializeObjectAttributes(&ObjectAttributes, &KeyName, OBJ_CASE_INSENSITIVE, 0, NULL);
997 Status = ZwOpenKey(&ResourceMapKey, KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE, &ObjectAttributes);
998 if (!NT_SUCCESS(Status))
999 {
1000 /* The key is missing which means we are the first device */
1001 return STATUS_SUCCESS;
1002 }
1003
1004 while (TRUE)
1005 {
1006 Status = ZwEnumerateKey(ResourceMapKey,
1007 ChildKeyIndex1,
1008 KeyBasicInformation,
1009 NULL,
1010 0,
1011 &RequiredLength);
1012 if (Status == STATUS_NO_MORE_ENTRIES)
1013 break;
1014 else if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
1015 {
1016 KeyInformationLength = RequiredLength;
1017 KeyInformation = ExAllocatePool(PagedPool, KeyInformationLength);
1018 if (!KeyInformation)
1019 {
1020 Status = STATUS_INSUFFICIENT_RESOURCES;
1021 goto cleanup;
1022 }
1023
1024 Status = ZwEnumerateKey(ResourceMapKey,
1025 ChildKeyIndex1,
1026 KeyBasicInformation,
1027 KeyInformation,
1028 KeyInformationLength,
1029 &RequiredLength);
1030 }
1031 else
1032 goto cleanup;
1033 ChildKeyIndex1++;
1034 if (!NT_SUCCESS(Status))
1035 goto cleanup;
1036
1037 KeyName.Buffer = KeyInformation->Name;
1038 KeyName.MaximumLength = KeyName.Length = KeyInformation->NameLength;
1039 InitializeObjectAttributes(&ObjectAttributes,
1040 &KeyName,
1041 OBJ_CASE_INSENSITIVE,
1042 ResourceMapKey,
1043 NULL);
1044 Status = ZwOpenKey(&ChildKey2, KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE, &ObjectAttributes);
1045 ExFreePool(KeyInformation);
1046 if (!NT_SUCCESS(Status))
1047 goto cleanup;
1048
1049 while (TRUE)
1050 {
1051 Status = ZwEnumerateKey(ChildKey2,
1052 ChildKeyIndex2,
1053 KeyBasicInformation,
1054 NULL,
1055 0,
1056 &RequiredLength);
1057 if (Status == STATUS_NO_MORE_ENTRIES)
1058 break;
1059 else if (Status == STATUS_BUFFER_TOO_SMALL)
1060 {
1061 KeyInformationLength = RequiredLength;
1062 KeyInformation = ExAllocatePool(PagedPool, KeyInformationLength);
1063 if (!KeyInformation)
1064 {
1065 Status = STATUS_INSUFFICIENT_RESOURCES;
1066 goto cleanup;
1067 }
1068
1069 Status = ZwEnumerateKey(ChildKey2,
1070 ChildKeyIndex2,
1071 KeyBasicInformation,
1072 KeyInformation,
1073 KeyInformationLength,
1074 &RequiredLength);
1075 }
1076 else
1077 goto cleanup;
1078 ChildKeyIndex2++;
1079 if (!NT_SUCCESS(Status))
1080 goto cleanup;
1081
1082 KeyName.Buffer = KeyInformation->Name;
1083 KeyName.MaximumLength = KeyName.Length = KeyInformation->NameLength;
1084 InitializeObjectAttributes(&ObjectAttributes,
1085 &KeyName,
1086 OBJ_CASE_INSENSITIVE,
1087 ChildKey2,
1088 NULL);
1089 Status = ZwOpenKey(&ChildKey3, KEY_QUERY_VALUE, &ObjectAttributes);
1090 ExFreePool(KeyInformation);
1091 if (!NT_SUCCESS(Status))
1092 goto cleanup;
1093
1094 while (TRUE)
1095 {
1096 Status = ZwEnumerateValueKey(ChildKey3,
1097 ChildKeyIndex3,
1098 KeyValuePartialInformation,
1099 NULL,
1100 0,
1101 &RequiredLength);
1102 if (Status == STATUS_NO_MORE_ENTRIES)
1103 break;
1104 else if (Status == STATUS_BUFFER_TOO_SMALL)
1105 {
1106 KeyValueInformationLength = RequiredLength;
1107 KeyValueInformation = ExAllocatePool(PagedPool, KeyValueInformationLength);
1108 if (!KeyValueInformation)
1109 {
1110 Status = STATUS_INSUFFICIENT_RESOURCES;
1111 goto cleanup;
1112 }
1113
1114 Status = ZwEnumerateValueKey(ChildKey3,
1115 ChildKeyIndex3,
1116 KeyValuePartialInformation,
1117 KeyValueInformation,
1118 KeyValueInformationLength,
1119 &RequiredLength);
1120 }
1121 else
1122 goto cleanup;
1123 if (!NT_SUCCESS(Status))
1124 goto cleanup;
1125
1126 Status = ZwEnumerateValueKey(ChildKey3,
1127 ChildKeyIndex3,
1128 KeyValueBasicInformation,
1129 NULL,
1130 0,
1131 &RequiredLength);
1132 if (Status == STATUS_BUFFER_TOO_SMALL)
1133 {
1134 KeyNameInformationLength = RequiredLength;
1135 KeyNameInformation = ExAllocatePool(PagedPool, KeyNameInformationLength + sizeof(WCHAR));
1136 if (!KeyNameInformation)
1137 {
1138 Status = STATUS_INSUFFICIENT_RESOURCES;
1139 goto cleanup;
1140 }
1141
1142 Status = ZwEnumerateValueKey(ChildKey3,
1143 ChildKeyIndex3,
1144 KeyValueBasicInformation,
1145 KeyNameInformation,
1146 KeyNameInformationLength,
1147 &RequiredLength);
1148 }
1149 else
1150 goto cleanup;
1151
1152 ChildKeyIndex3++;
1153
1154 if (!NT_SUCCESS(Status))
1155 goto cleanup;
1156
1157 KeyNameInformation->Name[KeyNameInformation->NameLength / sizeof(WCHAR)] = UNICODE_NULL;
1158
1159 /* Skip translated entries */
1160 if (wcsstr(KeyNameInformation->Name, L".Translated"))
1161 {
1162 ExFreePool(KeyNameInformation);
1163 continue;
1164 }
1165
1166 ExFreePool(KeyNameInformation);
1167
1168 if (IopCheckForResourceConflict(ResourceList,
1169 (PCM_RESOURCE_LIST)KeyValueInformation->Data,
1170 Silent,
1171 ConflictingDescriptor))
1172 {
1173 ExFreePool(KeyValueInformation);
1174 Status = STATUS_CONFLICTING_ADDRESSES;
1175 goto cleanup;
1176 }
1177
1178 ExFreePool(KeyValueInformation);
1179 }
1180 }
1181 }
1182
1183 cleanup:
1184 if (ResourceMapKey != INVALID_HANDLE_VALUE)
1185 ZwClose(ResourceMapKey);
1186 if (ChildKey2 != INVALID_HANDLE_VALUE)
1187 ZwClose(ChildKey2);
1188 if (ChildKey3 != INVALID_HANDLE_VALUE)
1189 ZwClose(ChildKey3);
1190
1191 if (Status == STATUS_NO_MORE_ENTRIES)
1192 Status = STATUS_SUCCESS;
1193
1194 return Status;
1195 }
1196