[NTOS:IO] Move device manipulation functions from pnpmgr/pnpmgr.c to pnpmgr/devaction.c
[reactos.git] / ntoskrnl / io / pnpmgr / devaction.c
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 }