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