[NTOS:IO] Fix result length for DevicePropertyRemovalPolicy request
[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 PDEVICE_NODE NextDeviceNode;
1522 NTSTATUS Status;
1523
1524 /* Copy context data so we don't overwrite it in subsequent calls to this function */
1525 ParentDeviceNode = Context->DeviceNode;
1526
1527 /* HACK: Keep a reference to the PDO so we can keep traversing the tree
1528 * if the device is deleted. In a perfect world, children would have to be
1529 * deleted before their parents, and we'd restart the traversal after
1530 * deleting a device node. */
1531 ObReferenceObject(ParentDeviceNode->PhysicalDeviceObject);
1532
1533 /* Call the action routine */
1534 Status = (Context->Action)(ParentDeviceNode, Context->Context);
1535 if (!NT_SUCCESS(Status))
1536 {
1537 ObDereferenceObject(ParentDeviceNode->PhysicalDeviceObject);
1538 return Status;
1539 }
1540
1541 /* Traversal of all children nodes */
1542 for (ChildDeviceNode = ParentDeviceNode->Child;
1543 ChildDeviceNode != NULL;
1544 ChildDeviceNode = NextDeviceNode)
1545 {
1546 /* HACK: We need this reference to ensure we can get Sibling below. */
1547 ObReferenceObject(ChildDeviceNode->PhysicalDeviceObject);
1548
1549 /* Pass the current device node to the action routine */
1550 Context->DeviceNode = ChildDeviceNode;
1551
1552 Status = IopTraverseDeviceTreeNode(Context);
1553 if (!NT_SUCCESS(Status))
1554 {
1555 ObDereferenceObject(ChildDeviceNode->PhysicalDeviceObject);
1556 ObDereferenceObject(ParentDeviceNode->PhysicalDeviceObject);
1557 return Status;
1558 }
1559
1560 NextDeviceNode = ChildDeviceNode->Sibling;
1561 ObDereferenceObject(ChildDeviceNode->PhysicalDeviceObject);
1562 }
1563
1564 ObDereferenceObject(ParentDeviceNode->PhysicalDeviceObject);
1565 return Status;
1566 }
1567
1568
1569 NTSTATUS
1570 IopTraverseDeviceTree(PDEVICETREE_TRAVERSE_CONTEXT Context)
1571 {
1572 NTSTATUS Status;
1573
1574 DPRINT("Context 0x%p\n", Context);
1575
1576 DPRINT("IopTraverseDeviceTree(DeviceNode 0x%p FirstDeviceNode 0x%p Action %p Context 0x%p)\n",
1577 Context->DeviceNode, Context->FirstDeviceNode, Context->Action, Context->Context);
1578
1579 /* Start from the specified device node */
1580 Context->DeviceNode = Context->FirstDeviceNode;
1581
1582 /* Recursively traverse the device tree */
1583 Status = IopTraverseDeviceTreeNode(Context);
1584 if (Status == STATUS_UNSUCCESSFUL)
1585 {
1586 /* The action routine just wanted to terminate the traversal with status
1587 code STATUS_SUCCESS */
1588 Status = STATUS_SUCCESS;
1589 }
1590
1591 return Status;
1592 }
1593
1594
1595 /*
1596 * IopCreateDeviceKeyPath
1597 *
1598 * Creates a registry key
1599 *
1600 * Parameters
1601 * RegistryPath
1602 * Name of the key to be created.
1603 * Handle
1604 * Handle to the newly created key
1605 *
1606 * Remarks
1607 * This method can create nested trees, so parent of RegistryPath can
1608 * be not existant, and will be created if needed.
1609 */
1610 NTSTATUS
1611 NTAPI
1612 IopCreateDeviceKeyPath(IN PCUNICODE_STRING RegistryPath,
1613 IN ULONG CreateOptions,
1614 OUT PHANDLE Handle)
1615 {
1616 UNICODE_STRING EnumU = RTL_CONSTANT_STRING(ENUM_ROOT);
1617 HANDLE hParent = NULL, hKey;
1618 OBJECT_ATTRIBUTES ObjectAttributes;
1619 UNICODE_STRING KeyName;
1620 PCWSTR Current, Last;
1621 USHORT Length;
1622 NTSTATUS Status;
1623
1624 /* Assume failure */
1625 *Handle = NULL;
1626
1627 /* Open root key for device instances */
1628 Status = IopOpenRegistryKeyEx(&hParent, NULL, &EnumU, KEY_CREATE_SUB_KEY);
1629 if (!NT_SUCCESS(Status))
1630 {
1631 DPRINT1("ZwOpenKey('%wZ') failed with status 0x%08lx\n", &EnumU, Status);
1632 return Status;
1633 }
1634
1635 Current = KeyName.Buffer = RegistryPath->Buffer;
1636 Last = &RegistryPath->Buffer[RegistryPath->Length / sizeof(WCHAR)];
1637
1638 /* Go up to the end of the string */
1639 while (Current <= Last)
1640 {
1641 if (Current != Last && *Current != L'\\')
1642 {
1643 /* Not the end of the string and not a separator */
1644 Current++;
1645 continue;
1646 }
1647
1648 /* Prepare relative key name */
1649 Length = (USHORT)((ULONG_PTR)Current - (ULONG_PTR)KeyName.Buffer);
1650 KeyName.MaximumLength = KeyName.Length = Length;
1651 DPRINT("Create '%wZ'\n", &KeyName);
1652
1653 /* Open key */
1654 InitializeObjectAttributes(&ObjectAttributes,
1655 &KeyName,
1656 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
1657 hParent,
1658 NULL);
1659 Status = ZwCreateKey(&hKey,
1660 Current == Last ? KEY_ALL_ACCESS : KEY_CREATE_SUB_KEY,
1661 &ObjectAttributes,
1662 0,
1663 NULL,
1664 CreateOptions,
1665 NULL);
1666
1667 /* Close parent key handle, we don't need it anymore */
1668 if (hParent)
1669 ZwClose(hParent);
1670
1671 /* Key opening/creating failed? */
1672 if (!NT_SUCCESS(Status))
1673 {
1674 DPRINT1("ZwCreateKey('%wZ') failed with status 0x%08lx\n", &KeyName, Status);
1675 return Status;
1676 }
1677
1678 /* Check if it is the end of the string */
1679 if (Current == Last)
1680 {
1681 /* Yes, return success */
1682 *Handle = hKey;
1683 return STATUS_SUCCESS;
1684 }
1685
1686 /* Start with this new parent key */
1687 hParent = hKey;
1688 Current++;
1689 KeyName.Buffer = (PWSTR)Current;
1690 }
1691
1692 return STATUS_UNSUCCESSFUL;
1693 }
1694
1695 NTSTATUS
1696 IopSetDeviceInstanceData(HANDLE InstanceKey,
1697 PDEVICE_NODE DeviceNode)
1698 {
1699 OBJECT_ATTRIBUTES ObjectAttributes;
1700 UNICODE_STRING KeyName;
1701 HANDLE LogConfKey, ControlKey, DeviceParamsKey;
1702 ULONG ResCount;
1703 ULONG ResultLength;
1704 NTSTATUS Status;
1705
1706 DPRINT("IopSetDeviceInstanceData() called\n");
1707
1708 /* Create the 'LogConf' key */
1709 RtlInitUnicodeString(&KeyName, L"LogConf");
1710 InitializeObjectAttributes(&ObjectAttributes,
1711 &KeyName,
1712 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
1713 InstanceKey,
1714 NULL);
1715 Status = ZwCreateKey(&LogConfKey,
1716 KEY_ALL_ACCESS,
1717 &ObjectAttributes,
1718 0,
1719 NULL,
1720 // FIXME? In r53694 it was silently turned from non-volatile into this,
1721 // without any extra warning. Is this still needed??
1722 REG_OPTION_VOLATILE,
1723 NULL);
1724 if (NT_SUCCESS(Status))
1725 {
1726 /* Set 'BootConfig' value */
1727 if (DeviceNode->BootResources != NULL)
1728 {
1729 ResCount = DeviceNode->BootResources->Count;
1730 if (ResCount != 0)
1731 {
1732 RtlInitUnicodeString(&KeyName, L"BootConfig");
1733 Status = ZwSetValueKey(LogConfKey,
1734 &KeyName,
1735 0,
1736 REG_RESOURCE_LIST,
1737 DeviceNode->BootResources,
1738 PnpDetermineResourceListSize(DeviceNode->BootResources));
1739 }
1740 }
1741
1742 /* Set 'BasicConfigVector' value */
1743 if (DeviceNode->ResourceRequirements != NULL &&
1744 DeviceNode->ResourceRequirements->ListSize != 0)
1745 {
1746 RtlInitUnicodeString(&KeyName, L"BasicConfigVector");
1747 Status = ZwSetValueKey(LogConfKey,
1748 &KeyName,
1749 0,
1750 REG_RESOURCE_REQUIREMENTS_LIST,
1751 DeviceNode->ResourceRequirements,
1752 DeviceNode->ResourceRequirements->ListSize);
1753 }
1754
1755 ZwClose(LogConfKey);
1756 }
1757
1758 /* Set the 'ConfigFlags' value */
1759 RtlInitUnicodeString(&KeyName, L"ConfigFlags");
1760 Status = ZwQueryValueKey(InstanceKey,
1761 &KeyName,
1762 KeyValueBasicInformation,
1763 NULL,
1764 0,
1765 &ResultLength);
1766 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
1767 {
1768 /* Write the default value */
1769 ULONG DefaultConfigFlags = 0;
1770 Status = ZwSetValueKey(InstanceKey,
1771 &KeyName,
1772 0,
1773 REG_DWORD,
1774 &DefaultConfigFlags,
1775 sizeof(DefaultConfigFlags));
1776 }
1777
1778 /* Create the 'Control' key */
1779 RtlInitUnicodeString(&KeyName, L"Control");
1780 InitializeObjectAttributes(&ObjectAttributes,
1781 &KeyName,
1782 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
1783 InstanceKey,
1784 NULL);
1785 Status = ZwCreateKey(&ControlKey,
1786 0,
1787 &ObjectAttributes,
1788 0,
1789 NULL,
1790 REG_OPTION_VOLATILE,
1791 NULL);
1792 if (NT_SUCCESS(Status))
1793 ZwClose(ControlKey);
1794
1795 /* Create the 'Device Parameters' key and set the 'FirmwareIdentified' value for all ACPI-enumerated devices */
1796 if (_wcsnicmp(DeviceNode->InstancePath.Buffer, L"ACPI\\", 5) == 0)
1797 {
1798 RtlInitUnicodeString(&KeyName, L"Device Parameters");
1799 InitializeObjectAttributes(&ObjectAttributes,
1800 &KeyName,
1801 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
1802 InstanceKey,
1803 NULL);
1804 Status = ZwCreateKey(&DeviceParamsKey,
1805 0,
1806 &ObjectAttributes,
1807 0,
1808 NULL,
1809 REG_OPTION_NON_VOLATILE,
1810 NULL);
1811 if (NT_SUCCESS(Status))
1812 {
1813 ULONG FirmwareIdentified = 1;
1814 RtlInitUnicodeString(&KeyName, L"FirmwareIdentified");
1815 Status = ZwSetValueKey(DeviceParamsKey,
1816 &KeyName,
1817 0,
1818 REG_DWORD,
1819 &FirmwareIdentified,
1820 sizeof(FirmwareIdentified));
1821
1822 ZwClose(DeviceParamsKey);
1823 }
1824 }
1825
1826 DPRINT("IopSetDeviceInstanceData() done\n");
1827
1828 return Status;
1829 }
1830
1831 /*
1832 * IopGetParentIdPrefix
1833 *
1834 * Retrieve (or create) a string which identifies a device.
1835 *
1836 * Parameters
1837 * DeviceNode
1838 * Pointer to device node.
1839 * ParentIdPrefix
1840 * Pointer to the string where is returned the parent node identifier
1841 *
1842 * Remarks
1843 * If the return code is STATUS_SUCCESS, the ParentIdPrefix string is
1844 * valid and its Buffer field is NULL-terminated. The caller needs to
1845 * to free the string with RtlFreeUnicodeString when it is no longer
1846 * needed.
1847 */
1848
1849 NTSTATUS
1850 IopGetParentIdPrefix(PDEVICE_NODE DeviceNode,
1851 PUNICODE_STRING ParentIdPrefix)
1852 {
1853 const UNICODE_STRING EnumKeyPath = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
1854 ULONG KeyNameBufferLength;
1855 PKEY_VALUE_PARTIAL_INFORMATION ParentIdPrefixInformation = NULL;
1856 UNICODE_STRING KeyName = {0, 0, NULL};
1857 UNICODE_STRING KeyValue;
1858 UNICODE_STRING ValueName;
1859 HANDLE hKey = NULL;
1860 ULONG crc32;
1861 NTSTATUS Status;
1862
1863 /* HACK: As long as some devices have a NULL device
1864 * instance path, the following test is required :(
1865 */
1866 if (DeviceNode->Parent->InstancePath.Length == 0)
1867 {
1868 DPRINT1("Parent of %wZ has NULL Instance path, please report!\n",
1869 &DeviceNode->InstancePath);
1870 return STATUS_UNSUCCESSFUL;
1871 }
1872
1873 /* 1. Try to retrieve ParentIdPrefix from registry */
1874 KeyNameBufferLength = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data) + sizeof(L"12345678&12345678");
1875 ParentIdPrefixInformation = ExAllocatePoolWithTag(PagedPool,
1876 KeyNameBufferLength + sizeof(UNICODE_NULL),
1877 TAG_IO);
1878 if (!ParentIdPrefixInformation)
1879 {
1880 return STATUS_INSUFFICIENT_RESOURCES;
1881 }
1882
1883 KeyName.Length = 0;
1884 KeyName.MaximumLength = EnumKeyPath.Length +
1885 DeviceNode->Parent->InstancePath.Length +
1886 sizeof(UNICODE_NULL);
1887 KeyName.Buffer = ExAllocatePoolWithTag(PagedPool,
1888 KeyName.MaximumLength,
1889 TAG_IO);
1890 if (!KeyName.Buffer)
1891 {
1892 Status = STATUS_INSUFFICIENT_RESOURCES;
1893 goto cleanup;
1894 }
1895
1896 RtlCopyUnicodeString(&KeyName, &EnumKeyPath);
1897 RtlAppendUnicodeStringToString(&KeyName, &DeviceNode->Parent->InstancePath);
1898
1899 Status = IopOpenRegistryKeyEx(&hKey, NULL, &KeyName, KEY_QUERY_VALUE | KEY_SET_VALUE);
1900 if (!NT_SUCCESS(Status))
1901 {
1902 goto cleanup;
1903 }
1904 RtlInitUnicodeString(&ValueName, L"ParentIdPrefix");
1905 Status = ZwQueryValueKey(hKey,
1906 &ValueName,
1907 KeyValuePartialInformation,
1908 ParentIdPrefixInformation,
1909 KeyNameBufferLength,
1910 &KeyNameBufferLength);
1911 if (NT_SUCCESS(Status))
1912 {
1913 if (ParentIdPrefixInformation->Type != REG_SZ)
1914 {
1915 Status = STATUS_UNSUCCESSFUL;
1916 }
1917 else
1918 {
1919 KeyValue.MaximumLength = (USHORT)ParentIdPrefixInformation->DataLength;
1920 KeyValue.Length = KeyValue.MaximumLength - sizeof(UNICODE_NULL);
1921 KeyValue.Buffer = (PWSTR)ParentIdPrefixInformation->Data;
1922 ASSERT(KeyValue.Buffer[KeyValue.Length / sizeof(WCHAR)] == UNICODE_NULL);
1923 }
1924 goto cleanup;
1925 }
1926 if (Status != STATUS_OBJECT_NAME_NOT_FOUND)
1927 {
1928 /* FIXME how do we get here and why is ParentIdPrefixInformation valid? */
1929 KeyValue.MaximumLength = (USHORT)ParentIdPrefixInformation->DataLength;
1930 KeyValue.Length = KeyValue.MaximumLength - sizeof(UNICODE_NULL);
1931 KeyValue.Buffer = (PWSTR)ParentIdPrefixInformation->Data;
1932 ASSERT(KeyValue.Buffer[KeyValue.Length / sizeof(WCHAR)] == UNICODE_NULL);
1933 goto cleanup;
1934 }
1935
1936 /* 2. Create the ParentIdPrefix value */
1937 crc32 = RtlComputeCrc32(0,
1938 (PUCHAR)DeviceNode->Parent->InstancePath.Buffer,
1939 DeviceNode->Parent->InstancePath.Length);
1940
1941 RtlStringCbPrintfW((PWSTR)ParentIdPrefixInformation,
1942 KeyNameBufferLength,
1943 L"%lx&%lx",
1944 DeviceNode->Parent->Level,
1945 crc32);
1946 RtlInitUnicodeString(&KeyValue, (PWSTR)ParentIdPrefixInformation);
1947
1948 /* 3. Try to write the ParentIdPrefix to registry */
1949 Status = ZwSetValueKey(hKey,
1950 &ValueName,
1951 0,
1952 REG_SZ,
1953 KeyValue.Buffer,
1954 ((ULONG)wcslen(KeyValue.Buffer) + 1) * sizeof(WCHAR));
1955
1956 cleanup:
1957 if (NT_SUCCESS(Status))
1958 {
1959 /* Duplicate the string to return it */
1960 Status = RtlDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
1961 &KeyValue,
1962 ParentIdPrefix);
1963 }
1964 ExFreePoolWithTag(ParentIdPrefixInformation, TAG_IO);
1965 RtlFreeUnicodeString(&KeyName);
1966 if (hKey != NULL)
1967 {
1968 ZwClose(hKey);
1969 }
1970 return Status;
1971 }
1972
1973 static
1974 BOOLEAN
1975 IopValidateID(
1976 _In_ PWCHAR Id,
1977 _In_ BUS_QUERY_ID_TYPE QueryType)
1978 {
1979 PWCHAR PtrChar;
1980 PWCHAR StringEnd;
1981 WCHAR Char;
1982 ULONG SeparatorsCount = 0;
1983 PWCHAR PtrPrevChar = NULL;
1984 ULONG MaxSeparators;
1985 BOOLEAN IsMultiSz;
1986
1987 PAGED_CODE();
1988
1989 switch (QueryType)
1990 {
1991 case BusQueryDeviceID:
1992 MaxSeparators = MAX_SEPARATORS_DEVICEID;
1993 IsMultiSz = FALSE;
1994 break;
1995 case BusQueryInstanceID:
1996 MaxSeparators = MAX_SEPARATORS_INSTANCEID;
1997 IsMultiSz = FALSE;
1998 break;
1999
2000 case BusQueryHardwareIDs:
2001 case BusQueryCompatibleIDs:
2002 MaxSeparators = MAX_SEPARATORS_DEVICEID;
2003 IsMultiSz = TRUE;
2004 break;
2005
2006 default:
2007 DPRINT1("IopValidateID: Not handled QueryType - %x\n", QueryType);
2008 return FALSE;
2009 }
2010
2011 StringEnd = Id + MAX_DEVICE_ID_LEN;
2012
2013 for (PtrChar = Id; PtrChar < StringEnd; PtrChar++)
2014 {
2015 Char = *PtrChar;
2016
2017 if (Char == UNICODE_NULL)
2018 {
2019 if (!IsMultiSz || (PtrPrevChar && PtrChar == PtrPrevChar + 1))
2020 {
2021 if (MaxSeparators == SeparatorsCount || IsMultiSz)
2022 {
2023 return TRUE;
2024 }
2025
2026 DPRINT1("IopValidateID: SeparatorsCount - %lu, MaxSeparators - %lu\n",
2027 SeparatorsCount, MaxSeparators);
2028 goto ErrorExit;
2029 }
2030
2031 StringEnd = PtrChar + MAX_DEVICE_ID_LEN + 1;
2032 PtrPrevChar = PtrChar;
2033 SeparatorsCount = 0;
2034 }
2035 else if (Char < ' ' || Char > 0x7F || Char == ',')
2036 {
2037 DPRINT1("IopValidateID: Invalid character - %04X\n", Char);
2038 goto ErrorExit;
2039 }
2040 else if (Char == ' ')
2041 {
2042 *PtrChar = '_';
2043 }
2044 else if (Char == '\\')
2045 {
2046 SeparatorsCount++;
2047
2048 if (SeparatorsCount > MaxSeparators)
2049 {
2050 DPRINT1("IopValidateID: SeparatorsCount - %lu, MaxSeparators - %lu\n",
2051 SeparatorsCount, MaxSeparators);
2052 goto ErrorExit;
2053 }
2054 }
2055 }
2056
2057 DPRINT1("IopValidateID: Not terminated ID\n");
2058
2059 ErrorExit:
2060 // FIXME logging
2061 return FALSE;
2062 }
2063
2064 NTSTATUS
2065 IopQueryHardwareIds(PDEVICE_NODE DeviceNode,
2066 HANDLE InstanceKey)
2067 {
2068 IO_STACK_LOCATION Stack;
2069 IO_STATUS_BLOCK IoStatusBlock;
2070 PWSTR Ptr;
2071 UNICODE_STRING ValueName;
2072 NTSTATUS Status;
2073 ULONG Length, TotalLength;
2074 BOOLEAN IsValidID;
2075
2076 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryHardwareIDs to device stack\n");
2077
2078 RtlZeroMemory(&Stack, sizeof(Stack));
2079 Stack.Parameters.QueryId.IdType = BusQueryHardwareIDs;
2080 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
2081 &IoStatusBlock,
2082 IRP_MN_QUERY_ID,
2083 &Stack);
2084 if (NT_SUCCESS(Status))
2085 {
2086 IsValidID = IopValidateID((PWCHAR)IoStatusBlock.Information, BusQueryHardwareIDs);
2087
2088 if (!IsValidID)
2089 {
2090 DPRINT1("Invalid HardwareIDs. DeviceNode - %p\n", DeviceNode);
2091 }
2092
2093 TotalLength = 0;
2094
2095 Ptr = (PWSTR)IoStatusBlock.Information;
2096 DPRINT("Hardware IDs:\n");
2097 while (*Ptr)
2098 {
2099 DPRINT(" %S\n", Ptr);
2100 Length = (ULONG)wcslen(Ptr) + 1;
2101
2102 Ptr += Length;
2103 TotalLength += Length;
2104 }
2105 DPRINT("TotalLength: %hu\n", TotalLength);
2106 DPRINT("\n");
2107
2108 RtlInitUnicodeString(&ValueName, L"HardwareID");
2109 Status = ZwSetValueKey(InstanceKey,
2110 &ValueName,
2111 0,
2112 REG_MULTI_SZ,
2113 (PVOID)IoStatusBlock.Information,
2114 (TotalLength + 1) * sizeof(WCHAR));
2115 if (!NT_SUCCESS(Status))
2116 {
2117 DPRINT1("ZwSetValueKey() failed (Status %lx)\n", Status);
2118 }
2119 }
2120 else
2121 {
2122 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
2123 }
2124
2125 return Status;
2126 }
2127
2128 NTSTATUS
2129 IopQueryCompatibleIds(PDEVICE_NODE DeviceNode,
2130 HANDLE InstanceKey)
2131 {
2132 IO_STACK_LOCATION Stack;
2133 IO_STATUS_BLOCK IoStatusBlock;
2134 PWSTR Ptr;
2135 UNICODE_STRING ValueName;
2136 NTSTATUS Status;
2137 ULONG Length, TotalLength;
2138 BOOLEAN IsValidID;
2139
2140 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryCompatibleIDs to device stack\n");
2141
2142 RtlZeroMemory(&Stack, sizeof(Stack));
2143 Stack.Parameters.QueryId.IdType = BusQueryCompatibleIDs;
2144 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
2145 &IoStatusBlock,
2146 IRP_MN_QUERY_ID,
2147 &Stack);
2148 if (NT_SUCCESS(Status) && IoStatusBlock.Information)
2149 {
2150 IsValidID = IopValidateID((PWCHAR)IoStatusBlock.Information, BusQueryCompatibleIDs);
2151
2152 if (!IsValidID)
2153 {
2154 DPRINT1("Invalid CompatibleIDs. DeviceNode - %p\n", DeviceNode);
2155 }
2156
2157 TotalLength = 0;
2158
2159 Ptr = (PWSTR)IoStatusBlock.Information;
2160 DPRINT("Compatible IDs:\n");
2161 while (*Ptr)
2162 {
2163 DPRINT(" %S\n", Ptr);
2164 Length = (ULONG)wcslen(Ptr) + 1;
2165
2166 Ptr += Length;
2167 TotalLength += Length;
2168 }
2169 DPRINT("TotalLength: %hu\n", TotalLength);
2170 DPRINT("\n");
2171
2172 RtlInitUnicodeString(&ValueName, L"CompatibleIDs");
2173 Status = ZwSetValueKey(InstanceKey,
2174 &ValueName,
2175 0,
2176 REG_MULTI_SZ,
2177 (PVOID)IoStatusBlock.Information,
2178 (TotalLength + 1) * sizeof(WCHAR));
2179 if (!NT_SUCCESS(Status))
2180 {
2181 DPRINT1("ZwSetValueKey() failed (Status %lx) or no Compatible ID returned\n", Status);
2182 }
2183 }
2184 else
2185 {
2186 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
2187 }
2188
2189 return Status;
2190 }
2191
2192 NTSTATUS
2193 IopCreateDeviceInstancePath(
2194 _In_ PDEVICE_NODE DeviceNode,
2195 _Out_ PUNICODE_STRING InstancePath)
2196 {
2197 IO_STATUS_BLOCK IoStatusBlock;
2198 UNICODE_STRING DeviceId;
2199 UNICODE_STRING InstanceId;
2200 IO_STACK_LOCATION Stack;
2201 NTSTATUS Status;
2202 UNICODE_STRING ParentIdPrefix = { 0, 0, NULL };
2203 DEVICE_CAPABILITIES DeviceCapabilities;
2204 BOOLEAN IsValidID;
2205
2206 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryDeviceID to device stack\n");
2207
2208 Stack.Parameters.QueryId.IdType = BusQueryDeviceID;
2209 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
2210 &IoStatusBlock,
2211 IRP_MN_QUERY_ID,
2212 &Stack);
2213 if (!NT_SUCCESS(Status))
2214 {
2215 DPRINT1("IopInitiatePnpIrp(BusQueryDeviceID) failed (Status %x)\n", Status);
2216 return Status;
2217 }
2218
2219 IsValidID = IopValidateID((PWCHAR)IoStatusBlock.Information, BusQueryDeviceID);
2220
2221 if (!IsValidID)
2222 {
2223 DPRINT1("Invalid DeviceID. DeviceNode - %p\n", DeviceNode);
2224 }
2225
2226 /* Save the device id string */
2227 RtlInitUnicodeString(&DeviceId, (PWSTR)IoStatusBlock.Information);
2228
2229 DPRINT("Sending IRP_MN_QUERY_CAPABILITIES to device stack (after enumeration)\n");
2230
2231 Status = IopQueryDeviceCapabilities(DeviceNode, &DeviceCapabilities);
2232 if (!NT_SUCCESS(Status))
2233 {
2234 DPRINT1("IopQueryDeviceCapabilities() failed (Status 0x%08lx)\n", Status);
2235 RtlFreeUnicodeString(&DeviceId);
2236 return Status;
2237 }
2238
2239 /* This bit is only check after enumeration */
2240 if (DeviceCapabilities.HardwareDisabled)
2241 {
2242 /* FIXME: Cleanup device */
2243 DeviceNode->Flags |= DNF_DISABLED;
2244 RtlFreeUnicodeString(&DeviceId);
2245 return STATUS_PLUGPLAY_NO_DEVICE;
2246 }
2247 else
2248 {
2249 DeviceNode->Flags &= ~DNF_DISABLED;
2250 }
2251
2252 if (!DeviceCapabilities.UniqueID)
2253 {
2254 /* Device has not a unique ID. We need to prepend parent bus unique identifier */
2255 DPRINT("Instance ID is not unique\n");
2256 Status = IopGetParentIdPrefix(DeviceNode, &ParentIdPrefix);
2257 if (!NT_SUCCESS(Status))
2258 {
2259 DPRINT1("IopGetParentIdPrefix() failed (Status 0x%08lx)\n", Status);
2260 RtlFreeUnicodeString(&DeviceId);
2261 return Status;
2262 }
2263 }
2264
2265 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryInstanceID to device stack\n");
2266
2267 Stack.Parameters.QueryId.IdType = BusQueryInstanceID;
2268 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
2269 &IoStatusBlock,
2270 IRP_MN_QUERY_ID,
2271 &Stack);
2272 if (!NT_SUCCESS(Status))
2273 {
2274 DPRINT("IopInitiatePnpIrp(BusQueryInstanceID) failed (Status %lx)\n", Status);
2275 ASSERT(IoStatusBlock.Information == 0);
2276 }
2277
2278 if (IoStatusBlock.Information)
2279 {
2280 IsValidID = IopValidateID((PWCHAR)IoStatusBlock.Information, BusQueryInstanceID);
2281
2282 if (!IsValidID)
2283 {
2284 DPRINT1("Invalid InstanceID. DeviceNode - %p\n", DeviceNode);
2285 }
2286 }
2287
2288 RtlInitUnicodeString(&InstanceId,
2289 (PWSTR)IoStatusBlock.Information);
2290
2291 InstancePath->Length = 0;
2292 InstancePath->MaximumLength = DeviceId.Length + sizeof(WCHAR) +
2293 ParentIdPrefix.Length +
2294 InstanceId.Length +
2295 sizeof(UNICODE_NULL);
2296 if (ParentIdPrefix.Length && InstanceId.Length)
2297 {
2298 InstancePath->MaximumLength += sizeof(WCHAR);
2299 }
2300
2301 InstancePath->Buffer = ExAllocatePoolWithTag(PagedPool,
2302 InstancePath->MaximumLength,
2303 TAG_IO);
2304 if (!InstancePath->Buffer)
2305 {
2306 RtlFreeUnicodeString(&InstanceId);
2307 RtlFreeUnicodeString(&ParentIdPrefix);
2308 RtlFreeUnicodeString(&DeviceId);
2309 return STATUS_INSUFFICIENT_RESOURCES;
2310 }
2311
2312 /* Start with the device id */
2313 RtlCopyUnicodeString(InstancePath, &DeviceId);
2314 RtlAppendUnicodeToString(InstancePath, L"\\");
2315
2316 /* Add information from parent bus device to InstancePath */
2317 RtlAppendUnicodeStringToString(InstancePath, &ParentIdPrefix);
2318 if (ParentIdPrefix.Length && InstanceId.Length)
2319 {
2320 RtlAppendUnicodeToString(InstancePath, L"&");
2321 }
2322
2323 /* Finally, add the id returned by the driver stack */
2324 RtlAppendUnicodeStringToString(InstancePath, &InstanceId);
2325
2326 /*
2327 * FIXME: Check for valid characters, if there is invalid characters
2328 * then bugcheck
2329 */
2330
2331 RtlFreeUnicodeString(&InstanceId);
2332 RtlFreeUnicodeString(&DeviceId);
2333 RtlFreeUnicodeString(&ParentIdPrefix);
2334
2335 return STATUS_SUCCESS;
2336 }
2337
2338 /*
2339 * IopActionInterrogateDeviceStack
2340 *
2341 * Retrieve information for all (direct) child nodes of a parent node.
2342 *
2343 * Parameters
2344 * DeviceNode
2345 * Pointer to device node.
2346 * Context
2347 * Pointer to parent node to retrieve child node information for.
2348 *
2349 * Remarks
2350 * Any errors that occur are logged instead so that all child services have a chance
2351 * of being interrogated.
2352 */
2353
2354 NTSTATUS
2355 IopActionInterrogateDeviceStack(PDEVICE_NODE DeviceNode,
2356 PVOID Context)
2357 {
2358 IO_STATUS_BLOCK IoStatusBlock;
2359 PWSTR DeviceDescription;
2360 PWSTR LocationInformation;
2361 PDEVICE_NODE ParentDeviceNode;
2362 IO_STACK_LOCATION Stack;
2363 NTSTATUS Status;
2364 ULONG RequiredLength;
2365 LCID LocaleId;
2366 HANDLE InstanceKey = NULL;
2367 UNICODE_STRING ValueName;
2368 UNICODE_STRING InstancePathU;
2369 PDEVICE_OBJECT OldDeviceObject;
2370
2371 DPRINT("IopActionInterrogateDeviceStack(%p, %p)\n", DeviceNode, Context);
2372 DPRINT("PDO 0x%p\n", DeviceNode->PhysicalDeviceObject);
2373
2374 ParentDeviceNode = (PDEVICE_NODE)Context;
2375
2376 /*
2377 * We are called for the parent too, but we don't need to do special
2378 * handling for this node
2379 */
2380 if (DeviceNode == ParentDeviceNode)
2381 {
2382 DPRINT("Success\n");
2383 return STATUS_SUCCESS;
2384 }
2385
2386 /*
2387 * Make sure this device node is a direct child of the parent device node
2388 * that is given as an argument
2389 */
2390 if (DeviceNode->Parent != ParentDeviceNode)
2391 {
2392 DPRINT("Skipping 2+ level child\n");
2393 return STATUS_SUCCESS;
2394 }
2395
2396 /* Skip processing if it was already completed before */
2397 if (DeviceNode->Flags & DNF_PROCESSED)
2398 {
2399 /* Nothing to do */
2400 return STATUS_SUCCESS;
2401 }
2402
2403 /* Get Locale ID */
2404 Status = ZwQueryDefaultLocale(FALSE, &LocaleId);
2405 if (!NT_SUCCESS(Status))
2406 {
2407 DPRINT1("ZwQueryDefaultLocale() failed with status 0x%lx\n", Status);
2408 return Status;
2409 }
2410
2411 /*
2412 * FIXME: For critical errors, cleanup and disable device, but always
2413 * return STATUS_SUCCESS.
2414 */
2415
2416 Status = IopCreateDeviceInstancePath(DeviceNode, &InstancePathU);
2417 if (!NT_SUCCESS(Status))
2418 {
2419 if (Status != STATUS_PLUGPLAY_NO_DEVICE)
2420 {
2421 DPRINT1("IopCreateDeviceInstancePath() failed with status 0x%lx\n", Status);
2422 }
2423
2424 /* We have to return success otherwise we abort the traverse operation */
2425 return STATUS_SUCCESS;
2426 }
2427
2428 /* Verify that this is not a duplicate */
2429 OldDeviceObject = IopGetDeviceObjectFromDeviceInstance(&InstancePathU);
2430 if (OldDeviceObject != NULL)
2431 {
2432 PDEVICE_NODE OldDeviceNode = IopGetDeviceNode(OldDeviceObject);
2433
2434 DPRINT1("Duplicate device instance '%wZ'\n", &InstancePathU);
2435 DPRINT1("Current instance parent: '%wZ'\n", &DeviceNode->Parent->InstancePath);
2436 DPRINT1("Old instance parent: '%wZ'\n", &OldDeviceNode->Parent->InstancePath);
2437
2438 KeBugCheckEx(PNP_DETECTED_FATAL_ERROR,
2439 0x01,
2440 (ULONG_PTR)DeviceNode->PhysicalDeviceObject,
2441 (ULONG_PTR)OldDeviceObject,
2442 0);
2443 }
2444
2445 DeviceNode->InstancePath = InstancePathU;
2446
2447 DPRINT("InstancePath is %S\n", DeviceNode->InstancePath.Buffer);
2448
2449 /*
2450 * Create registry key for the instance id, if it doesn't exist yet
2451 */
2452 Status = IopCreateDeviceKeyPath(&DeviceNode->InstancePath, REG_OPTION_NON_VOLATILE, &InstanceKey);
2453 if (!NT_SUCCESS(Status))
2454 {
2455 DPRINT1("Failed to create the instance key! (Status %lx)\n", Status);
2456
2457 /* We have to return success otherwise we abort the traverse operation */
2458 return STATUS_SUCCESS;
2459 }
2460
2461 IopQueryHardwareIds(DeviceNode, InstanceKey);
2462
2463 IopQueryCompatibleIds(DeviceNode, InstanceKey);
2464
2465 DPRINT("Sending IRP_MN_QUERY_DEVICE_TEXT.DeviceTextDescription to device stack\n");
2466
2467 Stack.Parameters.QueryDeviceText.DeviceTextType = DeviceTextDescription;
2468 Stack.Parameters.QueryDeviceText.LocaleId = LocaleId;
2469 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
2470 &IoStatusBlock,
2471 IRP_MN_QUERY_DEVICE_TEXT,
2472 &Stack);
2473 DeviceDescription = NT_SUCCESS(Status) ? (PWSTR)IoStatusBlock.Information
2474 : NULL;
2475 /* This key is mandatory, so even if the Irp fails, we still write it */
2476 RtlInitUnicodeString(&ValueName, L"DeviceDesc");
2477 if (ZwQueryValueKey(InstanceKey, &ValueName, KeyValueBasicInformation, NULL, 0, &RequiredLength) == STATUS_OBJECT_NAME_NOT_FOUND)
2478 {
2479 if (DeviceDescription &&
2480 *DeviceDescription != UNICODE_NULL)
2481 {
2482 /* This key is overriden when a driver is installed. Don't write the
2483 * new description if another one already exists */
2484 Status = ZwSetValueKey(InstanceKey,
2485 &ValueName,
2486 0,
2487 REG_SZ,
2488 DeviceDescription,
2489 ((ULONG)wcslen(DeviceDescription) + 1) * sizeof(WCHAR));
2490 }
2491 else
2492 {
2493 UNICODE_STRING DeviceDesc = RTL_CONSTANT_STRING(L"Unknown device");
2494 DPRINT("Driver didn't return DeviceDesc (Status 0x%08lx), so place unknown device there\n", Status);
2495
2496 Status = ZwSetValueKey(InstanceKey,
2497 &ValueName,
2498 0,
2499 REG_SZ,
2500 DeviceDesc.Buffer,
2501 DeviceDesc.MaximumLength);
2502 if (!NT_SUCCESS(Status))
2503 {
2504 DPRINT1("ZwSetValueKey() failed (Status 0x%lx)\n", Status);
2505 }
2506
2507 }
2508 }
2509
2510 if (DeviceDescription)
2511 {
2512 ExFreePoolWithTag(DeviceDescription, 0);
2513 }
2514
2515 DPRINT("Sending IRP_MN_QUERY_DEVICE_TEXT.DeviceTextLocation to device stack\n");
2516
2517 Stack.Parameters.QueryDeviceText.DeviceTextType = DeviceTextLocationInformation;
2518 Stack.Parameters.QueryDeviceText.LocaleId = LocaleId;
2519 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
2520 &IoStatusBlock,
2521 IRP_MN_QUERY_DEVICE_TEXT,
2522 &Stack);
2523 if (NT_SUCCESS(Status) && IoStatusBlock.Information)
2524 {
2525 LocationInformation = (PWSTR)IoStatusBlock.Information;
2526 DPRINT("LocationInformation: %S\n", LocationInformation);
2527 RtlInitUnicodeString(&ValueName, L"LocationInformation");
2528 Status = ZwSetValueKey(InstanceKey,
2529 &ValueName,
2530 0,
2531 REG_SZ,
2532 LocationInformation,
2533 ((ULONG)wcslen(LocationInformation) + 1) * sizeof(WCHAR));
2534 if (!NT_SUCCESS(Status))
2535 {
2536 DPRINT1("ZwSetValueKey() failed (Status %lx)\n", Status);
2537 }
2538
2539 ExFreePoolWithTag(LocationInformation, 0);
2540 }
2541 else
2542 {
2543 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status);
2544 }
2545
2546 DPRINT("Sending IRP_MN_QUERY_BUS_INFORMATION to device stack\n");
2547
2548 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
2549 &IoStatusBlock,
2550 IRP_MN_QUERY_BUS_INFORMATION,
2551 NULL);
2552 if (NT_SUCCESS(Status) && IoStatusBlock.Information)
2553 {
2554 PPNP_BUS_INFORMATION BusInformation = (PPNP_BUS_INFORMATION)IoStatusBlock.Information;
2555
2556 DeviceNode->ChildBusNumber = BusInformation->BusNumber;
2557 DeviceNode->ChildInterfaceType = BusInformation->LegacyBusType;
2558 DeviceNode->ChildBusTypeIndex = IopGetBusTypeGuidIndex(&BusInformation->BusTypeGuid);
2559 ExFreePoolWithTag(BusInformation, 0);
2560 }
2561 else
2562 {
2563 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status);
2564
2565 DeviceNode->ChildBusNumber = 0xFFFFFFF0;
2566 DeviceNode->ChildInterfaceType = InterfaceTypeUndefined;
2567 DeviceNode->ChildBusTypeIndex = -1;
2568 }
2569
2570 DPRINT("Sending IRP_MN_QUERY_RESOURCES to device stack\n");
2571
2572 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
2573 &IoStatusBlock,
2574 IRP_MN_QUERY_RESOURCES,
2575 NULL);
2576 if (NT_SUCCESS(Status) && IoStatusBlock.Information)
2577 {
2578 DeviceNode->BootResources = (PCM_RESOURCE_LIST)IoStatusBlock.Information;
2579 IopDeviceNodeSetFlag(DeviceNode, DNF_HAS_BOOT_CONFIG);
2580 }
2581 else
2582 {
2583 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status);
2584 DeviceNode->BootResources = NULL;
2585 }
2586
2587 DPRINT("Sending IRP_MN_QUERY_RESOURCE_REQUIREMENTS to device stack\n");
2588
2589 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
2590 &IoStatusBlock,
2591 IRP_MN_QUERY_RESOURCE_REQUIREMENTS,
2592 NULL);
2593 if (NT_SUCCESS(Status))
2594 {
2595 DeviceNode->ResourceRequirements = (PIO_RESOURCE_REQUIREMENTS_LIST)IoStatusBlock.Information;
2596 }
2597 else
2598 {
2599 DPRINT("IopInitiatePnpIrp() failed (Status %08lx)\n", Status);
2600 DeviceNode->ResourceRequirements = NULL;
2601 }
2602
2603 if (InstanceKey != NULL)
2604 {
2605 IopSetDeviceInstanceData(InstanceKey, DeviceNode);
2606 }
2607
2608 ZwClose(InstanceKey);
2609
2610 IopDeviceNodeSetFlag(DeviceNode, DNF_PROCESSED);
2611
2612 if (!IopDeviceNodeHasFlag(DeviceNode, DNF_LEGACY_DRIVER))
2613 {
2614 /* Report the device to the user-mode pnp manager */
2615 IopQueueTargetDeviceEvent(&GUID_DEVICE_ENUMERATED,
2616 &DeviceNode->InstancePath);
2617 }
2618
2619 return STATUS_SUCCESS;
2620 }
2621
2622 static
2623 VOID
2624 IopHandleDeviceRemoval(
2625 IN PDEVICE_NODE DeviceNode,
2626 IN PDEVICE_RELATIONS DeviceRelations)
2627 {
2628 PDEVICE_NODE Child = DeviceNode->Child, NextChild;
2629 ULONG i;
2630 BOOLEAN Found;
2631
2632 if (DeviceNode == IopRootDeviceNode)
2633 return;
2634
2635 while (Child != NULL)
2636 {
2637 NextChild = Child->Sibling;
2638 Found = FALSE;
2639
2640 for (i = 0; DeviceRelations && i < DeviceRelations->Count; i++)
2641 {
2642 if (IopGetDeviceNode(DeviceRelations->Objects[i]) == Child)
2643 {
2644 Found = TRUE;
2645 break;
2646 }
2647 }
2648
2649 if (!Found && !(Child->Flags & DNF_WILL_BE_REMOVED))
2650 {
2651 /* Send removal IRPs to all of its children */
2652 IopPrepareDeviceForRemoval(Child->PhysicalDeviceObject, TRUE);
2653
2654 /* Send the surprise removal IRP */
2655 IopSendSurpriseRemoval(Child->PhysicalDeviceObject);
2656
2657 /* Tell the user-mode PnP manager that a device was removed */
2658 IopQueueTargetDeviceEvent(&GUID_DEVICE_SURPRISE_REMOVAL,
2659 &Child->InstancePath);
2660
2661 /* Send the remove device IRP */
2662 IopSendRemoveDevice(Child->PhysicalDeviceObject);
2663 }
2664
2665 Child = NextChild;
2666 }
2667 }
2668
2669 NTSTATUS
2670 IopEnumerateDevice(
2671 IN PDEVICE_OBJECT DeviceObject)
2672 {
2673 PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject);
2674 DEVICETREE_TRAVERSE_CONTEXT Context;
2675 PDEVICE_RELATIONS DeviceRelations;
2676 PDEVICE_OBJECT ChildDeviceObject;
2677 IO_STATUS_BLOCK IoStatusBlock;
2678 PDEVICE_NODE ChildDeviceNode;
2679 IO_STACK_LOCATION Stack;
2680 NTSTATUS Status;
2681 ULONG i;
2682
2683 DPRINT("DeviceObject 0x%p\n", DeviceObject);
2684
2685 if (DeviceNode->Flags & DNF_NEED_ENUMERATION_ONLY)
2686 {
2687 DeviceNode->Flags &= ~DNF_NEED_ENUMERATION_ONLY;
2688
2689 DPRINT("Sending GUID_DEVICE_ARRIVAL\n");
2690 IopQueueTargetDeviceEvent(&GUID_DEVICE_ARRIVAL,
2691 &DeviceNode->InstancePath);
2692 }
2693
2694 DPRINT("Sending IRP_MN_QUERY_DEVICE_RELATIONS to device stack\n");
2695
2696 Stack.Parameters.QueryDeviceRelations.Type = BusRelations;
2697
2698 Status = IopInitiatePnpIrp(
2699 DeviceObject,
2700 &IoStatusBlock,
2701 IRP_MN_QUERY_DEVICE_RELATIONS,
2702 &Stack);
2703 if (!NT_SUCCESS(Status) || Status == STATUS_PENDING)
2704 {
2705 DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status);
2706 return Status;
2707 }
2708
2709 DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information;
2710
2711 /*
2712 * Send removal IRPs for devices that have disappeared
2713 * NOTE: This code handles the case where no relations are specified
2714 */
2715 IopHandleDeviceRemoval(DeviceNode, DeviceRelations);
2716
2717 /* Now we bail if nothing was returned */
2718 if (!DeviceRelations)
2719 {
2720 /* We're all done */
2721 DPRINT("No PDOs\n");
2722 return STATUS_SUCCESS;
2723 }
2724
2725 DPRINT("Got %u PDOs\n", DeviceRelations->Count);
2726
2727 /*
2728 * Create device nodes for all discovered devices
2729 */
2730 for (i = 0; i < DeviceRelations->Count; i++)
2731 {
2732 ChildDeviceObject = DeviceRelations->Objects[i];
2733 ASSERT((ChildDeviceObject->Flags & DO_DEVICE_INITIALIZING) == 0);
2734
2735 ChildDeviceNode = IopGetDeviceNode(ChildDeviceObject);
2736 if (!ChildDeviceNode)
2737 {
2738 /* One doesn't exist, create it */
2739 Status = IopCreateDeviceNode(
2740 DeviceNode,
2741 ChildDeviceObject,
2742 NULL,
2743 &ChildDeviceNode);
2744 if (NT_SUCCESS(Status))
2745 {
2746 /* Mark the node as enumerated */
2747 ChildDeviceNode->Flags |= DNF_ENUMERATED;
2748
2749 /* Mark the DO as bus enumerated */
2750 ChildDeviceObject->Flags |= DO_BUS_ENUMERATED_DEVICE;
2751 }
2752 else
2753 {
2754 /* Ignore this DO */
2755 DPRINT1("IopCreateDeviceNode() failed with status 0x%08x. Skipping PDO %u\n", Status, i);
2756 ObDereferenceObject(ChildDeviceObject);
2757 }
2758 }
2759 else
2760 {
2761 /* Mark it as enumerated */
2762 ChildDeviceNode->Flags |= DNF_ENUMERATED;
2763 ObDereferenceObject(ChildDeviceObject);
2764 }
2765 }
2766 ExFreePool(DeviceRelations);
2767
2768 /*
2769 * Retrieve information about all discovered children from the bus driver
2770 */
2771 IopInitDeviceTreeTraverseContext(
2772 &Context,
2773 DeviceNode,
2774 IopActionInterrogateDeviceStack,
2775 DeviceNode);
2776
2777 Status = IopTraverseDeviceTree(&Context);
2778 if (!NT_SUCCESS(Status))
2779 {
2780 DPRINT("IopTraverseDeviceTree() failed with status 0x%08lx\n", Status);
2781 return Status;
2782 }
2783
2784 /*
2785 * Retrieve configuration from the registry for discovered children
2786 */
2787 IopInitDeviceTreeTraverseContext(
2788 &Context,
2789 DeviceNode,
2790 IopActionConfigureChildServices,
2791 DeviceNode);
2792
2793 Status = IopTraverseDeviceTree(&Context);
2794 if (!NT_SUCCESS(Status))
2795 {
2796 DPRINT("IopTraverseDeviceTree() failed with status 0x%08lx\n", Status);
2797 return Status;
2798 }
2799
2800 /*
2801 * Initialize services for discovered children.
2802 */
2803 Status = IopInitializePnpServices(DeviceNode);
2804 if (!NT_SUCCESS(Status))
2805 {
2806 DPRINT("IopInitializePnpServices() failed with status 0x%08lx\n", Status);
2807 return Status;
2808 }
2809
2810 DPRINT("IopEnumerateDevice() finished\n");
2811 return STATUS_SUCCESS;
2812 }
2813
2814
2815 /*
2816 * IopActionConfigureChildServices
2817 *
2818 * Retrieve configuration for all (direct) child nodes of a parent node.
2819 *
2820 * Parameters
2821 * DeviceNode
2822 * Pointer to device node.
2823 * Context
2824 * Pointer to parent node to retrieve child node configuration for.
2825 *
2826 * Remarks
2827 * Any errors that occur are logged instead so that all child services have a chance of beeing
2828 * configured.
2829 */
2830
2831 NTSTATUS
2832 IopActionConfigureChildServices(PDEVICE_NODE DeviceNode,
2833 PVOID Context)
2834 {
2835 RTL_QUERY_REGISTRY_TABLE QueryTable[3];
2836 PDEVICE_NODE ParentDeviceNode;
2837 PUNICODE_STRING Service;
2838 UNICODE_STRING ClassGUID;
2839 NTSTATUS Status;
2840 DEVICE_CAPABILITIES DeviceCaps;
2841
2842 DPRINT("IopActionConfigureChildServices(%p, %p)\n", DeviceNode, Context);
2843
2844 ParentDeviceNode = (PDEVICE_NODE)Context;
2845
2846 /*
2847 * We are called for the parent too, but we don't need to do special
2848 * handling for this node
2849 */
2850 if (DeviceNode == ParentDeviceNode)
2851 {
2852 DPRINT("Success\n");
2853 return STATUS_SUCCESS;
2854 }
2855
2856 /*
2857 * Make sure this device node is a direct child of the parent device node
2858 * that is given as an argument
2859 */
2860
2861 if (DeviceNode->Parent != ParentDeviceNode)
2862 {
2863 DPRINT("Skipping 2+ level child\n");
2864 return STATUS_SUCCESS;
2865 }
2866
2867 if (!(DeviceNode->Flags & DNF_PROCESSED))
2868 {
2869 DPRINT1("Child not ready to be configured\n");
2870 return STATUS_SUCCESS;
2871 }
2872
2873 if (!(DeviceNode->Flags & (DNF_DISABLED | DNF_STARTED | DNF_ADDED)))
2874 {
2875 UNICODE_STRING RegKey;
2876
2877 /* Install the service for this if it's in the CDDB */
2878 IopInstallCriticalDevice(DeviceNode);
2879
2880 /*
2881 * Retrieve configuration from Enum key
2882 */
2883
2884 Service = &DeviceNode->ServiceName;
2885
2886 RtlZeroMemory(QueryTable, sizeof(QueryTable));
2887 RtlInitUnicodeString(Service, NULL);
2888 RtlInitUnicodeString(&ClassGUID, NULL);
2889
2890 QueryTable[0].Name = L"Service";
2891 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
2892 QueryTable[0].EntryContext = Service;
2893
2894 QueryTable[1].Name = L"ClassGUID";
2895 QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
2896 QueryTable[1].EntryContext = &ClassGUID;
2897 QueryTable[1].DefaultType = REG_SZ;
2898 QueryTable[1].DefaultData = L"";
2899 QueryTable[1].DefaultLength = 0;
2900
2901 RegKey.Length = 0;
2902 RegKey.MaximumLength = sizeof(ENUM_ROOT) + sizeof(WCHAR) + DeviceNode->InstancePath.Length;
2903 RegKey.Buffer = ExAllocatePoolWithTag(PagedPool,
2904 RegKey.MaximumLength,
2905 TAG_IO);
2906 if (RegKey.Buffer == NULL)
2907 {
2908 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
2909 return STATUS_INSUFFICIENT_RESOURCES;
2910 }
2911
2912 RtlAppendUnicodeToString(&RegKey, ENUM_ROOT);
2913 RtlAppendUnicodeToString(&RegKey, L"\\");
2914 RtlAppendUnicodeStringToString(&RegKey, &DeviceNode->InstancePath);
2915
2916 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
2917 RegKey.Buffer, QueryTable, NULL, NULL);
2918 ExFreePoolWithTag(RegKey.Buffer, TAG_IO);
2919
2920 if (!NT_SUCCESS(Status))
2921 {
2922 /* FIXME: Log the error */
2923 DPRINT("Could not retrieve configuration for device %wZ (Status 0x%08x)\n",
2924 &DeviceNode->InstancePath, Status);
2925 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
2926 return STATUS_SUCCESS;
2927 }
2928
2929 if (Service->Buffer == NULL)
2930 {
2931 if (NT_SUCCESS(IopQueryDeviceCapabilities(DeviceNode, &DeviceCaps)) &&
2932 DeviceCaps.RawDeviceOK)
2933 {
2934 DPRINT("%wZ is using parent bus driver (%wZ)\n", &DeviceNode->InstancePath, &ParentDeviceNode->ServiceName);
2935 RtlInitEmptyUnicodeString(&DeviceNode->ServiceName, NULL, 0);
2936 }
2937 else if (ClassGUID.Length != 0)
2938 {
2939 /* Device has a ClassGUID value, but no Service value.
2940 * Suppose it is using the NULL driver, so state the
2941 * device is started */
2942 DPRINT("%wZ is using NULL driver\n", &DeviceNode->InstancePath);
2943 IopDeviceNodeSetFlag(DeviceNode, DNF_STARTED);
2944 }
2945 else
2946 {
2947 DeviceNode->Problem = CM_PROB_FAILED_INSTALL;
2948 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
2949 }
2950 return STATUS_SUCCESS;
2951 }
2952
2953 DPRINT("Got Service %S\n", Service->Buffer);
2954 }
2955
2956 return STATUS_SUCCESS;
2957 }
2958
2959 /*
2960 * IopActionInitChildServices
2961 *
2962 * Initialize the service for all (direct) child nodes of a parent node
2963 *
2964 * Parameters
2965 * DeviceNode
2966 * Pointer to device node.
2967 * Context
2968 * Pointer to parent node to initialize child node services for.
2969 *
2970 * Remarks
2971 * If the driver image for a service is not loaded and initialized
2972 * it is done here too. Any errors that occur are logged instead so
2973 * that all child services have a chance of being initialized.
2974 */
2975
2976 NTSTATUS
2977 IopActionInitChildServices(PDEVICE_NODE DeviceNode,
2978 PVOID Context)
2979 {
2980 PDEVICE_NODE ParentDeviceNode;
2981 NTSTATUS Status;
2982 BOOLEAN BootDrivers = !PnpSystemInit;
2983
2984 DPRINT("IopActionInitChildServices(%p, %p)\n", DeviceNode, Context);
2985
2986 ParentDeviceNode = Context;
2987
2988 /*
2989 * We are called for the parent too, but we don't need to do special
2990 * handling for this node
2991 */
2992 if (DeviceNode == ParentDeviceNode)
2993 {
2994 DPRINT("Success\n");
2995 return STATUS_SUCCESS;
2996 }
2997
2998 /*
2999 * We don't want to check for a direct child because
3000 * this function is called during boot to reinitialize
3001 * devices with drivers that couldn't load yet due to
3002 * stage 0 limitations (ie can't load from disk yet).
3003 */
3004
3005 if (!(DeviceNode->Flags & DNF_PROCESSED))
3006 {
3007 DPRINT1("Child not ready to be added\n");
3008 return STATUS_SUCCESS;
3009 }
3010
3011 if (IopDeviceNodeHasFlag(DeviceNode, DNF_STARTED) ||
3012 IopDeviceNodeHasFlag(DeviceNode, DNF_ADDED) ||
3013 IopDeviceNodeHasFlag(DeviceNode, DNF_DISABLED))
3014 return STATUS_SUCCESS;
3015
3016 if (DeviceNode->ServiceName.Buffer == NULL)
3017 {
3018 /* We don't need to worry about loading the driver because we're
3019 * being driven in raw mode so our parent must be loaded to get here */
3020 Status = IopInitializeDevice(DeviceNode, NULL);
3021 if (NT_SUCCESS(Status))
3022 {
3023 Status = IopStartDevice(DeviceNode);
3024 if (!NT_SUCCESS(Status))
3025 {
3026 DPRINT1("IopStartDevice(%wZ) failed with status 0x%08x\n",
3027 &DeviceNode->InstancePath, Status);
3028 }
3029 }
3030 }
3031 else
3032 {
3033 PLDR_DATA_TABLE_ENTRY ModuleObject;
3034 PDRIVER_OBJECT DriverObject;
3035
3036 KeEnterCriticalRegion();
3037 ExAcquireResourceExclusiveLite(&IopDriverLoadResource, TRUE);
3038 /* Get existing DriverObject pointer (in case the driver has
3039 already been loaded and initialized) */
3040 Status = IopGetDriverObject(
3041 &DriverObject,
3042 &DeviceNode->ServiceName,
3043 FALSE);
3044
3045 if (!NT_SUCCESS(Status))
3046 {
3047 /* Driver is not initialized, try to load it */
3048 Status = IopLoadServiceModule(&DeviceNode->ServiceName, &ModuleObject);
3049
3050 if (NT_SUCCESS(Status) || Status == STATUS_IMAGE_ALREADY_LOADED)
3051 {
3052 /* Initialize the driver */
3053 Status = IopInitializeDriverModule(DeviceNode, ModuleObject,
3054 &DeviceNode->ServiceName, FALSE, &DriverObject);
3055 if (!NT_SUCCESS(Status)) DeviceNode->Problem = CM_PROB_FAILED_DRIVER_ENTRY;
3056 }
3057 else if (Status == STATUS_DRIVER_UNABLE_TO_LOAD)
3058 {
3059 DPRINT1("Service '%wZ' is disabled\n", &DeviceNode->ServiceName);
3060 DeviceNode->Problem = CM_PROB_DISABLED_SERVICE;
3061 }
3062 else
3063 {
3064 DPRINT("IopLoadServiceModule(%wZ) failed with status 0x%08x\n",
3065 &DeviceNode->ServiceName, Status);
3066 if (!BootDrivers) DeviceNode->Problem = CM_PROB_DRIVER_FAILED_LOAD;
3067 }
3068 }
3069 ExReleaseResourceLite(&IopDriverLoadResource);
3070 KeLeaveCriticalRegion();
3071
3072 /* Driver is loaded and initialized at this point */
3073 if (NT_SUCCESS(Status))
3074 {
3075 /* Initialize the device, including all filters */
3076 Status = PipCallDriverAddDevice(DeviceNode, FALSE, DriverObject);
3077
3078 /* Remove the extra reference */
3079 ObDereferenceObject(DriverObject);
3080 }
3081 else
3082 {
3083 /*
3084 * Don't disable when trying to load only boot drivers
3085 */
3086 if (!BootDrivers)
3087 {
3088 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
3089 }
3090 }
3091 }
3092
3093 return STATUS_SUCCESS;
3094 }
3095
3096 /*
3097 * IopInitializePnpServices
3098 *
3099 * Initialize services for discovered children
3100 *
3101 * Parameters
3102 * DeviceNode
3103 * Top device node to start initializing services.
3104 *
3105 * Return Value
3106 * Status
3107 */
3108 NTSTATUS
3109 IopInitializePnpServices(IN PDEVICE_NODE DeviceNode)
3110 {
3111 DEVICETREE_TRAVERSE_CONTEXT Context;
3112
3113 DPRINT("IopInitializePnpServices(%p)\n", DeviceNode);
3114
3115 IopInitDeviceTreeTraverseContext(
3116 &Context,
3117 DeviceNode,
3118 IopActionInitChildServices,
3119 DeviceNode);
3120
3121 return IopTraverseDeviceTree(&Context);
3122 }
3123
3124 static
3125 INIT_FUNCTION
3126 NTSTATUS
3127 IopEnumerateDetectedDevices(
3128 IN HANDLE hBaseKey,
3129 IN PUNICODE_STRING RelativePath OPTIONAL,
3130 IN HANDLE hRootKey,
3131 IN BOOLEAN EnumerateSubKeys,
3132 IN PCM_FULL_RESOURCE_DESCRIPTOR ParentBootResources,
3133 IN ULONG ParentBootResourcesLength)
3134 {
3135 UNICODE_STRING IdentifierU = RTL_CONSTANT_STRING(L"Identifier");
3136 UNICODE_STRING HardwareIDU = RTL_CONSTANT_STRING(L"HardwareID");
3137 UNICODE_STRING ConfigurationDataU = RTL_CONSTANT_STRING(L"Configuration Data");
3138 UNICODE_STRING BootConfigU = RTL_CONSTANT_STRING(L"BootConfig");
3139 UNICODE_STRING LogConfU = RTL_CONSTANT_STRING(L"LogConf");
3140 OBJECT_ATTRIBUTES ObjectAttributes;
3141 HANDLE hDevicesKey = NULL;
3142 HANDLE hDeviceKey = NULL;
3143 HANDLE hLevel1Key, hLevel2Key = NULL, hLogConf;
3144 UNICODE_STRING Level2NameU;
3145 WCHAR Level2Name[5];
3146 ULONG IndexDevice = 0;
3147 ULONG IndexSubKey;
3148 PKEY_BASIC_INFORMATION pDeviceInformation = NULL;
3149 ULONG DeviceInfoLength = sizeof(KEY_BASIC_INFORMATION) + 50 * sizeof(WCHAR);
3150 PKEY_VALUE_PARTIAL_INFORMATION pValueInformation = NULL;
3151 ULONG ValueInfoLength = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 50 * sizeof(WCHAR);
3152 UNICODE_STRING DeviceName, ValueName;
3153 ULONG RequiredSize;
3154 PCM_FULL_RESOURCE_DESCRIPTOR BootResources = NULL;
3155 ULONG BootResourcesLength;
3156 NTSTATUS Status;
3157
3158 const UNICODE_STRING IdentifierSerial = RTL_CONSTANT_STRING(L"SerialController");
3159 UNICODE_STRING HardwareIdSerial = RTL_CONSTANT_STRING(L"*PNP0501\0");
3160 static ULONG DeviceIndexSerial = 0;
3161 const UNICODE_STRING IdentifierKeyboard = RTL_CONSTANT_STRING(L"KeyboardController");
3162 UNICODE_STRING HardwareIdKeyboard = RTL_CONSTANT_STRING(L"*PNP0303\0");
3163 static ULONG DeviceIndexKeyboard = 0;
3164 const UNICODE_STRING IdentifierMouse = RTL_CONSTANT_STRING(L"PointerController");
3165 UNICODE_STRING HardwareIdMouse = RTL_CONSTANT_STRING(L"*PNP0F13\0");
3166 static ULONG DeviceIndexMouse = 0;
3167 const UNICODE_STRING IdentifierParallel = RTL_CONSTANT_STRING(L"ParallelController");
3168 UNICODE_STRING HardwareIdParallel = RTL_CONSTANT_STRING(L"*PNP0400\0");
3169 static ULONG DeviceIndexParallel = 0;
3170 const UNICODE_STRING IdentifierFloppy = RTL_CONSTANT_STRING(L"FloppyDiskPeripheral");
3171 UNICODE_STRING HardwareIdFloppy = RTL_CONSTANT_STRING(L"*PNP0700\0");
3172 static ULONG DeviceIndexFloppy = 0;
3173 UNICODE_STRING HardwareIdKey;
3174 PUNICODE_STRING pHardwareId;
3175 ULONG DeviceIndex = 0;
3176 PUCHAR CmResourceList;
3177 ULONG ListCount;
3178
3179 if (RelativePath)
3180 {
3181 Status = IopOpenRegistryKeyEx(&hDevicesKey, hBaseKey, RelativePath, KEY_ENUMERATE_SUB_KEYS);
3182 if (!NT_SUCCESS(Status))
3183 {
3184 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
3185 goto cleanup;
3186 }
3187 }
3188 else
3189 hDevicesKey = hBaseKey;
3190
3191 pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength);
3192 if (!pDeviceInformation)
3193 {
3194 DPRINT("ExAllocatePool() failed\n");
3195 Status = STATUS_NO_MEMORY;
3196 goto cleanup;
3197 }
3198
3199 pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength);
3200 if (!pValueInformation)
3201 {
3202 DPRINT("ExAllocatePool() failed\n");
3203 Status = STATUS_NO_MEMORY;
3204 goto cleanup;
3205 }
3206
3207 while (TRUE)
3208 {
3209 Status = ZwEnumerateKey(hDevicesKey, IndexDevice, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
3210 if (Status == STATUS_NO_MORE_ENTRIES)
3211 break;
3212 else if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
3213 {
3214 ExFreePool(pDeviceInformation);
3215 DeviceInfoLength = RequiredSize;
3216 pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength);
3217 if (!pDeviceInformation)
3218 {
3219 DPRINT("ExAllocatePool() failed\n");
3220 Status = STATUS_NO_MEMORY;
3221 goto cleanup;
3222 }
3223 Status = ZwEnumerateKey(hDevicesKey, IndexDevice, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
3224 }
3225 if (!NT_SUCCESS(Status))
3226 {
3227 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status);
3228 goto cleanup;
3229 }
3230 IndexDevice++;
3231
3232 /* Open device key */
3233 DeviceName.Length = DeviceName.MaximumLength = (USHORT)pDeviceInformation->NameLength;
3234 DeviceName.Buffer = pDeviceInformation->Name;
3235
3236 Status = IopOpenRegistryKeyEx(&hDeviceKey, hDevicesKey, &DeviceName,
3237 KEY_QUERY_VALUE + (EnumerateSubKeys ? KEY_ENUMERATE_SUB_KEYS : 0));
3238 if (!NT_SUCCESS(Status))
3239 {
3240 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
3241 goto cleanup;
3242 }
3243
3244 /* Read boot resources, and add then to parent ones */
3245 Status = ZwQueryValueKey(hDeviceKey, &ConfigurationDataU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
3246 if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
3247 {
3248 ExFreePool(pValueInformation);
3249 ValueInfoLength = RequiredSize;
3250 pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength);
3251 if (!pValueInformation)
3252 {
3253 DPRINT("ExAllocatePool() failed\n");
3254 ZwDeleteKey(hLevel2Key);
3255 Status = STATUS_NO_MEMORY;
3256 goto cleanup;
3257 }
3258 Status = ZwQueryValueKey(hDeviceKey, &ConfigurationDataU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
3259 }
3260 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
3261 {
3262 BootResources = ParentBootResources;
3263 BootResourcesLength = ParentBootResourcesLength;
3264 }
3265 else if (!NT_SUCCESS(Status))
3266 {
3267 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status);
3268 goto nextdevice;
3269 }
3270 else if (pValueInformation->Type != REG_FULL_RESOURCE_DESCRIPTOR)
3271 {
3272 DPRINT("Wrong registry type: got 0x%lx, expected 0x%lx\n", pValueInformation->Type, REG_FULL_RESOURCE_DESCRIPTOR);
3273 goto nextdevice;
3274 }
3275 else
3276 {
3277 static const ULONG Header = FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList.PartialDescriptors);
3278
3279 /* Concatenate current resources and parent ones */
3280 if (ParentBootResourcesLength == 0)
3281 BootResourcesLength = pValueInformation->DataLength;
3282 else
3283 BootResourcesLength = ParentBootResourcesLength
3284 + pValueInformation->DataLength
3285 - Header;
3286 BootResources = ExAllocatePool(PagedPool, BootResourcesLength);
3287 if (!BootResources)
3288 {
3289 DPRINT("ExAllocatePool() failed\n");
3290 goto nextdevice;
3291 }
3292 if (ParentBootResourcesLength < sizeof(CM_FULL_RESOURCE_DESCRIPTOR))
3293 {
3294 RtlCopyMemory(BootResources, pValueInformation->Data, pValueInformation->DataLength);
3295 }
3296 else if (ParentBootResources->PartialResourceList.PartialDescriptors[ParentBootResources->PartialResourceList.Count - 1].Type == CmResourceTypeDeviceSpecific)
3297 {
3298 RtlCopyMemory(BootResources, pValueInformation->Data, pValueInformation->DataLength);
3299 RtlCopyMemory(
3300 (PVOID)((ULONG_PTR)BootResources + pValueInformation->DataLength),
3301 (PVOID)((ULONG_PTR)ParentBootResources + Header),
3302 ParentBootResourcesLength - Header);
3303 BootResources->PartialResourceList.Count += ParentBootResources->PartialResourceList.Count;
3304 }
3305 else
3306 {
3307 RtlCopyMemory(BootResources, pValueInformation->Data, Header);
3308 RtlCopyMemory(
3309 (PVOID)((ULONG_PTR)BootResources + Header),
3310 (PVOID)((ULONG_PTR)ParentBootResources + Header),
3311 ParentBootResourcesLength - Header);
3312 RtlCopyMemory(
3313 (PVOID)((ULONG_PTR)BootResources + ParentBootResourcesLength),
3314 pValueInformation->Data + Header,
3315 pValueInformation->DataLength - Header);
3316 BootResources->PartialResourceList.Count += ParentBootResources->PartialResourceList.Count;
3317 }
3318 }
3319
3320 if (EnumerateSubKeys)
3321 {
3322 IndexSubKey = 0;
3323 while (TRUE)
3324 {
3325 Status = ZwEnumerateKey(hDeviceKey, IndexSubKey, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
3326 if (Status == STATUS_NO_MORE_ENTRIES)
3327 break;
3328 else if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
3329 {
3330 ExFreePool(pDeviceInformation);
3331 DeviceInfoLength = RequiredSize;
3332 pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength);
3333 if (!pDeviceInformation)
3334 {
3335 DPRINT("ExAllocatePool() failed\n");
3336 Status = STATUS_NO_MEMORY;
3337 goto cleanup;
3338 }
3339 Status = ZwEnumerateKey(hDeviceKey, IndexSubKey, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
3340 }
3341 if (!NT_SUCCESS(Status))
3342 {
3343 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status);
3344 goto cleanup;
3345 }
3346 IndexSubKey++;
3347 DeviceName.Length = DeviceName.MaximumLength = (USHORT)pDeviceInformation->NameLength;
3348 DeviceName.Buffer = pDeviceInformation->Name;
3349
3350 Status = IopEnumerateDetectedDevices(
3351 hDeviceKey,
3352 &DeviceName,
3353 hRootKey,
3354 TRUE,
3355 BootResources,
3356 BootResourcesLength);
3357 if (!NT_SUCCESS(Status))
3358 goto cleanup;
3359 }
3360 }
3361
3362 /* Read identifier */
3363 Status = ZwQueryValueKey(hDeviceKey, &IdentifierU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
3364 if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
3365 {
3366 ExFreePool(pValueInformation);
3367 ValueInfoLength = RequiredSize;
3368 pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength);
3369 if (!pValueInformation)
3370 {
3371 DPRINT("ExAllocatePool() failed\n");
3372 Status = STATUS_NO_MEMORY;
3373 goto cleanup;
3374 }
3375 Status = ZwQueryValueKey(hDeviceKey, &IdentifierU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
3376 }
3377 if (!NT_SUCCESS(Status))
3378 {
3379 if (Status != STATUS_OBJECT_NAME_NOT_FOUND)
3380 {
3381 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status);
3382 goto nextdevice;
3383 }
3384 ValueName.Length = ValueName.MaximumLength = 0;
3385 }
3386 else if (pValueInformation->Type != REG_SZ)
3387 {
3388 DPRINT("Wrong registry type: got 0x%lx, expected 0x%lx\n", pValueInformation->Type, REG_SZ);
3389 goto nextdevice;
3390 }
3391 else
3392 {
3393 /* Assign hardware id to this device */
3394 ValueName.Length = ValueName.MaximumLength = (USHORT)pValueInformation->DataLength;
3395 ValueName.Buffer = (PWCHAR)pValueInformation->Data;
3396 if (ValueName.Length >= sizeof(WCHAR) && ValueName.Buffer[ValueName.Length / sizeof(WCHAR) - 1] == UNICODE_NULL)
3397 ValueName.Length -= sizeof(WCHAR);
3398 }
3399
3400 if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierSerial, FALSE) == 0)
3401 {
3402 pHardwareId = &HardwareIdSerial;
3403 DeviceIndex = DeviceIndexSerial++;
3404 }
3405 else if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierKeyboard, FALSE) == 0)
3406 {
3407 pHardwareId = &HardwareIdKeyboard;
3408 DeviceIndex = DeviceIndexKeyboard++;
3409 }
3410 else if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierMouse, FALSE) == 0)
3411 {
3412 pHardwareId = &HardwareIdMouse;
3413 DeviceIndex = DeviceIndexMouse++;
3414 }
3415 else if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierParallel, FALSE) == 0)
3416 {
3417 pHardwareId = &HardwareIdParallel;
3418 DeviceIndex = DeviceIndexParallel++;
3419 }
3420 else if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierFloppy, FALSE) == 0)
3421 {
3422 pHardwareId = &HardwareIdFloppy;
3423 DeviceIndex = DeviceIndexFloppy++;
3424 }
3425 else
3426 {
3427 /* Unknown key path */
3428 DPRINT("Unknown key path '%wZ'\n", RelativePath);
3429 goto nextdevice;
3430 }
3431
3432 /* Prepare hardware id key (hardware id value without final \0) */
3433 HardwareIdKey = *pHardwareId;
3434 HardwareIdKey.Length -= sizeof(UNICODE_NULL);
3435
3436 /* Add the detected device to Root key */
3437 InitializeObjectAttributes(&ObjectAttributes, &HardwareIdKey, OBJ_KERNEL_HANDLE, hRootKey, NULL);
3438 Status = ZwCreateKey(
3439 &hLevel1Key,
3440 KEY_CREATE_SUB_KEY,
3441 &ObjectAttributes,
3442 0,
3443 NULL,
3444 REG_OPTION_NON_VOLATILE,
3445 NULL);
3446 if (!NT_SUCCESS(Status))
3447 {
3448 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status);
3449 goto nextdevice;
3450 }
3451 swprintf(Level2Name, L"%04lu", DeviceIndex);
3452 RtlInitUnicodeString(&Level2NameU, Level2Name);
3453 InitializeObjectAttributes(&ObjectAttributes, &Level2NameU, OBJ_KERNEL_HANDLE, hLevel1Key, NULL);
3454 Status = ZwCreateKey(
3455 &hLevel2Key,
3456 KEY_SET_VALUE | KEY_CREATE_SUB_KEY,
3457 &ObjectAttributes,
3458 0,
3459 NULL,
3460 REG_OPTION_NON_VOLATILE,
3461 NULL);
3462 ZwClose(hLevel1Key);
3463 if (!NT_SUCCESS(Status))
3464 {
3465 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status);
3466 goto nextdevice;
3467 }
3468 DPRINT("Found %wZ #%lu (%wZ)\n", &ValueName, DeviceIndex, &HardwareIdKey);
3469 Status = ZwSetValueKey(hLevel2Key, &HardwareIDU, 0, REG_MULTI_SZ, pHardwareId->Buffer, pHardwareId->MaximumLength);
3470 if (!NT_SUCCESS(Status))
3471 {
3472 DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status);
3473 ZwDeleteKey(hLevel2Key);
3474 goto nextdevice;
3475 }
3476 /* Create 'LogConf' subkey */
3477 InitializeObjectAttributes(&ObjectAttributes, &LogConfU, OBJ_KERNEL_HANDLE, hLevel2Key, NULL);
3478 Status = ZwCreateKey(
3479 &hLogConf,
3480 KEY_SET_VALUE,
3481 &ObjectAttributes,
3482 0,
3483 NULL,
3484 REG_OPTION_VOLATILE,
3485 NULL);
3486 if (!NT_SUCCESS(Status))
3487 {
3488 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status);
3489 ZwDeleteKey(hLevel2Key);
3490 goto nextdevice;
3491 }
3492 if (BootResourcesLength >= sizeof(CM_FULL_RESOURCE_DESCRIPTOR))
3493 {
3494 CmResourceList = ExAllocatePool(PagedPool, BootResourcesLength + sizeof(ULONG));
3495 if (!CmResourceList)
3496 {
3497 ZwClose(hLogConf);
3498 ZwDeleteKey(hLevel2Key);
3499 goto nextdevice;
3500 }
3501
3502 /* Add the list count (1st member of CM_RESOURCE_LIST) */
3503 ListCount = 1;
3504 RtlCopyMemory(CmResourceList,
3505 &ListCount,
3506 sizeof(ULONG));
3507
3508 /* Now add the actual list (2nd member of CM_RESOURCE_LIST) */
3509 RtlCopyMemory(CmResourceList + sizeof(ULONG),
3510 BootResources,
3511 BootResourcesLength);
3512
3513 /* Save boot resources to 'LogConf\BootConfig' */
3514 Status = ZwSetValueKey(hLogConf, &BootConfigU, 0, REG_RESOURCE_LIST, CmResourceList, BootResourcesLength + sizeof(ULONG));
3515 if (!NT_SUCCESS(Status))
3516 {
3517 DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status);
3518 ZwClose(hLogConf);
3519 ZwDeleteKey(hLevel2Key);
3520 goto nextdevice;
3521 }
3522 }
3523 ZwClose(hLogConf);
3524
3525 nextdevice:
3526 if (BootResources && BootResources != ParentBootResources)
3527 {
3528 ExFreePool(BootResources);
3529 BootResources = NULL;
3530 }
3531 if (hLevel2Key)
3532 {
3533 ZwClose(hLevel2Key);
3534 hLevel2Key = NULL;
3535 }
3536 if (hDeviceKey)
3537 {
3538 ZwClose(hDeviceKey);
3539 hDeviceKey = NULL;
3540 }
3541 }
3542
3543 Status = STATUS_SUCCESS;
3544
3545 cleanup:
3546 if (hDevicesKey && hDevicesKey != hBaseKey)
3547 ZwClose(hDevicesKey);
3548 if (hDeviceKey)
3549 ZwClose(hDeviceKey);
3550 if (pDeviceInformation)
3551 ExFreePool(pDeviceInformation);
3552 if (pValueInformation)
3553 ExFreePool(pValueInformation);
3554 return Status;
3555 }
3556
3557 static
3558 INIT_FUNCTION
3559 BOOLEAN
3560 IopIsFirmwareMapperDisabled(VOID)
3561 {
3562 UNICODE_STRING KeyPathU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\CURRENTCONTROLSET\\Control\\Pnp");
3563 UNICODE_STRING KeyNameU = RTL_CONSTANT_STRING(L"DisableFirmwareMapper");
3564 OBJECT_ATTRIBUTES ObjectAttributes;
3565 HANDLE hPnpKey;
3566 PKEY_VALUE_PARTIAL_INFORMATION KeyInformation;
3567 ULONG DesiredLength, Length;
3568 ULONG KeyValue = 0;
3569 NTSTATUS Status;
3570
3571 InitializeObjectAttributes(&ObjectAttributes, &KeyPathU, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
3572 Status = ZwOpenKey(&hPnpKey, KEY_QUERY_VALUE, &ObjectAttributes);
3573 if (NT_SUCCESS(Status))
3574 {
3575 Status = ZwQueryValueKey(hPnpKey,
3576 &KeyNameU,
3577 KeyValuePartialInformation,
3578 NULL,
3579 0,
3580 &DesiredLength);
3581 if ((Status == STATUS_BUFFER_TOO_SMALL) ||
3582 (Status == STATUS_BUFFER_OVERFLOW))
3583 {
3584 Length = DesiredLength;
3585 KeyInformation = ExAllocatePool(PagedPool, Length);
3586 if (KeyInformation)
3587 {
3588 Status = ZwQueryValueKey(hPnpKey,
3589 &KeyNameU,
3590 KeyValuePartialInformation,
3591 KeyInformation,
3592 Length,
3593 &DesiredLength);
3594 if (NT_SUCCESS(Status) && KeyInformation->DataLength == sizeof(ULONG))
3595 {
3596 KeyValue = (ULONG)(*KeyInformation->Data);
3597 }
3598 else
3599 {
3600 DPRINT1("ZwQueryValueKey(%wZ%wZ) failed\n", &KeyPathU, &KeyNameU);
3601 }
3602
3603 ExFreePool(KeyInformation);
3604 }
3605 else
3606 {
3607 DPRINT1("Failed to allocate memory for registry query\n");
3608 }
3609 }
3610 else
3611 {
3612 DPRINT1("ZwQueryValueKey(%wZ%wZ) failed with status 0x%08lx\n", &KeyPathU, &KeyNameU, Status);
3613 }
3614
3615 ZwClose(hPnpKey);
3616 }
3617 else
3618 {
3619 DPRINT1("ZwOpenKey(%wZ) failed with status 0x%08lx\n", &KeyPathU, Status);
3620 }
3621
3622 DPRINT("Firmware mapper is %s\n", KeyValue != 0 ? "disabled" : "enabled");
3623
3624 return (KeyValue != 0) ? TRUE : FALSE;
3625 }
3626
3627 INIT_FUNCTION
3628 NTSTATUS
3629 NTAPI
3630 IopUpdateRootKey(VOID)
3631 {
3632 UNICODE_STRING EnumU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Enum");
3633 UNICODE_STRING RootPathU = RTL_CONSTANT_STRING(L"Root");
3634 UNICODE_STRING MultiKeyPathU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\MultifunctionAdapter");
3635 OBJECT_ATTRIBUTES ObjectAttributes;
3636 HANDLE hEnum, hRoot;
3637 NTSTATUS Status;
3638
3639 InitializeObjectAttributes(&ObjectAttributes, &EnumU, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
3640 Status = ZwCreateKey(&hEnum, KEY_CREATE_SUB_KEY, &ObjectAttributes, 0, NULL, REG_OPTION_NON_VOLATILE, NULL);
3641 if (!NT_SUCCESS(Status))
3642 {
3643 DPRINT1("ZwCreateKey() failed with status 0x%08lx\n", Status);
3644 return Status;
3645 }
3646
3647 InitializeObjectAttributes(&ObjectAttributes, &RootPathU, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, hEnum, NULL);
3648 Status = ZwCreateKey(&hRoot, KEY_CREATE_SUB_KEY, &ObjectAttributes, 0, NULL, REG_OPTION_NON_VOLATILE, NULL);
3649 ZwClose(hEnum);
3650 if (!NT_SUCCESS(Status))
3651 {
3652 DPRINT1("ZwOpenKey() failed with status 0x%08lx\n", Status);
3653 return Status;
3654 }
3655
3656 if (!IopIsFirmwareMapperDisabled())
3657 {
3658 Status = IopOpenRegistryKeyEx(&hEnum, NULL, &MultiKeyPathU, KEY_ENUMERATE_SUB_KEYS);
3659 if (!NT_SUCCESS(Status))
3660 {
3661 /* Nothing to do, don't return with an error status */
3662 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
3663 ZwClose(hRoot);
3664 return STATUS_SUCCESS;
3665 }
3666 Status = IopEnumerateDetectedDevices(
3667 hEnum,
3668 NULL,
3669 hRoot,
3670 TRUE,
3671 NULL,
3672 0);
3673 ZwClose(hEnum);
3674 }
3675 else
3676 {
3677 /* Enumeration is disabled */
3678 Status = STATUS_SUCCESS;
3679 }
3680
3681 ZwClose(hRoot);
3682
3683 return Status;
3684 }
3685
3686 NTSTATUS
3687 NTAPI
3688 IopOpenRegistryKeyEx(PHANDLE KeyHandle,
3689 HANDLE ParentKey,
3690 PUNICODE_STRING Name,
3691 ACCESS_MASK DesiredAccess)
3692 {
3693 OBJECT_ATTRIBUTES ObjectAttributes;
3694 NTSTATUS Status;
3695
3696 PAGED_CODE();
3697
3698 *KeyHandle = NULL;
3699
3700 InitializeObjectAttributes(&ObjectAttributes,
3701 Name,
3702 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
3703 ParentKey,
3704 NULL);
3705
3706 Status = ZwOpenKey(KeyHandle, DesiredAccess, &ObjectAttributes);
3707
3708 return Status;
3709 }
3710
3711 NTSTATUS
3712 NTAPI
3713 IopCreateRegistryKeyEx(OUT PHANDLE Handle,
3714 IN HANDLE RootHandle OPTIONAL,
3715 IN PUNICODE_STRING KeyName,
3716 IN ACCESS_MASK DesiredAccess,
3717 IN ULONG CreateOptions,
3718 OUT PULONG Disposition OPTIONAL)
3719 {
3720 OBJECT_ATTRIBUTES ObjectAttributes;
3721 ULONG KeyDisposition, RootHandleIndex = 0, i = 1, NestedCloseLevel = 0;
3722 USHORT Length;
3723 HANDLE HandleArray[2];
3724 BOOLEAN Recursing = TRUE;
3725 PWCHAR pp, p, p1;
3726 UNICODE_STRING KeyString;
3727 NTSTATUS Status = STATUS_SUCCESS;
3728 PAGED_CODE();
3729
3730 /* P1 is start, pp is end */
3731 p1 = KeyName->Buffer;
3732 pp = (PVOID)((ULONG_PTR)p1 + KeyName->Length);
3733
3734 /* Create the target key */
3735 InitializeObjectAttributes(&ObjectAttributes,
3736 KeyName,
3737 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
3738 RootHandle,
3739 NULL);
3740 Status = ZwCreateKey(&HandleArray[i],
3741 DesiredAccess,
3742 &ObjectAttributes,
3743 0,
3744 NULL,
3745 CreateOptions,
3746 &KeyDisposition);
3747
3748 /* Now we check if this failed */
3749 if ((Status == STATUS_OBJECT_NAME_NOT_FOUND) && (RootHandle))
3750 {
3751 /* Target key failed, so we'll need to create its parent. Setup array */
3752 HandleArray[0] = NULL;
3753 HandleArray[1] = RootHandle;
3754
3755 /* Keep recursing for each missing parent */
3756 while (Recursing)
3757 {
3758 /* And if we're deep enough, close the last handle */
3759 if (NestedCloseLevel > 1) ZwClose(HandleArray[RootHandleIndex]);
3760
3761 /* We're setup to ping-pong between the two handle array entries */
3762 RootHandleIndex = i;
3763 i = (i + 1) & 1;
3764
3765 /* Clear the one we're attempting to open now */
3766 HandleArray[i] = NULL;
3767
3768 /* Process the parent key name */
3769 for (p = p1; ((p < pp) && (*p != OBJ_NAME_PATH_SEPARATOR)); p++);
3770 Length = (USHORT)(p - p1) * sizeof(WCHAR);
3771
3772 /* Is there a parent name? */
3773 if (Length)
3774 {
3775 /* Build the unicode string for it */
3776 KeyString.Buffer = p1;
3777 KeyString.Length = KeyString.MaximumLength = Length;
3778
3779 /* Now try opening the parent */
3780 InitializeObjectAttributes(&ObjectAttributes,
3781 &KeyString,
3782 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
3783 HandleArray[RootHandleIndex],
3784 NULL);
3785 Status = ZwCreateKey(&HandleArray[i],
3786 DesiredAccess,
3787 &ObjectAttributes,
3788 0,
3789 NULL,
3790 CreateOptions,
3791 &KeyDisposition);
3792 if (NT_SUCCESS(Status))
3793 {
3794 /* It worked, we have one more handle */
3795 NestedCloseLevel++;
3796 }
3797 else
3798 {
3799 /* Parent key creation failed, abandon loop */
3800 Recursing = FALSE;
3801 continue;
3802 }
3803 }
3804 else
3805 {
3806 /* We don't have a parent name, probably corrupted key name */
3807 Status = STATUS_INVALID_PARAMETER;
3808 Recursing = FALSE;
3809 continue;
3810 }
3811
3812 /* Now see if there's more parents to create */
3813 p1 = p + 1;
3814 if ((p == pp) || (p1 == pp))
3815 {
3816 /* We're done, hopefully successfully, so stop */
3817 Recursing = FALSE;
3818 }
3819 }
3820
3821 /* Outer loop check for handle nesting that requires closing the top handle */
3822 if (NestedCloseLevel > 1) ZwClose(HandleArray[RootHandleIndex]);
3823 }
3824
3825 /* Check if we broke out of the loop due to success */
3826 if (NT_SUCCESS(Status))
3827 {
3828 /* Return the target handle (we closed all the parent ones) and disposition */
3829 *Handle = HandleArray[i];
3830 if (Disposition) *Disposition = KeyDisposition;
3831 }
3832
3833 /* Return the success state */
3834 return Status;
3835 }
3836
3837 NTSTATUS
3838 NTAPI
3839 IopGetRegistryValue(IN HANDLE Handle,
3840 IN PWSTR ValueName,
3841 OUT PKEY_VALUE_FULL_INFORMATION *Information)
3842 {
3843 UNICODE_STRING ValueString;
3844 NTSTATUS Status;
3845 PKEY_VALUE_FULL_INFORMATION FullInformation;
3846 ULONG Size;
3847 PAGED_CODE();
3848
3849 RtlInitUnicodeString(&ValueString, ValueName);
3850
3851 Status = ZwQueryValueKey(Handle,
3852 &ValueString,
3853 KeyValueFullInformation,
3854 NULL,
3855 0,
3856 &Size);
3857 if ((Status != STATUS_BUFFER_OVERFLOW) &&
3858 (Status != STATUS_BUFFER_TOO_SMALL))
3859 {
3860 return Status;
3861 }
3862
3863 FullInformation = ExAllocatePool(NonPagedPool, Size);
3864 if (!FullInformation) return STATUS_INSUFFICIENT_RESOURCES;
3865
3866 Status = ZwQueryValueKey(Handle,
3867 &ValueString,
3868 KeyValueFullInformation,
3869 FullInformation,
3870 Size,
3871 &Size);
3872 if (!NT_SUCCESS(Status))
3873 {
3874 ExFreePool(FullInformation);
3875 return Status;
3876 }
3877
3878 *Information = FullInformation;
3879 return STATUS_SUCCESS;
3880 }
3881
3882 RTL_GENERIC_COMPARE_RESULTS
3883 NTAPI
3884 PiCompareInstancePath(IN PRTL_AVL_TABLE Table,
3885 IN PVOID FirstStruct,
3886 IN PVOID SecondStruct)
3887 {
3888 /* FIXME: TODO */
3889 ASSERT(FALSE);
3890 return 0;
3891 }
3892
3893 //
3894 // The allocation function is called by the generic table package whenever
3895 // it needs to allocate memory for the table.
3896 //
3897
3898 PVOID
3899 NTAPI
3900 PiAllocateGenericTableEntry(IN PRTL_AVL_TABLE Table,
3901 IN CLONG ByteSize)
3902 {
3903 /* FIXME: TODO */
3904 ASSERT(FALSE);
3905 return NULL;
3906 }
3907
3908 VOID
3909 NTAPI
3910 PiFreeGenericTableEntry(IN PRTL_AVL_TABLE Table,
3911 IN PVOID Buffer)
3912 {
3913 /* FIXME: TODO */
3914 ASSERT(FALSE);
3915 }
3916
3917 VOID
3918 NTAPI
3919 PpInitializeDeviceReferenceTable(VOID)
3920 {
3921 /* Setup the guarded mutex and AVL table */
3922 KeInitializeGuardedMutex(&PpDeviceReferenceTableLock);
3923 RtlInitializeGenericTableAvl(
3924 &PpDeviceReferenceTable,
3925 (PRTL_AVL_COMPARE_ROUTINE)PiCompareInstancePath,
3926 (PRTL_AVL_ALLOCATE_ROUTINE)PiAllocateGenericTableEntry,
3927 (PRTL_AVL_FREE_ROUTINE)PiFreeGenericTableEntry,
3928 NULL);
3929 }
3930
3931 BOOLEAN
3932 NTAPI
3933 PiInitPhase0(VOID)
3934 {
3935 /* Initialize the resource when accessing device registry data */
3936 ExInitializeResourceLite(&PpRegistryDeviceResource);
3937
3938 /* Setup the device reference AVL table */
3939 PpInitializeDeviceReferenceTable();
3940 return TRUE;
3941 }
3942
3943 BOOLEAN
3944 NTAPI
3945 PpInitSystem(VOID)
3946 {
3947 /* Check the initialization phase */
3948 switch (ExpInitializationPhase)
3949 {
3950 case 0:
3951
3952 /* Do Phase 0 */
3953 return PiInitPhase0();
3954
3955 case 1:
3956
3957 /* Do Phase 1 */
3958 return TRUE;
3959 //return PiInitPhase1();
3960
3961 default:
3962
3963 /* Don't know any other phase! Bugcheck! */
3964 KeBugCheck(UNEXPECTED_INITIALIZATION_CALL);
3965 return FALSE;
3966 }
3967 }
3968
3969 LONG IopNumberDeviceNodes;
3970
3971 PDEVICE_NODE
3972 NTAPI
3973 PipAllocateDeviceNode(IN PDEVICE_OBJECT PhysicalDeviceObject)
3974 {
3975 PDEVICE_NODE DeviceNode;
3976 PAGED_CODE();
3977
3978 /* Allocate it */
3979 DeviceNode = ExAllocatePoolWithTag(NonPagedPool, sizeof(DEVICE_NODE), TAG_IO_DEVNODE);
3980 if (!DeviceNode) return DeviceNode;
3981
3982 /* Statistics */
3983 InterlockedIncrement(&IopNumberDeviceNodes);
3984
3985 /* Set it up */
3986 RtlZeroMemory(DeviceNode, sizeof(DEVICE_NODE));
3987 DeviceNode->InterfaceType = InterfaceTypeUndefined;
3988 DeviceNode->BusNumber = -1;
3989 DeviceNode->ChildInterfaceType = InterfaceTypeUndefined;
3990 DeviceNode->ChildBusNumber = -1;
3991 DeviceNode->ChildBusTypeIndex = -1;
3992 // KeInitializeEvent(&DeviceNode->EnumerationMutex, SynchronizationEvent, TRUE);
3993 InitializeListHead(&DeviceNode->DeviceArbiterList);
3994 InitializeListHead(&DeviceNode->DeviceTranslatorList);
3995 InitializeListHead(&DeviceNode->TargetDeviceNotify);
3996 InitializeListHead(&DeviceNode->DockInfo.ListEntry);
3997 InitializeListHead(&DeviceNode->PendedSetInterfaceState);
3998
3999 /* Check if there is a PDO */
4000 if (PhysicalDeviceObject)
4001 {
4002 /* Link it and remove the init flag */
4003 DeviceNode->PhysicalDeviceObject = PhysicalDeviceObject;
4004 ((PEXTENDED_DEVOBJ_EXTENSION)PhysicalDeviceObject->DeviceObjectExtension)->DeviceNode = DeviceNode;
4005 PhysicalDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
4006 }
4007
4008 /* Return the node */
4009 return DeviceNode;
4010 }
4011
4012 /* PUBLIC FUNCTIONS **********************************************************/
4013
4014 NTSTATUS
4015 NTAPI
4016 PnpBusTypeGuidGet(IN USHORT Index,
4017 IN LPGUID BusTypeGuid)
4018 {
4019 NTSTATUS Status = STATUS_SUCCESS;
4020
4021 /* Acquire the lock */
4022 ExAcquireFastMutex(&PnpBusTypeGuidList->Lock);
4023
4024 /* Validate size */
4025 if (Index < PnpBusTypeGuidList->GuidCount)
4026 {
4027 /* Copy the data */
4028 RtlCopyMemory(BusTypeGuid, &PnpBusTypeGuidList->Guids[Index], sizeof(GUID));
4029 }
4030 else
4031 {
4032 /* Failure path */
4033 Status = STATUS_OBJECT_NAME_NOT_FOUND;
4034 }
4035
4036 /* Release lock and return status */
4037 ExReleaseFastMutex(&PnpBusTypeGuidList->Lock);
4038 return Status;
4039 }
4040
4041 NTSTATUS
4042 NTAPI
4043 PnpDeviceObjectToDeviceInstance(IN PDEVICE_OBJECT DeviceObject,
4044 IN PHANDLE DeviceInstanceHandle,
4045 IN ACCESS_MASK DesiredAccess)
4046 {
4047 NTSTATUS Status;
4048 HANDLE KeyHandle;
4049 PDEVICE_NODE DeviceNode;
4050 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET\\ENUM");
4051 PAGED_CODE();
4052
4053 /* Open the enum key */
4054 Status = IopOpenRegistryKeyEx(&KeyHandle,
4055 NULL,
4056 &KeyName,
4057 KEY_READ);
4058 if (!NT_SUCCESS(Status)) return Status;
4059
4060 /* Make sure we have an instance path */
4061 DeviceNode = IopGetDeviceNode(DeviceObject);
4062 if ((DeviceNode) && (DeviceNode->InstancePath.Length))
4063 {
4064 /* Get the instance key */
4065 Status = IopOpenRegistryKeyEx(DeviceInstanceHandle,
4066 KeyHandle,
4067 &DeviceNode->InstancePath,
4068 DesiredAccess);
4069 }
4070 else
4071 {
4072 /* Fail */
4073 Status = STATUS_INVALID_DEVICE_REQUEST;
4074 }
4075
4076 /* Close the handle and return status */
4077 ZwClose(KeyHandle);
4078 return Status;
4079 }
4080
4081 ULONG
4082 NTAPI
4083 PnpDetermineResourceListSize(IN PCM_RESOURCE_LIST ResourceList)
4084 {
4085 ULONG FinalSize, PartialSize, EntrySize, i, j;
4086 PCM_FULL_RESOURCE_DESCRIPTOR FullDescriptor;
4087 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor;
4088
4089 /* If we don't have one, that's easy */
4090 if (!ResourceList) return 0;
4091
4092 /* Start with the minimum size possible */
4093 FinalSize = FIELD_OFFSET(CM_RESOURCE_LIST, List);
4094
4095 /* Loop each full descriptor */
4096 FullDescriptor = ResourceList->List;
4097 for (i = 0; i < ResourceList->Count; i++)
4098 {
4099 /* Start with the minimum size possible */
4100 PartialSize = FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList) +
4101 FIELD_OFFSET(CM_PARTIAL_RESOURCE_LIST, PartialDescriptors);
4102
4103 /* Loop each partial descriptor */
4104 PartialDescriptor = FullDescriptor->PartialResourceList.PartialDescriptors;
4105 for (j = 0; j < FullDescriptor->PartialResourceList.Count; j++)
4106 {
4107 /* Start with the minimum size possible */
4108 EntrySize = sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
4109
4110 /* Check if there is extra data */
4111 if (PartialDescriptor->Type == CmResourceTypeDeviceSpecific)
4112 {
4113 /* Add that data */
4114 EntrySize += PartialDescriptor->u.DeviceSpecificData.DataSize;
4115 }
4116
4117 /* The size of partial descriptors is bigger */
4118 PartialSize += EntrySize;
4119
4120 /* Go to the next partial descriptor */
4121 PartialDescriptor = (PVOID)((ULONG_PTR)PartialDescriptor + EntrySize);
4122 }
4123
4124 /* The size of full descriptors is bigger */
4125 FinalSize += PartialSize;
4126
4127 /* Go to the next full descriptor */
4128 FullDescriptor = (PVOID)((ULONG_PTR)FullDescriptor + PartialSize);
4129 }
4130
4131 /* Return the final size */
4132 return FinalSize;
4133 }
4134
4135 NTSTATUS
4136 NTAPI
4137 PiGetDeviceRegistryProperty(IN PDEVICE_OBJECT DeviceObject,
4138 IN ULONG ValueType,
4139 IN PWSTR ValueName,
4140 IN PWSTR KeyName,
4141 OUT PVOID Buffer,
4142 IN PULONG BufferLength)
4143 {
4144 NTSTATUS Status;
4145 HANDLE KeyHandle, SubHandle;
4146 UNICODE_STRING KeyString;
4147 PKEY_VALUE_FULL_INFORMATION KeyValueInfo = NULL;
4148 ULONG Length;
4149 PAGED_CODE();
4150
4151 /* Find the instance key */
4152 Status = PnpDeviceObjectToDeviceInstance(DeviceObject, &KeyHandle, KEY_READ);
4153 if (NT_SUCCESS(Status))
4154 {
4155 /* Check for name given by caller */
4156 if (KeyName)
4157 {
4158 /* Open this key */
4159 RtlInitUnicodeString(&KeyString, KeyName);
4160 Status = IopOpenRegistryKeyEx(&SubHandle,
4161 KeyHandle,
4162 &KeyString,
4163 KEY_READ);
4164 if (NT_SUCCESS(Status))
4165 {
4166 /* And use this handle instead */
4167 ZwClose(KeyHandle);
4168 KeyHandle = SubHandle;
4169 }
4170 }
4171
4172 /* Check if sub-key handle succeeded (or no-op if no key name given) */
4173 if (NT_SUCCESS(Status))
4174 {
4175 /* Now get the size of the property */
4176 Status = IopGetRegistryValue(KeyHandle,
4177 ValueName,
4178 &KeyValueInfo);
4179 }
4180
4181 /* Close the key */
4182 ZwClose(KeyHandle);
4183 }
4184
4185 /* Fail if any of the registry operations failed */
4186 if (!NT_SUCCESS(Status)) return Status;
4187
4188 /* Check how much data we have to copy */
4189 Length = KeyValueInfo->DataLength;
4190 if (*BufferLength >= Length)
4191 {
4192 /* Check for a match in the value type */
4193 if (KeyValueInfo->Type == ValueType)
4194 {
4195 /* Copy the data */
4196 RtlCopyMemory(Buffer,
4197 (PVOID)((ULONG_PTR)KeyValueInfo +
4198 KeyValueInfo->DataOffset),
4199 Length);
4200 }
4201 else
4202 {
4203 /* Invalid registry property type, fail */
4204 Status = STATUS_INVALID_PARAMETER_2;
4205 }
4206 }
4207 else
4208 {
4209 /* Buffer is too small to hold data */
4210 Status = STATUS_BUFFER_TOO_SMALL;
4211 }
4212
4213 /* Return the required buffer length, free the buffer, and return status */
4214 *BufferLength = Length;
4215 ExFreePool(KeyValueInfo);
4216 return Status;
4217 }
4218
4219 #define PIP_RETURN_DATA(x, y) {ReturnLength = x; Data = y; Status = STATUS_SUCCESS; break;}
4220 #define PIP_REGISTRY_DATA(x, y) {ValueName = x; ValueType = y; break;}
4221 #define PIP_UNIMPLEMENTED() {UNIMPLEMENTED_DBGBREAK(); break;}
4222
4223 /*
4224 * @implemented
4225 */
4226 NTSTATUS
4227 NTAPI
4228 IoGetDeviceProperty(IN PDEVICE_OBJECT DeviceObject,
4229 IN DEVICE_REGISTRY_PROPERTY DeviceProperty,
4230 IN ULONG BufferLength,
4231 OUT PVOID PropertyBuffer,
4232 OUT PULONG ResultLength)
4233 {
4234 PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject);
4235 DEVICE_CAPABILITIES DeviceCaps;
4236 ULONG ReturnLength = 0, Length = 0, ValueType;
4237 PWCHAR ValueName = NULL, EnumeratorNameEnd, DeviceInstanceName;
4238 PVOID Data = NULL;
4239 NTSTATUS Status = STATUS_BUFFER_TOO_SMALL;
4240 GUID BusTypeGuid;
4241 POBJECT_NAME_INFORMATION ObjectNameInfo = NULL;
4242 BOOLEAN NullTerminate = FALSE;
4243 DEVICE_REMOVAL_POLICY Policy;
4244
4245 DPRINT("IoGetDeviceProperty(0x%p %d)\n", DeviceObject, DeviceProperty);
4246
4247 /* Assume failure */
4248 *ResultLength = 0;
4249
4250 /* Only PDOs can call this */
4251 if (!DeviceNode) return STATUS_INVALID_DEVICE_REQUEST;
4252
4253 /* Handle all properties */
4254 switch (DeviceProperty)
4255 {
4256 case DevicePropertyBusTypeGuid:
4257
4258 /* Get the GUID from the internal cache */
4259 Status = PnpBusTypeGuidGet(DeviceNode->ChildBusTypeIndex, &BusTypeGuid);
4260 if (!NT_SUCCESS(Status)) return Status;
4261
4262 /* This is the format of the returned data */
4263 PIP_RETURN_DATA(sizeof(GUID), &BusTypeGuid);
4264
4265 case DevicePropertyLegacyBusType:
4266
4267 /* Validate correct interface type */
4268 if (DeviceNode->ChildInterfaceType == InterfaceTypeUndefined)
4269 return STATUS_OBJECT_NAME_NOT_FOUND;
4270
4271 /* This is the format of the returned data */
4272 PIP_RETURN_DATA(sizeof(INTERFACE_TYPE), &DeviceNode->ChildInterfaceType);
4273
4274 case DevicePropertyBusNumber:
4275
4276 /* Validate correct bus number */
4277 if ((DeviceNode->ChildBusNumber & 0x80000000) == 0x80000000)
4278 return STATUS_OBJECT_NAME_NOT_FOUND;
4279
4280 /* This is the format of the returned data */
4281 PIP_RETURN_DATA(sizeof(ULONG), &DeviceNode->ChildBusNumber);
4282
4283 case DevicePropertyEnumeratorName:
4284
4285 /* Get the instance path */
4286 DeviceInstanceName = DeviceNode->InstancePath.Buffer;
4287
4288 /* Sanity checks */
4289 ASSERT((BufferLength & 1) == 0);
4290 ASSERT(DeviceInstanceName != NULL);
4291
4292 /* Get the name from the path */
4293 EnumeratorNameEnd = wcschr(DeviceInstanceName, OBJ_NAME_PATH_SEPARATOR);
4294 ASSERT(EnumeratorNameEnd);
4295
4296 /* This string needs to be NULL-terminated */
4297 NullTerminate = TRUE;
4298
4299 /* This is the format of the returned data */
4300 PIP_RETURN_DATA((ULONG)(EnumeratorNameEnd - DeviceInstanceName) * sizeof(WCHAR),
4301 DeviceInstanceName);
4302
4303 case DevicePropertyAddress:
4304
4305 /* Query the device caps */
4306 Status = IopQueryDeviceCapabilities(DeviceNode, &DeviceCaps);
4307 if (!NT_SUCCESS(Status) || (DeviceCaps.Address == MAXULONG))
4308 return STATUS_OBJECT_NAME_NOT_FOUND;
4309
4310 /* This is the format of the returned data */
4311 PIP_RETURN_DATA(sizeof(ULONG), &DeviceCaps.Address);
4312
4313 case DevicePropertyBootConfigurationTranslated:
4314
4315 /* Validate we have resources */
4316 if (!DeviceNode->BootResources)
4317 // if (!DeviceNode->BootResourcesTranslated) // FIXFIX: Need this field
4318 {
4319 /* No resources will still fake success, but with 0 bytes */
4320 *ResultLength = 0;
4321 return STATUS_SUCCESS;
4322 }
4323
4324 /* This is the format of the returned data */
4325 PIP_RETURN_DATA(PnpDetermineResourceListSize(DeviceNode->BootResources), // FIXFIX: Should use BootResourcesTranslated
4326 DeviceNode->BootResources); // FIXFIX: Should use BootResourcesTranslated
4327
4328 case DevicePropertyPhysicalDeviceObjectName:
4329
4330 /* Sanity check for Unicode-sized string */
4331 ASSERT((BufferLength & 1) == 0);
4332
4333 /* Allocate name buffer */
4334 Length = BufferLength + sizeof(OBJECT_NAME_INFORMATION);
4335 ObjectNameInfo = ExAllocatePool(PagedPool, Length);
4336 if (!ObjectNameInfo) return STATUS_INSUFFICIENT_RESOURCES;
4337
4338 /* Query the PDO name */
4339 Status = ObQueryNameString(DeviceObject,
4340 ObjectNameInfo,
4341 Length,
4342 ResultLength);
4343 if (Status == STATUS_INFO_LENGTH_MISMATCH)
4344 {
4345 /* It's up to the caller to try again */
4346 Status = STATUS_BUFFER_TOO_SMALL;
4347 }
4348
4349 /* This string needs to be NULL-terminated */
4350 NullTerminate = TRUE;
4351
4352 /* Return if successful */
4353 if (NT_SUCCESS(Status)) PIP_RETURN_DATA(ObjectNameInfo->Name.Length,
4354 ObjectNameInfo->Name.Buffer);
4355
4356 /* Let the caller know how big the name is */
4357 *ResultLength -= sizeof(OBJECT_NAME_INFORMATION);
4358 break;
4359
4360 case DevicePropertyRemovalPolicy:
4361
4362 Policy = DeviceNode->RemovalPolicy;
4363 PIP_RETURN_DATA(sizeof(Policy), &Policy);
4364
4365 /* Handle the registry-based properties */
4366 case DevicePropertyUINumber:
4367 PIP_REGISTRY_DATA(REGSTR_VAL_UI_NUMBER, REG_DWORD);
4368 case DevicePropertyLocationInformation:
4369 PIP_REGISTRY_DATA(REGSTR_VAL_LOCATION_INFORMATION, REG_SZ);
4370 case DevicePropertyDeviceDescription:
4371 PIP_REGISTRY_DATA(REGSTR_VAL_DEVDESC, REG_SZ);
4372 case DevicePropertyHardwareID:
4373 PIP_REGISTRY_DATA(REGSTR_VAL_HARDWAREID, REG_MULTI_SZ);
4374 case DevicePropertyCompatibleIDs:
4375 PIP_REGISTRY_DATA(REGSTR_VAL_COMPATIBLEIDS, REG_MULTI_SZ);
4376 case DevicePropertyBootConfiguration:
4377 PIP_REGISTRY_DATA(REGSTR_VAL_BOOTCONFIG, REG_RESOURCE_LIST);
4378 case DevicePropertyClassName:
4379 PIP_REGISTRY_DATA(REGSTR_VAL_CLASS, REG_SZ);
4380 case DevicePropertyClassGuid:
4381 PIP_REGISTRY_DATA(REGSTR_VAL_CLASSGUID, REG_SZ);
4382 case DevicePropertyDriverKeyName:
4383 PIP_REGISTRY_DATA(REGSTR_VAL_DRIVER, REG_SZ);
4384 case DevicePropertyManufacturer:
4385 PIP_REGISTRY_DATA(REGSTR_VAL_MFG, REG_SZ);
4386 case DevicePropertyFriendlyName:
4387 PIP_REGISTRY_DATA(REGSTR_VAL_FRIENDLYNAME, REG_SZ);
4388 case DevicePropertyContainerID:
4389 //PIP_REGISTRY_DATA(REGSTR_VAL_CONTAINERID, REG_SZ); // Win7
4390 PIP_UNIMPLEMENTED();
4391 break;
4392 case DevicePropertyInstallState:
4393 PIP_REGISTRY_DATA(REGSTR_VAL_CONFIGFLAGS, REG_DWORD);
4394 break;
4395 case DevicePropertyResourceRequirements:
4396 PIP_UNIMPLEMENTED();
4397 case DevicePropertyAllocatedResources:
4398 PIP_UNIMPLEMENTED();
4399 default:
4400 return STATUS_INVALID_PARAMETER_2;
4401 }
4402
4403 /* Having a registry value name implies registry data */
4404 if (ValueName)
4405 {
4406 /* We know up-front how much data to expect */
4407 *ResultLength = BufferLength;
4408
4409 /* Go get the data, use the LogConf subkey if necessary */
4410 Status = PiGetDeviceRegistryProperty(DeviceObject,
4411 ValueType,
4412 ValueName,
4413 (DeviceProperty ==
4414 DevicePropertyBootConfiguration) ?
4415 L"LogConf": NULL,
4416 PropertyBuffer,
4417 ResultLength);
4418 }
4419 else if (NT_SUCCESS(Status))
4420 {
4421 /* We know up-front how much data to expect, check the caller's buffer */
4422 *ResultLength = ReturnLength + (NullTerminate ? sizeof(UNICODE_NULL) : 0);
4423 if (*ResultLength <= BufferLength)
4424 {
4425 /* Buffer is all good, copy the data */
4426 RtlCopyMemory(PropertyBuffer, Data, ReturnLength);
4427
4428 /* Check if we need to NULL-terminate the string */
4429 if (NullTerminate)
4430 {
4431 /* Terminate the string */
4432 ((PWCHAR)PropertyBuffer)[ReturnLength / sizeof(WCHAR)] = UNICODE_NULL;
4433 }
4434
4435 /* This is the success path */
4436 Status = STATUS_SUCCESS;
4437 }
4438 else
4439 {
4440 /* Failure path */
4441 Status = STATUS_BUFFER_TOO_SMALL;
4442 }
4443 }
4444
4445 /* Free any allocation we may have made, and return the status code */
4446 if (ObjectNameInfo) ExFreePool(ObjectNameInfo);
4447 return Status;
4448 }
4449
4450 /*
4451 * @implemented
4452 */
4453 VOID
4454 NTAPI
4455 IoInvalidateDeviceState(IN PDEVICE_OBJECT PhysicalDeviceObject)
4456 {
4457 PDEVICE_NODE DeviceNode = IopGetDeviceNode(PhysicalDeviceObject);
4458 IO_STACK_LOCATION Stack;
4459 ULONG PnPFlags;
4460 NTSTATUS Status;
4461 IO_STATUS_BLOCK IoStatusBlock;
4462
4463 RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION));
4464 Stack.MajorFunction = IRP_MJ_PNP;
4465 Stack.MinorFunction = IRP_MN_QUERY_PNP_DEVICE_STATE;
4466
4467 Status = IopSynchronousCall(PhysicalDeviceObject, &Stack, (PVOID*)&PnPFlags);
4468 if (!NT_SUCCESS(Status))
4469 {
4470 if (Status != STATUS_NOT_SUPPORTED)
4471 {
4472 DPRINT1("IRP_MN_QUERY_PNP_DEVICE_STATE failed with status 0x%lx\n", Status);
4473 }
4474 return;
4475 }
4476
4477 if (PnPFlags & PNP_DEVICE_NOT_DISABLEABLE)
4478 DeviceNode->UserFlags |= DNUF_NOT_DISABLEABLE;
4479 else
4480 DeviceNode->UserFlags &= ~DNUF_NOT_DISABLEABLE;
4481
4482 if (PnPFlags & PNP_DEVICE_DONT_DISPLAY_IN_UI)
4483 DeviceNode->UserFlags |= DNUF_DONT_SHOW_IN_UI;
4484 else
4485 DeviceNode->UserFlags &= ~DNUF_DONT_SHOW_IN_UI;
4486
4487 if ((PnPFlags & PNP_DEVICE_REMOVED) ||
4488 ((PnPFlags & PNP_DEVICE_FAILED) && !(PnPFlags & PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED)))
4489 {
4490 /* Flag it if it's failed */
4491 if (PnPFlags & PNP_DEVICE_FAILED) DeviceNode->Problem = CM_PROB_FAILED_POST_START;
4492
4493 /* Send removal IRPs to all of its children */
4494 IopPrepareDeviceForRemoval(PhysicalDeviceObject, TRUE);
4495
4496 /* Send surprise removal */
4497 IopSendSurpriseRemoval(PhysicalDeviceObject);
4498
4499 /* Tell the user-mode PnP manager that a device was removed */
4500 IopQueueTargetDeviceEvent(&GUID_DEVICE_SURPRISE_REMOVAL,
4501 &DeviceNode->InstancePath);
4502
4503 IopSendRemoveDevice(PhysicalDeviceObject);
4504 }
4505 else if ((PnPFlags & PNP_DEVICE_FAILED) && (PnPFlags & PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED))
4506 {
4507 /* Stop for resource rebalance */
4508 Status = IopStopDevice(DeviceNode);
4509 if (!NT_SUCCESS(Status))
4510 {
4511 DPRINT1("Failed to stop device for rebalancing\n");
4512
4513 /* Stop failed so don't rebalance */
4514 PnPFlags &= ~PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED;
4515 }
4516 }
4517
4518 /* Resource rebalance */
4519 if (PnPFlags & PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED)
4520 {
4521 DPRINT("Sending IRP_MN_QUERY_RESOURCES to device stack\n");
4522
4523 Status = IopInitiatePnpIrp(PhysicalDeviceObject,
4524 &IoStatusBlock,
4525 IRP_MN_QUERY_RESOURCES,
4526 NULL);
4527 if (NT_SUCCESS(Status) && IoStatusBlock.Information)
4528 {
4529 DeviceNode->BootResources =
4530 (PCM_RESOURCE_LIST)IoStatusBlock.Information;
4531 IopDeviceNodeSetFlag(DeviceNode, DNF_HAS_BOOT_CONFIG);
4532 }
4533 else
4534 {
4535 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status);
4536 DeviceNode->BootResources = NULL;
4537 }
4538
4539 DPRINT("Sending IRP_MN_QUERY_RESOURCE_REQUIREMENTS to device stack\n");
4540
4541 Status = IopInitiatePnpIrp(PhysicalDeviceObject,
4542 &IoStatusBlock,
4543 IRP_MN_QUERY_RESOURCE_REQUIREMENTS,
4544 NULL);
4545 if (NT_SUCCESS(Status))
4546 {
4547 DeviceNode->ResourceRequirements =
4548 (PIO_RESOURCE_REQUIREMENTS_LIST)IoStatusBlock.Information;
4549 }
4550 else
4551 {
4552 DPRINT("IopInitiatePnpIrp() failed (Status %08lx)\n", Status);
4553 DeviceNode->ResourceRequirements = NULL;
4554 }
4555
4556 /* IRP_MN_FILTER_RESOURCE_REQUIREMENTS is called indirectly by IopStartDevice */
4557 if (IopStartDevice(DeviceNode) != STATUS_SUCCESS)
4558 {
4559 DPRINT1("Restart after resource rebalance failed\n");
4560
4561 DeviceNode->Flags &= ~(DNF_STARTED | DNF_START_REQUEST_PENDING);
4562 DeviceNode->Flags |= DNF_START_FAILED;
4563
4564 IopRemoveDevice(DeviceNode);
4565 }
4566 }
4567 }
4568
4569 /**
4570 * @name IoOpenDeviceRegistryKey
4571 *
4572 * Open a registry key unique for a specified driver or device instance.
4573 *
4574 * @param DeviceObject Device to get the registry key for.
4575 * @param DevInstKeyType Type of the key to return.
4576 * @param DesiredAccess Access mask (eg. KEY_READ | KEY_WRITE).
4577 * @param DevInstRegKey Handle to the opened registry key on
4578 * successful return.
4579 *
4580 * @return Status.
4581 *
4582 * @implemented
4583 */
4584 NTSTATUS
4585 NTAPI
4586 IoOpenDeviceRegistryKey(IN PDEVICE_OBJECT DeviceObject,
4587 IN ULONG DevInstKeyType,
4588 IN ACCESS_MASK DesiredAccess,
4589 OUT PHANDLE DevInstRegKey)
4590 {
4591 static WCHAR RootKeyName[] =
4592 L"\\Registry\\Machine\\System\\CurrentControlSet\\";
4593 static WCHAR ProfileKeyName[] =
4594 L"Hardware Profiles\\Current\\System\\CurrentControlSet\\";
4595 static WCHAR ClassKeyName[] = L"Control\\Class\\";
4596 static WCHAR EnumKeyName[] = L"Enum\\";
4597 static WCHAR DeviceParametersKeyName[] = L"Device Parameters";
4598 ULONG KeyNameLength;
4599 PWSTR KeyNameBuffer;
4600 UNICODE_STRING KeyName;
4601 ULONG DriverKeyLength;
4602 OBJECT_ATTRIBUTES ObjectAttributes;
4603 PDEVICE_NODE DeviceNode = NULL;
4604 NTSTATUS Status;
4605
4606 DPRINT("IoOpenDeviceRegistryKey() called\n");
4607
4608 if ((DevInstKeyType & (PLUGPLAY_REGKEY_DEVICE | PLUGPLAY_REGKEY_DRIVER)) == 0)
4609 {
4610 DPRINT1("IoOpenDeviceRegistryKey(): got wrong params, exiting... \n");
4611 return STATUS_INVALID_PARAMETER;
4612 }
4613
4614 if (!IopIsValidPhysicalDeviceObject(DeviceObject))
4615 return STATUS_INVALID_DEVICE_REQUEST;
4616 DeviceNode = IopGetDeviceNode(DeviceObject);
4617
4618 /*
4619 * Calculate the length of the base key name. This is the full
4620 * name for driver key or the name excluding "Device Parameters"
4621 * subkey for device key.
4622 */
4623
4624 KeyNameLength = sizeof(RootKeyName);
4625 if (DevInstKeyType & PLUGPLAY_REGKEY_CURRENT_HWPROFILE)
4626 KeyNameLength += sizeof(ProfileKeyName) - sizeof(UNICODE_NULL);
4627 if (DevInstKeyType & PLUGPLAY_REGKEY_DRIVER)
4628 {
4629 KeyNameLength += sizeof(ClassKeyName) - sizeof(UNICODE_NULL);
4630 Status = IoGetDeviceProperty(DeviceObject, DevicePropertyDriverKeyName,
4631 0, NULL, &DriverKeyLength);
4632 if (Status != STATUS_BUFFER_TOO_SMALL)
4633 return Status;
4634 KeyNameLength += DriverKeyLength;
4635 }
4636 else
4637 {
4638 KeyNameLength += sizeof(EnumKeyName) - sizeof(UNICODE_NULL) +
4639 DeviceNode->InstancePath.Length;
4640 }
4641
4642 /*
4643 * Now allocate the buffer for the key name...
4644 */
4645
4646 KeyNameBuffer = ExAllocatePool(PagedPool, KeyNameLength);
4647 if (KeyNameBuffer == NULL)
4648 return STATUS_INSUFFICIENT_RESOURCES;
4649
4650 KeyName.Length = 0;
4651 KeyName.MaximumLength = (USHORT)KeyNameLength;
4652 KeyName.Buffer = KeyNameBuffer;
4653
4654 /*
4655 * ...and build the key name.
4656 */
4657
4658 KeyName.Length += sizeof(RootKeyName) - sizeof(UNICODE_NULL);
4659 RtlCopyMemory(KeyNameBuffer, RootKeyName, KeyName.Length);
4660
4661 if (DevInstKeyType & PLUGPLAY_REGKEY_CURRENT_HWPROFILE)
4662 RtlAppendUnicodeToString(&KeyName, ProfileKeyName);
4663
4664 if (DevInstKeyType & PLUGPLAY_REGKEY_DRIVER)
4665 {
4666 RtlAppendUnicodeToString(&KeyName, ClassKeyName);
4667 Status = IoGetDeviceProperty(DeviceObject, DevicePropertyDriverKeyName,
4668 DriverKeyLength, KeyNameBuffer +
4669 (KeyName.Length / sizeof(WCHAR)),
4670 &DriverKeyLength);
4671 if (!NT_SUCCESS(Status))
4672 {
4673 DPRINT1("Call to IoGetDeviceProperty() failed with Status 0x%08lx\n", Status);
4674 ExFreePool(KeyNameBuffer);
4675 return Status;
4676 }
4677 KeyName.Length += (USHORT)DriverKeyLength - sizeof(UNICODE_NULL);
4678 }
4679 else
4680 {
4681 RtlAppendUnicodeToString(&KeyName, EnumKeyName);
4682 Status = RtlAppendUnicodeStringToString(&KeyName, &DeviceNode->InstancePath);
4683 if (DeviceNode->InstancePath.Length == 0)
4684 {
4685 ExFreePool(KeyNameBuffer);
4686 return Status;
4687 }
4688 }
4689
4690 /*
4691 * Open the base key.
4692 */
4693 Status = IopOpenRegistryKeyEx(DevInstRegKey, NULL, &KeyName, DesiredAccess);
4694 if (!NT_SUCCESS(Status))
4695 {
4696 DPRINT1("IoOpenDeviceRegistryKey(%wZ): Base key doesn't exist, exiting... (Status 0x%08lx)\n", &KeyName, Status);
4697 ExFreePool(KeyNameBuffer);
4698 return Status;
4699 }
4700 ExFreePool(KeyNameBuffer);
4701
4702 /*
4703 * For driver key we're done now.
4704 */
4705
4706 if (DevInstKeyType & PLUGPLAY_REGKEY_DRIVER)
4707 return Status;
4708
4709 /*
4710 * Let's go further. For device key we must open "Device Parameters"
4711 * subkey and create it if it doesn't exist yet.
4712 */
4713
4714 RtlInitUnicodeString(&KeyName, DeviceParametersKeyName);
4715 InitializeObjectAttributes(&ObjectAttributes,
4716 &KeyName,
4717 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
4718 *DevInstRegKey,
4719 NULL);
4720 Status = ZwCreateKey(DevInstRegKey,
4721 DesiredAccess,
4722 &ObjectAttributes,
4723 0,
4724 NULL,
4725 REG_OPTION_NON_VOLATILE,
4726 NULL);
4727 ZwClose(ObjectAttributes.RootDirectory);
4728
4729 return Status;
4730 }
4731
4732 static
4733 NTSTATUS
4734 IopQueryRemoveChildDevices(PDEVICE_NODE ParentDeviceNode, BOOLEAN Force)
4735 {
4736 PDEVICE_NODE ChildDeviceNode, NextDeviceNode, FailedRemoveDevice;
4737 NTSTATUS Status;
4738 KIRQL OldIrql;
4739
4740 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
4741 ChildDeviceNode = ParentDeviceNode->Child;
4742 while (ChildDeviceNode != NULL)
4743 {
4744 NextDeviceNode = ChildDeviceNode->Sibling;
4745 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
4746
4747 Status = IopPrepareDeviceForRemoval(ChildDeviceNode->PhysicalDeviceObject, Force);
4748 if (!NT_SUCCESS(Status))
4749 {
4750 FailedRemoveDevice = ChildDeviceNode;
4751 goto cleanup;
4752 }
4753
4754 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
4755 ChildDeviceNode = NextDeviceNode;
4756 }
4757 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
4758
4759 return STATUS_SUCCESS;
4760
4761 cleanup:
4762 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
4763 ChildDeviceNode = ParentDeviceNode->Child;
4764 while (ChildDeviceNode != NULL)
4765 {
4766 NextDeviceNode = ChildDeviceNode->Sibling;
4767 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
4768
4769 IopCancelPrepareDeviceForRemoval(ChildDeviceNode->PhysicalDeviceObject);
4770
4771 /* IRP_MN_CANCEL_REMOVE_DEVICE is also sent to the device
4772 * that failed the IRP_MN_QUERY_REMOVE_DEVICE request */
4773 if (ChildDeviceNode == FailedRemoveDevice)
4774 return Status;
4775
4776 ChildDeviceNode = NextDeviceNode;
4777
4778 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
4779 }
4780 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
4781
4782 return Status;
4783 }
4784
4785 static
4786 VOID
4787 IopSendRemoveChildDevices(PDEVICE_NODE ParentDeviceNode)
4788 {
4789 PDEVICE_NODE ChildDeviceNode, NextDeviceNode;
4790 KIRQL OldIrql;
4791
4792 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
4793 ChildDeviceNode = ParentDeviceNode->Child;
4794 while (ChildDeviceNode != NULL)
4795 {
4796 NextDeviceNode = ChildDeviceNode->Sibling;
4797 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
4798
4799 IopSendRemoveDevice(ChildDeviceNode->PhysicalDeviceObject);
4800
4801 ChildDeviceNode = NextDeviceNode;
4802
4803 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
4804 }
4805 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
4806 }
4807
4808 static
4809 VOID
4810 IopCancelRemoveChildDevices(PDEVICE_NODE ParentDeviceNode)
4811 {
4812 PDEVICE_NODE ChildDeviceNode, NextDeviceNode;
4813 KIRQL OldIrql;
4814
4815 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
4816 ChildDeviceNode = ParentDeviceNode->Child;
4817 while (ChildDeviceNode != NULL)
4818 {
4819 NextDeviceNode = ChildDeviceNode->Sibling;
4820 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
4821
4822 IopCancelPrepareDeviceForRemoval(ChildDeviceNode->PhysicalDeviceObject);
4823
4824 ChildDeviceNode = NextDeviceNode;
4825
4826 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
4827 }
4828 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
4829 }
4830
4831 static
4832 NTSTATUS
4833 IopQueryRemoveDeviceRelations(PDEVICE_RELATIONS DeviceRelations, BOOLEAN Force)
4834 {
4835 /* This function DOES NOT dereference the device objects on SUCCESS
4836 * but it DOES dereference device objects on FAILURE */
4837
4838 ULONG i, j;
4839 NTSTATUS Status;
4840
4841 for (i = 0; i < DeviceRelations->Count; i++)
4842 {
4843 Status = IopPrepareDeviceForRemoval(DeviceRelations->Objects[i], Force);
4844 if (!NT_SUCCESS(Status))
4845 {
4846 j = i;
4847 goto cleanup;
4848 }
4849 }
4850
4851 return STATUS_SUCCESS;
4852
4853 cleanup:
4854 /* IRP_MN_CANCEL_REMOVE_DEVICE is also sent to the device
4855 * that failed the IRP_MN_QUERY_REMOVE_DEVICE request */
4856 for (i = 0; i <= j; i++)
4857 {
4858 IopCancelPrepareDeviceForRemoval(DeviceRelations->Objects[i]);
4859 ObDereferenceObject(DeviceRelations->Objects[i]);
4860 DeviceRelations->Objects[i] = NULL;
4861 }
4862 for (; i < DeviceRelations->Count; i++)
4863 {
4864 ObDereferenceObject(DeviceRelations->Objects[i]);
4865 DeviceRelations->Objects[i] = NULL;
4866 }
4867 ExFreePool(DeviceRelations);
4868
4869 return Status;
4870 }
4871
4872 static
4873 VOID
4874 IopSendRemoveDeviceRelations(PDEVICE_RELATIONS DeviceRelations)
4875 {
4876 /* This function DOES dereference the device objects in all cases */
4877
4878 ULONG i;
4879
4880 for (i = 0; i < DeviceRelations->Count; i++)
4881 {
4882 IopSendRemoveDevice(DeviceRelations->Objects[i]);
4883 DeviceRelations->Objects[i] = NULL;
4884 }
4885
4886 ExFreePool(DeviceRelations);
4887 }
4888
4889 static
4890 VOID
4891 IopCancelRemoveDeviceRelations(PDEVICE_RELATIONS DeviceRelations)
4892 {
4893 /* This function DOES dereference the device objects in all cases */
4894
4895 ULONG i;
4896
4897 for (i = 0; i < DeviceRelations->Count; i++)
4898 {
4899 IopCancelPrepareDeviceForRemoval(DeviceRelations->Objects[i]);
4900 ObDereferenceObject(DeviceRelations->Objects[i]);
4901 DeviceRelations->Objects[i] = NULL;
4902 }
4903
4904 ExFreePool(DeviceRelations);
4905 }
4906
4907 VOID
4908 IopCancelPrepareDeviceForRemoval(PDEVICE_OBJECT DeviceObject)
4909 {
4910 IO_STACK_LOCATION Stack;
4911 IO_STATUS_BLOCK IoStatusBlock;
4912 PDEVICE_RELATIONS DeviceRelations;
4913 NTSTATUS Status;
4914
4915 IopCancelRemoveDevice(DeviceObject);
4916
4917 Stack.Parameters.QueryDeviceRelations.Type = RemovalRelations;
4918
4919 Status = IopInitiatePnpIrp(DeviceObject,
4920 &IoStatusBlock,
4921 IRP_MN_QUERY_DEVICE_RELATIONS,
4922 &Stack);
4923 if (!NT_SUCCESS(Status))
4924 {
4925 DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status);
4926 DeviceRelations = NULL;
4927 }
4928 else
4929 {
4930 DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information;
4931 }
4932
4933 if (DeviceRelations)
4934 IopCancelRemoveDeviceRelations(DeviceRelations);
4935 }
4936
4937 NTSTATUS
4938 IopPrepareDeviceForRemoval(IN PDEVICE_OBJECT DeviceObject, BOOLEAN Force)
4939 {
4940 PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject);
4941 IO_STACK_LOCATION Stack;
4942 IO_STATUS_BLOCK IoStatusBlock;
4943 PDEVICE_RELATIONS DeviceRelations;
4944 NTSTATUS Status;
4945
4946 if ((DeviceNode->UserFlags & DNUF_NOT_DISABLEABLE) && !Force)
4947 {
4948 DPRINT1("Removal not allowed for %wZ\n", &DeviceNode->InstancePath);
4949 return STATUS_UNSUCCESSFUL;
4950 }
4951
4952 if (!Force && IopQueryRemoveDevice(DeviceObject) != STATUS_SUCCESS)
4953 {
4954 DPRINT1("Removal vetoed by failing the query remove request\n");
4955
4956 IopCancelRemoveDevice(DeviceObject);
4957
4958 return STATUS_UNSUCCESSFUL;
4959 }
4960
4961 Stack.Parameters.QueryDeviceRelations.Type = RemovalRelations;
4962
4963 Status = IopInitiatePnpIrp(DeviceObject,
4964 &IoStatusBlock,
4965 IRP_MN_QUERY_DEVICE_RELATIONS,
4966 &Stack);
4967 if (!NT_SUCCESS(Status))
4968 {
4969 DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status);
4970 DeviceRelations = NULL;
4971 }
4972 else
4973 {
4974 DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information;
4975 }
4976
4977 if (DeviceRelations)
4978 {
4979 Status = IopQueryRemoveDeviceRelations(DeviceRelations, Force);
4980 if (!NT_SUCCESS(Status))
4981 return Status;
4982 }
4983
4984 Status = IopQueryRemoveChildDevices(DeviceNode, Force);
4985 if (!NT_SUCCESS(Status))
4986 {
4987 if (DeviceRelations)
4988 IopCancelRemoveDeviceRelations(DeviceRelations);
4989 return Status;
4990 }
4991
4992 if (DeviceRelations)
4993 IopSendRemoveDeviceRelations(DeviceRelations);
4994 IopSendRemoveChildDevices(DeviceNode);
4995
4996 return STATUS_SUCCESS;
4997 }
4998
4999 NTSTATUS
5000 IopRemoveDevice(PDEVICE_NODE DeviceNode)
5001 {
5002 NTSTATUS Status;
5003
5004 DPRINT("Removing device: %wZ\n", &DeviceNode->InstancePath);
5005
5006 Status = IopPrepareDeviceForRemoval(DeviceNode->PhysicalDeviceObject, FALSE);
5007 if (NT_SUCCESS(Status))
5008 {
5009 IopSendRemoveDevice(DeviceNode->PhysicalDeviceObject);
5010 IopQueueTargetDeviceEvent(&GUID_DEVICE_SAFE_REMOVAL,
5011 &DeviceNode->InstancePath);
5012 return STATUS_SUCCESS;
5013 }
5014
5015 return Status;
5016 }
5017
5018 /*
5019 * @implemented
5020 */
5021 VOID
5022 NTAPI
5023 IoRequestDeviceEject(IN PDEVICE_OBJECT PhysicalDeviceObject)
5024 {
5025 PDEVICE_NODE DeviceNode = IopGetDeviceNode(PhysicalDeviceObject);
5026 PDEVICE_RELATIONS DeviceRelations;
5027 IO_STATUS_BLOCK IoStatusBlock;
5028 IO_STACK_LOCATION Stack;
5029 DEVICE_CAPABILITIES Capabilities;
5030 NTSTATUS Status;
5031
5032 IopQueueTargetDeviceEvent(&GUID_DEVICE_KERNEL_INITIATED_EJECT,
5033 &DeviceNode->InstancePath);
5034
5035 if (IopQueryDeviceCapabilities(DeviceNode, &Capabilities) != STATUS_SUCCESS)
5036 {
5037 goto cleanup;
5038 }
5039
5040 Stack.Parameters.QueryDeviceRelations.Type = EjectionRelations;
5041
5042 Status = IopInitiatePnpIrp(PhysicalDeviceObject,
5043 &IoStatusBlock,
5044 IRP_MN_QUERY_DEVICE_RELATIONS,
5045 &Stack);
5046 if (!NT_SUCCESS(Status))
5047 {
5048 DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status);
5049 DeviceRelations = NULL;
5050 }
5051 else
5052 {
5053 DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information;
5054 }
5055
5056 if (DeviceRelations)
5057 {
5058 Status = IopQueryRemoveDeviceRelations(DeviceRelations, FALSE);
5059 if (!NT_SUCCESS(Status))
5060 goto cleanup;
5061 }
5062
5063 Status = IopQueryRemoveChildDevices(DeviceNode, FALSE);
5064 if (!NT_SUCCESS(Status))
5065 {
5066 if (DeviceRelations)
5067 IopCancelRemoveDeviceRelations(DeviceRelations);
5068 goto cleanup;
5069 }
5070
5071 if (IopPrepareDeviceForRemoval(PhysicalDeviceObject, FALSE) != STATUS_SUCCESS)
5072 {
5073 if (DeviceRelations)
5074 IopCancelRemoveDeviceRelations(DeviceRelations);
5075 IopCancelRemoveChildDevices(DeviceNode);
5076 goto cleanup;
5077 }
5078
5079 if (DeviceRelations)
5080 IopSendRemoveDeviceRelations(DeviceRelations);
5081 IopSendRemoveChildDevices(DeviceNode);
5082
5083 DeviceNode->Problem = CM_PROB_HELD_FOR_EJECT;
5084 if (Capabilities.EjectSupported)
5085 {
5086 if (IopSendEject(PhysicalDeviceObject) != STATUS_SUCCESS)
5087 {
5088 goto cleanup;
5089 }
5090 }
5091 else
5092 {
5093 DeviceNode->Flags |= DNF_DISABLED;
5094 }
5095
5096 IopQueueTargetDeviceEvent(&GUID_DEVICE_EJECT,
5097 &DeviceNode->InstancePath);
5098
5099 return;
5100
5101 cleanup:
5102 IopQueueTargetDeviceEvent(&GUID_DEVICE_EJECT_VETOED,
5103 &DeviceNode->InstancePath);
5104 }
5105
5106 /*
5107 * @implemented
5108 */
5109 VOID
5110 NTAPI
5111 IoInvalidateDeviceRelations(
5112 IN PDEVICE_OBJECT DeviceObject,
5113 IN DEVICE_RELATION_TYPE Type)
5114 {
5115 PDEVICE_ACTION_DATA Data;
5116 KIRQL OldIrql;
5117
5118 Data = ExAllocatePoolWithTag(NonPagedPool,
5119 sizeof(DEVICE_ACTION_DATA),
5120 TAG_IO);
5121 if (!Data)
5122 return;
5123
5124 ObReferenceObject(DeviceObject);
5125 Data->DeviceObject = DeviceObject;
5126 Data->Type = Type;
5127
5128 KeAcquireSpinLock(&IopDeviceActionLock, &OldIrql);
5129 InsertTailList(&IopDeviceActionRequestList, &Data->RequestListEntry);
5130 if (IopDeviceActionInProgress)
5131 {
5132 KeReleaseSpinLock(&IopDeviceActionLock, OldIrql);
5133 return;
5134 }
5135 IopDeviceActionInProgress = TRUE;
5136 KeReleaseSpinLock(&IopDeviceActionLock, OldIrql);
5137
5138 ExInitializeWorkItem(&IopDeviceActionWorkItem,
5139 IopDeviceActionWorker,
5140 NULL);
5141 ExQueueWorkItem(&IopDeviceActionWorkItem,
5142 DelayedWorkQueue);
5143 }
5144
5145 /*
5146 * @implemented
5147 */
5148 NTSTATUS
5149 NTAPI
5150 IoSynchronousInvalidateDeviceRelations(
5151 IN PDEVICE_OBJECT DeviceObject,
5152 IN DEVICE_RELATION_TYPE Type)
5153 {
5154 PAGED_CODE();
5155
5156 switch (Type)
5157 {
5158 case BusRelations:
5159 /* Enumerate the device */
5160 return IopEnumerateDevice(DeviceObject);
5161 case PowerRelations:
5162 /* Not handled yet */
5163 return STATUS_NOT_IMPLEMENTED;
5164 case TargetDeviceRelation:
5165 /* Nothing to do */
5166 return STATUS_SUCCESS;
5167 default:
5168 /* Ejection relations are not supported */
5169 return STATUS_NOT_SUPPORTED;
5170 }
5171 }
5172
5173 /*
5174 * @implemented
5175 */
5176 BOOLEAN
5177 NTAPI
5178 IoTranslateBusAddress(IN INTERFACE_TYPE InterfaceType,
5179 IN ULONG BusNumber,
5180 IN PHYSICAL_ADDRESS BusAddress,
5181 IN OUT PULONG AddressSpace,
5182 OUT PPHYSICAL_ADDRESS TranslatedAddress)
5183 {
5184 /* FIXME: Notify the resource arbiter */
5185
5186 return HalTranslateBusAddress(InterfaceType,
5187 BusNumber,
5188 BusAddress,
5189 AddressSpace,
5190 TranslatedAddress);
5191 }