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