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