436e1376f9a1c6571c9fcf56e9773d589d1dccf8
[reactos.git] / ntoskrnl / io / pnpmgr / pnpmgr.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * COPYRIGHT: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/io/pnpmgr/pnpmgr.c
5 * PURPOSE: Initializes the PnP manager
6 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 * Copyright 2007 Hervé Poussineau (hpoussin@reactos.org)
8 */
9
10 /* INCLUDES ******************************************************************/
11
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <debug.h>
15
16 /* GLOBALS *******************************************************************/
17
18 ERESOURCE PpRegistryDeviceResource;
19 KGUARDED_MUTEX PpDeviceReferenceTableLock;
20 RTL_AVL_TABLE PpDeviceReferenceTable;
21
22 extern ERESOURCE IopDriverLoadResource;
23 extern ULONG ExpInitializationPhase;
24 extern BOOLEAN PnpSystemInit;
25 extern PDEVICE_NODE IopRootDeviceNode;
26
27 #define MAX_DEVICE_ID_LEN 200
28 #define MAX_SEPARATORS_INSTANCEID 0
29 #define MAX_SEPARATORS_DEVICEID 1
30
31 /* DATA **********************************************************************/
32
33 PDRIVER_OBJECT IopRootDriverObject;
34 PIO_BUS_TYPE_GUID_LIST PnpBusTypeGuidList = NULL;
35 LIST_ENTRY IopDeviceActionRequestList;
36 WORK_QUEUE_ITEM IopDeviceActionWorkItem;
37 BOOLEAN IopDeviceActionInProgress;
38 KSPIN_LOCK IopDeviceActionLock;
39
40 /* FUNCTIONS *****************************************************************/
41
42 VOID
43 IopCancelPrepareDeviceForRemoval(PDEVICE_OBJECT DeviceObject);
44
45 NTSTATUS
46 IopPrepareDeviceForRemoval(PDEVICE_OBJECT DeviceObject, BOOLEAN Force);
47
48 PDEVICE_OBJECT
49 IopGetDeviceObjectFromDeviceInstance(PUNICODE_STRING DeviceInstance);
50
51 VOID
52 IopFixupDeviceId(PWCHAR String)
53 {
54 SIZE_T Length = wcslen(String), i;
55
56 for (i = 0; i < Length; i++)
57 {
58 if (String[i] == L'\\')
59 String[i] = L'#';
60 }
61 }
62
63 VOID
64 NTAPI
65 IopInstallCriticalDevice(PDEVICE_NODE DeviceNode)
66 {
67 NTSTATUS Status;
68 HANDLE CriticalDeviceKey, InstanceKey;
69 OBJECT_ATTRIBUTES ObjectAttributes;
70 UNICODE_STRING CriticalDeviceKeyU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\CriticalDeviceDatabase");
71 UNICODE_STRING CompatibleIdU = RTL_CONSTANT_STRING(L"CompatibleIDs");
72 UNICODE_STRING HardwareIdU = RTL_CONSTANT_STRING(L"HardwareID");
73 UNICODE_STRING ServiceU = RTL_CONSTANT_STRING(L"Service");
74 UNICODE_STRING ClassGuidU = RTL_CONSTANT_STRING(L"ClassGUID");
75 PKEY_VALUE_PARTIAL_INFORMATION PartialInfo;
76 ULONG HidLength = 0, CidLength = 0, BufferLength;
77 PWCHAR IdBuffer, OriginalIdBuffer;
78
79 /* Open the device instance key */
80 Status = IopCreateDeviceKeyPath(&DeviceNode->InstancePath, REG_OPTION_NON_VOLATILE, &InstanceKey);
81 if (Status != STATUS_SUCCESS)
82 return;
83
84 Status = ZwQueryValueKey(InstanceKey,
85 &HardwareIdU,
86 KeyValuePartialInformation,
87 NULL,
88 0,
89 &HidLength);
90 if (Status != STATUS_BUFFER_OVERFLOW && Status != STATUS_BUFFER_TOO_SMALL)
91 {
92 ZwClose(InstanceKey);
93 return;
94 }
95
96 Status = ZwQueryValueKey(InstanceKey,
97 &CompatibleIdU,
98 KeyValuePartialInformation,
99 NULL,
100 0,
101 &CidLength);
102 if (Status != STATUS_BUFFER_OVERFLOW && Status != STATUS_BUFFER_TOO_SMALL)
103 {
104 CidLength = 0;
105 }
106
107 BufferLength = HidLength + CidLength;
108 BufferLength -= (((CidLength != 0) ? 2 : 1) * FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data));
109
110 /* Allocate a buffer to hold data from both */
111 OriginalIdBuffer = IdBuffer = ExAllocatePool(PagedPool, BufferLength);
112 if (!IdBuffer)
113 {
114 ZwClose(InstanceKey);
115 return;
116 }
117
118 /* Compute the buffer size */
119 if (HidLength > CidLength)
120 BufferLength = HidLength;
121 else
122 BufferLength = CidLength;
123
124 PartialInfo = ExAllocatePool(PagedPool, BufferLength);
125 if (!PartialInfo)
126 {
127 ZwClose(InstanceKey);
128 ExFreePool(OriginalIdBuffer);
129 return;
130 }
131
132 Status = ZwQueryValueKey(InstanceKey,
133 &HardwareIdU,
134 KeyValuePartialInformation,
135 PartialInfo,
136 HidLength,
137 &HidLength);
138 if (Status != STATUS_SUCCESS)
139 {
140 ExFreePool(PartialInfo);
141 ExFreePool(OriginalIdBuffer);
142 ZwClose(InstanceKey);
143 return;
144 }
145
146 /* Copy in HID info first (without 2nd terminating NULL if CID is present) */
147 HidLength = PartialInfo->DataLength - ((CidLength != 0) ? sizeof(WCHAR) : 0);
148 RtlCopyMemory(IdBuffer, PartialInfo->Data, HidLength);
149
150 if (CidLength != 0)
151 {
152 Status = ZwQueryValueKey(InstanceKey,
153 &CompatibleIdU,
154 KeyValuePartialInformation,
155 PartialInfo,
156 CidLength,
157 &CidLength);
158 if (Status != STATUS_SUCCESS)
159 {
160 ExFreePool(PartialInfo);
161 ExFreePool(OriginalIdBuffer);
162 ZwClose(InstanceKey);
163 return;
164 }
165
166 /* Copy CID next */
167 CidLength = PartialInfo->DataLength;
168 RtlCopyMemory(((PUCHAR)IdBuffer) + HidLength, PartialInfo->Data, CidLength);
169 }
170
171 /* Free our temp buffer */
172 ExFreePool(PartialInfo);
173
174 InitializeObjectAttributes(&ObjectAttributes,
175 &CriticalDeviceKeyU,
176 OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
177 NULL,
178 NULL);
179 Status = ZwOpenKey(&CriticalDeviceKey,
180 KEY_ENUMERATE_SUB_KEYS,
181 &ObjectAttributes);
182 if (!NT_SUCCESS(Status))
183 {
184 /* The critical device database doesn't exist because
185 * we're probably in 1st stage setup, but it's ok */
186 ExFreePool(OriginalIdBuffer);
187 ZwClose(InstanceKey);
188 return;
189 }
190
191 while (*IdBuffer)
192 {
193 USHORT StringLength = (USHORT)wcslen(IdBuffer) + 1, Index;
194
195 IopFixupDeviceId(IdBuffer);
196
197 /* Look through all subkeys for a match */
198 for (Index = 0; TRUE; Index++)
199 {
200 ULONG NeededLength;
201 PKEY_BASIC_INFORMATION BasicInfo;
202
203 Status = ZwEnumerateKey(CriticalDeviceKey,
204 Index,
205 KeyBasicInformation,
206 NULL,
207 0,
208 &NeededLength);
209 if (Status == STATUS_NO_MORE_ENTRIES)
210 break;
211 else if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
212 {
213 UNICODE_STRING ChildIdNameU, RegKeyNameU;
214
215 BasicInfo = ExAllocatePool(PagedPool, NeededLength);
216 if (!BasicInfo)
217 {
218 /* No memory */
219 ExFreePool(OriginalIdBuffer);
220 ZwClose(CriticalDeviceKey);
221 ZwClose(InstanceKey);
222 return;
223 }
224
225 Status = ZwEnumerateKey(CriticalDeviceKey,
226 Index,
227 KeyBasicInformation,
228 BasicInfo,
229 NeededLength,
230 &NeededLength);
231 if (Status != STATUS_SUCCESS)
232 {
233 /* This shouldn't happen */
234 ExFreePool(BasicInfo);
235 continue;
236 }
237
238 ChildIdNameU.Buffer = IdBuffer;
239 ChildIdNameU.MaximumLength = ChildIdNameU.Length = (StringLength - 1) * sizeof(WCHAR);
240 RegKeyNameU.Buffer = BasicInfo->Name;
241 RegKeyNameU.MaximumLength = RegKeyNameU.Length = (USHORT)BasicInfo->NameLength;
242
243 if (RtlEqualUnicodeString(&ChildIdNameU, &RegKeyNameU, TRUE))
244 {
245 HANDLE ChildKeyHandle;
246
247 InitializeObjectAttributes(&ObjectAttributes,
248 &ChildIdNameU,
249 OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
250 CriticalDeviceKey,
251 NULL);
252
253 Status = ZwOpenKey(&ChildKeyHandle,
254 KEY_QUERY_VALUE,
255 &ObjectAttributes);
256 if (Status != STATUS_SUCCESS)
257 {
258 ExFreePool(BasicInfo);
259 continue;
260 }
261
262 /* Check if there's already a driver installed */
263 Status = ZwQueryValueKey(InstanceKey,
264 &ClassGuidU,
265 KeyValuePartialInformation,
266 NULL,
267 0,
268 &NeededLength);
269 if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
270 {
271 ExFreePool(BasicInfo);
272 continue;
273 }
274
275 Status = ZwQueryValueKey(ChildKeyHandle,
276 &ClassGuidU,
277 KeyValuePartialInformation,
278 NULL,
279 0,
280 &NeededLength);
281 if (Status != STATUS_BUFFER_OVERFLOW && Status != STATUS_BUFFER_TOO_SMALL)
282 {
283 ExFreePool(BasicInfo);
284 continue;
285 }
286
287 PartialInfo = ExAllocatePool(PagedPool, NeededLength);
288 if (!PartialInfo)
289 {
290 ExFreePool(OriginalIdBuffer);
291 ExFreePool(BasicInfo);
292 ZwClose(InstanceKey);
293 ZwClose(ChildKeyHandle);
294 ZwClose(CriticalDeviceKey);
295 return;
296 }
297
298 /* Read ClassGUID entry in the CDDB */
299 Status = ZwQueryValueKey(ChildKeyHandle,
300 &ClassGuidU,
301 KeyValuePartialInformation,
302 PartialInfo,
303 NeededLength,
304 &NeededLength);
305 if (Status != STATUS_SUCCESS)
306 {
307 ExFreePool(BasicInfo);
308 continue;
309 }
310
311 /* Write it to the ENUM key */
312 Status = ZwSetValueKey(InstanceKey,
313 &ClassGuidU,
314 0,
315 REG_SZ,
316 PartialInfo->Data,
317 PartialInfo->DataLength);
318 if (Status != STATUS_SUCCESS)
319 {
320 ExFreePool(BasicInfo);
321 ExFreePool(PartialInfo);
322 ZwClose(ChildKeyHandle);
323 continue;
324 }
325
326 Status = ZwQueryValueKey(ChildKeyHandle,
327 &ServiceU,
328 KeyValuePartialInformation,
329 NULL,
330 0,
331 &NeededLength);
332 if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
333 {
334 ExFreePool(PartialInfo);
335 PartialInfo = ExAllocatePool(PagedPool, NeededLength);
336 if (!PartialInfo)
337 {
338 ExFreePool(OriginalIdBuffer);
339 ExFreePool(BasicInfo);
340 ZwClose(InstanceKey);
341 ZwClose(ChildKeyHandle);
342 ZwClose(CriticalDeviceKey);
343 return;
344 }
345
346 /* Read the service entry from the CDDB */
347 Status = ZwQueryValueKey(ChildKeyHandle,
348 &ServiceU,
349 KeyValuePartialInformation,
350 PartialInfo,
351 NeededLength,
352 &NeededLength);
353 if (Status != STATUS_SUCCESS)
354 {
355 ExFreePool(BasicInfo);
356 ExFreePool(PartialInfo);
357 ZwClose(ChildKeyHandle);
358 continue;
359 }
360
361 /* Write it to the ENUM key */
362 Status = ZwSetValueKey(InstanceKey,
363 &ServiceU,
364 0,
365 REG_SZ,
366 PartialInfo->Data,
367 PartialInfo->DataLength);
368 if (Status != STATUS_SUCCESS)
369 {
370 ExFreePool(BasicInfo);
371 ExFreePool(PartialInfo);
372 ZwClose(ChildKeyHandle);
373 continue;
374 }
375
376 DPRINT("Installed service '%S' for critical device '%wZ'\n", PartialInfo->Data, &ChildIdNameU);
377 }
378 else
379 {
380 DPRINT1("Installed NULL service for critical device '%wZ'\n", &ChildIdNameU);
381 }
382
383 ExFreePool(OriginalIdBuffer);
384 ExFreePool(PartialInfo);
385 ExFreePool(BasicInfo);
386 ZwClose(InstanceKey);
387 ZwClose(ChildKeyHandle);
388 ZwClose(CriticalDeviceKey);
389
390 /* That's it */
391 return;
392 }
393
394 ExFreePool(BasicInfo);
395 }
396 else
397 {
398 /* Umm, not sure what happened here */
399 continue;
400 }
401 }
402
403 /* Advance to the next ID */
404 IdBuffer += StringLength;
405 }
406
407 ExFreePool(OriginalIdBuffer);
408 ZwClose(InstanceKey);
409 ZwClose(CriticalDeviceKey);
410 }
411
412 NTSTATUS
413 FASTCALL
414 IopInitializeDevice(PDEVICE_NODE DeviceNode,
415 PDRIVER_OBJECT DriverObject)
416 {
417 PDEVICE_OBJECT Fdo;
418 NTSTATUS Status;
419
420 if (!DriverObject)
421 {
422 /* Special case for bus driven devices */
423 DeviceNode->Flags |= DNF_ADDED;
424 return STATUS_SUCCESS;
425 }
426
427 if (!DriverObject->DriverExtension->AddDevice)
428 {
429 DeviceNode->Flags |= DNF_LEGACY_DRIVER;
430 }
431
432 if (DeviceNode->Flags & DNF_LEGACY_DRIVER)
433 {
434 DeviceNode->Flags |= (DNF_ADDED | DNF_STARTED);
435 return STATUS_SUCCESS;
436 }
437
438 /* This is a Plug and Play driver */
439 DPRINT("Plug and Play driver found\n");
440 ASSERT(DeviceNode->PhysicalDeviceObject);
441
442 DPRINT("Calling %wZ->AddDevice(%wZ)\n",
443 &DriverObject->DriverName,
444 &DeviceNode->InstancePath);
445 Status = DriverObject->DriverExtension->AddDevice(DriverObject,
446 DeviceNode->PhysicalDeviceObject);
447 if (!NT_SUCCESS(Status))
448 {
449 DPRINT1("%wZ->AddDevice(%wZ) failed with status 0x%x\n",
450 &DriverObject->DriverName,
451 &DeviceNode->InstancePath,
452 Status);
453 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
454 DeviceNode->Problem = CM_PROB_FAILED_ADD;
455 return Status;
456 }
457
458 Fdo = IoGetAttachedDeviceReference(DeviceNode->PhysicalDeviceObject);
459
460 /* Check if we have a ACPI device (needed for power management) */
461 if (Fdo->DeviceType == FILE_DEVICE_ACPI)
462 {
463 static BOOLEAN SystemPowerDeviceNodeCreated = FALSE;
464
465 /* There can be only one system power device */
466 if (!SystemPowerDeviceNodeCreated)
467 {
468 PopSystemPowerDeviceNode = DeviceNode;
469 ObReferenceObject(PopSystemPowerDeviceNode->PhysicalDeviceObject);
470 SystemPowerDeviceNodeCreated = TRUE;
471 }
472 }
473
474 ObDereferenceObject(Fdo);
475
476 IopDeviceNodeSetFlag(DeviceNode, DNF_ADDED);
477
478 return STATUS_SUCCESS;
479 }
480
481 static
482 NTSTATUS
483 NTAPI
484 IopSendEject(IN PDEVICE_OBJECT DeviceObject)
485 {
486 IO_STACK_LOCATION Stack;
487 PVOID Dummy;
488
489 RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION));
490 Stack.MajorFunction = IRP_MJ_PNP;
491 Stack.MinorFunction = IRP_MN_EJECT;
492
493 return IopSynchronousCall(DeviceObject, &Stack, &Dummy);
494 }
495
496 static
497 VOID
498 NTAPI
499 IopSendSurpriseRemoval(IN PDEVICE_OBJECT DeviceObject)
500 {
501 IO_STACK_LOCATION Stack;
502 PVOID Dummy;
503
504 RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION));
505 Stack.MajorFunction = IRP_MJ_PNP;
506 Stack.MinorFunction = IRP_MN_SURPRISE_REMOVAL;
507
508 /* Drivers should never fail a IRP_MN_SURPRISE_REMOVAL request */
509 IopSynchronousCall(DeviceObject, &Stack, &Dummy);
510 }
511
512 static
513 NTSTATUS
514 NTAPI
515 IopQueryRemoveDevice(IN PDEVICE_OBJECT DeviceObject)
516 {
517 PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject);
518 IO_STACK_LOCATION Stack;
519 PVOID Dummy;
520 NTSTATUS Status;
521
522 ASSERT(DeviceNode);
523
524 IopQueueTargetDeviceEvent(&GUID_DEVICE_REMOVE_PENDING,
525 &DeviceNode->InstancePath);
526
527 RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION));
528 Stack.MajorFunction = IRP_MJ_PNP;
529 Stack.MinorFunction = IRP_MN_QUERY_REMOVE_DEVICE;
530
531 Status = IopSynchronousCall(DeviceObject, &Stack, &Dummy);
532
533 IopNotifyPlugPlayNotification(DeviceObject,
534 EventCategoryTargetDeviceChange,
535 &GUID_TARGET_DEVICE_QUERY_REMOVE,
536 NULL,
537 NULL);
538
539 if (!NT_SUCCESS(Status))
540 {
541 DPRINT1("Removal vetoed by %wZ\n", &DeviceNode->InstancePath);
542 IopQueueTargetDeviceEvent(&GUID_DEVICE_REMOVAL_VETOED,
543 &DeviceNode->InstancePath);
544 }
545
546 return Status;
547 }
548
549 static
550 NTSTATUS
551 NTAPI
552 IopQueryStopDevice(IN PDEVICE_OBJECT DeviceObject)
553 {
554 IO_STACK_LOCATION Stack;
555 PVOID Dummy;
556
557 RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION));
558 Stack.MajorFunction = IRP_MJ_PNP;
559 Stack.MinorFunction = IRP_MN_QUERY_STOP_DEVICE;
560
561 return IopSynchronousCall(DeviceObject, &Stack, &Dummy);
562 }
563
564 static
565 VOID
566 NTAPI
567 IopSendRemoveDevice(IN PDEVICE_OBJECT DeviceObject)
568 {
569 IO_STACK_LOCATION Stack;
570 PVOID Dummy;
571 PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject);
572
573 /* Drop all our state for this device in case it isn't really going away */
574 DeviceNode->Flags &= DNF_ENUMERATED | DNF_PROCESSED;
575
576 RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION));
577 Stack.MajorFunction = IRP_MJ_PNP;
578 Stack.MinorFunction = IRP_MN_REMOVE_DEVICE;
579
580 /* Drivers should never fail a IRP_MN_REMOVE_DEVICE request */
581 IopSynchronousCall(DeviceObject, &Stack, &Dummy);
582
583 IopNotifyPlugPlayNotification(DeviceObject,
584 EventCategoryTargetDeviceChange,
585 &GUID_TARGET_DEVICE_REMOVE_COMPLETE,
586 NULL,
587 NULL);
588 ObDereferenceObject(DeviceObject);
589 }
590
591 static
592 VOID
593 NTAPI
594 IopCancelRemoveDevice(IN PDEVICE_OBJECT DeviceObject)
595 {
596 IO_STACK_LOCATION Stack;
597 PVOID Dummy;
598
599 RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION));
600 Stack.MajorFunction = IRP_MJ_PNP;
601 Stack.MinorFunction = IRP_MN_CANCEL_REMOVE_DEVICE;
602
603 /* Drivers should never fail a IRP_MN_CANCEL_REMOVE_DEVICE request */
604 IopSynchronousCall(DeviceObject, &Stack, &Dummy);
605
606 IopNotifyPlugPlayNotification(DeviceObject,
607 EventCategoryTargetDeviceChange,
608 &GUID_TARGET_DEVICE_REMOVE_CANCELLED,
609 NULL,
610 NULL);
611 }
612
613 static
614 VOID
615 NTAPI
616 IopSendStopDevice(IN PDEVICE_OBJECT DeviceObject)
617 {
618 IO_STACK_LOCATION Stack;
619 PVOID Dummy;
620
621 RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION));
622 Stack.MajorFunction = IRP_MJ_PNP;
623 Stack.MinorFunction = IRP_MN_STOP_DEVICE;
624
625 /* Drivers should never fail a IRP_MN_STOP_DEVICE request */
626 IopSynchronousCall(DeviceObject, &Stack, &Dummy);
627 }
628
629 static
630 NTSTATUS
631 IopSetServiceEnumData(PDEVICE_NODE DeviceNode)
632 {
633 UNICODE_STRING ServicesKeyPath = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
634 UNICODE_STRING ServiceKeyName;
635 UNICODE_STRING EnumKeyName;
636 UNICODE_STRING ValueName;
637 PKEY_VALUE_FULL_INFORMATION KeyValueInformation;
638 HANDLE ServiceKey = NULL, ServiceEnumKey = NULL;
639 ULONG Disposition;
640 ULONG Count = 0, NextInstance = 0;
641 WCHAR ValueBuffer[6];
642 NTSTATUS Status = STATUS_SUCCESS;
643
644 DPRINT("IopSetServiceEnumData(%p)\n", DeviceNode);
645 DPRINT("Instance: %wZ\n", &DeviceNode->InstancePath);
646 DPRINT("Service: %wZ\n", &DeviceNode->ServiceName);
647
648 if (DeviceNode->ServiceName.Buffer == NULL)
649 {
650 DPRINT1("No service!\n");
651 return STATUS_SUCCESS;
652 }
653
654 ServiceKeyName.MaximumLength = ServicesKeyPath.Length + DeviceNode->ServiceName.Length + sizeof(UNICODE_NULL);
655 ServiceKeyName.Length = 0;
656 ServiceKeyName.Buffer = ExAllocatePool(PagedPool, ServiceKeyName.MaximumLength);
657 if (ServiceKeyName.Buffer == NULL)
658 {
659 DPRINT1("No ServiceKeyName.Buffer!\n");
660 return STATUS_INSUFFICIENT_RESOURCES;
661 }
662
663 RtlAppendUnicodeStringToString(&ServiceKeyName, &ServicesKeyPath);
664 RtlAppendUnicodeStringToString(&ServiceKeyName, &DeviceNode->ServiceName);
665
666 DPRINT("ServiceKeyName: %wZ\n", &ServiceKeyName);
667
668 Status = IopOpenRegistryKeyEx(&ServiceKey, NULL, &ServiceKeyName, KEY_CREATE_SUB_KEY);
669 if (!NT_SUCCESS(Status))
670 {
671 goto done;
672 }
673
674 RtlInitUnicodeString(&EnumKeyName, L"Enum");
675 Status = IopCreateRegistryKeyEx(&ServiceEnumKey,
676 ServiceKey,
677 &EnumKeyName,
678 KEY_SET_VALUE,
679 REG_OPTION_VOLATILE,
680 &Disposition);
681 if (NT_SUCCESS(Status))
682 {
683 if (Disposition == REG_OPENED_EXISTING_KEY)
684 {
685 /* Read the NextInstance value */
686 Status = IopGetRegistryValue(ServiceEnumKey,
687 L"Count",
688 &KeyValueInformation);
689 if (!NT_SUCCESS(Status))
690 goto done;
691
692 if ((KeyValueInformation->Type == REG_DWORD) &&
693 (KeyValueInformation->DataLength))
694 {
695 /* Read it */
696 Count = *(PULONG)((ULONG_PTR)KeyValueInformation +
697 KeyValueInformation->DataOffset);
698 }
699
700 ExFreePool(KeyValueInformation);
701 KeyValueInformation = NULL;
702
703 /* Read the NextInstance value */
704 Status = IopGetRegistryValue(ServiceEnumKey,
705 L"NextInstance",
706 &KeyValueInformation);
707 if (!NT_SUCCESS(Status))
708 goto done;
709
710 if ((KeyValueInformation->Type == REG_DWORD) &&
711 (KeyValueInformation->DataLength))
712 {
713 NextInstance = *(PULONG)((ULONG_PTR)KeyValueInformation +
714 KeyValueInformation->DataOffset);
715 }
716
717 ExFreePool(KeyValueInformation);
718 KeyValueInformation = NULL;
719 }
720
721 /* Set the instance path */
722 swprintf(ValueBuffer, L"%lu", NextInstance);
723 RtlInitUnicodeString(&ValueName, ValueBuffer);
724 Status = ZwSetValueKey(ServiceEnumKey,
725 &ValueName,
726 0,
727 REG_SZ,
728 DeviceNode->InstancePath.Buffer,
729 DeviceNode->InstancePath.MaximumLength);
730 if (!NT_SUCCESS(Status))
731 goto done;
732
733 /* Increment Count and NextInstance */
734 Count++;
735 NextInstance++;
736
737 /* Set the new Count value */
738 RtlInitUnicodeString(&ValueName, L"Count");
739 Status = ZwSetValueKey(ServiceEnumKey,
740 &ValueName,
741 0,
742 REG_DWORD,
743 &Count,
744 sizeof(Count));
745 if (!NT_SUCCESS(Status))
746 goto done;
747
748 /* Set the new NextInstance value */
749 RtlInitUnicodeString(&ValueName, L"NextInstance");
750 Status = ZwSetValueKey(ServiceEnumKey,
751 &ValueName,
752 0,
753 REG_DWORD,
754 &NextInstance,
755 sizeof(NextInstance));
756 }
757
758 done:
759 if (ServiceEnumKey != NULL)
760 ZwClose(ServiceEnumKey);
761
762 if (ServiceKey != NULL)
763 ZwClose(ServiceKey);
764
765 ExFreePool(ServiceKeyName.Buffer);
766
767 return Status;
768 }
769
770 VOID
771 NTAPI
772 IopStartDevice2(IN PDEVICE_OBJECT DeviceObject)
773 {
774 IO_STACK_LOCATION Stack;
775 PDEVICE_NODE DeviceNode;
776 NTSTATUS Status;
777 PVOID Dummy;
778 DEVICE_CAPABILITIES DeviceCapabilities;
779
780 /* Get the device node */
781 DeviceNode = IopGetDeviceNode(DeviceObject);
782
783 ASSERT(!(DeviceNode->Flags & DNF_DISABLED));
784
785 /* Build the I/O stack location */
786 RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION));
787 Stack.MajorFunction = IRP_MJ_PNP;
788 Stack.MinorFunction = IRP_MN_START_DEVICE;
789
790 Stack.Parameters.StartDevice.AllocatedResources =
791 DeviceNode->ResourceList;
792 Stack.Parameters.StartDevice.AllocatedResourcesTranslated =
793 DeviceNode->ResourceListTranslated;
794
795 /* Do the call */
796 Status = IopSynchronousCall(DeviceObject, &Stack, &Dummy);
797 if (!NT_SUCCESS(Status))
798 {
799 /* Send an IRP_MN_REMOVE_DEVICE request */
800 IopRemoveDevice(DeviceNode);
801
802 /* Set the appropriate flag */
803 DeviceNode->Flags |= DNF_START_FAILED;
804 DeviceNode->Problem = CM_PROB_FAILED_START;
805
806 DPRINT1("Warning: PnP Start failed (%wZ) [Status: 0x%x]\n", &DeviceNode->InstancePath, Status);
807 return;
808 }
809
810 DPRINT("Sending IRP_MN_QUERY_CAPABILITIES to device stack (after start)\n");
811
812 Status = IopQueryDeviceCapabilities(DeviceNode, &DeviceCapabilities);
813 if (!NT_SUCCESS(Status))
814 {
815 DPRINT("IopInitiatePnpIrp() failed (Status 0x%08lx)\n", Status);
816 }
817
818 /* Invalidate device state so IRP_MN_QUERY_PNP_DEVICE_STATE is sent */
819 IoInvalidateDeviceState(DeviceObject);
820
821 /* Otherwise, mark us as started */
822 DeviceNode->Flags |= DNF_STARTED;
823 DeviceNode->Flags &= ~DNF_STOPPED;
824
825 /* We now need enumeration */
826 DeviceNode->Flags |= DNF_NEED_ENUMERATION_ONLY;
827 }
828
829 NTSTATUS
830 NTAPI
831 IopStartAndEnumerateDevice(IN PDEVICE_NODE DeviceNode)
832 {
833 PDEVICE_OBJECT DeviceObject;
834 NTSTATUS Status;
835 PAGED_CODE();
836
837 /* Sanity check */
838 ASSERT((DeviceNode->Flags & DNF_ADDED));
839 ASSERT((DeviceNode->Flags & (DNF_RESOURCE_ASSIGNED |
840 DNF_RESOURCE_REPORTED |
841 DNF_NO_RESOURCE_REQUIRED)));
842
843 /* Get the device object */
844 DeviceObject = DeviceNode->PhysicalDeviceObject;
845
846 /* Check if we're not started yet */
847 if (!(DeviceNode->Flags & DNF_STARTED))
848 {
849 /* Start us */
850 IopStartDevice2(DeviceObject);
851 }
852
853 /* Do we need to query IDs? This happens in the case of manual reporting */
854 #if 0
855 if (DeviceNode->Flags & DNF_NEED_QUERY_IDS)
856 {
857 DPRINT1("Warning: Device node has DNF_NEED_QUERY_IDS\n");
858 /* And that case shouldn't happen yet */
859 ASSERT(FALSE);
860 }
861 #endif
862
863 IopSetServiceEnumData(DeviceNode);
864
865 /* Make sure we're started, and check if we need enumeration */
866 if ((DeviceNode->Flags & DNF_STARTED) &&
867 (DeviceNode->Flags & DNF_NEED_ENUMERATION_ONLY))
868 {
869 /* Enumerate us */
870 IoSynchronousInvalidateDeviceRelations(DeviceObject, BusRelations);
871 Status = STATUS_SUCCESS;
872 }
873 else
874 {
875 /* Nothing to do */
876 Status = STATUS_SUCCESS;
877 }
878
879 /* Return */
880 return Status;
881 }
882
883 NTSTATUS
884 IopStopDevice(
885 PDEVICE_NODE DeviceNode)
886 {
887 NTSTATUS Status;
888
889 DPRINT("Stopping device: %wZ\n", &DeviceNode->InstancePath);
890
891 Status = IopQueryStopDevice(DeviceNode->PhysicalDeviceObject);
892 if (NT_SUCCESS(Status))
893 {
894 IopSendStopDevice(DeviceNode->PhysicalDeviceObject);
895
896 DeviceNode->Flags &= ~(DNF_STARTED | DNF_START_REQUEST_PENDING);
897 DeviceNode->Flags |= DNF_STOPPED;
898
899 return STATUS_SUCCESS;
900 }
901
902 return Status;
903 }
904
905 NTSTATUS
906 IopStartDevice(
907 PDEVICE_NODE DeviceNode)
908 {
909 NTSTATUS Status;
910 HANDLE InstanceHandle = NULL, ControlHandle = NULL;
911 UNICODE_STRING KeyName, ValueString;
912 OBJECT_ATTRIBUTES ObjectAttributes;
913
914 if (DeviceNode->Flags & DNF_DISABLED)
915 return STATUS_SUCCESS;
916
917 Status = IopAssignDeviceResources(DeviceNode);
918 if (!NT_SUCCESS(Status))
919 goto ByeBye;
920
921 /* New PnP ABI */
922 IopStartAndEnumerateDevice(DeviceNode);
923
924 /* FIX: Should be done in new device instance code */
925 Status = IopCreateDeviceKeyPath(&DeviceNode->InstancePath, REG_OPTION_NON_VOLATILE, &InstanceHandle);
926 if (!NT_SUCCESS(Status))
927 goto ByeBye;
928
929 /* FIX: Should be done in IoXxxPrepareDriverLoading */
930 // {
931 RtlInitUnicodeString(&KeyName, L"Control");
932 InitializeObjectAttributes(&ObjectAttributes,
933 &KeyName,
934 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
935 InstanceHandle,
936 NULL);
937 Status = ZwCreateKey(&ControlHandle,
938 KEY_SET_VALUE,
939 &ObjectAttributes,
940 0,
941 NULL,
942 REG_OPTION_VOLATILE,
943 NULL);
944 if (!NT_SUCCESS(Status))
945 goto ByeBye;
946
947 RtlInitUnicodeString(&KeyName, L"ActiveService");
948 ValueString = DeviceNode->ServiceName;
949 if (!ValueString.Buffer)
950 RtlInitUnicodeString(&ValueString, L"");
951 Status = ZwSetValueKey(ControlHandle, &KeyName, 0, REG_SZ, ValueString.Buffer, ValueString.Length + sizeof(UNICODE_NULL));
952 // }
953
954 ByeBye:
955 if (ControlHandle != NULL)
956 ZwClose(ControlHandle);
957
958 if (InstanceHandle != NULL)
959 ZwClose(InstanceHandle);
960
961 return Status;
962 }
963
964 NTSTATUS
965 NTAPI
966 IopQueryDeviceCapabilities(PDEVICE_NODE DeviceNode,
967 PDEVICE_CAPABILITIES DeviceCaps)
968 {
969 IO_STATUS_BLOCK StatusBlock;
970 IO_STACK_LOCATION Stack;
971 NTSTATUS Status;
972 HANDLE InstanceKey;
973 UNICODE_STRING ValueName;
974
975 /* Set up the Header */
976 RtlZeroMemory(DeviceCaps, sizeof(DEVICE_CAPABILITIES));
977 DeviceCaps->Size = sizeof(DEVICE_CAPABILITIES);
978 DeviceCaps->Version = 1;
979 DeviceCaps->Address = -1;
980 DeviceCaps->UINumber = -1;
981
982 /* Set up the Stack */
983 RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION));
984 Stack.Parameters.DeviceCapabilities.Capabilities = DeviceCaps;
985
986 /* Send the IRP */
987 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
988 &StatusBlock,
989 IRP_MN_QUERY_CAPABILITIES,
990 &Stack);
991 if (!NT_SUCCESS(Status))
992 {
993 if (Status != STATUS_NOT_SUPPORTED)
994 {
995 DPRINT1("IRP_MN_QUERY_CAPABILITIES failed with status 0x%lx\n", Status);
996 }
997 return Status;
998 }
999
1000 /* Map device capabilities to capability flags */
1001 DeviceNode->CapabilityFlags = 0;
1002 if (DeviceCaps->LockSupported)
1003 DeviceNode->CapabilityFlags |= 0x00000001; // CM_DEVCAP_LOCKSUPPORTED
1004
1005 if (DeviceCaps->EjectSupported)
1006 DeviceNode->CapabilityFlags |= 0x00000002; // CM_DEVCAP_EJECTSUPPORTED
1007
1008 if (DeviceCaps->Removable)
1009 DeviceNode->CapabilityFlags |= 0x00000004; // CM_DEVCAP_REMOVABLE
1010
1011 if (DeviceCaps->DockDevice)
1012 DeviceNode->CapabilityFlags |= 0x00000008; // CM_DEVCAP_DOCKDEVICE
1013
1014 if (DeviceCaps->UniqueID)
1015 DeviceNode->CapabilityFlags |= 0x00000010; // CM_DEVCAP_UNIQUEID
1016
1017 if (DeviceCaps->SilentInstall)
1018 DeviceNode->CapabilityFlags |= 0x00000020; // CM_DEVCAP_SILENTINSTALL
1019
1020 if (DeviceCaps->RawDeviceOK)
1021 DeviceNode->CapabilityFlags |= 0x00000040; // CM_DEVCAP_RAWDEVICEOK
1022
1023 if (DeviceCaps->SurpriseRemovalOK)
1024 DeviceNode->CapabilityFlags |= 0x00000080; // CM_DEVCAP_SURPRISEREMOVALOK
1025
1026 if (DeviceCaps->HardwareDisabled)
1027 DeviceNode->CapabilityFlags |= 0x00000100; // CM_DEVCAP_HARDWAREDISABLED
1028
1029 if (DeviceCaps->NonDynamic)
1030 DeviceNode->CapabilityFlags |= 0x00000200; // CM_DEVCAP_NONDYNAMIC
1031
1032 if (DeviceCaps->NoDisplayInUI)
1033 DeviceNode->UserFlags |= DNUF_DONT_SHOW_IN_UI;
1034 else
1035 DeviceNode->UserFlags &= ~DNUF_DONT_SHOW_IN_UI;
1036
1037 Status = IopCreateDeviceKeyPath(&DeviceNode->InstancePath, REG_OPTION_NON_VOLATILE, &InstanceKey);
1038 if (NT_SUCCESS(Status))
1039 {
1040 /* Set 'Capabilities' value */
1041 RtlInitUnicodeString(&ValueName, L"Capabilities");
1042 Status = ZwSetValueKey(InstanceKey,
1043 &ValueName,
1044 0,
1045 REG_DWORD,
1046 &DeviceNode->CapabilityFlags,
1047 sizeof(ULONG));
1048
1049 /* Set 'UINumber' value */
1050 if (DeviceCaps->UINumber != MAXULONG)
1051 {
1052 RtlInitUnicodeString(&ValueName, L"UINumber");
1053 Status = ZwSetValueKey(InstanceKey,
1054 &ValueName,
1055 0,
1056 REG_DWORD,
1057 &DeviceCaps->UINumber,
1058 sizeof(ULONG));
1059 }
1060
1061 ZwClose(InstanceKey);
1062 }
1063
1064 return Status;
1065 }
1066
1067 static
1068 VOID
1069 NTAPI
1070 IopDeviceActionWorker(
1071 _In_ PVOID Context)
1072 {
1073 PLIST_ENTRY ListEntry;
1074 PDEVICE_ACTION_DATA Data;
1075 KIRQL OldIrql;
1076
1077 KeAcquireSpinLock(&IopDeviceActionLock, &OldIrql);
1078 while (!IsListEmpty(&IopDeviceActionRequestList))
1079 {
1080 ListEntry = RemoveHeadList(&IopDeviceActionRequestList);
1081 KeReleaseSpinLock(&IopDeviceActionLock, OldIrql);
1082 Data = CONTAINING_RECORD(ListEntry,
1083 DEVICE_ACTION_DATA,
1084 RequestListEntry);
1085
1086 switch (Data->Action)
1087 {
1088 case DeviceActionInvalidateDeviceRelations:
1089 IoSynchronousInvalidateDeviceRelations(Data->DeviceObject,
1090 Data->InvalidateDeviceRelations.Type);
1091 break;
1092
1093 default:
1094 DPRINT1("Unimplemented device action %u\n", Data->Action);
1095 break;
1096 }
1097
1098 ObDereferenceObject(Data->DeviceObject);
1099 ExFreePoolWithTag(Data, TAG_IO);
1100 KeAcquireSpinLock(&IopDeviceActionLock, &OldIrql);
1101 }
1102 IopDeviceActionInProgress = FALSE;
1103 KeReleaseSpinLock(&IopDeviceActionLock, OldIrql);
1104 }
1105
1106 VOID
1107 IopQueueDeviceAction(
1108 _In_ PDEVICE_ACTION_DATA ActionData)
1109 {
1110 PDEVICE_ACTION_DATA Data;
1111 KIRQL OldIrql;
1112
1113 DPRINT("IopQueueDeviceAction(%p)\n", ActionData);
1114
1115 Data = ExAllocatePoolWithTag(NonPagedPool,
1116 sizeof(DEVICE_ACTION_DATA),
1117 TAG_IO);
1118 if (!Data)
1119 return;
1120
1121 ObReferenceObject(ActionData->DeviceObject);
1122 RtlCopyMemory(Data, ActionData, sizeof(DEVICE_ACTION_DATA));
1123
1124 DPRINT("Action %u\n", Data->Action);
1125
1126 KeAcquireSpinLock(&IopDeviceActionLock, &OldIrql);
1127 InsertTailList(&IopDeviceActionRequestList, &Data->RequestListEntry);
1128 if (IopDeviceActionInProgress)
1129 {
1130 KeReleaseSpinLock(&IopDeviceActionLock, OldIrql);
1131 return;
1132 }
1133 IopDeviceActionInProgress = TRUE;
1134 KeReleaseSpinLock(&IopDeviceActionLock, OldIrql);
1135
1136 ExInitializeWorkItem(&IopDeviceActionWorkItem,
1137 IopDeviceActionWorker,
1138 NULL);
1139 ExQueueWorkItem(&IopDeviceActionWorkItem,
1140 DelayedWorkQueue);
1141 }
1142
1143 NTSTATUS
1144 IopGetSystemPowerDeviceObject(PDEVICE_OBJECT *DeviceObject)
1145 {
1146 KIRQL OldIrql;
1147
1148 if (PopSystemPowerDeviceNode)
1149 {
1150 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
1151 *DeviceObject = PopSystemPowerDeviceNode->PhysicalDeviceObject;
1152 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
1153
1154 return STATUS_SUCCESS;
1155 }
1156
1157 return STATUS_UNSUCCESSFUL;
1158 }
1159
1160 USHORT
1161 NTAPI
1162 IopGetBusTypeGuidIndex(LPGUID BusTypeGuid)
1163 {
1164 USHORT i = 0, FoundIndex = 0xFFFF;
1165 ULONG NewSize;
1166 PVOID NewList;
1167
1168 /* Acquire the lock */
1169 ExAcquireFastMutex(&PnpBusTypeGuidList->Lock);
1170
1171 /* Loop all entries */
1172 while (i < PnpBusTypeGuidList->GuidCount)
1173 {
1174 /* Try to find a match */
1175 if (RtlCompareMemory(BusTypeGuid,
1176 &PnpBusTypeGuidList->Guids[i],
1177 sizeof(GUID)) == sizeof(GUID))
1178 {
1179 /* Found it */
1180 FoundIndex = i;
1181 goto Quickie;
1182 }
1183 i++;
1184 }
1185
1186 /* Check if we have to grow the list */
1187 if (PnpBusTypeGuidList->GuidCount)
1188 {
1189 /* Calculate the new size */
1190 NewSize = sizeof(IO_BUS_TYPE_GUID_LIST) +
1191 (sizeof(GUID) * PnpBusTypeGuidList->GuidCount);
1192
1193 /* Allocate the new copy */
1194 NewList = ExAllocatePool(PagedPool, NewSize);
1195
1196 if (!NewList)
1197 {
1198 /* Fail */
1199 ExFreePool(PnpBusTypeGuidList);
1200 goto Quickie;
1201 }
1202
1203 /* Now copy them, decrease the size too */
1204 NewSize -= sizeof(GUID);
1205 RtlCopyMemory(NewList, PnpBusTypeGuidList, NewSize);
1206
1207 /* Free the old list */
1208 ExFreePool(PnpBusTypeGuidList);
1209
1210 /* Use the new buffer */
1211 PnpBusTypeGuidList = NewList;
1212 }
1213
1214 /* Copy the new GUID */
1215 RtlCopyMemory(&PnpBusTypeGuidList->Guids[PnpBusTypeGuidList->GuidCount],
1216 BusTypeGuid,
1217 sizeof(GUID));
1218
1219 /* The new entry is the index */
1220 FoundIndex = (USHORT)PnpBusTypeGuidList->GuidCount;
1221 PnpBusTypeGuidList->GuidCount++;
1222
1223 Quickie:
1224 ExReleaseFastMutex(&PnpBusTypeGuidList->Lock);
1225 return FoundIndex;
1226 }
1227
1228 NTSTATUS
1229 NTAPI
1230 IopSynchronousCall(IN PDEVICE_OBJECT DeviceObject,
1231 IN PIO_STACK_LOCATION IoStackLocation,
1232 OUT PVOID *Information)
1233 {
1234 PIRP Irp;
1235 PIO_STACK_LOCATION IrpStack;
1236 IO_STATUS_BLOCK IoStatusBlock;
1237 KEVENT Event;
1238 NTSTATUS Status;
1239 PDEVICE_OBJECT TopDeviceObject;
1240 PAGED_CODE();
1241
1242 /* Call the top of the device stack */
1243 TopDeviceObject = IoGetAttachedDeviceReference(DeviceObject);
1244
1245 /* Allocate an IRP */
1246 Irp = IoAllocateIrp(TopDeviceObject->StackSize, FALSE);
1247 if (!Irp) return STATUS_INSUFFICIENT_RESOURCES;
1248
1249 /* Initialize to failure */
1250 Irp->IoStatus.Status = IoStatusBlock.Status = STATUS_NOT_SUPPORTED;
1251 Irp->IoStatus.Information = IoStatusBlock.Information = 0;
1252
1253 /* Special case for IRP_MN_FILTER_RESOURCE_REQUIREMENTS */
1254 if ((IoStackLocation->MajorFunction == IRP_MJ_PNP) &&
1255 (IoStackLocation->MinorFunction == IRP_MN_FILTER_RESOURCE_REQUIREMENTS))
1256 {
1257 /* Copy the resource requirements list into the IOSB */
1258 Irp->IoStatus.Information =
1259 IoStatusBlock.Information = (ULONG_PTR)IoStackLocation->Parameters.FilterResourceRequirements.IoResourceRequirementList;
1260 }
1261
1262 /* Initialize the event */
1263 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
1264
1265 /* Set them up */
1266 Irp->UserIosb = &IoStatusBlock;
1267 Irp->UserEvent = &Event;
1268
1269 /* Queue the IRP */
1270 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
1271 IoQueueThreadIrp(Irp);
1272
1273 /* Copy-in the stack */
1274 IrpStack = IoGetNextIrpStackLocation(Irp);
1275 *IrpStack = *IoStackLocation;
1276
1277 /* Call the driver */
1278 Status = IoCallDriver(TopDeviceObject, Irp);
1279 if (Status == STATUS_PENDING)
1280 {
1281 /* Wait for it */
1282 KeWaitForSingleObject(&Event,
1283 Executive,
1284 KernelMode,
1285 FALSE,
1286 NULL);
1287 Status = IoStatusBlock.Status;
1288 }
1289
1290 /* Remove the reference */
1291 ObDereferenceObject(TopDeviceObject);
1292
1293 /* Return the information */
1294 *Information = (PVOID)IoStatusBlock.Information;
1295 return Status;
1296 }
1297
1298 NTSTATUS
1299 NTAPI
1300 IopInitiatePnpIrp(IN PDEVICE_OBJECT DeviceObject,
1301 IN OUT PIO_STATUS_BLOCK IoStatusBlock,
1302 IN UCHAR MinorFunction,
1303 IN PIO_STACK_LOCATION Stack OPTIONAL)
1304 {
1305 IO_STACK_LOCATION IoStackLocation;
1306
1307 /* Fill out the stack information */
1308 RtlZeroMemory(&IoStackLocation, sizeof(IO_STACK_LOCATION));
1309 IoStackLocation.MajorFunction = IRP_MJ_PNP;
1310 IoStackLocation.MinorFunction = MinorFunction;
1311 if (Stack)
1312 {
1313 /* Copy the rest */
1314 RtlCopyMemory(&IoStackLocation.Parameters,
1315 &Stack->Parameters,
1316 sizeof(Stack->Parameters));
1317 }
1318
1319 /* Do the PnP call */
1320 IoStatusBlock->Status = IopSynchronousCall(DeviceObject,
1321 &IoStackLocation,
1322 (PVOID)&IoStatusBlock->Information);
1323 return IoStatusBlock->Status;
1324 }
1325
1326 /*
1327 * IopCreateDeviceKeyPath
1328 *
1329 * Creates a registry key
1330 *
1331 * Parameters
1332 * RegistryPath
1333 * Name of the key to be created.
1334 * Handle
1335 * Handle to the newly created key
1336 *
1337 * Remarks
1338 * This method can create nested trees, so parent of RegistryPath can
1339 * be not existant, and will be created if needed.
1340 */
1341 NTSTATUS
1342 NTAPI
1343 IopCreateDeviceKeyPath(IN PCUNICODE_STRING RegistryPath,
1344 IN ULONG CreateOptions,
1345 OUT PHANDLE Handle)
1346 {
1347 UNICODE_STRING EnumU = RTL_CONSTANT_STRING(ENUM_ROOT);
1348 HANDLE hParent = NULL, hKey;
1349 OBJECT_ATTRIBUTES ObjectAttributes;
1350 UNICODE_STRING KeyName;
1351 PCWSTR Current, Last;
1352 USHORT Length;
1353 NTSTATUS Status;
1354
1355 /* Assume failure */
1356 *Handle = NULL;
1357
1358 /* Open root key for device instances */
1359 Status = IopOpenRegistryKeyEx(&hParent, NULL, &EnumU, KEY_CREATE_SUB_KEY);
1360 if (!NT_SUCCESS(Status))
1361 {
1362 DPRINT1("ZwOpenKey('%wZ') failed with status 0x%08lx\n", &EnumU, Status);
1363 return Status;
1364 }
1365
1366 Current = KeyName.Buffer = RegistryPath->Buffer;
1367 Last = &RegistryPath->Buffer[RegistryPath->Length / sizeof(WCHAR)];
1368
1369 /* Go up to the end of the string */
1370 while (Current <= Last)
1371 {
1372 if (Current != Last && *Current != L'\\')
1373 {
1374 /* Not the end of the string and not a separator */
1375 Current++;
1376 continue;
1377 }
1378
1379 /* Prepare relative key name */
1380 Length = (USHORT)((ULONG_PTR)Current - (ULONG_PTR)KeyName.Buffer);
1381 KeyName.MaximumLength = KeyName.Length = Length;
1382 DPRINT("Create '%wZ'\n", &KeyName);
1383
1384 /* Open key */
1385 InitializeObjectAttributes(&ObjectAttributes,
1386 &KeyName,
1387 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
1388 hParent,
1389 NULL);
1390 Status = ZwCreateKey(&hKey,
1391 Current == Last ? KEY_ALL_ACCESS : KEY_CREATE_SUB_KEY,
1392 &ObjectAttributes,
1393 0,
1394 NULL,
1395 CreateOptions,
1396 NULL);
1397
1398 /* Close parent key handle, we don't need it anymore */
1399 if (hParent)
1400 ZwClose(hParent);
1401
1402 /* Key opening/creating failed? */
1403 if (!NT_SUCCESS(Status))
1404 {
1405 DPRINT1("ZwCreateKey('%wZ') failed with status 0x%08lx\n", &KeyName, Status);
1406 return Status;
1407 }
1408
1409 /* Check if it is the end of the string */
1410 if (Current == Last)
1411 {
1412 /* Yes, return success */
1413 *Handle = hKey;
1414 return STATUS_SUCCESS;
1415 }
1416
1417 /* Start with this new parent key */
1418 hParent = hKey;
1419 Current++;
1420 KeyName.Buffer = (PWSTR)Current;
1421 }
1422
1423 return STATUS_UNSUCCESSFUL;
1424 }
1425
1426 NTSTATUS
1427 IopSetDeviceInstanceData(HANDLE InstanceKey,
1428 PDEVICE_NODE DeviceNode)
1429 {
1430 OBJECT_ATTRIBUTES ObjectAttributes;
1431 UNICODE_STRING KeyName;
1432 HANDLE LogConfKey, ControlKey, DeviceParamsKey;
1433 ULONG ResCount;
1434 ULONG ResultLength;
1435 NTSTATUS Status;
1436
1437 DPRINT("IopSetDeviceInstanceData() called\n");
1438
1439 /* Create the 'LogConf' key */
1440 RtlInitUnicodeString(&KeyName, L"LogConf");
1441 InitializeObjectAttributes(&ObjectAttributes,
1442 &KeyName,
1443 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
1444 InstanceKey,
1445 NULL);
1446 Status = ZwCreateKey(&LogConfKey,
1447 KEY_ALL_ACCESS,
1448 &ObjectAttributes,
1449 0,
1450 NULL,
1451 // FIXME? In r53694 it was silently turned from non-volatile into this,
1452 // without any extra warning. Is this still needed??
1453 REG_OPTION_VOLATILE,
1454 NULL);
1455 if (NT_SUCCESS(Status))
1456 {
1457 /* Set 'BootConfig' value */
1458 if (DeviceNode->BootResources != NULL)
1459 {
1460 ResCount = DeviceNode->BootResources->Count;
1461 if (ResCount != 0)
1462 {
1463 RtlInitUnicodeString(&KeyName, L"BootConfig");
1464 Status = ZwSetValueKey(LogConfKey,
1465 &KeyName,
1466 0,
1467 REG_RESOURCE_LIST,
1468 DeviceNode->BootResources,
1469 PnpDetermineResourceListSize(DeviceNode->BootResources));
1470 }
1471 }
1472
1473 /* Set 'BasicConfigVector' value */
1474 if (DeviceNode->ResourceRequirements != NULL &&
1475 DeviceNode->ResourceRequirements->ListSize != 0)
1476 {
1477 RtlInitUnicodeString(&KeyName, L"BasicConfigVector");
1478 Status = ZwSetValueKey(LogConfKey,
1479 &KeyName,
1480 0,
1481 REG_RESOURCE_REQUIREMENTS_LIST,
1482 DeviceNode->ResourceRequirements,
1483 DeviceNode->ResourceRequirements->ListSize);
1484 }
1485
1486 ZwClose(LogConfKey);
1487 }
1488
1489 /* Set the 'ConfigFlags' value */
1490 RtlInitUnicodeString(&KeyName, L"ConfigFlags");
1491 Status = ZwQueryValueKey(InstanceKey,
1492 &KeyName,
1493 KeyValueBasicInformation,
1494 NULL,
1495 0,
1496 &ResultLength);
1497 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
1498 {
1499 /* Write the default value */
1500 ULONG DefaultConfigFlags = 0;
1501 Status = ZwSetValueKey(InstanceKey,
1502 &KeyName,
1503 0,
1504 REG_DWORD,
1505 &DefaultConfigFlags,
1506 sizeof(DefaultConfigFlags));
1507 }
1508
1509 /* Create the 'Control' key */
1510 RtlInitUnicodeString(&KeyName, L"Control");
1511 InitializeObjectAttributes(&ObjectAttributes,
1512 &KeyName,
1513 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
1514 InstanceKey,
1515 NULL);
1516 Status = ZwCreateKey(&ControlKey,
1517 0,
1518 &ObjectAttributes,
1519 0,
1520 NULL,
1521 REG_OPTION_VOLATILE,
1522 NULL);
1523 if (NT_SUCCESS(Status))
1524 ZwClose(ControlKey);
1525
1526 /* Create the 'Device Parameters' key and set the 'FirmwareIdentified' value for all ACPI-enumerated devices */
1527 if (_wcsnicmp(DeviceNode->InstancePath.Buffer, L"ACPI\\", 5) == 0)
1528 {
1529 RtlInitUnicodeString(&KeyName, L"Device Parameters");
1530 InitializeObjectAttributes(&ObjectAttributes,
1531 &KeyName,
1532 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
1533 InstanceKey,
1534 NULL);
1535 Status = ZwCreateKey(&DeviceParamsKey,
1536 0,
1537 &ObjectAttributes,
1538 0,
1539 NULL,
1540 REG_OPTION_NON_VOLATILE,
1541 NULL);
1542 if (NT_SUCCESS(Status))
1543 {
1544 ULONG FirmwareIdentified = 1;
1545 RtlInitUnicodeString(&KeyName, L"FirmwareIdentified");
1546 Status = ZwSetValueKey(DeviceParamsKey,
1547 &KeyName,
1548 0,
1549 REG_DWORD,
1550 &FirmwareIdentified,
1551 sizeof(FirmwareIdentified));
1552
1553 ZwClose(DeviceParamsKey);
1554 }
1555 }
1556
1557 DPRINT("IopSetDeviceInstanceData() done\n");
1558
1559 return Status;
1560 }
1561
1562 /*
1563 * IopGetParentIdPrefix
1564 *
1565 * Retrieve (or create) a string which identifies a device.
1566 *
1567 * Parameters
1568 * DeviceNode
1569 * Pointer to device node.
1570 * ParentIdPrefix
1571 * Pointer to the string where is returned the parent node identifier
1572 *
1573 * Remarks
1574 * If the return code is STATUS_SUCCESS, the ParentIdPrefix string is
1575 * valid and its Buffer field is NULL-terminated. The caller needs to
1576 * to free the string with RtlFreeUnicodeString when it is no longer
1577 * needed.
1578 */
1579
1580 NTSTATUS
1581 IopGetParentIdPrefix(PDEVICE_NODE DeviceNode,
1582 PUNICODE_STRING ParentIdPrefix)
1583 {
1584 const UNICODE_STRING EnumKeyPath = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
1585 ULONG KeyNameBufferLength;
1586 PKEY_VALUE_PARTIAL_INFORMATION ParentIdPrefixInformation = NULL;
1587 UNICODE_STRING KeyName = {0, 0, NULL};
1588 UNICODE_STRING KeyValue;
1589 UNICODE_STRING ValueName;
1590 HANDLE hKey = NULL;
1591 ULONG crc32;
1592 NTSTATUS Status;
1593
1594 /* HACK: As long as some devices have a NULL device
1595 * instance path, the following test is required :(
1596 */
1597 if (DeviceNode->Parent->InstancePath.Length == 0)
1598 {
1599 DPRINT1("Parent of %wZ has NULL Instance path, please report!\n",
1600 &DeviceNode->InstancePath);
1601 return STATUS_UNSUCCESSFUL;
1602 }
1603
1604 /* 1. Try to retrieve ParentIdPrefix from registry */
1605 KeyNameBufferLength = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data) + sizeof(L"12345678&12345678");
1606 ParentIdPrefixInformation = ExAllocatePoolWithTag(PagedPool,
1607 KeyNameBufferLength + sizeof(UNICODE_NULL),
1608 TAG_IO);
1609 if (!ParentIdPrefixInformation)
1610 {
1611 return STATUS_INSUFFICIENT_RESOURCES;
1612 }
1613
1614 KeyName.Length = 0;
1615 KeyName.MaximumLength = EnumKeyPath.Length +
1616 DeviceNode->Parent->InstancePath.Length +
1617 sizeof(UNICODE_NULL);
1618 KeyName.Buffer = ExAllocatePoolWithTag(PagedPool,
1619 KeyName.MaximumLength,
1620 TAG_IO);
1621 if (!KeyName.Buffer)
1622 {
1623 Status = STATUS_INSUFFICIENT_RESOURCES;
1624 goto cleanup;
1625 }
1626
1627 RtlCopyUnicodeString(&KeyName, &EnumKeyPath);
1628 RtlAppendUnicodeStringToString(&KeyName, &DeviceNode->Parent->InstancePath);
1629
1630 Status = IopOpenRegistryKeyEx(&hKey, NULL, &KeyName, KEY_QUERY_VALUE | KEY_SET_VALUE);
1631 if (!NT_SUCCESS(Status))
1632 {
1633 goto cleanup;
1634 }
1635 RtlInitUnicodeString(&ValueName, L"ParentIdPrefix");
1636 Status = ZwQueryValueKey(hKey,
1637 &ValueName,
1638 KeyValuePartialInformation,
1639 ParentIdPrefixInformation,
1640 KeyNameBufferLength,
1641 &KeyNameBufferLength);
1642 if (NT_SUCCESS(Status))
1643 {
1644 if (ParentIdPrefixInformation->Type != REG_SZ)
1645 {
1646 Status = STATUS_UNSUCCESSFUL;
1647 }
1648 else
1649 {
1650 KeyValue.MaximumLength = (USHORT)ParentIdPrefixInformation->DataLength;
1651 KeyValue.Length = KeyValue.MaximumLength - sizeof(UNICODE_NULL);
1652 KeyValue.Buffer = (PWSTR)ParentIdPrefixInformation->Data;
1653 ASSERT(KeyValue.Buffer[KeyValue.Length / sizeof(WCHAR)] == UNICODE_NULL);
1654 }
1655 goto cleanup;
1656 }
1657 if (Status != STATUS_OBJECT_NAME_NOT_FOUND)
1658 {
1659 /* FIXME how do we get here and why is ParentIdPrefixInformation valid? */
1660 KeyValue.MaximumLength = (USHORT)ParentIdPrefixInformation->DataLength;
1661 KeyValue.Length = KeyValue.MaximumLength - sizeof(UNICODE_NULL);
1662 KeyValue.Buffer = (PWSTR)ParentIdPrefixInformation->Data;
1663 ASSERT(KeyValue.Buffer[KeyValue.Length / sizeof(WCHAR)] == UNICODE_NULL);
1664 goto cleanup;
1665 }
1666
1667 /* 2. Create the ParentIdPrefix value */
1668 crc32 = RtlComputeCrc32(0,
1669 (PUCHAR)DeviceNode->Parent->InstancePath.Buffer,
1670 DeviceNode->Parent->InstancePath.Length);
1671
1672 RtlStringCbPrintfW((PWSTR)ParentIdPrefixInformation,
1673 KeyNameBufferLength,
1674 L"%lx&%lx",
1675 DeviceNode->Parent->Level,
1676 crc32);
1677 RtlInitUnicodeString(&KeyValue, (PWSTR)ParentIdPrefixInformation);
1678
1679 /* 3. Try to write the ParentIdPrefix to registry */
1680 Status = ZwSetValueKey(hKey,
1681 &ValueName,
1682 0,
1683 REG_SZ,
1684 KeyValue.Buffer,
1685 ((ULONG)wcslen(KeyValue.Buffer) + 1) * sizeof(WCHAR));
1686
1687 cleanup:
1688 if (NT_SUCCESS(Status))
1689 {
1690 /* Duplicate the string to return it */
1691 Status = RtlDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
1692 &KeyValue,
1693 ParentIdPrefix);
1694 }
1695 ExFreePoolWithTag(ParentIdPrefixInformation, TAG_IO);
1696 RtlFreeUnicodeString(&KeyName);
1697 if (hKey != NULL)
1698 {
1699 ZwClose(hKey);
1700 }
1701 return Status;
1702 }
1703
1704 static
1705 BOOLEAN
1706 IopValidateID(
1707 _In_ PWCHAR Id,
1708 _In_ BUS_QUERY_ID_TYPE QueryType)
1709 {
1710 PWCHAR PtrChar;
1711 PWCHAR StringEnd;
1712 WCHAR Char;
1713 ULONG SeparatorsCount = 0;
1714 PWCHAR PtrPrevChar = NULL;
1715 ULONG MaxSeparators;
1716 BOOLEAN IsMultiSz;
1717
1718 PAGED_CODE();
1719
1720 switch (QueryType)
1721 {
1722 case BusQueryDeviceID:
1723 MaxSeparators = MAX_SEPARATORS_DEVICEID;
1724 IsMultiSz = FALSE;
1725 break;
1726 case BusQueryInstanceID:
1727 MaxSeparators = MAX_SEPARATORS_INSTANCEID;
1728 IsMultiSz = FALSE;
1729 break;
1730
1731 case BusQueryHardwareIDs:
1732 case BusQueryCompatibleIDs:
1733 MaxSeparators = MAX_SEPARATORS_DEVICEID;
1734 IsMultiSz = TRUE;
1735 break;
1736
1737 default:
1738 DPRINT1("IopValidateID: Not handled QueryType - %x\n", QueryType);
1739 return FALSE;
1740 }
1741
1742 StringEnd = Id + MAX_DEVICE_ID_LEN;
1743
1744 for (PtrChar = Id; PtrChar < StringEnd; PtrChar++)
1745 {
1746 Char = *PtrChar;
1747
1748 if (Char == UNICODE_NULL)
1749 {
1750 if (!IsMultiSz || (PtrPrevChar && PtrChar == PtrPrevChar + 1))
1751 {
1752 if (MaxSeparators == SeparatorsCount || IsMultiSz)
1753 {
1754 return TRUE;
1755 }
1756
1757 DPRINT1("IopValidateID: SeparatorsCount - %lu, MaxSeparators - %lu\n",
1758 SeparatorsCount, MaxSeparators);
1759 goto ErrorExit;
1760 }
1761
1762 StringEnd = PtrChar + MAX_DEVICE_ID_LEN + 1;
1763 PtrPrevChar = PtrChar;
1764 SeparatorsCount = 0;
1765 }
1766 else if (Char < ' ' || Char > 0x7F || Char == ',')
1767 {
1768 DPRINT1("IopValidateID: Invalid character - %04X\n", Char);
1769 goto ErrorExit;
1770 }
1771 else if (Char == ' ')
1772 {
1773 *PtrChar = '_';
1774 }
1775 else if (Char == '\\')
1776 {
1777 SeparatorsCount++;
1778
1779 if (SeparatorsCount > MaxSeparators)
1780 {
1781 DPRINT1("IopValidateID: SeparatorsCount - %lu, MaxSeparators - %lu\n",
1782 SeparatorsCount, MaxSeparators);
1783 goto ErrorExit;
1784 }
1785 }
1786 }
1787
1788 DPRINT1("IopValidateID: Not terminated ID\n");
1789
1790 ErrorExit:
1791 // FIXME logging
1792 return FALSE;
1793 }
1794
1795 NTSTATUS
1796 IopQueryHardwareIds(PDEVICE_NODE DeviceNode,
1797 HANDLE InstanceKey)
1798 {
1799 IO_STACK_LOCATION Stack;
1800 IO_STATUS_BLOCK IoStatusBlock;
1801 PWSTR Ptr;
1802 UNICODE_STRING ValueName;
1803 NTSTATUS Status;
1804 ULONG Length, TotalLength;
1805 BOOLEAN IsValidID;
1806
1807 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryHardwareIDs to device stack\n");
1808
1809 RtlZeroMemory(&Stack, sizeof(Stack));
1810 Stack.Parameters.QueryId.IdType = BusQueryHardwareIDs;
1811 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
1812 &IoStatusBlock,
1813 IRP_MN_QUERY_ID,
1814 &Stack);
1815 if (NT_SUCCESS(Status))
1816 {
1817 IsValidID = IopValidateID((PWCHAR)IoStatusBlock.Information, BusQueryHardwareIDs);
1818
1819 if (!IsValidID)
1820 {
1821 DPRINT1("Invalid HardwareIDs. DeviceNode - %p\n", DeviceNode);
1822 }
1823
1824 TotalLength = 0;
1825
1826 Ptr = (PWSTR)IoStatusBlock.Information;
1827 DPRINT("Hardware IDs:\n");
1828 while (*Ptr)
1829 {
1830 DPRINT(" %S\n", Ptr);
1831 Length = (ULONG)wcslen(Ptr) + 1;
1832
1833 Ptr += Length;
1834 TotalLength += Length;
1835 }
1836 DPRINT("TotalLength: %hu\n", TotalLength);
1837 DPRINT("\n");
1838
1839 RtlInitUnicodeString(&ValueName, L"HardwareID");
1840 Status = ZwSetValueKey(InstanceKey,
1841 &ValueName,
1842 0,
1843 REG_MULTI_SZ,
1844 (PVOID)IoStatusBlock.Information,
1845 (TotalLength + 1) * sizeof(WCHAR));
1846 if (!NT_SUCCESS(Status))
1847 {
1848 DPRINT1("ZwSetValueKey() failed (Status %lx)\n", Status);
1849 }
1850 }
1851 else
1852 {
1853 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
1854 }
1855
1856 return Status;
1857 }
1858
1859 NTSTATUS
1860 IopQueryCompatibleIds(PDEVICE_NODE DeviceNode,
1861 HANDLE InstanceKey)
1862 {
1863 IO_STACK_LOCATION Stack;
1864 IO_STATUS_BLOCK IoStatusBlock;
1865 PWSTR Ptr;
1866 UNICODE_STRING ValueName;
1867 NTSTATUS Status;
1868 ULONG Length, TotalLength;
1869 BOOLEAN IsValidID;
1870
1871 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryCompatibleIDs to device stack\n");
1872
1873 RtlZeroMemory(&Stack, sizeof(Stack));
1874 Stack.Parameters.QueryId.IdType = BusQueryCompatibleIDs;
1875 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
1876 &IoStatusBlock,
1877 IRP_MN_QUERY_ID,
1878 &Stack);
1879 if (NT_SUCCESS(Status) && IoStatusBlock.Information)
1880 {
1881 IsValidID = IopValidateID((PWCHAR)IoStatusBlock.Information, BusQueryCompatibleIDs);
1882
1883 if (!IsValidID)
1884 {
1885 DPRINT1("Invalid CompatibleIDs. DeviceNode - %p\n", DeviceNode);
1886 }
1887
1888 TotalLength = 0;
1889
1890 Ptr = (PWSTR)IoStatusBlock.Information;
1891 DPRINT("Compatible IDs:\n");
1892 while (*Ptr)
1893 {
1894 DPRINT(" %S\n", Ptr);
1895 Length = (ULONG)wcslen(Ptr) + 1;
1896
1897 Ptr += Length;
1898 TotalLength += Length;
1899 }
1900 DPRINT("TotalLength: %hu\n", TotalLength);
1901 DPRINT("\n");
1902
1903 RtlInitUnicodeString(&ValueName, L"CompatibleIDs");
1904 Status = ZwSetValueKey(InstanceKey,
1905 &ValueName,
1906 0,
1907 REG_MULTI_SZ,
1908 (PVOID)IoStatusBlock.Information,
1909 (TotalLength + 1) * sizeof(WCHAR));
1910 if (!NT_SUCCESS(Status))
1911 {
1912 DPRINT1("ZwSetValueKey() failed (Status %lx) or no Compatible ID returned\n", Status);
1913 }
1914 }
1915 else
1916 {
1917 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
1918 }
1919
1920 return Status;
1921 }
1922
1923 NTSTATUS
1924 IopCreateDeviceInstancePath(
1925 _In_ PDEVICE_NODE DeviceNode,
1926 _Out_ PUNICODE_STRING InstancePath)
1927 {
1928 IO_STATUS_BLOCK IoStatusBlock;
1929 UNICODE_STRING DeviceId;
1930 UNICODE_STRING InstanceId;
1931 IO_STACK_LOCATION Stack;
1932 NTSTATUS Status;
1933 UNICODE_STRING ParentIdPrefix = { 0, 0, NULL };
1934 DEVICE_CAPABILITIES DeviceCapabilities;
1935 BOOLEAN IsValidID;
1936
1937 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryDeviceID to device stack\n");
1938
1939 Stack.Parameters.QueryId.IdType = BusQueryDeviceID;
1940 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
1941 &IoStatusBlock,
1942 IRP_MN_QUERY_ID,
1943 &Stack);
1944 if (!NT_SUCCESS(Status))
1945 {
1946 DPRINT1("IopInitiatePnpIrp(BusQueryDeviceID) failed (Status %x)\n", Status);
1947 return Status;
1948 }
1949
1950 IsValidID = IopValidateID((PWCHAR)IoStatusBlock.Information, BusQueryDeviceID);
1951
1952 if (!IsValidID)
1953 {
1954 DPRINT1("Invalid DeviceID. DeviceNode - %p\n", DeviceNode);
1955 }
1956
1957 /* Save the device id string */
1958 RtlInitUnicodeString(&DeviceId, (PWSTR)IoStatusBlock.Information);
1959
1960 DPRINT("Sending IRP_MN_QUERY_CAPABILITIES to device stack (after enumeration)\n");
1961
1962 Status = IopQueryDeviceCapabilities(DeviceNode, &DeviceCapabilities);
1963 if (!NT_SUCCESS(Status))
1964 {
1965 DPRINT1("IopQueryDeviceCapabilities() failed (Status 0x%08lx)\n", Status);
1966 RtlFreeUnicodeString(&DeviceId);
1967 return Status;
1968 }
1969
1970 /* This bit is only check after enumeration */
1971 if (DeviceCapabilities.HardwareDisabled)
1972 {
1973 /* FIXME: Cleanup device */
1974 DeviceNode->Flags |= DNF_DISABLED;
1975 RtlFreeUnicodeString(&DeviceId);
1976 return STATUS_PLUGPLAY_NO_DEVICE;
1977 }
1978 else
1979 {
1980 DeviceNode->Flags &= ~DNF_DISABLED;
1981 }
1982
1983 if (!DeviceCapabilities.UniqueID)
1984 {
1985 /* Device has not a unique ID. We need to prepend parent bus unique identifier */
1986 DPRINT("Instance ID is not unique\n");
1987 Status = IopGetParentIdPrefix(DeviceNode, &ParentIdPrefix);
1988 if (!NT_SUCCESS(Status))
1989 {
1990 DPRINT1("IopGetParentIdPrefix() failed (Status 0x%08lx)\n", Status);
1991 RtlFreeUnicodeString(&DeviceId);
1992 return Status;
1993 }
1994 }
1995
1996 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryInstanceID to device stack\n");
1997
1998 Stack.Parameters.QueryId.IdType = BusQueryInstanceID;
1999 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
2000 &IoStatusBlock,
2001 IRP_MN_QUERY_ID,
2002 &Stack);
2003 if (!NT_SUCCESS(Status))
2004 {
2005 DPRINT("IopInitiatePnpIrp(BusQueryInstanceID) failed (Status %lx)\n", Status);
2006 ASSERT(IoStatusBlock.Information == 0);
2007 }
2008
2009 if (IoStatusBlock.Information)
2010 {
2011 IsValidID = IopValidateID((PWCHAR)IoStatusBlock.Information, BusQueryInstanceID);
2012
2013 if (!IsValidID)
2014 {
2015 DPRINT1("Invalid InstanceID. DeviceNode - %p\n", DeviceNode);
2016 }
2017 }
2018
2019 RtlInitUnicodeString(&InstanceId,
2020 (PWSTR)IoStatusBlock.Information);
2021
2022 InstancePath->Length = 0;
2023 InstancePath->MaximumLength = DeviceId.Length + sizeof(WCHAR) +
2024 ParentIdPrefix.Length +
2025 InstanceId.Length +
2026 sizeof(UNICODE_NULL);
2027 if (ParentIdPrefix.Length && InstanceId.Length)
2028 {
2029 InstancePath->MaximumLength += sizeof(WCHAR);
2030 }
2031
2032 InstancePath->Buffer = ExAllocatePoolWithTag(PagedPool,
2033 InstancePath->MaximumLength,
2034 TAG_IO);
2035 if (!InstancePath->Buffer)
2036 {
2037 RtlFreeUnicodeString(&InstanceId);
2038 RtlFreeUnicodeString(&ParentIdPrefix);
2039 RtlFreeUnicodeString(&DeviceId);
2040 return STATUS_INSUFFICIENT_RESOURCES;
2041 }
2042
2043 /* Start with the device id */
2044 RtlCopyUnicodeString(InstancePath, &DeviceId);
2045 RtlAppendUnicodeToString(InstancePath, L"\\");
2046
2047 /* Add information from parent bus device to InstancePath */
2048 RtlAppendUnicodeStringToString(InstancePath, &ParentIdPrefix);
2049 if (ParentIdPrefix.Length && InstanceId.Length)
2050 {
2051 RtlAppendUnicodeToString(InstancePath, L"&");
2052 }
2053
2054 /* Finally, add the id returned by the driver stack */
2055 RtlAppendUnicodeStringToString(InstancePath, &InstanceId);
2056
2057 /*
2058 * FIXME: Check for valid characters, if there is invalid characters
2059 * then bugcheck
2060 */
2061
2062 RtlFreeUnicodeString(&InstanceId);
2063 RtlFreeUnicodeString(&DeviceId);
2064 RtlFreeUnicodeString(&ParentIdPrefix);
2065
2066 return STATUS_SUCCESS;
2067 }
2068
2069 /*
2070 * IopActionInterrogateDeviceStack
2071 *
2072 * Retrieve information for all (direct) child nodes of a parent node.
2073 *
2074 * Parameters
2075 * DeviceNode
2076 * Pointer to device node.
2077 * Context
2078 * Pointer to parent node to retrieve child node information for.
2079 *
2080 * Remarks
2081 * Any errors that occur are logged instead so that all child services have a chance
2082 * of being interrogated.
2083 */
2084
2085 NTSTATUS
2086 IopActionInterrogateDeviceStack(PDEVICE_NODE DeviceNode,
2087 PVOID Context)
2088 {
2089 IO_STATUS_BLOCK IoStatusBlock;
2090 PWSTR DeviceDescription;
2091 PWSTR LocationInformation;
2092 PDEVICE_NODE ParentDeviceNode;
2093 IO_STACK_LOCATION Stack;
2094 NTSTATUS Status;
2095 ULONG RequiredLength;
2096 LCID LocaleId;
2097 HANDLE InstanceKey = NULL;
2098 UNICODE_STRING ValueName;
2099 UNICODE_STRING InstancePathU;
2100 PDEVICE_OBJECT OldDeviceObject;
2101
2102 DPRINT("IopActionInterrogateDeviceStack(%p, %p)\n", DeviceNode, Context);
2103 DPRINT("PDO 0x%p\n", DeviceNode->PhysicalDeviceObject);
2104
2105 ParentDeviceNode = (PDEVICE_NODE)Context;
2106
2107 /*
2108 * We are called for the parent too, but we don't need to do special
2109 * handling for this node
2110 */
2111 if (DeviceNode == ParentDeviceNode)
2112 {
2113 DPRINT("Success\n");
2114 return STATUS_SUCCESS;
2115 }
2116
2117 /*
2118 * Make sure this device node is a direct child of the parent device node
2119 * that is given as an argument
2120 */
2121 if (DeviceNode->Parent != ParentDeviceNode)
2122 {
2123 DPRINT("Skipping 2+ level child\n");
2124 return STATUS_SUCCESS;
2125 }
2126
2127 /* Skip processing if it was already completed before */
2128 if (DeviceNode->Flags & DNF_PROCESSED)
2129 {
2130 /* Nothing to do */
2131 return STATUS_SUCCESS;
2132 }
2133
2134 /* Get Locale ID */
2135 Status = ZwQueryDefaultLocale(FALSE, &LocaleId);
2136 if (!NT_SUCCESS(Status))
2137 {
2138 DPRINT1("ZwQueryDefaultLocale() failed with status 0x%lx\n", Status);
2139 return Status;
2140 }
2141
2142 /*
2143 * FIXME: For critical errors, cleanup and disable device, but always
2144 * return STATUS_SUCCESS.
2145 */
2146
2147 Status = IopCreateDeviceInstancePath(DeviceNode, &InstancePathU);
2148 if (!NT_SUCCESS(Status))
2149 {
2150 if (Status != STATUS_PLUGPLAY_NO_DEVICE)
2151 {
2152 DPRINT1("IopCreateDeviceInstancePath() failed with status 0x%lx\n", Status);
2153 }
2154
2155 /* We have to return success otherwise we abort the traverse operation */
2156 return STATUS_SUCCESS;
2157 }
2158
2159 /* Verify that this is not a duplicate */
2160 OldDeviceObject = IopGetDeviceObjectFromDeviceInstance(&InstancePathU);
2161 if (OldDeviceObject != NULL)
2162 {
2163 PDEVICE_NODE OldDeviceNode = IopGetDeviceNode(OldDeviceObject);
2164
2165 DPRINT1("Duplicate device instance '%wZ'\n", &InstancePathU);
2166 DPRINT1("Current instance parent: '%wZ'\n", &DeviceNode->Parent->InstancePath);
2167 DPRINT1("Old instance parent: '%wZ'\n", &OldDeviceNode->Parent->InstancePath);
2168
2169 KeBugCheckEx(PNP_DETECTED_FATAL_ERROR,
2170 0x01,
2171 (ULONG_PTR)DeviceNode->PhysicalDeviceObject,
2172 (ULONG_PTR)OldDeviceObject,
2173 0);
2174 }
2175
2176 DeviceNode->InstancePath = InstancePathU;
2177
2178 DPRINT("InstancePath is %S\n", DeviceNode->InstancePath.Buffer);
2179
2180 /*
2181 * Create registry key for the instance id, if it doesn't exist yet
2182 */
2183 Status = IopCreateDeviceKeyPath(&DeviceNode->InstancePath, REG_OPTION_NON_VOLATILE, &InstanceKey);
2184 if (!NT_SUCCESS(Status))
2185 {
2186 DPRINT1("Failed to create the instance key! (Status %lx)\n", Status);
2187
2188 /* We have to return success otherwise we abort the traverse operation */
2189 return STATUS_SUCCESS;
2190 }
2191
2192 IopQueryHardwareIds(DeviceNode, InstanceKey);
2193
2194 IopQueryCompatibleIds(DeviceNode, InstanceKey);
2195
2196 DPRINT("Sending IRP_MN_QUERY_DEVICE_TEXT.DeviceTextDescription to device stack\n");
2197
2198 Stack.Parameters.QueryDeviceText.DeviceTextType = DeviceTextDescription;
2199 Stack.Parameters.QueryDeviceText.LocaleId = LocaleId;
2200 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
2201 &IoStatusBlock,
2202 IRP_MN_QUERY_DEVICE_TEXT,
2203 &Stack);
2204 DeviceDescription = NT_SUCCESS(Status) ? (PWSTR)IoStatusBlock.Information
2205 : NULL;
2206 /* This key is mandatory, so even if the Irp fails, we still write it */
2207 RtlInitUnicodeString(&ValueName, L"DeviceDesc");
2208 if (ZwQueryValueKey(InstanceKey, &ValueName, KeyValueBasicInformation, NULL, 0, &RequiredLength) == STATUS_OBJECT_NAME_NOT_FOUND)
2209 {
2210 if (DeviceDescription &&
2211 *DeviceDescription != UNICODE_NULL)
2212 {
2213 /* This key is overriden when a driver is installed. Don't write the
2214 * new description if another one already exists */
2215 Status = ZwSetValueKey(InstanceKey,
2216 &ValueName,
2217 0,
2218 REG_SZ,
2219 DeviceDescription,
2220 ((ULONG)wcslen(DeviceDescription) + 1) * sizeof(WCHAR));
2221 }
2222 else
2223 {
2224 UNICODE_STRING DeviceDesc = RTL_CONSTANT_STRING(L"Unknown device");
2225 DPRINT("Driver didn't return DeviceDesc (Status 0x%08lx), so place unknown device there\n", Status);
2226
2227 Status = ZwSetValueKey(InstanceKey,
2228 &ValueName,
2229 0,
2230 REG_SZ,
2231 DeviceDesc.Buffer,
2232 DeviceDesc.MaximumLength);
2233 if (!NT_SUCCESS(Status))
2234 {
2235 DPRINT1("ZwSetValueKey() failed (Status 0x%lx)\n", Status);
2236 }
2237
2238 }
2239 }
2240
2241 if (DeviceDescription)
2242 {
2243 ExFreePoolWithTag(DeviceDescription, 0);
2244 }
2245
2246 DPRINT("Sending IRP_MN_QUERY_DEVICE_TEXT.DeviceTextLocation to device stack\n");
2247
2248 Stack.Parameters.QueryDeviceText.DeviceTextType = DeviceTextLocationInformation;
2249 Stack.Parameters.QueryDeviceText.LocaleId = LocaleId;
2250 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
2251 &IoStatusBlock,
2252 IRP_MN_QUERY_DEVICE_TEXT,
2253 &Stack);
2254 if (NT_SUCCESS(Status) && IoStatusBlock.Information)
2255 {
2256 LocationInformation = (PWSTR)IoStatusBlock.Information;
2257 DPRINT("LocationInformation: %S\n", LocationInformation);
2258 RtlInitUnicodeString(&ValueName, L"LocationInformation");
2259 Status = ZwSetValueKey(InstanceKey,
2260 &ValueName,
2261 0,
2262 REG_SZ,
2263 LocationInformation,
2264 ((ULONG)wcslen(LocationInformation) + 1) * sizeof(WCHAR));
2265 if (!NT_SUCCESS(Status))
2266 {
2267 DPRINT1("ZwSetValueKey() failed (Status %lx)\n", Status);
2268 }
2269
2270 ExFreePoolWithTag(LocationInformation, 0);
2271 }
2272 else
2273 {
2274 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status);
2275 }
2276
2277 DPRINT("Sending IRP_MN_QUERY_BUS_INFORMATION to device stack\n");
2278
2279 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
2280 &IoStatusBlock,
2281 IRP_MN_QUERY_BUS_INFORMATION,
2282 NULL);
2283 if (NT_SUCCESS(Status) && IoStatusBlock.Information)
2284 {
2285 PPNP_BUS_INFORMATION BusInformation = (PPNP_BUS_INFORMATION)IoStatusBlock.Information;
2286
2287 DeviceNode->ChildBusNumber = BusInformation->BusNumber;
2288 DeviceNode->ChildInterfaceType = BusInformation->LegacyBusType;
2289 DeviceNode->ChildBusTypeIndex = IopGetBusTypeGuidIndex(&BusInformation->BusTypeGuid);
2290 ExFreePoolWithTag(BusInformation, 0);
2291 }
2292 else
2293 {
2294 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status);
2295
2296 DeviceNode->ChildBusNumber = 0xFFFFFFF0;
2297 DeviceNode->ChildInterfaceType = InterfaceTypeUndefined;
2298 DeviceNode->ChildBusTypeIndex = -1;
2299 }
2300
2301 DPRINT("Sending IRP_MN_QUERY_RESOURCES to device stack\n");
2302
2303 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
2304 &IoStatusBlock,
2305 IRP_MN_QUERY_RESOURCES,
2306 NULL);
2307 if (NT_SUCCESS(Status) && IoStatusBlock.Information)
2308 {
2309 DeviceNode->BootResources = (PCM_RESOURCE_LIST)IoStatusBlock.Information;
2310 IopDeviceNodeSetFlag(DeviceNode, DNF_HAS_BOOT_CONFIG);
2311 }
2312 else
2313 {
2314 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status);
2315 DeviceNode->BootResources = NULL;
2316 }
2317
2318 DPRINT("Sending IRP_MN_QUERY_RESOURCE_REQUIREMENTS to device stack\n");
2319
2320 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
2321 &IoStatusBlock,
2322 IRP_MN_QUERY_RESOURCE_REQUIREMENTS,
2323 NULL);
2324 if (NT_SUCCESS(Status))
2325 {
2326 DeviceNode->ResourceRequirements = (PIO_RESOURCE_REQUIREMENTS_LIST)IoStatusBlock.Information;
2327 }
2328 else
2329 {
2330 DPRINT("IopInitiatePnpIrp() failed (Status %08lx)\n", Status);
2331 DeviceNode->ResourceRequirements = NULL;
2332 }
2333
2334 if (InstanceKey != NULL)
2335 {
2336 IopSetDeviceInstanceData(InstanceKey, DeviceNode);
2337 }
2338
2339 ZwClose(InstanceKey);
2340
2341 IopDeviceNodeSetFlag(DeviceNode, DNF_PROCESSED);
2342
2343 if (!IopDeviceNodeHasFlag(DeviceNode, DNF_LEGACY_DRIVER))
2344 {
2345 /* Report the device to the user-mode pnp manager */
2346 IopQueueTargetDeviceEvent(&GUID_DEVICE_ENUMERATED,
2347 &DeviceNode->InstancePath);
2348 }
2349
2350 return STATUS_SUCCESS;
2351 }
2352
2353 static
2354 VOID
2355 IopHandleDeviceRemoval(
2356 IN PDEVICE_NODE DeviceNode,
2357 IN PDEVICE_RELATIONS DeviceRelations)
2358 {
2359 PDEVICE_NODE Child = DeviceNode->Child, NextChild;
2360 ULONG i;
2361 BOOLEAN Found;
2362
2363 if (DeviceNode == IopRootDeviceNode)
2364 return;
2365
2366 while (Child != NULL)
2367 {
2368 NextChild = Child->Sibling;
2369 Found = FALSE;
2370
2371 for (i = 0; DeviceRelations && i < DeviceRelations->Count; i++)
2372 {
2373 if (IopGetDeviceNode(DeviceRelations->Objects[i]) == Child)
2374 {
2375 Found = TRUE;
2376 break;
2377 }
2378 }
2379
2380 if (!Found && !(Child->Flags & DNF_WILL_BE_REMOVED))
2381 {
2382 /* Send removal IRPs to all of its children */
2383 IopPrepareDeviceForRemoval(Child->PhysicalDeviceObject, TRUE);
2384
2385 /* Send the surprise removal IRP */
2386 IopSendSurpriseRemoval(Child->PhysicalDeviceObject);
2387
2388 /* Tell the user-mode PnP manager that a device was removed */
2389 IopQueueTargetDeviceEvent(&GUID_DEVICE_SURPRISE_REMOVAL,
2390 &Child->InstancePath);
2391
2392 /* Send the remove device IRP */
2393 IopSendRemoveDevice(Child->PhysicalDeviceObject);
2394 }
2395
2396 Child = NextChild;
2397 }
2398 }
2399
2400 NTSTATUS
2401 IopEnumerateDevice(
2402 IN PDEVICE_OBJECT DeviceObject)
2403 {
2404 PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject);
2405 DEVICETREE_TRAVERSE_CONTEXT Context;
2406 PDEVICE_RELATIONS DeviceRelations;
2407 PDEVICE_OBJECT ChildDeviceObject;
2408 IO_STATUS_BLOCK IoStatusBlock;
2409 PDEVICE_NODE ChildDeviceNode;
2410 IO_STACK_LOCATION Stack;
2411 NTSTATUS Status;
2412 ULONG i;
2413
2414 DPRINT("DeviceObject 0x%p\n", DeviceObject);
2415
2416 if (DeviceNode->Flags & DNF_NEED_ENUMERATION_ONLY)
2417 {
2418 DeviceNode->Flags &= ~DNF_NEED_ENUMERATION_ONLY;
2419
2420 DPRINT("Sending GUID_DEVICE_ARRIVAL\n");
2421 IopQueueTargetDeviceEvent(&GUID_DEVICE_ARRIVAL,
2422 &DeviceNode->InstancePath);
2423 }
2424
2425 DPRINT("Sending IRP_MN_QUERY_DEVICE_RELATIONS to device stack\n");
2426
2427 Stack.Parameters.QueryDeviceRelations.Type = BusRelations;
2428
2429 Status = IopInitiatePnpIrp(
2430 DeviceObject,
2431 &IoStatusBlock,
2432 IRP_MN_QUERY_DEVICE_RELATIONS,
2433 &Stack);
2434 if (!NT_SUCCESS(Status) || Status == STATUS_PENDING)
2435 {
2436 DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status);
2437 return Status;
2438 }
2439
2440 DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information;
2441
2442 /*
2443 * Send removal IRPs for devices that have disappeared
2444 * NOTE: This code handles the case where no relations are specified
2445 */
2446 IopHandleDeviceRemoval(DeviceNode, DeviceRelations);
2447
2448 /* Now we bail if nothing was returned */
2449 if (!DeviceRelations)
2450 {
2451 /* We're all done */
2452 DPRINT("No PDOs\n");
2453 return STATUS_SUCCESS;
2454 }
2455
2456 DPRINT("Got %u PDOs\n", DeviceRelations->Count);
2457
2458 /*
2459 * Create device nodes for all discovered devices
2460 */
2461 for (i = 0; i < DeviceRelations->Count; i++)
2462 {
2463 ChildDeviceObject = DeviceRelations->Objects[i];
2464 ASSERT((ChildDeviceObject->Flags & DO_DEVICE_INITIALIZING) == 0);
2465
2466 ChildDeviceNode = IopGetDeviceNode(ChildDeviceObject);
2467 if (!ChildDeviceNode)
2468 {
2469 /* One doesn't exist, create it */
2470 Status = IopCreateDeviceNode(
2471 DeviceNode,
2472 ChildDeviceObject,
2473 NULL,
2474 &ChildDeviceNode);
2475 if (NT_SUCCESS(Status))
2476 {
2477 /* Mark the node as enumerated */
2478 ChildDeviceNode->Flags |= DNF_ENUMERATED;
2479
2480 /* Mark the DO as bus enumerated */
2481 ChildDeviceObject->Flags |= DO_BUS_ENUMERATED_DEVICE;
2482 }
2483 else
2484 {
2485 /* Ignore this DO */
2486 DPRINT1("IopCreateDeviceNode() failed with status 0x%08x. Skipping PDO %u\n", Status, i);
2487 ObDereferenceObject(ChildDeviceObject);
2488 }
2489 }
2490 else
2491 {
2492 /* Mark it as enumerated */
2493 ChildDeviceNode->Flags |= DNF_ENUMERATED;
2494 ObDereferenceObject(ChildDeviceObject);
2495 }
2496 }
2497 ExFreePool(DeviceRelations);
2498
2499 /*
2500 * Retrieve information about all discovered children from the bus driver
2501 */
2502 IopInitDeviceTreeTraverseContext(
2503 &Context,
2504 DeviceNode,
2505 IopActionInterrogateDeviceStack,
2506 DeviceNode);
2507
2508 Status = IopTraverseDeviceTree(&Context);
2509 if (!NT_SUCCESS(Status))
2510 {
2511 DPRINT("IopTraverseDeviceTree() failed with status 0x%08lx\n", Status);
2512 return Status;
2513 }
2514
2515 /*
2516 * Retrieve configuration from the registry for discovered children
2517 */
2518 IopInitDeviceTreeTraverseContext(
2519 &Context,
2520 DeviceNode,
2521 IopActionConfigureChildServices,
2522 DeviceNode);
2523
2524 Status = IopTraverseDeviceTree(&Context);
2525 if (!NT_SUCCESS(Status))
2526 {
2527 DPRINT("IopTraverseDeviceTree() failed with status 0x%08lx\n", Status);
2528 return Status;
2529 }
2530
2531 /*
2532 * Initialize services for discovered children.
2533 */
2534 Status = IopInitializePnpServices(DeviceNode);
2535 if (!NT_SUCCESS(Status))
2536 {
2537 DPRINT("IopInitializePnpServices() failed with status 0x%08lx\n", Status);
2538 return Status;
2539 }
2540
2541 DPRINT("IopEnumerateDevice() finished\n");
2542 return STATUS_SUCCESS;
2543 }
2544
2545
2546 /*
2547 * IopActionConfigureChildServices
2548 *
2549 * Retrieve configuration for all (direct) child nodes of a parent node.
2550 *
2551 * Parameters
2552 * DeviceNode
2553 * Pointer to device node.
2554 * Context
2555 * Pointer to parent node to retrieve child node configuration for.
2556 *
2557 * Remarks
2558 * Any errors that occur are logged instead so that all child services have a chance of beeing
2559 * configured.
2560 */
2561
2562 NTSTATUS
2563 IopActionConfigureChildServices(PDEVICE_NODE DeviceNode,
2564 PVOID Context)
2565 {
2566 RTL_QUERY_REGISTRY_TABLE QueryTable[3];
2567 PDEVICE_NODE ParentDeviceNode;
2568 PUNICODE_STRING Service;
2569 UNICODE_STRING ClassGUID;
2570 NTSTATUS Status;
2571 DEVICE_CAPABILITIES DeviceCaps;
2572
2573 DPRINT("IopActionConfigureChildServices(%p, %p)\n", DeviceNode, Context);
2574
2575 ParentDeviceNode = (PDEVICE_NODE)Context;
2576
2577 /*
2578 * We are called for the parent too, but we don't need to do special
2579 * handling for this node
2580 */
2581 if (DeviceNode == ParentDeviceNode)
2582 {
2583 DPRINT("Success\n");
2584 return STATUS_SUCCESS;
2585 }
2586
2587 /*
2588 * Make sure this device node is a direct child of the parent device node
2589 * that is given as an argument
2590 */
2591
2592 if (DeviceNode->Parent != ParentDeviceNode)
2593 {
2594 DPRINT("Skipping 2+ level child\n");
2595 return STATUS_SUCCESS;
2596 }
2597
2598 if (!(DeviceNode->Flags & DNF_PROCESSED))
2599 {
2600 DPRINT1("Child not ready to be configured\n");
2601 return STATUS_SUCCESS;
2602 }
2603
2604 if (!(DeviceNode->Flags & (DNF_DISABLED | DNF_STARTED | DNF_ADDED)))
2605 {
2606 UNICODE_STRING RegKey;
2607
2608 /* Install the service for this if it's in the CDDB */
2609 IopInstallCriticalDevice(DeviceNode);
2610
2611 /*
2612 * Retrieve configuration from Enum key
2613 */
2614
2615 Service = &DeviceNode->ServiceName;
2616
2617 RtlZeroMemory(QueryTable, sizeof(QueryTable));
2618 RtlInitUnicodeString(Service, NULL);
2619 RtlInitUnicodeString(&ClassGUID, NULL);
2620
2621 QueryTable[0].Name = L"Service";
2622 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
2623 QueryTable[0].EntryContext = Service;
2624
2625 QueryTable[1].Name = L"ClassGUID";
2626 QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
2627 QueryTable[1].EntryContext = &ClassGUID;
2628 QueryTable[1].DefaultType = REG_SZ;
2629 QueryTable[1].DefaultData = L"";
2630 QueryTable[1].DefaultLength = 0;
2631
2632 RegKey.Length = 0;
2633 RegKey.MaximumLength = sizeof(ENUM_ROOT) + sizeof(WCHAR) + DeviceNode->InstancePath.Length;
2634 RegKey.Buffer = ExAllocatePoolWithTag(PagedPool,
2635 RegKey.MaximumLength,
2636 TAG_IO);
2637 if (RegKey.Buffer == NULL)
2638 {
2639 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
2640 return STATUS_INSUFFICIENT_RESOURCES;
2641 }
2642
2643 RtlAppendUnicodeToString(&RegKey, ENUM_ROOT);
2644 RtlAppendUnicodeToString(&RegKey, L"\\");
2645 RtlAppendUnicodeStringToString(&RegKey, &DeviceNode->InstancePath);
2646
2647 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
2648 RegKey.Buffer, QueryTable, NULL, NULL);
2649 ExFreePoolWithTag(RegKey.Buffer, TAG_IO);
2650
2651 if (!NT_SUCCESS(Status))
2652 {
2653 /* FIXME: Log the error */
2654 DPRINT("Could not retrieve configuration for device %wZ (Status 0x%08x)\n",
2655 &DeviceNode->InstancePath, Status);
2656 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
2657 return STATUS_SUCCESS;
2658 }
2659
2660 if (Service->Buffer == NULL)
2661 {
2662 if (NT_SUCCESS(IopQueryDeviceCapabilities(DeviceNode, &DeviceCaps)) &&
2663 DeviceCaps.RawDeviceOK)
2664 {
2665 DPRINT("%wZ is using parent bus driver (%wZ)\n", &DeviceNode->InstancePath, &ParentDeviceNode->ServiceName);
2666 RtlInitEmptyUnicodeString(&DeviceNode->ServiceName, NULL, 0);
2667 }
2668 else if (ClassGUID.Length != 0)
2669 {
2670 /* Device has a ClassGUID value, but no Service value.
2671 * Suppose it is using the NULL driver, so state the
2672 * device is started */
2673 DPRINT("%wZ is using NULL driver\n", &DeviceNode->InstancePath);
2674 IopDeviceNodeSetFlag(DeviceNode, DNF_STARTED);
2675 }
2676 else
2677 {
2678 DeviceNode->Problem = CM_PROB_FAILED_INSTALL;
2679 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
2680 }
2681 return STATUS_SUCCESS;
2682 }
2683
2684 DPRINT("Got Service %S\n", Service->Buffer);
2685 }
2686
2687 return STATUS_SUCCESS;
2688 }
2689
2690 /*
2691 * IopActionInitChildServices
2692 *
2693 * Initialize the service for all (direct) child nodes of a parent node
2694 *
2695 * Parameters
2696 * DeviceNode
2697 * Pointer to device node.
2698 * Context
2699 * Pointer to parent node to initialize child node services for.
2700 *
2701 * Remarks
2702 * If the driver image for a service is not loaded and initialized
2703 * it is done here too. Any errors that occur are logged instead so
2704 * that all child services have a chance of being initialized.
2705 */
2706
2707 NTSTATUS
2708 IopActionInitChildServices(PDEVICE_NODE DeviceNode,
2709 PVOID Context)
2710 {
2711 PDEVICE_NODE ParentDeviceNode;
2712 NTSTATUS Status;
2713 BOOLEAN BootDrivers = !PnpSystemInit;
2714
2715 DPRINT("IopActionInitChildServices(%p, %p)\n", DeviceNode, Context);
2716
2717 ParentDeviceNode = Context;
2718
2719 /*
2720 * We are called for the parent too, but we don't need to do special
2721 * handling for this node
2722 */
2723 if (DeviceNode == ParentDeviceNode)
2724 {
2725 DPRINT("Success\n");
2726 return STATUS_SUCCESS;
2727 }
2728
2729 /*
2730 * We don't want to check for a direct child because
2731 * this function is called during boot to reinitialize
2732 * devices with drivers that couldn't load yet due to
2733 * stage 0 limitations (ie can't load from disk yet).
2734 */
2735
2736 if (!(DeviceNode->Flags & DNF_PROCESSED))
2737 {
2738 DPRINT1("Child not ready to be added\n");
2739 return STATUS_SUCCESS;
2740 }
2741
2742 if (IopDeviceNodeHasFlag(DeviceNode, DNF_STARTED) ||
2743 IopDeviceNodeHasFlag(DeviceNode, DNF_ADDED) ||
2744 IopDeviceNodeHasFlag(DeviceNode, DNF_DISABLED))
2745 return STATUS_SUCCESS;
2746
2747 if (DeviceNode->ServiceName.Buffer == NULL)
2748 {
2749 /* We don't need to worry about loading the driver because we're
2750 * being driven in raw mode so our parent must be loaded to get here */
2751 Status = IopInitializeDevice(DeviceNode, NULL);
2752 if (NT_SUCCESS(Status))
2753 {
2754 Status = IopStartDevice(DeviceNode);
2755 if (!NT_SUCCESS(Status))
2756 {
2757 DPRINT1("IopStartDevice(%wZ) failed with status 0x%08x\n",
2758 &DeviceNode->InstancePath, Status);
2759 }
2760 }
2761 }
2762 else
2763 {
2764 PLDR_DATA_TABLE_ENTRY ModuleObject;
2765 PDRIVER_OBJECT DriverObject;
2766
2767 KeEnterCriticalRegion();
2768 ExAcquireResourceExclusiveLite(&IopDriverLoadResource, TRUE);
2769 /* Get existing DriverObject pointer (in case the driver has
2770 already been loaded and initialized) */
2771 Status = IopGetDriverObject(
2772 &DriverObject,
2773 &DeviceNode->ServiceName,
2774 FALSE);
2775
2776 if (!NT_SUCCESS(Status))
2777 {
2778 /* Driver is not initialized, try to load it */
2779 Status = IopLoadServiceModule(&DeviceNode->ServiceName, &ModuleObject);
2780
2781 if (NT_SUCCESS(Status) || Status == STATUS_IMAGE_ALREADY_LOADED)
2782 {
2783 /* Initialize the driver */
2784 Status = IopInitializeDriverModule(DeviceNode, ModuleObject,
2785 &DeviceNode->ServiceName, FALSE, &DriverObject);
2786 if (!NT_SUCCESS(Status))
2787 DeviceNode->Problem = CM_PROB_FAILED_DRIVER_ENTRY;
2788 }
2789 else if (Status == STATUS_DRIVER_UNABLE_TO_LOAD)
2790 {
2791 DPRINT1("Service '%wZ' is disabled\n", &DeviceNode->ServiceName);
2792 DeviceNode->Problem = CM_PROB_DISABLED_SERVICE;
2793 }
2794 else
2795 {
2796 DPRINT("IopLoadServiceModule(%wZ) failed with status 0x%08x\n",
2797 &DeviceNode->ServiceName, Status);
2798 if (!BootDrivers)
2799 DeviceNode->Problem = CM_PROB_DRIVER_FAILED_LOAD;
2800 }
2801 }
2802 ExReleaseResourceLite(&IopDriverLoadResource);
2803 KeLeaveCriticalRegion();
2804
2805 /* Driver is loaded and initialized at this point */
2806 if (NT_SUCCESS(Status))
2807 {
2808 /* Initialize the device, including all filters */
2809 Status = PipCallDriverAddDevice(DeviceNode, FALSE, DriverObject);
2810
2811 /* Remove the extra reference */
2812 ObDereferenceObject(DriverObject);
2813 }
2814 else
2815 {
2816 /*
2817 * Don't disable when trying to load only boot drivers
2818 */
2819 if (!BootDrivers)
2820 {
2821 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
2822 }
2823 }
2824 }
2825
2826 return STATUS_SUCCESS;
2827 }
2828
2829 /*
2830 * IopInitializePnpServices
2831 *
2832 * Initialize services for discovered children
2833 *
2834 * Parameters
2835 * DeviceNode
2836 * Top device node to start initializing services.
2837 *
2838 * Return Value
2839 * Status
2840 */
2841 NTSTATUS
2842 IopInitializePnpServices(IN PDEVICE_NODE DeviceNode)
2843 {
2844 DEVICETREE_TRAVERSE_CONTEXT Context;
2845
2846 DPRINT("IopInitializePnpServices(%p)\n", DeviceNode);
2847
2848 IopInitDeviceTreeTraverseContext(
2849 &Context,
2850 DeviceNode,
2851 IopActionInitChildServices,
2852 DeviceNode);
2853
2854 return IopTraverseDeviceTree(&Context);
2855 }
2856
2857 static
2858 INIT_FUNCTION
2859 NTSTATUS
2860 IopEnumerateDetectedDevices(
2861 IN HANDLE hBaseKey,
2862 IN PUNICODE_STRING RelativePath OPTIONAL,
2863 IN HANDLE hRootKey,
2864 IN BOOLEAN EnumerateSubKeys,
2865 IN PCM_FULL_RESOURCE_DESCRIPTOR ParentBootResources,
2866 IN ULONG ParentBootResourcesLength)
2867 {
2868 UNICODE_STRING IdentifierU = RTL_CONSTANT_STRING(L"Identifier");
2869 UNICODE_STRING HardwareIDU = RTL_CONSTANT_STRING(L"HardwareID");
2870 UNICODE_STRING ConfigurationDataU = RTL_CONSTANT_STRING(L"Configuration Data");
2871 UNICODE_STRING BootConfigU = RTL_CONSTANT_STRING(L"BootConfig");
2872 UNICODE_STRING LogConfU = RTL_CONSTANT_STRING(L"LogConf");
2873 OBJECT_ATTRIBUTES ObjectAttributes;
2874 HANDLE hDevicesKey = NULL;
2875 HANDLE hDeviceKey = NULL;
2876 HANDLE hLevel1Key, hLevel2Key = NULL, hLogConf;
2877 UNICODE_STRING Level2NameU;
2878 WCHAR Level2Name[5];
2879 ULONG IndexDevice = 0;
2880 ULONG IndexSubKey;
2881 PKEY_BASIC_INFORMATION pDeviceInformation = NULL;
2882 ULONG DeviceInfoLength = sizeof(KEY_BASIC_INFORMATION) + 50 * sizeof(WCHAR);
2883 PKEY_VALUE_PARTIAL_INFORMATION pValueInformation = NULL;
2884 ULONG ValueInfoLength = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 50 * sizeof(WCHAR);
2885 UNICODE_STRING DeviceName, ValueName;
2886 ULONG RequiredSize;
2887 PCM_FULL_RESOURCE_DESCRIPTOR BootResources = NULL;
2888 ULONG BootResourcesLength;
2889 NTSTATUS Status;
2890
2891 const UNICODE_STRING IdentifierSerial = RTL_CONSTANT_STRING(L"SerialController");
2892 UNICODE_STRING HardwareIdSerial = RTL_CONSTANT_STRING(L"*PNP0501\0");
2893 static ULONG DeviceIndexSerial = 0;
2894 const UNICODE_STRING IdentifierKeyboard = RTL_CONSTANT_STRING(L"KeyboardController");
2895 UNICODE_STRING HardwareIdKeyboard = RTL_CONSTANT_STRING(L"*PNP0303\0");
2896 static ULONG DeviceIndexKeyboard = 0;
2897 const UNICODE_STRING IdentifierMouse = RTL_CONSTANT_STRING(L"PointerController");
2898 UNICODE_STRING HardwareIdMouse = RTL_CONSTANT_STRING(L"*PNP0F13\0");
2899 static ULONG DeviceIndexMouse = 0;
2900 const UNICODE_STRING IdentifierParallel = RTL_CONSTANT_STRING(L"ParallelController");
2901 UNICODE_STRING HardwareIdParallel = RTL_CONSTANT_STRING(L"*PNP0400\0");
2902 static ULONG DeviceIndexParallel = 0;
2903 const UNICODE_STRING IdentifierFloppy = RTL_CONSTANT_STRING(L"FloppyDiskPeripheral");
2904 UNICODE_STRING HardwareIdFloppy = RTL_CONSTANT_STRING(L"*PNP0700\0");
2905 static ULONG DeviceIndexFloppy = 0;
2906 UNICODE_STRING HardwareIdKey;
2907 PUNICODE_STRING pHardwareId;
2908 ULONG DeviceIndex = 0;
2909 PUCHAR CmResourceList;
2910 ULONG ListCount;
2911
2912 if (RelativePath)
2913 {
2914 Status = IopOpenRegistryKeyEx(&hDevicesKey, hBaseKey, RelativePath, KEY_ENUMERATE_SUB_KEYS);
2915 if (!NT_SUCCESS(Status))
2916 {
2917 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
2918 goto cleanup;
2919 }
2920 }
2921 else
2922 hDevicesKey = hBaseKey;
2923
2924 pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength);
2925 if (!pDeviceInformation)
2926 {
2927 DPRINT("ExAllocatePool() failed\n");
2928 Status = STATUS_NO_MEMORY;
2929 goto cleanup;
2930 }
2931
2932 pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength);
2933 if (!pValueInformation)
2934 {
2935 DPRINT("ExAllocatePool() failed\n");
2936 Status = STATUS_NO_MEMORY;
2937 goto cleanup;
2938 }
2939
2940 while (TRUE)
2941 {
2942 Status = ZwEnumerateKey(hDevicesKey, IndexDevice, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
2943 if (Status == STATUS_NO_MORE_ENTRIES)
2944 break;
2945 else if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
2946 {
2947 ExFreePool(pDeviceInformation);
2948 DeviceInfoLength = RequiredSize;
2949 pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength);
2950 if (!pDeviceInformation)
2951 {
2952 DPRINT("ExAllocatePool() failed\n");
2953 Status = STATUS_NO_MEMORY;
2954 goto cleanup;
2955 }
2956 Status = ZwEnumerateKey(hDevicesKey, IndexDevice, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
2957 }
2958 if (!NT_SUCCESS(Status))
2959 {
2960 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status);
2961 goto cleanup;
2962 }
2963 IndexDevice++;
2964
2965 /* Open device key */
2966 DeviceName.Length = DeviceName.MaximumLength = (USHORT)pDeviceInformation->NameLength;
2967 DeviceName.Buffer = pDeviceInformation->Name;
2968
2969 Status = IopOpenRegistryKeyEx(&hDeviceKey, hDevicesKey, &DeviceName,
2970 KEY_QUERY_VALUE + (EnumerateSubKeys ? KEY_ENUMERATE_SUB_KEYS : 0));
2971 if (!NT_SUCCESS(Status))
2972 {
2973 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
2974 goto cleanup;
2975 }
2976
2977 /* Read boot resources, and add then to parent ones */
2978 Status = ZwQueryValueKey(hDeviceKey, &ConfigurationDataU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
2979 if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
2980 {
2981 ExFreePool(pValueInformation);
2982 ValueInfoLength = RequiredSize;
2983 pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength);
2984 if (!pValueInformation)
2985 {
2986 DPRINT("ExAllocatePool() failed\n");
2987 ZwDeleteKey(hLevel2Key);
2988 Status = STATUS_NO_MEMORY;
2989 goto cleanup;
2990 }
2991 Status = ZwQueryValueKey(hDeviceKey, &ConfigurationDataU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
2992 }
2993 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
2994 {
2995 BootResources = ParentBootResources;
2996 BootResourcesLength = ParentBootResourcesLength;
2997 }
2998 else if (!NT_SUCCESS(Status))
2999 {
3000 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status);
3001 goto nextdevice;
3002 }
3003 else if (pValueInformation->Type != REG_FULL_RESOURCE_DESCRIPTOR)
3004 {
3005 DPRINT("Wrong registry type: got 0x%lx, expected 0x%lx\n", pValueInformation->Type, REG_FULL_RESOURCE_DESCRIPTOR);
3006 goto nextdevice;
3007 }
3008 else
3009 {
3010 static const ULONG Header = FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList.PartialDescriptors);
3011
3012 /* Concatenate current resources and parent ones */
3013 if (ParentBootResourcesLength == 0)
3014 BootResourcesLength = pValueInformation->DataLength;
3015 else
3016 BootResourcesLength = ParentBootResourcesLength
3017 + pValueInformation->DataLength
3018 - Header;
3019 BootResources = ExAllocatePool(PagedPool, BootResourcesLength);
3020 if (!BootResources)
3021 {
3022 DPRINT("ExAllocatePool() failed\n");
3023 goto nextdevice;
3024 }
3025 if (ParentBootResourcesLength < sizeof(CM_FULL_RESOURCE_DESCRIPTOR))
3026 {
3027 RtlCopyMemory(BootResources, pValueInformation->Data, pValueInformation->DataLength);
3028 }
3029 else if (ParentBootResources->PartialResourceList.PartialDescriptors[ParentBootResources->PartialResourceList.Count - 1].Type == CmResourceTypeDeviceSpecific)
3030 {
3031 RtlCopyMemory(BootResources, pValueInformation->Data, pValueInformation->DataLength);
3032 RtlCopyMemory(
3033 (PVOID)((ULONG_PTR)BootResources + pValueInformation->DataLength),
3034 (PVOID)((ULONG_PTR)ParentBootResources + Header),
3035 ParentBootResourcesLength - Header);
3036 BootResources->PartialResourceList.Count += ParentBootResources->PartialResourceList.Count;
3037 }
3038 else
3039 {
3040 RtlCopyMemory(BootResources, pValueInformation->Data, Header);
3041 RtlCopyMemory(
3042 (PVOID)((ULONG_PTR)BootResources + Header),
3043 (PVOID)((ULONG_PTR)ParentBootResources + Header),
3044 ParentBootResourcesLength - Header);
3045 RtlCopyMemory(
3046 (PVOID)((ULONG_PTR)BootResources + ParentBootResourcesLength),
3047 pValueInformation->Data + Header,
3048 pValueInformation->DataLength - Header);
3049 BootResources->PartialResourceList.Count += ParentBootResources->PartialResourceList.Count;
3050 }
3051 }
3052
3053 if (EnumerateSubKeys)
3054 {
3055 IndexSubKey = 0;
3056 while (TRUE)
3057 {
3058 Status = ZwEnumerateKey(hDeviceKey, IndexSubKey, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
3059 if (Status == STATUS_NO_MORE_ENTRIES)
3060 break;
3061 else if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
3062 {
3063 ExFreePool(pDeviceInformation);
3064 DeviceInfoLength = RequiredSize;
3065 pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength);
3066 if (!pDeviceInformation)
3067 {
3068 DPRINT("ExAllocatePool() failed\n");
3069 Status = STATUS_NO_MEMORY;
3070 goto cleanup;
3071 }
3072 Status = ZwEnumerateKey(hDeviceKey, IndexSubKey, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
3073 }
3074 if (!NT_SUCCESS(Status))
3075 {
3076 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status);
3077 goto cleanup;
3078 }
3079 IndexSubKey++;
3080 DeviceName.Length = DeviceName.MaximumLength = (USHORT)pDeviceInformation->NameLength;
3081 DeviceName.Buffer = pDeviceInformation->Name;
3082
3083 Status = IopEnumerateDetectedDevices(
3084 hDeviceKey,
3085 &DeviceName,
3086 hRootKey,
3087 TRUE,
3088 BootResources,
3089 BootResourcesLength);
3090 if (!NT_SUCCESS(Status))
3091 goto cleanup;
3092 }
3093 }
3094
3095 /* Read identifier */
3096 Status = ZwQueryValueKey(hDeviceKey, &IdentifierU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
3097 if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
3098 {
3099 ExFreePool(pValueInformation);
3100 ValueInfoLength = RequiredSize;
3101 pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength);
3102 if (!pValueInformation)
3103 {
3104 DPRINT("ExAllocatePool() failed\n");
3105 Status = STATUS_NO_MEMORY;
3106 goto cleanup;
3107 }
3108 Status = ZwQueryValueKey(hDeviceKey, &IdentifierU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
3109 }
3110 if (!NT_SUCCESS(Status))
3111 {
3112 if (Status != STATUS_OBJECT_NAME_NOT_FOUND)
3113 {
3114 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status);
3115 goto nextdevice;
3116 }
3117 ValueName.Length = ValueName.MaximumLength = 0;
3118 }
3119 else if (pValueInformation->Type != REG_SZ)
3120 {
3121 DPRINT("Wrong registry type: got 0x%lx, expected 0x%lx\n", pValueInformation->Type, REG_SZ);
3122 goto nextdevice;
3123 }
3124 else
3125 {
3126 /* Assign hardware id to this device */
3127 ValueName.Length = ValueName.MaximumLength = (USHORT)pValueInformation->DataLength;
3128 ValueName.Buffer = (PWCHAR)pValueInformation->Data;
3129 if (ValueName.Length >= sizeof(WCHAR) && ValueName.Buffer[ValueName.Length / sizeof(WCHAR) - 1] == UNICODE_NULL)
3130 ValueName.Length -= sizeof(WCHAR);
3131 }
3132
3133 if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierSerial, FALSE) == 0)
3134 {
3135 pHardwareId = &HardwareIdSerial;
3136 DeviceIndex = DeviceIndexSerial++;
3137 }
3138 else if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierKeyboard, FALSE) == 0)
3139 {
3140 pHardwareId = &HardwareIdKeyboard;
3141 DeviceIndex = DeviceIndexKeyboard++;
3142 }
3143 else if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierMouse, FALSE) == 0)
3144 {
3145 pHardwareId = &HardwareIdMouse;
3146 DeviceIndex = DeviceIndexMouse++;
3147 }
3148 else if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierParallel, FALSE) == 0)
3149 {
3150 pHardwareId = &HardwareIdParallel;
3151 DeviceIndex = DeviceIndexParallel++;
3152 }
3153 else if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierFloppy, FALSE) == 0)
3154 {
3155 pHardwareId = &HardwareIdFloppy;
3156 DeviceIndex = DeviceIndexFloppy++;
3157 }
3158 else
3159 {
3160 /* Unknown key path */
3161 DPRINT("Unknown key path '%wZ'\n", RelativePath);
3162 goto nextdevice;
3163 }
3164
3165 /* Prepare hardware id key (hardware id value without final \0) */
3166 HardwareIdKey = *pHardwareId;
3167 HardwareIdKey.Length -= sizeof(UNICODE_NULL);
3168
3169 /* Add the detected device to Root key */
3170 InitializeObjectAttributes(&ObjectAttributes, &HardwareIdKey, OBJ_KERNEL_HANDLE, hRootKey, NULL);
3171 Status = ZwCreateKey(
3172 &hLevel1Key,
3173 KEY_CREATE_SUB_KEY,
3174 &ObjectAttributes,
3175 0,
3176 NULL,
3177 REG_OPTION_NON_VOLATILE,
3178 NULL);
3179 if (!NT_SUCCESS(Status))
3180 {
3181 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status);
3182 goto nextdevice;
3183 }
3184 swprintf(Level2Name, L"%04lu", DeviceIndex);
3185 RtlInitUnicodeString(&Level2NameU, Level2Name);
3186 InitializeObjectAttributes(&ObjectAttributes, &Level2NameU, OBJ_KERNEL_HANDLE, hLevel1Key, NULL);
3187 Status = ZwCreateKey(
3188 &hLevel2Key,
3189 KEY_SET_VALUE | KEY_CREATE_SUB_KEY,
3190 &ObjectAttributes,
3191 0,
3192 NULL,
3193 REG_OPTION_NON_VOLATILE,
3194 NULL);
3195 ZwClose(hLevel1Key);
3196 if (!NT_SUCCESS(Status))
3197 {
3198 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status);
3199 goto nextdevice;
3200 }
3201 DPRINT("Found %wZ #%lu (%wZ)\n", &ValueName, DeviceIndex, &HardwareIdKey);
3202 Status = ZwSetValueKey(hLevel2Key, &HardwareIDU, 0, REG_MULTI_SZ, pHardwareId->Buffer, pHardwareId->MaximumLength);
3203 if (!NT_SUCCESS(Status))
3204 {
3205 DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status);
3206 ZwDeleteKey(hLevel2Key);
3207 goto nextdevice;
3208 }
3209 /* Create 'LogConf' subkey */
3210 InitializeObjectAttributes(&ObjectAttributes, &LogConfU, OBJ_KERNEL_HANDLE, hLevel2Key, NULL);
3211 Status = ZwCreateKey(
3212 &hLogConf,
3213 KEY_SET_VALUE,
3214 &ObjectAttributes,
3215 0,
3216 NULL,
3217 REG_OPTION_VOLATILE,
3218 NULL);
3219 if (!NT_SUCCESS(Status))
3220 {
3221 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status);
3222 ZwDeleteKey(hLevel2Key);
3223 goto nextdevice;
3224 }
3225 if (BootResourcesLength >= sizeof(CM_FULL_RESOURCE_DESCRIPTOR))
3226 {
3227 CmResourceList = ExAllocatePool(PagedPool, BootResourcesLength + sizeof(ULONG));
3228 if (!CmResourceList)
3229 {
3230 ZwClose(hLogConf);
3231 ZwDeleteKey(hLevel2Key);
3232 goto nextdevice;
3233 }
3234
3235 /* Add the list count (1st member of CM_RESOURCE_LIST) */
3236 ListCount = 1;
3237 RtlCopyMemory(CmResourceList,
3238 &ListCount,
3239 sizeof(ULONG));
3240
3241 /* Now add the actual list (2nd member of CM_RESOURCE_LIST) */
3242 RtlCopyMemory(CmResourceList + sizeof(ULONG),
3243 BootResources,
3244 BootResourcesLength);
3245
3246 /* Save boot resources to 'LogConf\BootConfig' */
3247 Status = ZwSetValueKey(hLogConf, &BootConfigU, 0, REG_RESOURCE_LIST, CmResourceList, BootResourcesLength + sizeof(ULONG));
3248 if (!NT_SUCCESS(Status))
3249 {
3250 DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status);
3251 ZwClose(hLogConf);
3252 ZwDeleteKey(hLevel2Key);
3253 goto nextdevice;
3254 }
3255 }
3256 ZwClose(hLogConf);
3257
3258 nextdevice:
3259 if (BootResources && BootResources != ParentBootResources)
3260 {
3261 ExFreePool(BootResources);
3262 BootResources = NULL;
3263 }
3264 if (hLevel2Key)
3265 {
3266 ZwClose(hLevel2Key);
3267 hLevel2Key = NULL;
3268 }
3269 if (hDeviceKey)
3270 {
3271 ZwClose(hDeviceKey);
3272 hDeviceKey = NULL;
3273 }
3274 }
3275
3276 Status = STATUS_SUCCESS;
3277
3278 cleanup:
3279 if (hDevicesKey && hDevicesKey != hBaseKey)
3280 ZwClose(hDevicesKey);
3281 if (hDeviceKey)
3282 ZwClose(hDeviceKey);
3283 if (pDeviceInformation)
3284 ExFreePool(pDeviceInformation);
3285 if (pValueInformation)
3286 ExFreePool(pValueInformation);
3287 return Status;
3288 }
3289
3290 static
3291 INIT_FUNCTION
3292 BOOLEAN
3293 IopIsFirmwareMapperDisabled(VOID)
3294 {
3295 UNICODE_STRING KeyPathU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\CURRENTCONTROLSET\\Control\\Pnp");
3296 UNICODE_STRING KeyNameU = RTL_CONSTANT_STRING(L"DisableFirmwareMapper");
3297 OBJECT_ATTRIBUTES ObjectAttributes;
3298 HANDLE hPnpKey;
3299 PKEY_VALUE_PARTIAL_INFORMATION KeyInformation;
3300 ULONG DesiredLength, Length;
3301 ULONG KeyValue = 0;
3302 NTSTATUS Status;
3303
3304 InitializeObjectAttributes(&ObjectAttributes, &KeyPathU, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
3305 Status = ZwOpenKey(&hPnpKey, KEY_QUERY_VALUE, &ObjectAttributes);
3306 if (NT_SUCCESS(Status))
3307 {
3308 Status = ZwQueryValueKey(hPnpKey,
3309 &KeyNameU,
3310 KeyValuePartialInformation,
3311 NULL,
3312 0,
3313 &DesiredLength);
3314 if ((Status == STATUS_BUFFER_TOO_SMALL) ||
3315 (Status == STATUS_BUFFER_OVERFLOW))
3316 {
3317 Length = DesiredLength;
3318 KeyInformation = ExAllocatePool(PagedPool, Length);
3319 if (KeyInformation)
3320 {
3321 Status = ZwQueryValueKey(hPnpKey,
3322 &KeyNameU,
3323 KeyValuePartialInformation,
3324 KeyInformation,
3325 Length,
3326 &DesiredLength);
3327 if (NT_SUCCESS(Status) && KeyInformation->DataLength == sizeof(ULONG))
3328 {
3329 KeyValue = (ULONG)(*KeyInformation->Data);
3330 }
3331 else
3332 {
3333 DPRINT1("ZwQueryValueKey(%wZ%wZ) failed\n", &KeyPathU, &KeyNameU);
3334 }
3335
3336 ExFreePool(KeyInformation);
3337 }
3338 else
3339 {
3340 DPRINT1("Failed to allocate memory for registry query\n");
3341 }
3342 }
3343 else
3344 {
3345 DPRINT1("ZwQueryValueKey(%wZ%wZ) failed with status 0x%08lx\n", &KeyPathU, &KeyNameU, Status);
3346 }
3347
3348 ZwClose(hPnpKey);
3349 }
3350 else
3351 {
3352 DPRINT1("ZwOpenKey(%wZ) failed with status 0x%08lx\n", &KeyPathU, Status);
3353 }
3354
3355 DPRINT("Firmware mapper is %s\n", KeyValue != 0 ? "disabled" : "enabled");
3356
3357 return (KeyValue != 0) ? TRUE : FALSE;
3358 }
3359
3360 INIT_FUNCTION
3361 NTSTATUS
3362 NTAPI
3363 IopUpdateRootKey(VOID)
3364 {
3365 UNICODE_STRING EnumU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Enum");
3366 UNICODE_STRING RootPathU = RTL_CONSTANT_STRING(L"Root");
3367 UNICODE_STRING MultiKeyPathU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\MultifunctionAdapter");
3368 OBJECT_ATTRIBUTES ObjectAttributes;
3369 HANDLE hEnum, hRoot;
3370 NTSTATUS Status;
3371
3372 InitializeObjectAttributes(&ObjectAttributes, &EnumU, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
3373 Status = ZwCreateKey(&hEnum, KEY_CREATE_SUB_KEY, &ObjectAttributes, 0, NULL, REG_OPTION_NON_VOLATILE, NULL);
3374 if (!NT_SUCCESS(Status))
3375 {
3376 DPRINT1("ZwCreateKey() failed with status 0x%08lx\n", Status);
3377 return Status;
3378 }
3379
3380 InitializeObjectAttributes(&ObjectAttributes, &RootPathU, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, hEnum, NULL);
3381 Status = ZwCreateKey(&hRoot, KEY_CREATE_SUB_KEY, &ObjectAttributes, 0, NULL, REG_OPTION_NON_VOLATILE, NULL);
3382 ZwClose(hEnum);
3383 if (!NT_SUCCESS(Status))
3384 {
3385 DPRINT1("ZwOpenKey() failed with status 0x%08lx\n", Status);
3386 return Status;
3387 }
3388
3389 if (!IopIsFirmwareMapperDisabled())
3390 {
3391 Status = IopOpenRegistryKeyEx(&hEnum, NULL, &MultiKeyPathU, KEY_ENUMERATE_SUB_KEYS);
3392 if (!NT_SUCCESS(Status))
3393 {
3394 /* Nothing to do, don't return with an error status */
3395 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
3396 ZwClose(hRoot);
3397 return STATUS_SUCCESS;
3398 }
3399 Status = IopEnumerateDetectedDevices(
3400 hEnum,
3401 NULL,
3402 hRoot,
3403 TRUE,
3404 NULL,
3405 0);
3406 ZwClose(hEnum);
3407 }
3408 else
3409 {
3410 /* Enumeration is disabled */
3411 Status = STATUS_SUCCESS;
3412 }
3413
3414 ZwClose(hRoot);
3415
3416 return Status;
3417 }
3418
3419 NTSTATUS
3420 NTAPI
3421 IopOpenRegistryKeyEx(PHANDLE KeyHandle,
3422 HANDLE ParentKey,
3423 PUNICODE_STRING Name,
3424 ACCESS_MASK DesiredAccess)
3425 {
3426 OBJECT_ATTRIBUTES ObjectAttributes;
3427 NTSTATUS Status;
3428
3429 PAGED_CODE();
3430
3431 *KeyHandle = NULL;
3432
3433 InitializeObjectAttributes(&ObjectAttributes,
3434 Name,
3435 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
3436 ParentKey,
3437 NULL);
3438
3439 Status = ZwOpenKey(KeyHandle, DesiredAccess, &ObjectAttributes);
3440
3441 return Status;
3442 }
3443
3444 NTSTATUS
3445 NTAPI
3446 IopCreateRegistryKeyEx(OUT PHANDLE Handle,
3447 IN HANDLE RootHandle OPTIONAL,
3448 IN PUNICODE_STRING KeyName,
3449 IN ACCESS_MASK DesiredAccess,
3450 IN ULONG CreateOptions,
3451 OUT PULONG Disposition OPTIONAL)
3452 {
3453 OBJECT_ATTRIBUTES ObjectAttributes;
3454 ULONG KeyDisposition, RootHandleIndex = 0, i = 1, NestedCloseLevel = 0;
3455 USHORT Length;
3456 HANDLE HandleArray[2];
3457 BOOLEAN Recursing = TRUE;
3458 PWCHAR pp, p, p1;
3459 UNICODE_STRING KeyString;
3460 NTSTATUS Status = STATUS_SUCCESS;
3461 PAGED_CODE();
3462
3463 /* P1 is start, pp is end */
3464 p1 = KeyName->Buffer;
3465 pp = (PVOID)((ULONG_PTR)p1 + KeyName->Length);
3466
3467 /* Create the target key */
3468 InitializeObjectAttributes(&ObjectAttributes,
3469 KeyName,
3470 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
3471 RootHandle,
3472 NULL);
3473 Status = ZwCreateKey(&HandleArray[i],
3474 DesiredAccess,
3475 &ObjectAttributes,
3476 0,
3477 NULL,
3478 CreateOptions,
3479 &KeyDisposition);
3480
3481 /* Now we check if this failed */
3482 if ((Status == STATUS_OBJECT_NAME_NOT_FOUND) && (RootHandle))
3483 {
3484 /* Target key failed, so we'll need to create its parent. Setup array */
3485 HandleArray[0] = NULL;
3486 HandleArray[1] = RootHandle;
3487
3488 /* Keep recursing for each missing parent */
3489 while (Recursing)
3490 {
3491 /* And if we're deep enough, close the last handle */
3492 if (NestedCloseLevel > 1) ZwClose(HandleArray[RootHandleIndex]);
3493
3494 /* We're setup to ping-pong between the two handle array entries */
3495 RootHandleIndex = i;
3496 i = (i + 1) & 1;
3497
3498 /* Clear the one we're attempting to open now */
3499 HandleArray[i] = NULL;
3500
3501 /* Process the parent key name */
3502 for (p = p1; ((p < pp) && (*p != OBJ_NAME_PATH_SEPARATOR)); p++);
3503 Length = (USHORT)(p - p1) * sizeof(WCHAR);
3504
3505 /* Is there a parent name? */
3506 if (Length)
3507 {
3508 /* Build the unicode string for it */
3509 KeyString.Buffer = p1;
3510 KeyString.Length = KeyString.MaximumLength = Length;
3511
3512 /* Now try opening the parent */
3513 InitializeObjectAttributes(&ObjectAttributes,
3514 &KeyString,
3515 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
3516 HandleArray[RootHandleIndex],
3517 NULL);
3518 Status = ZwCreateKey(&HandleArray[i],
3519 DesiredAccess,
3520 &ObjectAttributes,
3521 0,
3522 NULL,
3523 CreateOptions,
3524 &KeyDisposition);
3525 if (NT_SUCCESS(Status))
3526 {
3527 /* It worked, we have one more handle */
3528 NestedCloseLevel++;
3529 }
3530 else
3531 {
3532 /* Parent key creation failed, abandon loop */
3533 Recursing = FALSE;
3534 continue;
3535 }
3536 }
3537 else
3538 {
3539 /* We don't have a parent name, probably corrupted key name */
3540 Status = STATUS_INVALID_PARAMETER;
3541 Recursing = FALSE;
3542 continue;
3543 }
3544
3545 /* Now see if there's more parents to create */
3546 p1 = p + 1;
3547 if ((p == pp) || (p1 == pp))
3548 {
3549 /* We're done, hopefully successfully, so stop */
3550 Recursing = FALSE;
3551 }
3552 }
3553
3554 /* Outer loop check for handle nesting that requires closing the top handle */
3555 if (NestedCloseLevel > 1) ZwClose(HandleArray[RootHandleIndex]);
3556 }
3557
3558 /* Check if we broke out of the loop due to success */
3559 if (NT_SUCCESS(Status))
3560 {
3561 /* Return the target handle (we closed all the parent ones) and disposition */
3562 *Handle = HandleArray[i];
3563 if (Disposition) *Disposition = KeyDisposition;
3564 }
3565
3566 /* Return the success state */
3567 return Status;
3568 }
3569
3570 NTSTATUS
3571 NTAPI
3572 IopGetRegistryValue(IN HANDLE Handle,
3573 IN PWSTR ValueName,
3574 OUT PKEY_VALUE_FULL_INFORMATION *Information)
3575 {
3576 UNICODE_STRING ValueString;
3577 NTSTATUS Status;
3578 PKEY_VALUE_FULL_INFORMATION FullInformation;
3579 ULONG Size;
3580 PAGED_CODE();
3581
3582 RtlInitUnicodeString(&ValueString, ValueName);
3583
3584 Status = ZwQueryValueKey(Handle,
3585 &ValueString,
3586 KeyValueFullInformation,
3587 NULL,
3588 0,
3589 &Size);
3590 if ((Status != STATUS_BUFFER_OVERFLOW) &&
3591 (Status != STATUS_BUFFER_TOO_SMALL))
3592 {
3593 return Status;
3594 }
3595
3596 FullInformation = ExAllocatePool(NonPagedPool, Size);
3597 if (!FullInformation) return STATUS_INSUFFICIENT_RESOURCES;
3598
3599 Status = ZwQueryValueKey(Handle,
3600 &ValueString,
3601 KeyValueFullInformation,
3602 FullInformation,
3603 Size,
3604 &Size);
3605 if (!NT_SUCCESS(Status))
3606 {
3607 ExFreePool(FullInformation);
3608 return Status;
3609 }
3610
3611 *Information = FullInformation;
3612 return STATUS_SUCCESS;
3613 }
3614
3615 RTL_GENERIC_COMPARE_RESULTS
3616 NTAPI
3617 PiCompareInstancePath(IN PRTL_AVL_TABLE Table,
3618 IN PVOID FirstStruct,
3619 IN PVOID SecondStruct)
3620 {
3621 /* FIXME: TODO */
3622 ASSERT(FALSE);
3623 return 0;
3624 }
3625
3626 //
3627 // The allocation function is called by the generic table package whenever
3628 // it needs to allocate memory for the table.
3629 //
3630
3631 PVOID
3632 NTAPI
3633 PiAllocateGenericTableEntry(IN PRTL_AVL_TABLE Table,
3634 IN CLONG ByteSize)
3635 {
3636 /* FIXME: TODO */
3637 ASSERT(FALSE);
3638 return NULL;
3639 }
3640
3641 VOID
3642 NTAPI
3643 PiFreeGenericTableEntry(IN PRTL_AVL_TABLE Table,
3644 IN PVOID Buffer)
3645 {
3646 /* FIXME: TODO */
3647 ASSERT(FALSE);
3648 }
3649
3650 VOID
3651 NTAPI
3652 PpInitializeDeviceReferenceTable(VOID)
3653 {
3654 /* Setup the guarded mutex and AVL table */
3655 KeInitializeGuardedMutex(&PpDeviceReferenceTableLock);
3656 RtlInitializeGenericTableAvl(
3657 &PpDeviceReferenceTable,
3658 (PRTL_AVL_COMPARE_ROUTINE)PiCompareInstancePath,
3659 (PRTL_AVL_ALLOCATE_ROUTINE)PiAllocateGenericTableEntry,
3660 (PRTL_AVL_FREE_ROUTINE)PiFreeGenericTableEntry,
3661 NULL);
3662 }
3663
3664 BOOLEAN
3665 NTAPI
3666 PiInitPhase0(VOID)
3667 {
3668 /* Initialize the resource when accessing device registry data */
3669 ExInitializeResourceLite(&PpRegistryDeviceResource);
3670
3671 /* Setup the device reference AVL table */
3672 PpInitializeDeviceReferenceTable();
3673 return TRUE;
3674 }
3675
3676 BOOLEAN
3677 NTAPI
3678 PpInitSystem(VOID)
3679 {
3680 /* Check the initialization phase */
3681 switch (ExpInitializationPhase)
3682 {
3683 case 0:
3684
3685 /* Do Phase 0 */
3686 return PiInitPhase0();
3687
3688 case 1:
3689
3690 /* Do Phase 1 */
3691 return TRUE;
3692 //return PiInitPhase1();
3693
3694 default:
3695
3696 /* Don't know any other phase! Bugcheck! */
3697 KeBugCheck(UNEXPECTED_INITIALIZATION_CALL);
3698 return FALSE;
3699 }
3700 }
3701
3702 /* PUBLIC FUNCTIONS **********************************************************/
3703
3704 NTSTATUS
3705 NTAPI
3706 PnpBusTypeGuidGet(IN USHORT Index,
3707 IN LPGUID BusTypeGuid)
3708 {
3709 NTSTATUS Status = STATUS_SUCCESS;
3710
3711 /* Acquire the lock */
3712 ExAcquireFastMutex(&PnpBusTypeGuidList->Lock);
3713
3714 /* Validate size */
3715 if (Index < PnpBusTypeGuidList->GuidCount)
3716 {
3717 /* Copy the data */
3718 RtlCopyMemory(BusTypeGuid, &PnpBusTypeGuidList->Guids[Index], sizeof(GUID));
3719 }
3720 else
3721 {
3722 /* Failure path */
3723 Status = STATUS_OBJECT_NAME_NOT_FOUND;
3724 }
3725
3726 /* Release lock and return status */
3727 ExReleaseFastMutex(&PnpBusTypeGuidList->Lock);
3728 return Status;
3729 }
3730
3731 NTSTATUS
3732 NTAPI
3733 PnpDeviceObjectToDeviceInstance(IN PDEVICE_OBJECT DeviceObject,
3734 IN PHANDLE DeviceInstanceHandle,
3735 IN ACCESS_MASK DesiredAccess)
3736 {
3737 NTSTATUS Status;
3738 HANDLE KeyHandle;
3739 PDEVICE_NODE DeviceNode;
3740 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET\\ENUM");
3741 PAGED_CODE();
3742
3743 /* Open the enum key */
3744 Status = IopOpenRegistryKeyEx(&KeyHandle,
3745 NULL,
3746 &KeyName,
3747 KEY_READ);
3748 if (!NT_SUCCESS(Status)) return Status;
3749
3750 /* Make sure we have an instance path */
3751 DeviceNode = IopGetDeviceNode(DeviceObject);
3752 if ((DeviceNode) && (DeviceNode->InstancePath.Length))
3753 {
3754 /* Get the instance key */
3755 Status = IopOpenRegistryKeyEx(DeviceInstanceHandle,
3756 KeyHandle,
3757 &DeviceNode->InstancePath,
3758 DesiredAccess);
3759 }
3760 else
3761 {
3762 /* Fail */
3763 Status = STATUS_INVALID_DEVICE_REQUEST;
3764 }
3765
3766 /* Close the handle and return status */
3767 ZwClose(KeyHandle);
3768 return Status;
3769 }
3770
3771 ULONG
3772 NTAPI
3773 PnpDetermineResourceListSize(IN PCM_RESOURCE_LIST ResourceList)
3774 {
3775 ULONG FinalSize, PartialSize, EntrySize, i, j;
3776 PCM_FULL_RESOURCE_DESCRIPTOR FullDescriptor;
3777 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor;
3778
3779 /* If we don't have one, that's easy */
3780 if (!ResourceList) return 0;
3781
3782 /* Start with the minimum size possible */
3783 FinalSize = FIELD_OFFSET(CM_RESOURCE_LIST, List);
3784
3785 /* Loop each full descriptor */
3786 FullDescriptor = ResourceList->List;
3787 for (i = 0; i < ResourceList->Count; i++)
3788 {
3789 /* Start with the minimum size possible */
3790 PartialSize = FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList) +
3791 FIELD_OFFSET(CM_PARTIAL_RESOURCE_LIST, PartialDescriptors);
3792
3793 /* Loop each partial descriptor */
3794 PartialDescriptor = FullDescriptor->PartialResourceList.PartialDescriptors;
3795 for (j = 0; j < FullDescriptor->PartialResourceList.Count; j++)
3796 {
3797 /* Start with the minimum size possible */
3798 EntrySize = sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
3799
3800 /* Check if there is extra data */
3801 if (PartialDescriptor->Type == CmResourceTypeDeviceSpecific)
3802 {
3803 /* Add that data */
3804 EntrySize += PartialDescriptor->u.DeviceSpecificData.DataSize;
3805 }
3806
3807 /* The size of partial descriptors is bigger */
3808 PartialSize += EntrySize;
3809
3810 /* Go to the next partial descriptor */
3811 PartialDescriptor = (PVOID)((ULONG_PTR)PartialDescriptor + EntrySize);
3812 }
3813
3814 /* The size of full descriptors is bigger */
3815 FinalSize += PartialSize;
3816
3817 /* Go to the next full descriptor */
3818 FullDescriptor = (PVOID)((ULONG_PTR)FullDescriptor + PartialSize);
3819 }
3820
3821 /* Return the final size */
3822 return FinalSize;
3823 }
3824
3825 NTSTATUS
3826 NTAPI
3827 PiGetDeviceRegistryProperty(IN PDEVICE_OBJECT DeviceObject,
3828 IN ULONG ValueType,
3829 IN PWSTR ValueName,
3830 IN PWSTR KeyName,
3831 OUT PVOID Buffer,
3832 IN PULONG BufferLength)
3833 {
3834 NTSTATUS Status;
3835 HANDLE KeyHandle, SubHandle;
3836 UNICODE_STRING KeyString;
3837 PKEY_VALUE_FULL_INFORMATION KeyValueInfo = NULL;
3838 ULONG Length;
3839 PAGED_CODE();
3840
3841 /* Find the instance key */
3842 Status = PnpDeviceObjectToDeviceInstance(DeviceObject, &KeyHandle, KEY_READ);
3843 if (NT_SUCCESS(Status))
3844 {
3845 /* Check for name given by caller */
3846 if (KeyName)
3847 {
3848 /* Open this key */
3849 RtlInitUnicodeString(&KeyString, KeyName);
3850 Status = IopOpenRegistryKeyEx(&SubHandle,
3851 KeyHandle,
3852 &KeyString,
3853 KEY_READ);
3854 if (NT_SUCCESS(Status))
3855 {
3856 /* And use this handle instead */
3857 ZwClose(KeyHandle);
3858 KeyHandle = SubHandle;
3859 }
3860 }
3861
3862 /* Check if sub-key handle succeeded (or no-op if no key name given) */
3863 if (NT_SUCCESS(Status))
3864 {
3865 /* Now get the size of the property */
3866 Status = IopGetRegistryValue(KeyHandle,
3867 ValueName,
3868 &KeyValueInfo);
3869 }
3870
3871 /* Close the key */
3872 ZwClose(KeyHandle);
3873 }
3874
3875 /* Fail if any of the registry operations failed */
3876 if (!NT_SUCCESS(Status)) return Status;
3877
3878 /* Check how much data we have to copy */
3879 Length = KeyValueInfo->DataLength;
3880 if (*BufferLength >= Length)
3881 {
3882 /* Check for a match in the value type */
3883 if (KeyValueInfo->Type == ValueType)
3884 {
3885 /* Copy the data */
3886 RtlCopyMemory(Buffer,
3887 (PVOID)((ULONG_PTR)KeyValueInfo +
3888 KeyValueInfo->DataOffset),
3889 Length);
3890 }
3891 else
3892 {
3893 /* Invalid registry property type, fail */
3894 Status = STATUS_INVALID_PARAMETER_2;
3895 }
3896 }
3897 else
3898 {
3899 /* Buffer is too small to hold data */
3900 Status = STATUS_BUFFER_TOO_SMALL;
3901 }
3902
3903 /* Return the required buffer length, free the buffer, and return status */
3904 *BufferLength = Length;
3905 ExFreePool(KeyValueInfo);
3906 return Status;
3907 }
3908
3909 #define PIP_RETURN_DATA(x, y) {ReturnLength = x; Data = y; Status = STATUS_SUCCESS; break;}
3910 #define PIP_REGISTRY_DATA(x, y) {ValueName = x; ValueType = y; break;}
3911 #define PIP_UNIMPLEMENTED() {UNIMPLEMENTED_DBGBREAK(); break;}
3912
3913 /*
3914 * @implemented
3915 */
3916 NTSTATUS
3917 NTAPI
3918 IoGetDeviceProperty(IN PDEVICE_OBJECT DeviceObject,
3919 IN DEVICE_REGISTRY_PROPERTY DeviceProperty,
3920 IN ULONG BufferLength,
3921 OUT PVOID PropertyBuffer,
3922 OUT PULONG ResultLength)
3923 {
3924 PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject);
3925 DEVICE_CAPABILITIES DeviceCaps;
3926 ULONG ReturnLength = 0, Length = 0, ValueType;
3927 PWCHAR ValueName = NULL, EnumeratorNameEnd, DeviceInstanceName;
3928 PVOID Data = NULL;
3929 NTSTATUS Status = STATUS_BUFFER_TOO_SMALL;
3930 GUID BusTypeGuid;
3931 POBJECT_NAME_INFORMATION ObjectNameInfo = NULL;
3932 BOOLEAN NullTerminate = FALSE;
3933 DEVICE_REMOVAL_POLICY Policy;
3934
3935 DPRINT("IoGetDeviceProperty(0x%p %d)\n", DeviceObject, DeviceProperty);
3936
3937 /* Assume failure */
3938 *ResultLength = 0;
3939