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