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