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