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