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