xref: /reactos/ntoskrnl/io/pnpmgr/devaction.c (revision 41805926)
1 /*
2  * PROJECT:     ReactOS Kernel
3  * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4  * PURPOSE:     PnP manager device manipulation functions
5  * COPYRIGHT:   Casper S. Hornstrup (chorns@users.sourceforge.net)
6  *              2007 Hervé Poussineau (hpoussin@reactos.org)
7  *              2014-2017 Thomas Faber (thomas.faber@reactos.org)
8  */
9 
10 /* INCLUDES ******************************************************************/
11 
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <debug.h>
15 
16 /* GLOBALS *******************************************************************/
17 
18 extern ERESOURCE IopDriverLoadResource;
19 extern BOOLEAN PnpSystemInit;
20 extern PDEVICE_NODE IopRootDeviceNode;
21 
22 #define MAX_DEVICE_ID_LEN          200
23 #define MAX_SEPARATORS_INSTANCEID  0
24 #define MAX_SEPARATORS_DEVICEID    1
25 
26 /* DATA **********************************************************************/
27 
28 LIST_ENTRY IopDeviceActionRequestList;
29 WORK_QUEUE_ITEM IopDeviceActionWorkItem;
30 BOOLEAN IopDeviceActionInProgress;
31 KSPIN_LOCK IopDeviceActionLock;
32 
33 /* FUNCTIONS *****************************************************************/
34 
35 PDEVICE_OBJECT
36 IopGetDeviceObjectFromDeviceInstance(PUNICODE_STRING DeviceInstance);
37 
38 NTSTATUS
39 IopGetParentIdPrefix(PDEVICE_NODE DeviceNode, PUNICODE_STRING ParentIdPrefix);
40 
41 USHORT
42 NTAPI
43 IopGetBusTypeGuidIndex(LPGUID BusTypeGuid);
44 
45 NTSTATUS
46 IopSetDeviceInstanceData(HANDLE InstanceKey, PDEVICE_NODE DeviceNode);
47 
48 VOID
49 NTAPI
50 IopInstallCriticalDevice(PDEVICE_NODE DeviceNode);
51 
52 static
53 VOID
54 IopCancelPrepareDeviceForRemoval(PDEVICE_OBJECT DeviceObject);
55 
56 static
57 NTSTATUS
58 IopPrepareDeviceForRemoval(PDEVICE_OBJECT DeviceObject, BOOLEAN Force);
59 
60 static
61 BOOLEAN
62 IopValidateID(
63     _In_ PWCHAR Id,
64     _In_ BUS_QUERY_ID_TYPE QueryType)
65 {
66     PWCHAR PtrChar;
67     PWCHAR StringEnd;
68     WCHAR Char;
69     ULONG SeparatorsCount = 0;
70     PWCHAR PtrPrevChar = NULL;
71     ULONG MaxSeparators;
72     BOOLEAN IsMultiSz;
73 
74     PAGED_CODE();
75 
76     switch (QueryType)
77     {
78         case BusQueryDeviceID:
79             MaxSeparators = MAX_SEPARATORS_DEVICEID;
80             IsMultiSz = FALSE;
81             break;
82         case BusQueryInstanceID:
83             MaxSeparators = MAX_SEPARATORS_INSTANCEID;
84             IsMultiSz = FALSE;
85             break;
86 
87         case BusQueryHardwareIDs:
88         case BusQueryCompatibleIDs:
89             MaxSeparators = MAX_SEPARATORS_DEVICEID;
90             IsMultiSz = TRUE;
91             break;
92 
93         default:
94             DPRINT1("IopValidateID: Not handled QueryType - %x\n", QueryType);
95             return FALSE;
96     }
97 
98     StringEnd = Id + MAX_DEVICE_ID_LEN;
99 
100     for (PtrChar = Id; PtrChar < StringEnd; PtrChar++)
101     {
102         Char = *PtrChar;
103 
104         if (Char == UNICODE_NULL)
105         {
106             if (!IsMultiSz || (PtrPrevChar && PtrChar == PtrPrevChar + 1))
107             {
108                 if (MaxSeparators == SeparatorsCount || IsMultiSz)
109                 {
110                     return TRUE;
111                 }
112 
113                 DPRINT1("IopValidateID: SeparatorsCount - %lu, MaxSeparators - %lu\n",
114                         SeparatorsCount, MaxSeparators);
115                 goto ErrorExit;
116             }
117 
118             StringEnd = PtrChar + MAX_DEVICE_ID_LEN + 1;
119             PtrPrevChar = PtrChar;
120             SeparatorsCount = 0;
121         }
122         else if (Char < ' ' || Char > 0x7F || Char == ',')
123         {
124             DPRINT1("IopValidateID: Invalid character - %04X\n", Char);
125             goto ErrorExit;
126         }
127         else if (Char == ' ')
128         {
129             *PtrChar = '_';
130         }
131         else if (Char == '\\')
132         {
133             SeparatorsCount++;
134 
135             if (SeparatorsCount > MaxSeparators)
136             {
137                 DPRINT1("IopValidateID: SeparatorsCount - %lu, MaxSeparators - %lu\n",
138                         SeparatorsCount, MaxSeparators);
139                 goto ErrorExit;
140             }
141         }
142     }
143 
144     DPRINT1("IopValidateID: Not terminated ID\n");
145 
146 ErrorExit:
147     // FIXME logging
148     return FALSE;
149 }
150 
151 static
152 NTSTATUS
153 IopCreateDeviceInstancePath(
154     _In_ PDEVICE_NODE DeviceNode,
155     _Out_ PUNICODE_STRING InstancePath)
156 {
157     IO_STATUS_BLOCK IoStatusBlock;
158     UNICODE_STRING DeviceId;
159     UNICODE_STRING InstanceId;
160     IO_STACK_LOCATION Stack;
161     NTSTATUS Status;
162     UNICODE_STRING ParentIdPrefix = { 0, 0, NULL };
163     DEVICE_CAPABILITIES DeviceCapabilities;
164     BOOLEAN IsValidID;
165 
166     DPRINT("Sending IRP_MN_QUERY_ID.BusQueryDeviceID to device stack\n");
167 
168     Stack.Parameters.QueryId.IdType = BusQueryDeviceID;
169     Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
170                                &IoStatusBlock,
171                                IRP_MN_QUERY_ID,
172                                &Stack);
173     if (!NT_SUCCESS(Status))
174     {
175         DPRINT1("IopInitiatePnpIrp(BusQueryDeviceID) failed (Status %x)\n", Status);
176         return Status;
177     }
178 
179     IsValidID = IopValidateID((PWCHAR)IoStatusBlock.Information, BusQueryDeviceID);
180 
181     if (!IsValidID)
182     {
183         DPRINT1("Invalid DeviceID. DeviceNode - %p\n", DeviceNode);
184     }
185 
186     /* Save the device id string */
187     RtlInitUnicodeString(&DeviceId, (PWSTR)IoStatusBlock.Information);
188 
189     DPRINT("Sending IRP_MN_QUERY_CAPABILITIES to device stack (after enumeration)\n");
190 
191     Status = IopQueryDeviceCapabilities(DeviceNode, &DeviceCapabilities);
192     if (!NT_SUCCESS(Status))
193     {
194         DPRINT1("IopQueryDeviceCapabilities() failed (Status 0x%08lx)\n", Status);
195         RtlFreeUnicodeString(&DeviceId);
196         return Status;
197     }
198 
199     /* This bit is only check after enumeration */
200     if (DeviceCapabilities.HardwareDisabled)
201     {
202         /* FIXME: Cleanup device */
203         DeviceNode->Flags |= DNF_DISABLED;
204         RtlFreeUnicodeString(&DeviceId);
205         return STATUS_PLUGPLAY_NO_DEVICE;
206     }
207     else
208     {
209         DeviceNode->Flags &= ~DNF_DISABLED;
210     }
211 
212     if (!DeviceCapabilities.UniqueID)
213     {
214         /* Device has not a unique ID. We need to prepend parent bus unique identifier */
215         DPRINT("Instance ID is not unique\n");
216         Status = IopGetParentIdPrefix(DeviceNode, &ParentIdPrefix);
217         if (!NT_SUCCESS(Status))
218         {
219             DPRINT1("IopGetParentIdPrefix() failed (Status 0x%08lx)\n", Status);
220             RtlFreeUnicodeString(&DeviceId);
221             return Status;
222         }
223     }
224 
225     DPRINT("Sending IRP_MN_QUERY_ID.BusQueryInstanceID to device stack\n");
226 
227     Stack.Parameters.QueryId.IdType = BusQueryInstanceID;
228     Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
229                                &IoStatusBlock,
230                                IRP_MN_QUERY_ID,
231                                &Stack);
232     if (!NT_SUCCESS(Status))
233     {
234         DPRINT("IopInitiatePnpIrp(BusQueryInstanceID) failed (Status %lx)\n", Status);
235         ASSERT(IoStatusBlock.Information == 0);
236     }
237 
238     if (IoStatusBlock.Information)
239     {
240         IsValidID = IopValidateID((PWCHAR)IoStatusBlock.Information, BusQueryInstanceID);
241 
242         if (!IsValidID)
243         {
244             DPRINT1("Invalid InstanceID. DeviceNode - %p\n", DeviceNode);
245         }
246     }
247 
248     RtlInitUnicodeString(&InstanceId,
249                          (PWSTR)IoStatusBlock.Information);
250 
251     InstancePath->Length = 0;
252     InstancePath->MaximumLength = DeviceId.Length + sizeof(WCHAR) +
253                                   ParentIdPrefix.Length +
254                                   InstanceId.Length +
255                                   sizeof(UNICODE_NULL);
256     if (ParentIdPrefix.Length && InstanceId.Length)
257     {
258         InstancePath->MaximumLength += sizeof(WCHAR);
259     }
260 
261     InstancePath->Buffer = ExAllocatePoolWithTag(PagedPool,
262                                                  InstancePath->MaximumLength,
263                                                  TAG_IO);
264     if (!InstancePath->Buffer)
265     {
266         RtlFreeUnicodeString(&InstanceId);
267         RtlFreeUnicodeString(&ParentIdPrefix);
268         RtlFreeUnicodeString(&DeviceId);
269         return STATUS_INSUFFICIENT_RESOURCES;
270     }
271 
272     /* Start with the device id */
273     RtlCopyUnicodeString(InstancePath, &DeviceId);
274     RtlAppendUnicodeToString(InstancePath, L"\\");
275 
276     /* Add information from parent bus device to InstancePath */
277     RtlAppendUnicodeStringToString(InstancePath, &ParentIdPrefix);
278     if (ParentIdPrefix.Length && InstanceId.Length)
279     {
280         RtlAppendUnicodeToString(InstancePath, L"&");
281     }
282 
283     /* Finally, add the id returned by the driver stack */
284     RtlAppendUnicodeStringToString(InstancePath, &InstanceId);
285 
286     /*
287      * FIXME: Check for valid characters, if there is invalid characters
288      * then bugcheck
289      */
290 
291     RtlFreeUnicodeString(&InstanceId);
292     RtlFreeUnicodeString(&DeviceId);
293     RtlFreeUnicodeString(&ParentIdPrefix);
294 
295     return STATUS_SUCCESS;
296 }
297 
298 NTSTATUS
299 NTAPI
300 IopQueryDeviceCapabilities(PDEVICE_NODE DeviceNode,
301                            PDEVICE_CAPABILITIES DeviceCaps)
302 {
303     IO_STATUS_BLOCK StatusBlock;
304     IO_STACK_LOCATION Stack;
305     NTSTATUS Status;
306     HANDLE InstanceKey;
307     UNICODE_STRING ValueName;
308 
309     /* Set up the Header */
310     RtlZeroMemory(DeviceCaps, sizeof(DEVICE_CAPABILITIES));
311     DeviceCaps->Size = sizeof(DEVICE_CAPABILITIES);
312     DeviceCaps->Version = 1;
313     DeviceCaps->Address = -1;
314     DeviceCaps->UINumber = -1;
315 
316     /* Set up the Stack */
317     RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION));
318     Stack.Parameters.DeviceCapabilities.Capabilities = DeviceCaps;
319 
320     /* Send the IRP */
321     Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
322                                &StatusBlock,
323                                IRP_MN_QUERY_CAPABILITIES,
324                                &Stack);
325     if (!NT_SUCCESS(Status))
326     {
327         if (Status != STATUS_NOT_SUPPORTED)
328         {
329             DPRINT1("IRP_MN_QUERY_CAPABILITIES failed with status 0x%lx\n", Status);
330         }
331         return Status;
332     }
333 
334     /* Map device capabilities to capability flags */
335     DeviceNode->CapabilityFlags = 0;
336     if (DeviceCaps->LockSupported)
337         DeviceNode->CapabilityFlags |= 0x00000001;    // CM_DEVCAP_LOCKSUPPORTED
338 
339     if (DeviceCaps->EjectSupported)
340         DeviceNode->CapabilityFlags |= 0x00000002;    // CM_DEVCAP_EJECTSUPPORTED
341 
342     if (DeviceCaps->Removable)
343         DeviceNode->CapabilityFlags |= 0x00000004;    // CM_DEVCAP_REMOVABLE
344 
345     if (DeviceCaps->DockDevice)
346         DeviceNode->CapabilityFlags |= 0x00000008;    // CM_DEVCAP_DOCKDEVICE
347 
348     if (DeviceCaps->UniqueID)
349         DeviceNode->CapabilityFlags |= 0x00000010;    // CM_DEVCAP_UNIQUEID
350 
351     if (DeviceCaps->SilentInstall)
352         DeviceNode->CapabilityFlags |= 0x00000020;    // CM_DEVCAP_SILENTINSTALL
353 
354     if (DeviceCaps->RawDeviceOK)
355         DeviceNode->CapabilityFlags |= 0x00000040;    // CM_DEVCAP_RAWDEVICEOK
356 
357     if (DeviceCaps->SurpriseRemovalOK)
358         DeviceNode->CapabilityFlags |= 0x00000080;    // CM_DEVCAP_SURPRISEREMOVALOK
359 
360     if (DeviceCaps->HardwareDisabled)
361         DeviceNode->CapabilityFlags |= 0x00000100;    // CM_DEVCAP_HARDWAREDISABLED
362 
363     if (DeviceCaps->NonDynamic)
364         DeviceNode->CapabilityFlags |= 0x00000200;    // CM_DEVCAP_NONDYNAMIC
365 
366     if (DeviceCaps->NoDisplayInUI)
367         DeviceNode->UserFlags |= DNUF_DONT_SHOW_IN_UI;
368     else
369         DeviceNode->UserFlags &= ~DNUF_DONT_SHOW_IN_UI;
370 
371     Status = IopCreateDeviceKeyPath(&DeviceNode->InstancePath, REG_OPTION_NON_VOLATILE, &InstanceKey);
372     if (NT_SUCCESS(Status))
373     {
374         /* Set 'Capabilities' value */
375         RtlInitUnicodeString(&ValueName, L"Capabilities");
376         Status = ZwSetValueKey(InstanceKey,
377                                &ValueName,
378                                0,
379                                REG_DWORD,
380                                &DeviceNode->CapabilityFlags,
381                                sizeof(ULONG));
382 
383         /* Set 'UINumber' value */
384         if (DeviceCaps->UINumber != MAXULONG)
385         {
386             RtlInitUnicodeString(&ValueName, L"UINumber");
387             Status = ZwSetValueKey(InstanceKey,
388                                    &ValueName,
389                                    0,
390                                    REG_DWORD,
391                                    &DeviceCaps->UINumber,
392                                    sizeof(ULONG));
393         }
394 
395         ZwClose(InstanceKey);
396     }
397 
398     return Status;
399 }
400 
401 static
402 NTSTATUS
403 IopQueryHardwareIds(PDEVICE_NODE DeviceNode,
404                     HANDLE InstanceKey)
405 {
406     IO_STACK_LOCATION Stack;
407     IO_STATUS_BLOCK IoStatusBlock;
408     PWSTR Ptr;
409     UNICODE_STRING ValueName;
410     NTSTATUS Status;
411     ULONG Length, TotalLength;
412     BOOLEAN IsValidID;
413 
414     DPRINT("Sending IRP_MN_QUERY_ID.BusQueryHardwareIDs to device stack\n");
415 
416     RtlZeroMemory(&Stack, sizeof(Stack));
417     Stack.Parameters.QueryId.IdType = BusQueryHardwareIDs;
418     Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
419                                &IoStatusBlock,
420                                IRP_MN_QUERY_ID,
421                                &Stack);
422     if (NT_SUCCESS(Status))
423     {
424         IsValidID = IopValidateID((PWCHAR)IoStatusBlock.Information, BusQueryHardwareIDs);
425 
426         if (!IsValidID)
427         {
428             DPRINT1("Invalid HardwareIDs. DeviceNode - %p\n", DeviceNode);
429         }
430 
431         TotalLength = 0;
432 
433         Ptr = (PWSTR)IoStatusBlock.Information;
434         DPRINT("Hardware IDs:\n");
435         while (*Ptr)
436         {
437             DPRINT("  %S\n", Ptr);
438             Length = (ULONG)wcslen(Ptr) + 1;
439 
440             Ptr += Length;
441             TotalLength += Length;
442         }
443         DPRINT("TotalLength: %hu\n", TotalLength);
444         DPRINT("\n");
445 
446         RtlInitUnicodeString(&ValueName, L"HardwareID");
447         Status = ZwSetValueKey(InstanceKey,
448                                &ValueName,
449                                0,
450                                REG_MULTI_SZ,
451                                (PVOID)IoStatusBlock.Information,
452                                (TotalLength + 1) * sizeof(WCHAR));
453         if (!NT_SUCCESS(Status))
454         {
455             DPRINT1("ZwSetValueKey() failed (Status %lx)\n", Status);
456         }
457     }
458     else
459     {
460         DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
461     }
462 
463     return Status;
464 }
465 
466 static
467 NTSTATUS
468 IopQueryCompatibleIds(PDEVICE_NODE DeviceNode,
469                       HANDLE InstanceKey)
470 {
471     IO_STACK_LOCATION Stack;
472     IO_STATUS_BLOCK IoStatusBlock;
473     PWSTR Ptr;
474     UNICODE_STRING ValueName;
475     NTSTATUS Status;
476     ULONG Length, TotalLength;
477     BOOLEAN IsValidID;
478 
479     DPRINT("Sending IRP_MN_QUERY_ID.BusQueryCompatibleIDs to device stack\n");
480 
481     RtlZeroMemory(&Stack, sizeof(Stack));
482     Stack.Parameters.QueryId.IdType = BusQueryCompatibleIDs;
483     Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
484                                &IoStatusBlock,
485                                IRP_MN_QUERY_ID,
486                                &Stack);
487     if (NT_SUCCESS(Status) && IoStatusBlock.Information)
488     {
489         IsValidID = IopValidateID((PWCHAR)IoStatusBlock.Information, BusQueryCompatibleIDs);
490 
491         if (!IsValidID)
492         {
493             DPRINT1("Invalid CompatibleIDs. DeviceNode - %p\n", DeviceNode);
494         }
495 
496         TotalLength = 0;
497 
498         Ptr = (PWSTR)IoStatusBlock.Information;
499         DPRINT("Compatible IDs:\n");
500         while (*Ptr)
501         {
502             DPRINT("  %S\n", Ptr);
503             Length = (ULONG)wcslen(Ptr) + 1;
504 
505             Ptr += Length;
506             TotalLength += Length;
507         }
508         DPRINT("TotalLength: %hu\n", TotalLength);
509         DPRINT("\n");
510 
511         RtlInitUnicodeString(&ValueName, L"CompatibleIDs");
512         Status = ZwSetValueKey(InstanceKey,
513                                &ValueName,
514                                0,
515                                REG_MULTI_SZ,
516                                (PVOID)IoStatusBlock.Information,
517                                (TotalLength + 1) * sizeof(WCHAR));
518         if (!NT_SUCCESS(Status))
519         {
520             DPRINT1("ZwSetValueKey() failed (Status %lx) or no Compatible ID returned\n", Status);
521         }
522     }
523     else
524     {
525         DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
526     }
527 
528     return Status;
529 }
530 
531 /*
532  * IopActionInterrogateDeviceStack
533  *
534  * Retrieve information for all (direct) child nodes of a parent node.
535  *
536  * Parameters
537  *    DeviceNode
538  *       Pointer to device node.
539  *    Context
540  *       Pointer to parent node to retrieve child node information for.
541  *
542  * Remarks
543  *    Any errors that occur are logged instead so that all child services have a chance
544  *    of being interrogated.
545  */
546 
547 NTSTATUS
548 IopActionInterrogateDeviceStack(PDEVICE_NODE DeviceNode,
549                                 PVOID Context)
550 {
551     IO_STATUS_BLOCK IoStatusBlock;
552     PWSTR DeviceDescription;
553     PWSTR LocationInformation;
554     PDEVICE_NODE ParentDeviceNode;
555     IO_STACK_LOCATION Stack;
556     NTSTATUS Status;
557     ULONG RequiredLength;
558     LCID LocaleId;
559     HANDLE InstanceKey = NULL;
560     UNICODE_STRING ValueName;
561     UNICODE_STRING InstancePathU;
562     PDEVICE_OBJECT OldDeviceObject;
563 
564     DPRINT("IopActionInterrogateDeviceStack(%p, %p)\n", DeviceNode, Context);
565     DPRINT("PDO 0x%p\n", DeviceNode->PhysicalDeviceObject);
566 
567     ParentDeviceNode = (PDEVICE_NODE)Context;
568 
569     /*
570      * We are called for the parent too, but we don't need to do special
571      * handling for this node
572      */
573     if (DeviceNode == ParentDeviceNode)
574     {
575         DPRINT("Success\n");
576         return STATUS_SUCCESS;
577     }
578 
579     /*
580      * Make sure this device node is a direct child of the parent device node
581      * that is given as an argument
582      */
583     if (DeviceNode->Parent != ParentDeviceNode)
584     {
585         DPRINT("Skipping 2+ level child\n");
586         return STATUS_SUCCESS;
587     }
588 
589     /* Skip processing if it was already completed before */
590     if (DeviceNode->Flags & DNF_PROCESSED)
591     {
592         /* Nothing to do */
593         return STATUS_SUCCESS;
594     }
595 
596     /* Get Locale ID */
597     Status = ZwQueryDefaultLocale(FALSE, &LocaleId);
598     if (!NT_SUCCESS(Status))
599     {
600         DPRINT1("ZwQueryDefaultLocale() failed with status 0x%lx\n", Status);
601         return Status;
602     }
603 
604     /*
605      * FIXME: For critical errors, cleanup and disable device, but always
606      * return STATUS_SUCCESS.
607      */
608 
609     Status = IopCreateDeviceInstancePath(DeviceNode, &InstancePathU);
610     if (!NT_SUCCESS(Status))
611     {
612         if (Status != STATUS_PLUGPLAY_NO_DEVICE)
613         {
614             DPRINT1("IopCreateDeviceInstancePath() failed with status 0x%lx\n", Status);
615         }
616 
617         /* We have to return success otherwise we abort the traverse operation */
618         return STATUS_SUCCESS;
619     }
620 
621     /* Verify that this is not a duplicate */
622     OldDeviceObject = IopGetDeviceObjectFromDeviceInstance(&InstancePathU);
623     if (OldDeviceObject != NULL)
624     {
625         PDEVICE_NODE OldDeviceNode = IopGetDeviceNode(OldDeviceObject);
626 
627         DPRINT1("Duplicate device instance '%wZ'\n", &InstancePathU);
628         DPRINT1("Current instance parent: '%wZ'\n", &DeviceNode->Parent->InstancePath);
629         DPRINT1("Old instance parent: '%wZ'\n", &OldDeviceNode->Parent->InstancePath);
630 
631         KeBugCheckEx(PNP_DETECTED_FATAL_ERROR,
632                      0x01,
633                      (ULONG_PTR)DeviceNode->PhysicalDeviceObject,
634                      (ULONG_PTR)OldDeviceObject,
635                      0);
636     }
637 
638     DeviceNode->InstancePath = InstancePathU;
639 
640     DPRINT("InstancePath is %S\n", DeviceNode->InstancePath.Buffer);
641 
642     /*
643      * Create registry key for the instance id, if it doesn't exist yet
644      */
645     Status = IopCreateDeviceKeyPath(&DeviceNode->InstancePath, REG_OPTION_NON_VOLATILE, &InstanceKey);
646     if (!NT_SUCCESS(Status))
647     {
648         DPRINT1("Failed to create the instance key! (Status %lx)\n", Status);
649 
650         /* We have to return success otherwise we abort the traverse operation */
651         return STATUS_SUCCESS;
652     }
653 
654     IopQueryHardwareIds(DeviceNode, InstanceKey);
655 
656     IopQueryCompatibleIds(DeviceNode, InstanceKey);
657 
658     DPRINT("Sending IRP_MN_QUERY_DEVICE_TEXT.DeviceTextDescription to device stack\n");
659 
660     Stack.Parameters.QueryDeviceText.DeviceTextType = DeviceTextDescription;
661     Stack.Parameters.QueryDeviceText.LocaleId = LocaleId;
662     Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
663                                &IoStatusBlock,
664                                IRP_MN_QUERY_DEVICE_TEXT,
665                                &Stack);
666     DeviceDescription = NT_SUCCESS(Status) ? (PWSTR)IoStatusBlock.Information
667                                            : NULL;
668     /* This key is mandatory, so even if the Irp fails, we still write it */
669     RtlInitUnicodeString(&ValueName, L"DeviceDesc");
670     if (ZwQueryValueKey(InstanceKey, &ValueName, KeyValueBasicInformation, NULL, 0, &RequiredLength) == STATUS_OBJECT_NAME_NOT_FOUND)
671     {
672         if (DeviceDescription &&
673             *DeviceDescription != UNICODE_NULL)
674         {
675             /* This key is overriden when a driver is installed. Don't write the
676              * new description if another one already exists */
677             Status = ZwSetValueKey(InstanceKey,
678                                    &ValueName,
679                                    0,
680                                    REG_SZ,
681                                    DeviceDescription,
682                                    ((ULONG)wcslen(DeviceDescription) + 1) * sizeof(WCHAR));
683         }
684         else
685         {
686             UNICODE_STRING DeviceDesc = RTL_CONSTANT_STRING(L"Unknown device");
687             DPRINT("Driver didn't return DeviceDesc (Status 0x%08lx), so place unknown device there\n", Status);
688 
689             Status = ZwSetValueKey(InstanceKey,
690                                    &ValueName,
691                                    0,
692                                    REG_SZ,
693                                    DeviceDesc.Buffer,
694                                    DeviceDesc.MaximumLength);
695             if (!NT_SUCCESS(Status))
696             {
697                 DPRINT1("ZwSetValueKey() failed (Status 0x%lx)\n", Status);
698             }
699 
700         }
701     }
702 
703     if (DeviceDescription)
704     {
705         ExFreePoolWithTag(DeviceDescription, 0);
706     }
707 
708     DPRINT("Sending IRP_MN_QUERY_DEVICE_TEXT.DeviceTextLocation to device stack\n");
709 
710     Stack.Parameters.QueryDeviceText.DeviceTextType = DeviceTextLocationInformation;
711     Stack.Parameters.QueryDeviceText.LocaleId = LocaleId;
712     Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
713                                &IoStatusBlock,
714                                IRP_MN_QUERY_DEVICE_TEXT,
715                                &Stack);
716     if (NT_SUCCESS(Status) && IoStatusBlock.Information)
717     {
718         LocationInformation = (PWSTR)IoStatusBlock.Information;
719         DPRINT("LocationInformation: %S\n", LocationInformation);
720         RtlInitUnicodeString(&ValueName, L"LocationInformation");
721         Status = ZwSetValueKey(InstanceKey,
722                                &ValueName,
723                                0,
724                                REG_SZ,
725                                LocationInformation,
726                                ((ULONG)wcslen(LocationInformation) + 1) * sizeof(WCHAR));
727         if (!NT_SUCCESS(Status))
728         {
729             DPRINT1("ZwSetValueKey() failed (Status %lx)\n", Status);
730         }
731 
732         ExFreePoolWithTag(LocationInformation, 0);
733     }
734     else
735     {
736         DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status);
737     }
738 
739     DPRINT("Sending IRP_MN_QUERY_BUS_INFORMATION to device stack\n");
740 
741     Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
742                                &IoStatusBlock,
743                                IRP_MN_QUERY_BUS_INFORMATION,
744                                NULL);
745     if (NT_SUCCESS(Status) && IoStatusBlock.Information)
746     {
747         PPNP_BUS_INFORMATION BusInformation = (PPNP_BUS_INFORMATION)IoStatusBlock.Information;
748 
749         DeviceNode->ChildBusNumber = BusInformation->BusNumber;
750         DeviceNode->ChildInterfaceType = BusInformation->LegacyBusType;
751         DeviceNode->ChildBusTypeIndex = IopGetBusTypeGuidIndex(&BusInformation->BusTypeGuid);
752         ExFreePoolWithTag(BusInformation, 0);
753     }
754     else
755     {
756         DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status);
757 
758         DeviceNode->ChildBusNumber = 0xFFFFFFF0;
759         DeviceNode->ChildInterfaceType = InterfaceTypeUndefined;
760         DeviceNode->ChildBusTypeIndex = -1;
761     }
762 
763     DPRINT("Sending IRP_MN_QUERY_RESOURCES to device stack\n");
764 
765     Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
766                                &IoStatusBlock,
767                                IRP_MN_QUERY_RESOURCES,
768                                NULL);
769     if (NT_SUCCESS(Status) && IoStatusBlock.Information)
770     {
771         DeviceNode->BootResources = (PCM_RESOURCE_LIST)IoStatusBlock.Information;
772         IopDeviceNodeSetFlag(DeviceNode, DNF_HAS_BOOT_CONFIG);
773     }
774     else
775     {
776         DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status);
777         DeviceNode->BootResources = NULL;
778     }
779 
780     DPRINT("Sending IRP_MN_QUERY_RESOURCE_REQUIREMENTS to device stack\n");
781 
782     Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
783                                &IoStatusBlock,
784                                IRP_MN_QUERY_RESOURCE_REQUIREMENTS,
785                                NULL);
786     if (NT_SUCCESS(Status))
787     {
788         DeviceNode->ResourceRequirements = (PIO_RESOURCE_REQUIREMENTS_LIST)IoStatusBlock.Information;
789     }
790     else
791     {
792         DPRINT("IopInitiatePnpIrp() failed (Status %08lx)\n", Status);
793         DeviceNode->ResourceRequirements = NULL;
794     }
795 
796     if (InstanceKey != NULL)
797     {
798         IopSetDeviceInstanceData(InstanceKey, DeviceNode);
799     }
800 
801     ZwClose(InstanceKey);
802 
803     IopDeviceNodeSetFlag(DeviceNode, DNF_PROCESSED);
804 
805     if (!IopDeviceNodeHasFlag(DeviceNode, DNF_LEGACY_DRIVER))
806     {
807         /* Report the device to the user-mode pnp manager */
808         IopQueueTargetDeviceEvent(&GUID_DEVICE_ENUMERATED,
809                                   &DeviceNode->InstancePath);
810     }
811 
812     return STATUS_SUCCESS;
813 }
814 
815 /*
816  * IopActionConfigureChildServices
817  *
818  * Retrieve configuration for all (direct) child nodes of a parent node.
819  *
820  * Parameters
821  *    DeviceNode
822  *       Pointer to device node.
823  *    Context
824  *       Pointer to parent node to retrieve child node configuration for.
825  *
826  * Remarks
827  *    Any errors that occur are logged instead so that all child services have a chance of beeing
828  *    configured.
829  */
830 
831 NTSTATUS
832 IopActionConfigureChildServices(PDEVICE_NODE DeviceNode,
833                                 PVOID Context)
834 {
835     RTL_QUERY_REGISTRY_TABLE QueryTable[3];
836     PDEVICE_NODE ParentDeviceNode;
837     PUNICODE_STRING Service;
838     UNICODE_STRING ClassGUID;
839     NTSTATUS Status;
840     DEVICE_CAPABILITIES DeviceCaps;
841 
842     DPRINT("IopActionConfigureChildServices(%p, %p)\n", DeviceNode, Context);
843 
844     ParentDeviceNode = (PDEVICE_NODE)Context;
845 
846     /*
847      * We are called for the parent too, but we don't need to do special
848      * handling for this node
849      */
850     if (DeviceNode == ParentDeviceNode)
851     {
852         DPRINT("Success\n");
853         return STATUS_SUCCESS;
854     }
855 
856     /*
857      * Make sure this device node is a direct child of the parent device node
858      * that is given as an argument
859      */
860 
861     if (DeviceNode->Parent != ParentDeviceNode)
862     {
863         DPRINT("Skipping 2+ level child\n");
864         return STATUS_SUCCESS;
865     }
866 
867     if (!(DeviceNode->Flags & DNF_PROCESSED))
868     {
869         DPRINT1("Child not ready to be configured\n");
870         return STATUS_SUCCESS;
871     }
872 
873     if (!(DeviceNode->Flags & (DNF_DISABLED | DNF_STARTED | DNF_ADDED)))
874     {
875         UNICODE_STRING RegKey;
876 
877         /* Install the service for this if it's in the CDDB */
878         IopInstallCriticalDevice(DeviceNode);
879 
880         /*
881          * Retrieve configuration from Enum key
882          */
883 
884         Service = &DeviceNode->ServiceName;
885 
886         RtlZeroMemory(QueryTable, sizeof(QueryTable));
887         RtlInitUnicodeString(Service, NULL);
888         RtlInitUnicodeString(&ClassGUID, NULL);
889 
890         QueryTable[0].Name = L"Service";
891         QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
892         QueryTable[0].EntryContext = Service;
893 
894         QueryTable[1].Name = L"ClassGUID";
895         QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
896         QueryTable[1].EntryContext = &ClassGUID;
897         QueryTable[1].DefaultType = REG_SZ;
898         QueryTable[1].DefaultData = L"";
899         QueryTable[1].DefaultLength = 0;
900 
901         RegKey.Length = 0;
902         RegKey.MaximumLength = sizeof(ENUM_ROOT) + sizeof(WCHAR) + DeviceNode->InstancePath.Length;
903         RegKey.Buffer = ExAllocatePoolWithTag(PagedPool,
904                                               RegKey.MaximumLength,
905                                               TAG_IO);
906         if (RegKey.Buffer == NULL)
907         {
908             IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
909             return STATUS_INSUFFICIENT_RESOURCES;
910         }
911 
912         RtlAppendUnicodeToString(&RegKey, ENUM_ROOT);
913         RtlAppendUnicodeToString(&RegKey, L"\\");
914         RtlAppendUnicodeStringToString(&RegKey, &DeviceNode->InstancePath);
915 
916         Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
917             RegKey.Buffer, QueryTable, NULL, NULL);
918         ExFreePoolWithTag(RegKey.Buffer, TAG_IO);
919 
920         if (!NT_SUCCESS(Status))
921         {
922             /* FIXME: Log the error */
923             DPRINT("Could not retrieve configuration for device %wZ (Status 0x%08x)\n",
924                    &DeviceNode->InstancePath, Status);
925             IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
926             return STATUS_SUCCESS;
927         }
928 
929         if (Service->Buffer == NULL)
930         {
931             if (NT_SUCCESS(IopQueryDeviceCapabilities(DeviceNode, &DeviceCaps)) &&
932                 DeviceCaps.RawDeviceOK)
933             {
934                 DPRINT("%wZ is using parent bus driver (%wZ)\n", &DeviceNode->InstancePath, &ParentDeviceNode->ServiceName);
935                 RtlInitEmptyUnicodeString(&DeviceNode->ServiceName, NULL, 0);
936             }
937             else if (ClassGUID.Length != 0)
938             {
939                 /* Device has a ClassGUID value, but no Service value.
940                  * Suppose it is using the NULL driver, so state the
941                  * device is started */
942                 DPRINT("%wZ is using NULL driver\n", &DeviceNode->InstancePath);
943                 IopDeviceNodeSetFlag(DeviceNode, DNF_STARTED);
944             }
945             else
946             {
947                 DeviceNode->Problem = CM_PROB_FAILED_INSTALL;
948                 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
949             }
950             return STATUS_SUCCESS;
951         }
952 
953         DPRINT("Got Service %S\n", Service->Buffer);
954     }
955 
956     return STATUS_SUCCESS;
957 }
958 
959 /*
960  * IopActionInitChildServices
961  *
962  * Initialize the service for all (direct) child nodes of a parent node
963  *
964  * Parameters
965  *    DeviceNode
966  *       Pointer to device node.
967  *    Context
968  *       Pointer to parent node to initialize child node services for.
969  *
970  * Remarks
971  *    If the driver image for a service is not loaded and initialized
972  *    it is done here too. Any errors that occur are logged instead so
973  *    that all child services have a chance of being initialized.
974  */
975 
976 NTSTATUS
977 IopActionInitChildServices(PDEVICE_NODE DeviceNode,
978                            PVOID Context)
979 {
980     PDEVICE_NODE ParentDeviceNode;
981     NTSTATUS Status;
982     BOOLEAN BootDrivers = !PnpSystemInit;
983 
984     DPRINT("IopActionInitChildServices(%p, %p)\n", DeviceNode, Context);
985 
986     ParentDeviceNode = Context;
987 
988     /*
989      * We are called for the parent too, but we don't need to do special
990      * handling for this node
991      */
992     if (DeviceNode == ParentDeviceNode)
993     {
994         DPRINT("Success\n");
995         return STATUS_SUCCESS;
996     }
997 
998     /*
999      * We don't want to check for a direct child because
1000      * this function is called during boot to reinitialize
1001      * devices with drivers that couldn't load yet due to
1002      * stage 0 limitations (ie can't load from disk yet).
1003      */
1004 
1005     if (!(DeviceNode->Flags & DNF_PROCESSED))
1006     {
1007         DPRINT1("Child not ready to be added\n");
1008         return STATUS_SUCCESS;
1009     }
1010 
1011     if (IopDeviceNodeHasFlag(DeviceNode, DNF_STARTED) ||
1012         IopDeviceNodeHasFlag(DeviceNode, DNF_ADDED) ||
1013         IopDeviceNodeHasFlag(DeviceNode, DNF_DISABLED))
1014         return STATUS_SUCCESS;
1015 
1016     if (DeviceNode->ServiceName.Buffer == NULL)
1017     {
1018         /* We don't need to worry about loading the driver because we're
1019          * being driven in raw mode so our parent must be loaded to get here */
1020         Status = IopInitializeDevice(DeviceNode, NULL);
1021         if (NT_SUCCESS(Status))
1022         {
1023             Status = IopStartDevice(DeviceNode);
1024             if (!NT_SUCCESS(Status))
1025             {
1026                 DPRINT1("IopStartDevice(%wZ) failed with status 0x%08x\n",
1027                         &DeviceNode->InstancePath, Status);
1028             }
1029         }
1030     }
1031     else
1032     {
1033         PLDR_DATA_TABLE_ENTRY ModuleObject;
1034         PDRIVER_OBJECT DriverObject;
1035 
1036         KeEnterCriticalRegion();
1037         ExAcquireResourceExclusiveLite(&IopDriverLoadResource, TRUE);
1038         /* Get existing DriverObject pointer (in case the driver has
1039            already been loaded and initialized) */
1040         Status = IopGetDriverObject(
1041             &DriverObject,
1042             &DeviceNode->ServiceName,
1043             FALSE);
1044 
1045         if (!NT_SUCCESS(Status))
1046         {
1047             /* Driver is not initialized, try to load it */
1048             Status = IopLoadServiceModule(&DeviceNode->ServiceName, &ModuleObject);
1049 
1050             if (NT_SUCCESS(Status) || Status == STATUS_IMAGE_ALREADY_LOADED)
1051             {
1052                 /* Initialize the driver */
1053                 Status = IopInitializeDriverModule(DeviceNode, ModuleObject,
1054                     &DeviceNode->ServiceName, FALSE, &DriverObject);
1055                 if (!NT_SUCCESS(Status))
1056                     DeviceNode->Problem = CM_PROB_FAILED_DRIVER_ENTRY;
1057             }
1058             else if (Status == STATUS_DRIVER_UNABLE_TO_LOAD)
1059             {
1060                 DPRINT1("Service '%wZ' is disabled\n", &DeviceNode->ServiceName);
1061                 DeviceNode->Problem = CM_PROB_DISABLED_SERVICE;
1062             }
1063             else
1064             {
1065                 DPRINT("IopLoadServiceModule(%wZ) failed with status 0x%08x\n",
1066                        &DeviceNode->ServiceName, Status);
1067                 if (!BootDrivers)
1068                     DeviceNode->Problem = CM_PROB_DRIVER_FAILED_LOAD;
1069             }
1070         }
1071         ExReleaseResourceLite(&IopDriverLoadResource);
1072         KeLeaveCriticalRegion();
1073 
1074         /* Driver is loaded and initialized at this point */
1075         if (NT_SUCCESS(Status))
1076         {
1077             /* Initialize the device, including all filters */
1078             Status = PipCallDriverAddDevice(DeviceNode, FALSE, DriverObject);
1079 
1080             /* Remove the extra reference */
1081             ObDereferenceObject(DriverObject);
1082         }
1083         else
1084         {
1085             /*
1086              * Don't disable when trying to load only boot drivers
1087              */
1088             if (!BootDrivers)
1089             {
1090                 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
1091             }
1092         }
1093     }
1094 
1095     return STATUS_SUCCESS;
1096 }
1097 
1098 static
1099 NTSTATUS
1100 IopSetServiceEnumData(PDEVICE_NODE DeviceNode)
1101 {
1102     UNICODE_STRING ServicesKeyPath = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
1103     UNICODE_STRING ServiceKeyName;
1104     UNICODE_STRING EnumKeyName;
1105     UNICODE_STRING ValueName;
1106     PKEY_VALUE_FULL_INFORMATION KeyValueInformation;
1107     HANDLE ServiceKey = NULL, ServiceEnumKey = NULL;
1108     ULONG Disposition;
1109     ULONG Count = 0, NextInstance = 0;
1110     WCHAR ValueBuffer[6];
1111     NTSTATUS Status = STATUS_SUCCESS;
1112 
1113     DPRINT("IopSetServiceEnumData(%p)\n", DeviceNode);
1114     DPRINT("Instance: %wZ\n", &DeviceNode->InstancePath);
1115     DPRINT("Service: %wZ\n", &DeviceNode->ServiceName);
1116 
1117     if (DeviceNode->ServiceName.Buffer == NULL)
1118     {
1119         DPRINT1("No service!\n");
1120         return STATUS_SUCCESS;
1121     }
1122 
1123     ServiceKeyName.MaximumLength = ServicesKeyPath.Length + DeviceNode->ServiceName.Length + sizeof(UNICODE_NULL);
1124     ServiceKeyName.Length = 0;
1125     ServiceKeyName.Buffer = ExAllocatePool(PagedPool, ServiceKeyName.MaximumLength);
1126     if (ServiceKeyName.Buffer == NULL)
1127     {
1128         DPRINT1("No ServiceKeyName.Buffer!\n");
1129         return STATUS_INSUFFICIENT_RESOURCES;
1130     }
1131 
1132     RtlAppendUnicodeStringToString(&ServiceKeyName, &ServicesKeyPath);
1133     RtlAppendUnicodeStringToString(&ServiceKeyName, &DeviceNode->ServiceName);
1134 
1135     DPRINT("ServiceKeyName: %wZ\n", &ServiceKeyName);
1136 
1137     Status = IopOpenRegistryKeyEx(&ServiceKey, NULL, &ServiceKeyName, KEY_CREATE_SUB_KEY);
1138     if (!NT_SUCCESS(Status))
1139     {
1140         goto done;
1141     }
1142 
1143     RtlInitUnicodeString(&EnumKeyName, L"Enum");
1144     Status = IopCreateRegistryKeyEx(&ServiceEnumKey,
1145                                     ServiceKey,
1146                                     &EnumKeyName,
1147                                     KEY_SET_VALUE,
1148                                     REG_OPTION_VOLATILE,
1149                                     &Disposition);
1150     if (NT_SUCCESS(Status))
1151     {
1152         if (Disposition == REG_OPENED_EXISTING_KEY)
1153         {
1154             /* Read the NextInstance value */
1155             Status = IopGetRegistryValue(ServiceEnumKey,
1156                                          L"Count",
1157                                          &KeyValueInformation);
1158             if (!NT_SUCCESS(Status))
1159                 goto done;
1160 
1161             if ((KeyValueInformation->Type == REG_DWORD) &&
1162                 (KeyValueInformation->DataLength))
1163             {
1164                 /* Read it */
1165                 Count = *(PULONG)((ULONG_PTR)KeyValueInformation +
1166                                   KeyValueInformation->DataOffset);
1167             }
1168 
1169             ExFreePool(KeyValueInformation);
1170             KeyValueInformation = NULL;
1171 
1172             /* Read the NextInstance value */
1173             Status = IopGetRegistryValue(ServiceEnumKey,
1174                                          L"NextInstance",
1175                                          &KeyValueInformation);
1176             if (!NT_SUCCESS(Status))
1177                 goto done;
1178 
1179             if ((KeyValueInformation->Type == REG_DWORD) &&
1180                 (KeyValueInformation->DataLength))
1181             {
1182                 NextInstance = *(PULONG)((ULONG_PTR)KeyValueInformation +
1183                                          KeyValueInformation->DataOffset);
1184             }
1185 
1186             ExFreePool(KeyValueInformation);
1187             KeyValueInformation = NULL;
1188         }
1189 
1190         /* Set the instance path */
1191         swprintf(ValueBuffer, L"%lu", NextInstance);
1192         RtlInitUnicodeString(&ValueName, ValueBuffer);
1193         Status = ZwSetValueKey(ServiceEnumKey,
1194                                &ValueName,
1195                                0,
1196                                REG_SZ,
1197                                DeviceNode->InstancePath.Buffer,
1198                                DeviceNode->InstancePath.MaximumLength);
1199         if (!NT_SUCCESS(Status))
1200             goto done;
1201 
1202         /* Increment Count and NextInstance */
1203         Count++;
1204         NextInstance++;
1205 
1206         /* Set the new Count value */
1207         RtlInitUnicodeString(&ValueName, L"Count");
1208         Status = ZwSetValueKey(ServiceEnumKey,
1209                                &ValueName,
1210                                0,
1211                                REG_DWORD,
1212                                &Count,
1213                                sizeof(Count));
1214         if (!NT_SUCCESS(Status))
1215             goto done;
1216 
1217         /* Set the new NextInstance value */
1218         RtlInitUnicodeString(&ValueName, L"NextInstance");
1219         Status = ZwSetValueKey(ServiceEnumKey,
1220                                &ValueName,
1221                                0,
1222                                REG_DWORD,
1223                                &NextInstance,
1224                                sizeof(NextInstance));
1225     }
1226 
1227 done:
1228     if (ServiceEnumKey != NULL)
1229         ZwClose(ServiceEnumKey);
1230 
1231     if (ServiceKey != NULL)
1232         ZwClose(ServiceKey);
1233 
1234     ExFreePool(ServiceKeyName.Buffer);
1235 
1236     return Status;
1237 }
1238 
1239 static
1240 VOID
1241 NTAPI
1242 IopStartDevice2(IN PDEVICE_OBJECT DeviceObject)
1243 {
1244     IO_STACK_LOCATION Stack;
1245     PDEVICE_NODE DeviceNode;
1246     NTSTATUS Status;
1247     PVOID Dummy;
1248     DEVICE_CAPABILITIES DeviceCapabilities;
1249 
1250     /* Get the device node */
1251     DeviceNode = IopGetDeviceNode(DeviceObject);
1252 
1253     ASSERT(!(DeviceNode->Flags & DNF_DISABLED));
1254 
1255     /* Build the I/O stack location */
1256     RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION));
1257     Stack.MajorFunction = IRP_MJ_PNP;
1258     Stack.MinorFunction = IRP_MN_START_DEVICE;
1259 
1260     Stack.Parameters.StartDevice.AllocatedResources =
1261          DeviceNode->ResourceList;
1262     Stack.Parameters.StartDevice.AllocatedResourcesTranslated =
1263          DeviceNode->ResourceListTranslated;
1264 
1265     /* Do the call */
1266     Status = IopSynchronousCall(DeviceObject, &Stack, &Dummy);
1267     if (!NT_SUCCESS(Status))
1268     {
1269         /* Send an IRP_MN_REMOVE_DEVICE request */
1270         IopRemoveDevice(DeviceNode);
1271 
1272         /* Set the appropriate flag */
1273         DeviceNode->Flags |= DNF_START_FAILED;
1274         DeviceNode->Problem = CM_PROB_FAILED_START;
1275 
1276         DPRINT1("Warning: PnP Start failed (%wZ) [Status: 0x%x]\n", &DeviceNode->InstancePath, Status);
1277         return;
1278     }
1279 
1280     DPRINT("Sending IRP_MN_QUERY_CAPABILITIES to device stack (after start)\n");
1281 
1282     Status = IopQueryDeviceCapabilities(DeviceNode, &DeviceCapabilities);
1283     if (!NT_SUCCESS(Status))
1284     {
1285         DPRINT("IopInitiatePnpIrp() failed (Status 0x%08lx)\n", Status);
1286     }
1287 
1288     /* Invalidate device state so IRP_MN_QUERY_PNP_DEVICE_STATE is sent */
1289     IoInvalidateDeviceState(DeviceObject);
1290 
1291     /* Otherwise, mark us as started */
1292     DeviceNode->Flags |= DNF_STARTED;
1293     DeviceNode->Flags &= ~DNF_STOPPED;
1294 
1295     /* We now need enumeration */
1296     DeviceNode->Flags |= DNF_NEED_ENUMERATION_ONLY;
1297 }
1298 
1299 static
1300 NTSTATUS
1301 NTAPI
1302 IopStartAndEnumerateDevice(IN PDEVICE_NODE DeviceNode)
1303 {
1304     PDEVICE_OBJECT DeviceObject;
1305     NTSTATUS Status;
1306     PAGED_CODE();
1307 
1308     /* Sanity check */
1309     ASSERT((DeviceNode->Flags & DNF_ADDED));
1310     ASSERT((DeviceNode->Flags & (DNF_RESOURCE_ASSIGNED |
1311                                  DNF_RESOURCE_REPORTED |
1312                                  DNF_NO_RESOURCE_REQUIRED)));
1313 
1314     /* Get the device object */
1315     DeviceObject = DeviceNode->PhysicalDeviceObject;
1316 
1317     /* Check if we're not started yet */
1318     if (!(DeviceNode->Flags & DNF_STARTED))
1319     {
1320         /* Start us */
1321         IopStartDevice2(DeviceObject);
1322     }
1323 
1324     /* Do we need to query IDs? This happens in the case of manual reporting */
1325 #if 0
1326     if (DeviceNode->Flags & DNF_NEED_QUERY_IDS)
1327     {
1328         DPRINT1("Warning: Device node has DNF_NEED_QUERY_IDS\n");
1329         /* And that case shouldn't happen yet */
1330         ASSERT(FALSE);
1331     }
1332 #endif
1333 
1334     IopSetServiceEnumData(DeviceNode);
1335 
1336     /* Make sure we're started, and check if we need enumeration */
1337     if ((DeviceNode->Flags & DNF_STARTED) &&
1338         (DeviceNode->Flags & DNF_NEED_ENUMERATION_ONLY))
1339     {
1340         /* Enumerate us */
1341         IoSynchronousInvalidateDeviceRelations(DeviceObject, BusRelations);
1342         Status = STATUS_SUCCESS;
1343     }
1344     else
1345     {
1346         /* Nothing to do */
1347         Status = STATUS_SUCCESS;
1348     }
1349 
1350     /* Return */
1351     return Status;
1352 }
1353 
1354 NTSTATUS
1355 IopStartDevice(
1356     PDEVICE_NODE DeviceNode)
1357 {
1358     NTSTATUS Status;
1359     HANDLE InstanceHandle = NULL, ControlHandle = NULL;
1360     UNICODE_STRING KeyName, ValueString;
1361     OBJECT_ATTRIBUTES ObjectAttributes;
1362 
1363     if (DeviceNode->Flags & DNF_DISABLED)
1364         return STATUS_SUCCESS;
1365 
1366     Status = IopAssignDeviceResources(DeviceNode);
1367     if (!NT_SUCCESS(Status))
1368         goto ByeBye;
1369 
1370     /* New PnP ABI */
1371     IopStartAndEnumerateDevice(DeviceNode);
1372 
1373     /* FIX: Should be done in new device instance code */
1374     Status = IopCreateDeviceKeyPath(&DeviceNode->InstancePath, REG_OPTION_NON_VOLATILE, &InstanceHandle);
1375     if (!NT_SUCCESS(Status))
1376         goto ByeBye;
1377 
1378     /* FIX: Should be done in IoXxxPrepareDriverLoading */
1379     // {
1380     RtlInitUnicodeString(&KeyName, L"Control");
1381     InitializeObjectAttributes(&ObjectAttributes,
1382                                &KeyName,
1383                                OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
1384                                InstanceHandle,
1385                                NULL);
1386     Status = ZwCreateKey(&ControlHandle,
1387                          KEY_SET_VALUE,
1388                          &ObjectAttributes,
1389                          0,
1390                          NULL,
1391                          REG_OPTION_VOLATILE,
1392                          NULL);
1393     if (!NT_SUCCESS(Status))
1394         goto ByeBye;
1395 
1396     RtlInitUnicodeString(&KeyName, L"ActiveService");
1397     ValueString = DeviceNode->ServiceName;
1398     if (!ValueString.Buffer)
1399         RtlInitUnicodeString(&ValueString, L"");
1400     Status = ZwSetValueKey(ControlHandle, &KeyName, 0, REG_SZ, ValueString.Buffer, ValueString.Length + sizeof(UNICODE_NULL));
1401     // }
1402 
1403 ByeBye:
1404     if (ControlHandle != NULL)
1405         ZwClose(ControlHandle);
1406 
1407     if (InstanceHandle != NULL)
1408         ZwClose(InstanceHandle);
1409 
1410     return Status;
1411 }
1412 
1413 static
1414 NTSTATUS
1415 NTAPI
1416 IopQueryStopDevice(IN PDEVICE_OBJECT DeviceObject)
1417 {
1418     IO_STACK_LOCATION Stack;
1419     PVOID Dummy;
1420 
1421     RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION));
1422     Stack.MajorFunction = IRP_MJ_PNP;
1423     Stack.MinorFunction = IRP_MN_QUERY_STOP_DEVICE;
1424 
1425     return IopSynchronousCall(DeviceObject, &Stack, &Dummy);
1426 }
1427 
1428 static
1429 VOID
1430 NTAPI
1431 IopSendStopDevice(IN PDEVICE_OBJECT DeviceObject)
1432 {
1433     IO_STACK_LOCATION Stack;
1434     PVOID Dummy;
1435 
1436     RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION));
1437     Stack.MajorFunction = IRP_MJ_PNP;
1438     Stack.MinorFunction = IRP_MN_STOP_DEVICE;
1439 
1440     /* Drivers should never fail a IRP_MN_STOP_DEVICE request */
1441     IopSynchronousCall(DeviceObject, &Stack, &Dummy);
1442 }
1443 
1444 NTSTATUS
1445 IopStopDevice(
1446     PDEVICE_NODE DeviceNode)
1447 {
1448     NTSTATUS Status;
1449 
1450     DPRINT("Stopping device: %wZ\n", &DeviceNode->InstancePath);
1451 
1452     Status = IopQueryStopDevice(DeviceNode->PhysicalDeviceObject);
1453     if (NT_SUCCESS(Status))
1454     {
1455         IopSendStopDevice(DeviceNode->PhysicalDeviceObject);
1456 
1457         DeviceNode->Flags &= ~(DNF_STARTED | DNF_START_REQUEST_PENDING);
1458         DeviceNode->Flags |= DNF_STOPPED;
1459 
1460         return STATUS_SUCCESS;
1461     }
1462 
1463     return Status;
1464 }
1465 
1466 /* PUBLIC FUNCTIONS **********************************************************/
1467 
1468 static
1469 VOID
1470 NTAPI
1471 IopSendRemoveDevice(IN PDEVICE_OBJECT DeviceObject)
1472 {
1473     IO_STACK_LOCATION Stack;
1474     PVOID Dummy;
1475     PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject);
1476 
1477     /* Drop all our state for this device in case it isn't really going away */
1478     DeviceNode->Flags &= DNF_ENUMERATED | DNF_PROCESSED;
1479 
1480     RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION));
1481     Stack.MajorFunction = IRP_MJ_PNP;
1482     Stack.MinorFunction = IRP_MN_REMOVE_DEVICE;
1483 
1484     /* Drivers should never fail a IRP_MN_REMOVE_DEVICE request */
1485     IopSynchronousCall(DeviceObject, &Stack, &Dummy);
1486 
1487     IopNotifyPlugPlayNotification(DeviceObject,
1488                                   EventCategoryTargetDeviceChange,
1489                                   &GUID_TARGET_DEVICE_REMOVE_COMPLETE,
1490                                   NULL,
1491                                   NULL);
1492     ObDereferenceObject(DeviceObject);
1493 }
1494 
1495 static
1496 VOID
1497 IopSendRemoveDeviceRelations(PDEVICE_RELATIONS DeviceRelations)
1498 {
1499     /* This function DOES dereference the device objects in all cases */
1500 
1501     ULONG i;
1502 
1503     for (i = 0; i < DeviceRelations->Count; i++)
1504     {
1505         IopSendRemoveDevice(DeviceRelations->Objects[i]);
1506         DeviceRelations->Objects[i] = NULL;
1507     }
1508 
1509     ExFreePool(DeviceRelations);
1510 }
1511 
1512 static
1513 VOID
1514 IopSendRemoveChildDevices(PDEVICE_NODE ParentDeviceNode)
1515 {
1516     PDEVICE_NODE ChildDeviceNode, NextDeviceNode;
1517     KIRQL OldIrql;
1518 
1519     KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
1520     ChildDeviceNode = ParentDeviceNode->Child;
1521     while (ChildDeviceNode != NULL)
1522     {
1523         NextDeviceNode = ChildDeviceNode->Sibling;
1524         KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
1525 
1526         IopSendRemoveDevice(ChildDeviceNode->PhysicalDeviceObject);
1527 
1528         ChildDeviceNode = NextDeviceNode;
1529 
1530         KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
1531     }
1532     KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
1533 }
1534 
1535 static
1536 VOID
1537 NTAPI
1538 IopSendSurpriseRemoval(IN PDEVICE_OBJECT DeviceObject)
1539 {
1540     IO_STACK_LOCATION Stack;
1541     PVOID Dummy;
1542 
1543     RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION));
1544     Stack.MajorFunction = IRP_MJ_PNP;
1545     Stack.MinorFunction = IRP_MN_SURPRISE_REMOVAL;
1546 
1547     /* Drivers should never fail a IRP_MN_SURPRISE_REMOVAL request */
1548     IopSynchronousCall(DeviceObject, &Stack, &Dummy);
1549 }
1550 
1551 static
1552 VOID
1553 NTAPI
1554 IopCancelRemoveDevice(IN PDEVICE_OBJECT DeviceObject)
1555 {
1556     IO_STACK_LOCATION Stack;
1557     PVOID Dummy;
1558 
1559     RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION));
1560     Stack.MajorFunction = IRP_MJ_PNP;
1561     Stack.MinorFunction = IRP_MN_CANCEL_REMOVE_DEVICE;
1562 
1563     /* Drivers should never fail a IRP_MN_CANCEL_REMOVE_DEVICE request */
1564     IopSynchronousCall(DeviceObject, &Stack, &Dummy);
1565 
1566     IopNotifyPlugPlayNotification(DeviceObject,
1567                                   EventCategoryTargetDeviceChange,
1568                                   &GUID_TARGET_DEVICE_REMOVE_CANCELLED,
1569                                   NULL,
1570                                   NULL);
1571 }
1572 
1573 static
1574 VOID
1575 IopCancelRemoveChildDevices(PDEVICE_NODE ParentDeviceNode)
1576 {
1577     PDEVICE_NODE ChildDeviceNode, NextDeviceNode;
1578     KIRQL OldIrql;
1579 
1580     KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
1581     ChildDeviceNode = ParentDeviceNode->Child;
1582     while (ChildDeviceNode != NULL)
1583     {
1584         NextDeviceNode = ChildDeviceNode->Sibling;
1585         KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
1586 
1587         IopCancelPrepareDeviceForRemoval(ChildDeviceNode->PhysicalDeviceObject);
1588 
1589         ChildDeviceNode = NextDeviceNode;
1590 
1591         KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
1592     }
1593     KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
1594 }
1595 
1596 static
1597 VOID
1598 IopCancelRemoveDeviceRelations(PDEVICE_RELATIONS DeviceRelations)
1599 {
1600     /* This function DOES dereference the device objects in all cases */
1601 
1602     ULONG i;
1603 
1604     for (i = 0; i < DeviceRelations->Count; i++)
1605     {
1606         IopCancelPrepareDeviceForRemoval(DeviceRelations->Objects[i]);
1607         ObDereferenceObject(DeviceRelations->Objects[i]);
1608         DeviceRelations->Objects[i] = NULL;
1609     }
1610 
1611     ExFreePool(DeviceRelations);
1612 }
1613 
1614 static
1615 VOID
1616 IopCancelPrepareDeviceForRemoval(PDEVICE_OBJECT DeviceObject)
1617 {
1618     IO_STACK_LOCATION Stack;
1619     IO_STATUS_BLOCK IoStatusBlock;
1620     PDEVICE_RELATIONS DeviceRelations;
1621     NTSTATUS Status;
1622 
1623     IopCancelRemoveDevice(DeviceObject);
1624 
1625     Stack.Parameters.QueryDeviceRelations.Type = RemovalRelations;
1626 
1627     Status = IopInitiatePnpIrp(DeviceObject,
1628                                &IoStatusBlock,
1629                                IRP_MN_QUERY_DEVICE_RELATIONS,
1630                                &Stack);
1631     if (!NT_SUCCESS(Status))
1632     {
1633         DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status);
1634         DeviceRelations = NULL;
1635     }
1636     else
1637     {
1638         DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information;
1639     }
1640 
1641     if (DeviceRelations)
1642         IopCancelRemoveDeviceRelations(DeviceRelations);
1643 }
1644 
1645 static
1646 NTSTATUS
1647 NTAPI
1648 IopQueryRemoveDevice(IN PDEVICE_OBJECT DeviceObject)
1649 {
1650     PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject);
1651     IO_STACK_LOCATION Stack;
1652     PVOID Dummy;
1653     NTSTATUS Status;
1654 
1655     ASSERT(DeviceNode);
1656 
1657     IopQueueTargetDeviceEvent(&GUID_DEVICE_REMOVE_PENDING,
1658                               &DeviceNode->InstancePath);
1659 
1660     RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION));
1661     Stack.MajorFunction = IRP_MJ_PNP;
1662     Stack.MinorFunction = IRP_MN_QUERY_REMOVE_DEVICE;
1663 
1664     Status = IopSynchronousCall(DeviceObject, &Stack, &Dummy);
1665 
1666     IopNotifyPlugPlayNotification(DeviceObject,
1667                                   EventCategoryTargetDeviceChange,
1668                                   &GUID_TARGET_DEVICE_QUERY_REMOVE,
1669                                   NULL,
1670                                   NULL);
1671 
1672     if (!NT_SUCCESS(Status))
1673     {
1674         DPRINT1("Removal vetoed by %wZ\n", &DeviceNode->InstancePath);
1675         IopQueueTargetDeviceEvent(&GUID_DEVICE_REMOVAL_VETOED,
1676                                   &DeviceNode->InstancePath);
1677     }
1678 
1679     return Status;
1680 }
1681 
1682 static
1683 NTSTATUS
1684 IopQueryRemoveChildDevices(PDEVICE_NODE ParentDeviceNode, BOOLEAN Force)
1685 {
1686     PDEVICE_NODE ChildDeviceNode, NextDeviceNode, FailedRemoveDevice;
1687     NTSTATUS Status;
1688     KIRQL OldIrql;
1689 
1690     KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
1691     ChildDeviceNode = ParentDeviceNode->Child;
1692     while (ChildDeviceNode != NULL)
1693     {
1694         NextDeviceNode = ChildDeviceNode->Sibling;
1695         KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
1696 
1697         Status = IopPrepareDeviceForRemoval(ChildDeviceNode->PhysicalDeviceObject, Force);
1698         if (!NT_SUCCESS(Status))
1699         {
1700             FailedRemoveDevice = ChildDeviceNode;
1701             goto cleanup;
1702         }
1703 
1704         KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
1705         ChildDeviceNode = NextDeviceNode;
1706     }
1707     KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
1708 
1709     return STATUS_SUCCESS;
1710 
1711 cleanup:
1712     KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
1713     ChildDeviceNode = ParentDeviceNode->Child;
1714     while (ChildDeviceNode != NULL)
1715     {
1716         NextDeviceNode = ChildDeviceNode->Sibling;
1717         KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
1718 
1719         IopCancelPrepareDeviceForRemoval(ChildDeviceNode->PhysicalDeviceObject);
1720 
1721         /* IRP_MN_CANCEL_REMOVE_DEVICE is also sent to the device
1722          * that failed the IRP_MN_QUERY_REMOVE_DEVICE request */
1723         if (ChildDeviceNode == FailedRemoveDevice)
1724             return Status;
1725 
1726         ChildDeviceNode = NextDeviceNode;
1727 
1728         KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
1729     }
1730     KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
1731 
1732     return Status;
1733 }
1734 
1735 static
1736 NTSTATUS
1737 IopQueryRemoveDeviceRelations(PDEVICE_RELATIONS DeviceRelations, BOOLEAN Force)
1738 {
1739     /* This function DOES NOT dereference the device objects on SUCCESS
1740      * but it DOES dereference device objects on FAILURE */
1741 
1742     ULONG i, j;
1743     NTSTATUS Status;
1744 
1745     for (i = 0; i < DeviceRelations->Count; i++)
1746     {
1747         Status = IopPrepareDeviceForRemoval(DeviceRelations->Objects[i], Force);
1748         if (!NT_SUCCESS(Status))
1749         {
1750             j = i;
1751             goto cleanup;
1752         }
1753     }
1754 
1755     return STATUS_SUCCESS;
1756 
1757 cleanup:
1758     /* IRP_MN_CANCEL_REMOVE_DEVICE is also sent to the device
1759      * that failed the IRP_MN_QUERY_REMOVE_DEVICE request */
1760     for (i = 0; i <= j; i++)
1761     {
1762         IopCancelPrepareDeviceForRemoval(DeviceRelations->Objects[i]);
1763         ObDereferenceObject(DeviceRelations->Objects[i]);
1764         DeviceRelations->Objects[i] = NULL;
1765     }
1766     for (; i < DeviceRelations->Count; i++)
1767     {
1768         ObDereferenceObject(DeviceRelations->Objects[i]);
1769         DeviceRelations->Objects[i] = NULL;
1770     }
1771     ExFreePool(DeviceRelations);
1772 
1773     return Status;
1774 }
1775 
1776 static
1777 NTSTATUS
1778 IopPrepareDeviceForRemoval(IN PDEVICE_OBJECT DeviceObject, BOOLEAN Force)
1779 {
1780     PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject);
1781     IO_STACK_LOCATION Stack;
1782     IO_STATUS_BLOCK IoStatusBlock;
1783     PDEVICE_RELATIONS DeviceRelations;
1784     NTSTATUS Status;
1785 
1786     if ((DeviceNode->UserFlags & DNUF_NOT_DISABLEABLE) && !Force)
1787     {
1788         DPRINT1("Removal not allowed for %wZ\n", &DeviceNode->InstancePath);
1789         return STATUS_UNSUCCESSFUL;
1790     }
1791 
1792     if (!Force && IopQueryRemoveDevice(DeviceObject) != STATUS_SUCCESS)
1793     {
1794         DPRINT1("Removal vetoed by failing the query remove request\n");
1795 
1796         IopCancelRemoveDevice(DeviceObject);
1797 
1798         return STATUS_UNSUCCESSFUL;
1799     }
1800 
1801     Stack.Parameters.QueryDeviceRelations.Type = RemovalRelations;
1802 
1803     Status = IopInitiatePnpIrp(DeviceObject,
1804                                &IoStatusBlock,
1805                                IRP_MN_QUERY_DEVICE_RELATIONS,
1806                                &Stack);
1807     if (!NT_SUCCESS(Status))
1808     {
1809         DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status);
1810         DeviceRelations = NULL;
1811     }
1812     else
1813     {
1814         DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information;
1815     }
1816 
1817     if (DeviceRelations)
1818     {
1819         Status = IopQueryRemoveDeviceRelations(DeviceRelations, Force);
1820         if (!NT_SUCCESS(Status))
1821             return Status;
1822     }
1823 
1824     Status = IopQueryRemoveChildDevices(DeviceNode, Force);
1825     if (!NT_SUCCESS(Status))
1826     {
1827         if (DeviceRelations)
1828             IopCancelRemoveDeviceRelations(DeviceRelations);
1829         return Status;
1830     }
1831 
1832     if (DeviceRelations)
1833         IopSendRemoveDeviceRelations(DeviceRelations);
1834     IopSendRemoveChildDevices(DeviceNode);
1835 
1836     return STATUS_SUCCESS;
1837 }
1838 
1839 static
1840 VOID
1841 IopHandleDeviceRemoval(
1842     IN PDEVICE_NODE DeviceNode,
1843     IN PDEVICE_RELATIONS DeviceRelations)
1844 {
1845     PDEVICE_NODE Child = DeviceNode->Child, NextChild;
1846     ULONG i;
1847     BOOLEAN Found;
1848 
1849     if (DeviceNode == IopRootDeviceNode)
1850         return;
1851 
1852     while (Child != NULL)
1853     {
1854         NextChild = Child->Sibling;
1855         Found = FALSE;
1856 
1857         for (i = 0; DeviceRelations && i < DeviceRelations->Count; i++)
1858         {
1859             if (IopGetDeviceNode(DeviceRelations->Objects[i]) == Child)
1860             {
1861                 Found = TRUE;
1862                 break;
1863             }
1864         }
1865 
1866         if (!Found && !(Child->Flags & DNF_WILL_BE_REMOVED))
1867         {
1868             /* Send removal IRPs to all of its children */
1869             IopPrepareDeviceForRemoval(Child->PhysicalDeviceObject, TRUE);
1870 
1871             /* Send the surprise removal IRP */
1872             IopSendSurpriseRemoval(Child->PhysicalDeviceObject);
1873 
1874             /* Tell the user-mode PnP manager that a device was removed */
1875             IopQueueTargetDeviceEvent(&GUID_DEVICE_SURPRISE_REMOVAL,
1876                                       &Child->InstancePath);
1877 
1878             /* Send the remove device IRP */
1879             IopSendRemoveDevice(Child->PhysicalDeviceObject);
1880         }
1881 
1882         Child = NextChild;
1883     }
1884 }
1885 
1886 NTSTATUS
1887 IopRemoveDevice(PDEVICE_NODE DeviceNode)
1888 {
1889     NTSTATUS Status;
1890 
1891     DPRINT("Removing device: %wZ\n", &DeviceNode->InstancePath);
1892 
1893     Status = IopPrepareDeviceForRemoval(DeviceNode->PhysicalDeviceObject, FALSE);
1894     if (NT_SUCCESS(Status))
1895     {
1896         IopSendRemoveDevice(DeviceNode->PhysicalDeviceObject);
1897         IopQueueTargetDeviceEvent(&GUID_DEVICE_SAFE_REMOVAL,
1898                                   &DeviceNode->InstancePath);
1899         return STATUS_SUCCESS;
1900     }
1901 
1902     return Status;
1903 }
1904 
1905 /*
1906  * @implemented
1907  */
1908 VOID
1909 NTAPI
1910 IoInvalidateDeviceState(IN PDEVICE_OBJECT PhysicalDeviceObject)
1911 {
1912     PDEVICE_NODE DeviceNode = IopGetDeviceNode(PhysicalDeviceObject);
1913     IO_STACK_LOCATION Stack;
1914     ULONG_PTR PnPFlags;
1915     NTSTATUS Status;
1916     IO_STATUS_BLOCK IoStatusBlock;
1917 
1918     RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION));
1919     Stack.MajorFunction = IRP_MJ_PNP;
1920     Stack.MinorFunction = IRP_MN_QUERY_PNP_DEVICE_STATE;
1921 
1922     Status = IopSynchronousCall(PhysicalDeviceObject, &Stack, (PVOID*)&PnPFlags);
1923     if (!NT_SUCCESS(Status))
1924     {
1925         if (Status != STATUS_NOT_SUPPORTED)
1926         {
1927             DPRINT1("IRP_MN_QUERY_PNP_DEVICE_STATE failed with status 0x%lx\n", Status);
1928         }
1929         return;
1930     }
1931 
1932     if (PnPFlags & PNP_DEVICE_NOT_DISABLEABLE)
1933         DeviceNode->UserFlags |= DNUF_NOT_DISABLEABLE;
1934     else
1935         DeviceNode->UserFlags &= ~DNUF_NOT_DISABLEABLE;
1936 
1937     if (PnPFlags & PNP_DEVICE_DONT_DISPLAY_IN_UI)
1938         DeviceNode->UserFlags |= DNUF_DONT_SHOW_IN_UI;
1939     else
1940         DeviceNode->UserFlags &= ~DNUF_DONT_SHOW_IN_UI;
1941 
1942     if ((PnPFlags & PNP_DEVICE_REMOVED) ||
1943         ((PnPFlags & PNP_DEVICE_FAILED) && !(PnPFlags & PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED)))
1944     {
1945         /* Flag it if it's failed */
1946         if (PnPFlags & PNP_DEVICE_FAILED) DeviceNode->Problem = CM_PROB_FAILED_POST_START;
1947 
1948         /* Send removal IRPs to all of its children */
1949         IopPrepareDeviceForRemoval(PhysicalDeviceObject, TRUE);
1950 
1951         /* Send surprise removal */
1952         IopSendSurpriseRemoval(PhysicalDeviceObject);
1953 
1954         /* Tell the user-mode PnP manager that a device was removed */
1955         IopQueueTargetDeviceEvent(&GUID_DEVICE_SURPRISE_REMOVAL,
1956                                   &DeviceNode->InstancePath);
1957 
1958         IopSendRemoveDevice(PhysicalDeviceObject);
1959     }
1960     else if ((PnPFlags & PNP_DEVICE_FAILED) && (PnPFlags & PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED))
1961     {
1962         /* Stop for resource rebalance */
1963         Status = IopStopDevice(DeviceNode);
1964         if (!NT_SUCCESS(Status))
1965         {
1966             DPRINT1("Failed to stop device for rebalancing\n");
1967 
1968             /* Stop failed so don't rebalance */
1969             PnPFlags &= ~PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED;
1970         }
1971     }
1972 
1973     /* Resource rebalance */
1974     if (PnPFlags & PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED)
1975     {
1976         DPRINT("Sending IRP_MN_QUERY_RESOURCES to device stack\n");
1977 
1978         Status = IopInitiatePnpIrp(PhysicalDeviceObject,
1979                                    &IoStatusBlock,
1980                                    IRP_MN_QUERY_RESOURCES,
1981                                    NULL);
1982         if (NT_SUCCESS(Status) && IoStatusBlock.Information)
1983         {
1984             DeviceNode->BootResources =
1985             (PCM_RESOURCE_LIST)IoStatusBlock.Information;
1986             IopDeviceNodeSetFlag(DeviceNode, DNF_HAS_BOOT_CONFIG);
1987         }
1988         else
1989         {
1990             DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status);
1991             DeviceNode->BootResources = NULL;
1992         }
1993 
1994         DPRINT("Sending IRP_MN_QUERY_RESOURCE_REQUIREMENTS to device stack\n");
1995 
1996         Status = IopInitiatePnpIrp(PhysicalDeviceObject,
1997                                    &IoStatusBlock,
1998                                    IRP_MN_QUERY_RESOURCE_REQUIREMENTS,
1999                                    NULL);
2000         if (NT_SUCCESS(Status))
2001         {
2002             DeviceNode->ResourceRequirements =
2003             (PIO_RESOURCE_REQUIREMENTS_LIST)IoStatusBlock.Information;
2004         }
2005         else
2006         {
2007             DPRINT("IopInitiatePnpIrp() failed (Status %08lx)\n", Status);
2008             DeviceNode->ResourceRequirements = NULL;
2009         }
2010 
2011         /* IRP_MN_FILTER_RESOURCE_REQUIREMENTS is called indirectly by IopStartDevice */
2012         if (IopStartDevice(DeviceNode) != STATUS_SUCCESS)
2013         {
2014             DPRINT1("Restart after resource rebalance failed\n");
2015 
2016             DeviceNode->Flags &= ~(DNF_STARTED | DNF_START_REQUEST_PENDING);
2017             DeviceNode->Flags |= DNF_START_FAILED;
2018 
2019             IopRemoveDevice(DeviceNode);
2020         }
2021     }
2022 }
2023 
2024 /*
2025  * IopInitializePnpServices
2026  *
2027  * Initialize services for discovered children
2028  *
2029  * Parameters
2030  *    DeviceNode
2031  *       Top device node to start initializing services.
2032  *
2033  * Return Value
2034  *    Status
2035  */
2036 NTSTATUS
2037 IopInitializePnpServices(IN PDEVICE_NODE DeviceNode)
2038 {
2039     DEVICETREE_TRAVERSE_CONTEXT Context;
2040 
2041     DPRINT("IopInitializePnpServices(%p)\n", DeviceNode);
2042 
2043     IopInitDeviceTreeTraverseContext(
2044         &Context,
2045         DeviceNode,
2046         IopActionInitChildServices,
2047         DeviceNode);
2048 
2049     return IopTraverseDeviceTree(&Context);
2050 }
2051 
2052 
2053 NTSTATUS
2054 IopEnumerateDevice(
2055     IN PDEVICE_OBJECT DeviceObject)
2056 {
2057     PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject);
2058     DEVICETREE_TRAVERSE_CONTEXT Context;
2059     PDEVICE_RELATIONS DeviceRelations;
2060     PDEVICE_OBJECT ChildDeviceObject;
2061     IO_STATUS_BLOCK IoStatusBlock;
2062     PDEVICE_NODE ChildDeviceNode;
2063     IO_STACK_LOCATION Stack;
2064     NTSTATUS Status;
2065     ULONG i;
2066 
2067     DPRINT("DeviceObject 0x%p\n", DeviceObject);
2068 
2069     if (DeviceNode->Flags & DNF_NEED_ENUMERATION_ONLY)
2070     {
2071         DeviceNode->Flags &= ~DNF_NEED_ENUMERATION_ONLY;
2072 
2073         DPRINT("Sending GUID_DEVICE_ARRIVAL\n");
2074         IopQueueTargetDeviceEvent(&GUID_DEVICE_ARRIVAL,
2075                                   &DeviceNode->InstancePath);
2076     }
2077 
2078     DPRINT("Sending IRP_MN_QUERY_DEVICE_RELATIONS to device stack\n");
2079 
2080     Stack.Parameters.QueryDeviceRelations.Type = BusRelations;
2081 
2082     Status = IopInitiatePnpIrp(
2083         DeviceObject,
2084         &IoStatusBlock,
2085         IRP_MN_QUERY_DEVICE_RELATIONS,
2086         &Stack);
2087     if (!NT_SUCCESS(Status) || Status == STATUS_PENDING)
2088     {
2089         DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status);
2090         return Status;
2091     }
2092 
2093     DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information;
2094 
2095     /*
2096      * Send removal IRPs for devices that have disappeared
2097      * NOTE: This code handles the case where no relations are specified
2098      */
2099     IopHandleDeviceRemoval(DeviceNode, DeviceRelations);
2100 
2101     /* Now we bail if nothing was returned */
2102     if (!DeviceRelations)
2103     {
2104         /* We're all done */
2105         DPRINT("No PDOs\n");
2106         return STATUS_SUCCESS;
2107     }
2108 
2109     DPRINT("Got %u PDOs\n", DeviceRelations->Count);
2110 
2111     /*
2112      * Create device nodes for all discovered devices
2113      */
2114     for (i = 0; i < DeviceRelations->Count; i++)
2115     {
2116         ChildDeviceObject = DeviceRelations->Objects[i];
2117         ASSERT((ChildDeviceObject->Flags & DO_DEVICE_INITIALIZING) == 0);
2118 
2119         ChildDeviceNode = IopGetDeviceNode(ChildDeviceObject);
2120         if (!ChildDeviceNode)
2121         {
2122             /* One doesn't exist, create it */
2123             Status = IopCreateDeviceNode(
2124                 DeviceNode,
2125                 ChildDeviceObject,
2126                 NULL,
2127                 &ChildDeviceNode);
2128             if (NT_SUCCESS(Status))
2129             {
2130                 /* Mark the node as enumerated */
2131                 ChildDeviceNode->Flags |= DNF_ENUMERATED;
2132 
2133                 /* Mark the DO as bus enumerated */
2134                 ChildDeviceObject->Flags |= DO_BUS_ENUMERATED_DEVICE;
2135             }
2136             else
2137             {
2138                 /* Ignore this DO */
2139                 DPRINT1("IopCreateDeviceNode() failed with status 0x%08x. Skipping PDO %u\n", Status, i);
2140                 ObDereferenceObject(ChildDeviceObject);
2141             }
2142         }
2143         else
2144         {
2145             /* Mark it as enumerated */
2146             ChildDeviceNode->Flags |= DNF_ENUMERATED;
2147             ObDereferenceObject(ChildDeviceObject);
2148         }
2149     }
2150     ExFreePool(DeviceRelations);
2151 
2152     /*
2153      * Retrieve information about all discovered children from the bus driver
2154      */
2155     IopInitDeviceTreeTraverseContext(
2156         &Context,
2157         DeviceNode,
2158         IopActionInterrogateDeviceStack,
2159         DeviceNode);
2160 
2161     Status = IopTraverseDeviceTree(&Context);
2162     if (!NT_SUCCESS(Status))
2163     {
2164         DPRINT("IopTraverseDeviceTree() failed with status 0x%08lx\n", Status);
2165         return Status;
2166     }
2167 
2168     /*
2169      * Retrieve configuration from the registry for discovered children
2170      */
2171     IopInitDeviceTreeTraverseContext(
2172         &Context,
2173         DeviceNode,
2174         IopActionConfigureChildServices,
2175         DeviceNode);
2176 
2177     Status = IopTraverseDeviceTree(&Context);
2178     if (!NT_SUCCESS(Status))
2179     {
2180         DPRINT("IopTraverseDeviceTree() failed with status 0x%08lx\n", Status);
2181         return Status;
2182     }
2183 
2184     /*
2185      * Initialize services for discovered children.
2186      */
2187     Status = IopInitializePnpServices(DeviceNode);
2188     if (!NT_SUCCESS(Status))
2189     {
2190         DPRINT("IopInitializePnpServices() failed with status 0x%08lx\n", Status);
2191         return Status;
2192     }
2193 
2194     DPRINT("IopEnumerateDevice() finished\n");
2195     return STATUS_SUCCESS;
2196 }
2197 
2198 static
2199 NTSTATUS
2200 NTAPI
2201 IopSendEject(IN PDEVICE_OBJECT DeviceObject)
2202 {
2203     IO_STACK_LOCATION Stack;
2204     PVOID Dummy;
2205 
2206     RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION));
2207     Stack.MajorFunction = IRP_MJ_PNP;
2208     Stack.MinorFunction = IRP_MN_EJECT;
2209 
2210     return IopSynchronousCall(DeviceObject, &Stack, &Dummy);
2211 }
2212 
2213 /*
2214  * @implemented
2215  */
2216 VOID
2217 NTAPI
2218 IoRequestDeviceEject(IN PDEVICE_OBJECT PhysicalDeviceObject)
2219 {
2220     PDEVICE_NODE DeviceNode = IopGetDeviceNode(PhysicalDeviceObject);
2221     PDEVICE_RELATIONS DeviceRelations;
2222     IO_STATUS_BLOCK IoStatusBlock;
2223     IO_STACK_LOCATION Stack;
2224     DEVICE_CAPABILITIES Capabilities;
2225     NTSTATUS Status;
2226 
2227     IopQueueTargetDeviceEvent(&GUID_DEVICE_KERNEL_INITIATED_EJECT,
2228                               &DeviceNode->InstancePath);
2229 
2230     if (IopQueryDeviceCapabilities(DeviceNode, &Capabilities) != STATUS_SUCCESS)
2231     {
2232         goto cleanup;
2233     }
2234 
2235     Stack.Parameters.QueryDeviceRelations.Type = EjectionRelations;
2236 
2237     Status = IopInitiatePnpIrp(PhysicalDeviceObject,
2238                                &IoStatusBlock,
2239                                IRP_MN_QUERY_DEVICE_RELATIONS,
2240                                &Stack);
2241     if (!NT_SUCCESS(Status))
2242     {
2243         DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status);
2244         DeviceRelations = NULL;
2245     }
2246     else
2247     {
2248         DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information;
2249     }
2250 
2251     if (DeviceRelations)
2252     {
2253         Status = IopQueryRemoveDeviceRelations(DeviceRelations, FALSE);
2254         if (!NT_SUCCESS(Status))
2255             goto cleanup;
2256     }
2257 
2258     Status = IopQueryRemoveChildDevices(DeviceNode, FALSE);
2259     if (!NT_SUCCESS(Status))
2260     {
2261         if (DeviceRelations)
2262             IopCancelRemoveDeviceRelations(DeviceRelations);
2263         goto cleanup;
2264     }
2265 
2266     if (IopPrepareDeviceForRemoval(PhysicalDeviceObject, FALSE) != STATUS_SUCCESS)
2267     {
2268         if (DeviceRelations)
2269             IopCancelRemoveDeviceRelations(DeviceRelations);
2270         IopCancelRemoveChildDevices(DeviceNode);
2271         goto cleanup;
2272     }
2273 
2274     if (DeviceRelations)
2275         IopSendRemoveDeviceRelations(DeviceRelations);
2276     IopSendRemoveChildDevices(DeviceNode);
2277 
2278     DeviceNode->Problem = CM_PROB_HELD_FOR_EJECT;
2279     if (Capabilities.EjectSupported)
2280     {
2281         if (IopSendEject(PhysicalDeviceObject) != STATUS_SUCCESS)
2282         {
2283             goto cleanup;
2284         }
2285     }
2286     else
2287     {
2288         DeviceNode->Flags |= DNF_DISABLED;
2289     }
2290 
2291     IopQueueTargetDeviceEvent(&GUID_DEVICE_EJECT,
2292                               &DeviceNode->InstancePath);
2293 
2294     return;
2295 
2296 cleanup:
2297     IopQueueTargetDeviceEvent(&GUID_DEVICE_EJECT_VETOED,
2298                               &DeviceNode->InstancePath);
2299 }
2300 
2301 static
2302 VOID
2303 NTAPI
2304 IopDeviceActionWorker(
2305     _In_ PVOID Context)
2306 {
2307     PLIST_ENTRY ListEntry;
2308     PDEVICE_ACTION_DATA Data;
2309     KIRQL OldIrql;
2310 
2311     KeAcquireSpinLock(&IopDeviceActionLock, &OldIrql);
2312     while (!IsListEmpty(&IopDeviceActionRequestList))
2313     {
2314         ListEntry = RemoveHeadList(&IopDeviceActionRequestList);
2315         KeReleaseSpinLock(&IopDeviceActionLock, OldIrql);
2316         Data = CONTAINING_RECORD(ListEntry,
2317                                  DEVICE_ACTION_DATA,
2318                                  RequestListEntry);
2319 
2320         switch (Data->Action)
2321         {
2322             case DeviceActionInvalidateDeviceRelations:
2323                 IoSynchronousInvalidateDeviceRelations(Data->DeviceObject,
2324                                                        Data->InvalidateDeviceRelations.Type);
2325                 break;
2326 
2327             default:
2328                 DPRINT1("Unimplemented device action %u\n", Data->Action);
2329                 break;
2330         }
2331 
2332         ObDereferenceObject(Data->DeviceObject);
2333         ExFreePoolWithTag(Data, TAG_IO);
2334         KeAcquireSpinLock(&IopDeviceActionLock, &OldIrql);
2335     }
2336     IopDeviceActionInProgress = FALSE;
2337     KeReleaseSpinLock(&IopDeviceActionLock, OldIrql);
2338 }
2339 
2340 VOID
2341 IopQueueDeviceAction(
2342     _In_ PDEVICE_ACTION_DATA ActionData)
2343 {
2344     PDEVICE_ACTION_DATA Data;
2345     KIRQL OldIrql;
2346 
2347     DPRINT("IopQueueDeviceAction(%p)\n", ActionData);
2348 
2349     Data = ExAllocatePoolWithTag(NonPagedPool,
2350                                  sizeof(DEVICE_ACTION_DATA),
2351                                  TAG_IO);
2352     if (!Data)
2353         return;
2354 
2355     ObReferenceObject(ActionData->DeviceObject);
2356     RtlCopyMemory(Data, ActionData, sizeof(DEVICE_ACTION_DATA));
2357 
2358     DPRINT("Action %u\n", Data->Action);
2359 
2360     KeAcquireSpinLock(&IopDeviceActionLock, &OldIrql);
2361     InsertTailList(&IopDeviceActionRequestList, &Data->RequestListEntry);
2362     if (IopDeviceActionInProgress)
2363     {
2364         KeReleaseSpinLock(&IopDeviceActionLock, OldIrql);
2365         return;
2366     }
2367     IopDeviceActionInProgress = TRUE;
2368     KeReleaseSpinLock(&IopDeviceActionLock, OldIrql);
2369 
2370     ExInitializeWorkItem(&IopDeviceActionWorkItem,
2371                          IopDeviceActionWorker,
2372                          NULL);
2373     ExQueueWorkItem(&IopDeviceActionWorkItem,
2374                     DelayedWorkQueue);
2375 }
2376