1 /* 2 * PROJECT: ReactOS Kernel 3 * COPYRIGHT: GPL - See COPYING in the top level directory 4 * FILE: ntoskrnl/io/pnpmgr/pnproot.c 5 * PURPOSE: PnP manager root device 6 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net) 7 * Copyright 2007 Herv? Poussineau (hpoussin@reactos.org) 8 */ 9 10 /* INCLUDES ******************************************************************/ 11 12 #include <ntoskrnl.h> 13 #define NDEBUG 14 #include <debug.h> 15 16 /* GLOBALS *******************************************************************/ 17 18 #define ENUM_NAME_ROOT L"Root" 19 20 /* DATA **********************************************************************/ 21 22 typedef struct _PNPROOT_DEVICE 23 { 24 // Entry on device list 25 LIST_ENTRY ListEntry; 26 // Physical Device Object of device 27 PDEVICE_OBJECT Pdo; 28 // Device ID 29 UNICODE_STRING DeviceID; 30 // Instance ID 31 UNICODE_STRING InstanceID; 32 // Device description 33 UNICODE_STRING DeviceDescription; 34 // Resource requirement list 35 PIO_RESOURCE_REQUIREMENTS_LIST ResourceRequirementsList; 36 // Associated resource list 37 PCM_RESOURCE_LIST ResourceList; 38 ULONG ResourceListSize; 39 } PNPROOT_DEVICE, *PPNPROOT_DEVICE; 40 41 typedef enum 42 { 43 dsStopped, 44 dsStarted, 45 dsPaused, 46 dsRemoved, 47 dsSurpriseRemoved 48 } PNPROOT_DEVICE_STATE; 49 50 typedef struct _PNPROOT_COMMON_DEVICE_EXTENSION 51 { 52 // Wether this device extension is for an FDO or PDO 53 BOOLEAN IsFDO; 54 } PNPROOT_COMMON_DEVICE_EXTENSION, *PPNPROOT_COMMON_DEVICE_EXTENSION; 55 56 /* Physical Device Object device extension for a child device */ 57 typedef struct _PNPROOT_PDO_DEVICE_EXTENSION 58 { 59 // Common device data 60 PNPROOT_COMMON_DEVICE_EXTENSION Common; 61 // Informations about the device 62 PPNPROOT_DEVICE DeviceInfo; 63 } PNPROOT_PDO_DEVICE_EXTENSION, *PPNPROOT_PDO_DEVICE_EXTENSION; 64 65 /* Physical Device Object device extension for the Root bus device object */ 66 typedef struct _PNPROOT_FDO_DEVICE_EXTENSION 67 { 68 // Common device data 69 PNPROOT_COMMON_DEVICE_EXTENSION Common; 70 // Lower device object 71 PDEVICE_OBJECT Ldo; 72 // Current state of the driver 73 PNPROOT_DEVICE_STATE State; 74 // Namespace device list 75 LIST_ENTRY DeviceListHead; 76 // Number of (not removed) devices in device list 77 ULONG DeviceListCount; 78 // Lock for namespace device list 79 KGUARDED_MUTEX DeviceListLock; 80 } PNPROOT_FDO_DEVICE_EXTENSION, *PPNPROOT_FDO_DEVICE_EXTENSION; 81 82 typedef struct _BUFFER 83 { 84 PVOID *Data; 85 PULONG Length; 86 } BUFFER, *PBUFFER; 87 88 static PDEVICE_OBJECT PnpRootDeviceObject = NULL; 89 90 /* FUNCTIONS *****************************************************************/ 91 92 static NTSTATUS 93 LocateChildDevice( 94 IN PPNPROOT_FDO_DEVICE_EXTENSION DeviceExtension, 95 IN PCUNICODE_STRING DeviceId, 96 IN PCWSTR InstanceId, 97 OUT PPNPROOT_DEVICE* ChildDevice) 98 { 99 PPNPROOT_DEVICE Device; 100 UNICODE_STRING InstanceIdU; 101 PLIST_ENTRY NextEntry; 102 103 /* Initialize the string to compare */ 104 RtlInitUnicodeString(&InstanceIdU, InstanceId); 105 106 /* Start looping */ 107 for (NextEntry = DeviceExtension->DeviceListHead.Flink; 108 NextEntry != &DeviceExtension->DeviceListHead; 109 NextEntry = NextEntry->Flink) 110 { 111 /* Get the entry */ 112 Device = CONTAINING_RECORD(NextEntry, PNPROOT_DEVICE, ListEntry); 113 114 /* See if the strings match */ 115 if (RtlEqualUnicodeString(DeviceId, &Device->DeviceID, TRUE) && 116 RtlEqualUnicodeString(&InstanceIdU, &Device->InstanceID, TRUE)) 117 { 118 /* They do, so set the pointer and return success */ 119 *ChildDevice = Device; 120 return STATUS_SUCCESS; 121 } 122 } 123 124 /* No device found */ 125 return STATUS_NO_SUCH_DEVICE; 126 } 127 128 NTSTATUS 129 PnpRootRegisterDevice( 130 IN PDEVICE_OBJECT DeviceObject) 131 { 132 PPNPROOT_FDO_DEVICE_EXTENSION DeviceExtension = PnpRootDeviceObject->DeviceExtension; 133 PPNPROOT_DEVICE Device; 134 PDEVICE_NODE DeviceNode; 135 PWSTR InstancePath; 136 UNICODE_STRING InstancePathCopy; 137 138 Device = ExAllocatePoolWithTag(PagedPool, sizeof(PNPROOT_DEVICE), TAG_PNP_ROOT); 139 if (!Device) return STATUS_NO_MEMORY; 140 141 DeviceNode = IopGetDeviceNode(DeviceObject); 142 if (!RtlCreateUnicodeString(&InstancePathCopy, DeviceNode->InstancePath.Buffer)) 143 { 144 ExFreePoolWithTag(Device, TAG_PNP_ROOT); 145 return STATUS_NO_MEMORY; 146 } 147 148 InstancePath = wcsrchr(InstancePathCopy.Buffer, L'\\'); 149 ASSERT(InstancePath); 150 151 if (!RtlCreateUnicodeString(&Device->InstanceID, InstancePath + 1)) 152 { 153 RtlFreeUnicodeString(&InstancePathCopy); 154 ExFreePoolWithTag(Device, TAG_PNP_ROOT); 155 return STATUS_NO_MEMORY; 156 } 157 158 InstancePath[0] = UNICODE_NULL; 159 160 if (!RtlCreateUnicodeString(&Device->DeviceID, InstancePathCopy.Buffer)) 161 { 162 RtlFreeUnicodeString(&InstancePathCopy); 163 RtlFreeUnicodeString(&Device->InstanceID); 164 ExFreePoolWithTag(Device, TAG_PNP_ROOT); 165 return STATUS_NO_MEMORY; 166 } 167 168 InstancePath[0] = L'\\'; 169 170 Device->Pdo = DeviceObject; 171 172 KeAcquireGuardedMutex(&DeviceExtension->DeviceListLock); 173 InsertTailList(&DeviceExtension->DeviceListHead, 174 &Device->ListEntry); 175 DeviceExtension->DeviceListCount++; 176 KeReleaseGuardedMutex(&DeviceExtension->DeviceListLock); 177 178 RtlFreeUnicodeString(&InstancePathCopy); 179 180 return STATUS_SUCCESS; 181 } 182 183 /* Creates a new PnP device for a legacy driver */ 184 NTSTATUS 185 PnpRootCreateDevice( 186 IN PUNICODE_STRING ServiceName, 187 IN OPTIONAL PDRIVER_OBJECT DriverObject, 188 OUT PDEVICE_OBJECT *PhysicalDeviceObject, 189 OUT OPTIONAL PUNICODE_STRING FullInstancePath) 190 { 191 PPNPROOT_FDO_DEVICE_EXTENSION DeviceExtension; 192 PPNPROOT_PDO_DEVICE_EXTENSION PdoDeviceExtension; 193 UNICODE_STRING DevicePath; 194 WCHAR InstancePath[5]; 195 PPNPROOT_DEVICE Device = NULL; 196 NTSTATUS Status; 197 UNICODE_STRING PathSep = RTL_CONSTANT_STRING(L"\\"); 198 ULONG NextInstance; 199 UNICODE_STRING EnumKeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\" REGSTR_PATH_SYSTEMENUM); 200 HANDLE EnumHandle, DeviceKeyHandle = NULL, InstanceKeyHandle; 201 RTL_QUERY_REGISTRY_TABLE QueryTable[2]; 202 OBJECT_ATTRIBUTES ObjectAttributes; 203 204 DeviceExtension = PnpRootDeviceObject->DeviceExtension; 205 KeAcquireGuardedMutex(&DeviceExtension->DeviceListLock); 206 207 DPRINT("Creating a PnP root device for service '%wZ'\n", ServiceName); 208 209 DevicePath.Length = 0; 210 DevicePath.MaximumLength = sizeof(REGSTR_KEY_ROOTENUM) + sizeof(L'\\') + ServiceName->Length; 211 DevicePath.Buffer = ExAllocatePoolWithTag(PagedPool, 212 DevicePath.MaximumLength, 213 TAG_PNP_ROOT); 214 if (DevicePath.Buffer == NULL) 215 { 216 DPRINT1("ExAllocatePoolWithTag() failed\n"); 217 Status = STATUS_NO_MEMORY; 218 goto cleanup; 219 } 220 RtlAppendUnicodeToString(&DevicePath, REGSTR_KEY_ROOTENUM L"\\"); 221 RtlAppendUnicodeStringToString(&DevicePath, ServiceName); 222 223 /* Initialize a PNPROOT_DEVICE structure */ 224 Device = ExAllocatePoolWithTag(PagedPool, sizeof(PNPROOT_DEVICE), TAG_PNP_ROOT); 225 if (!Device) 226 { 227 DPRINT("ExAllocatePoolWithTag() failed\n"); 228 Status = STATUS_NO_MEMORY; 229 goto cleanup; 230 } 231 RtlZeroMemory(Device, sizeof(PNPROOT_DEVICE)); 232 Device->DeviceID = DevicePath; 233 RtlInitEmptyUnicodeString(&DevicePath, NULL, 0); 234 235 Status = IopOpenRegistryKeyEx(&EnumHandle, NULL, &EnumKeyName, KEY_READ); 236 if (NT_SUCCESS(Status)) 237 { 238 InitializeObjectAttributes(&ObjectAttributes, 239 &Device->DeviceID, 240 OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, 241 EnumHandle, 242 NULL); 243 Status = ZwCreateKey(&DeviceKeyHandle, KEY_SET_VALUE, &ObjectAttributes, 0, NULL, REG_OPTION_VOLATILE, NULL); 244 ObCloseHandle(EnumHandle, KernelMode); 245 } 246 247 if (!NT_SUCCESS(Status)) 248 { 249 DPRINT1("Failed to open registry key\n"); 250 goto cleanup; 251 } 252 253 tryagain: 254 RtlZeroMemory(QueryTable, sizeof(QueryTable)); 255 QueryTable[0].Name = L"NextInstance"; 256 QueryTable[0].EntryContext = &NextInstance; 257 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED; 258 259 Status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE, 260 (PWSTR)DeviceKeyHandle, 261 QueryTable, 262 NULL, 263 NULL); 264 if (!NT_SUCCESS(Status)) 265 { 266 for (NextInstance = 0; NextInstance <= 9999; NextInstance++) 267 { 268 _snwprintf(InstancePath, sizeof(InstancePath) / sizeof(WCHAR), L"%04lu", NextInstance); 269 Status = LocateChildDevice(DeviceExtension, &Device->DeviceID, InstancePath, &Device); 270 if (Status == STATUS_NO_SUCH_DEVICE) 271 break; 272 } 273 274 if (NextInstance > 9999) 275 { 276 DPRINT1("Too many legacy devices reported for service '%wZ'\n", ServiceName); 277 Status = STATUS_INSUFFICIENT_RESOURCES; 278 goto cleanup; 279 } 280 } 281 282 _snwprintf(InstancePath, sizeof(InstancePath) / sizeof(WCHAR), L"%04lu", NextInstance); 283 Status = LocateChildDevice(DeviceExtension, &Device->DeviceID, InstancePath, &Device); 284 if (Status != STATUS_NO_SUCH_DEVICE || NextInstance > 9999) 285 { 286 DPRINT1("NextInstance value is corrupt! (%lu)\n", NextInstance); 287 RtlDeleteRegistryValue(RTL_REGISTRY_HANDLE, 288 (PWSTR)DeviceKeyHandle, 289 L"NextInstance"); 290 goto tryagain; 291 } 292 293 NextInstance++; 294 Status = RtlWriteRegistryValue(RTL_REGISTRY_HANDLE, 295 (PWSTR)DeviceKeyHandle, 296 L"NextInstance", 297 REG_DWORD, 298 &NextInstance, 299 sizeof(NextInstance)); 300 if (!NT_SUCCESS(Status)) 301 { 302 DPRINT1("Failed to write new NextInstance value! (0x%x)\n", Status); 303 goto cleanup; 304 } 305 306 if (!RtlCreateUnicodeString(&Device->InstanceID, InstancePath)) 307 { 308 Status = STATUS_NO_MEMORY; 309 goto cleanup; 310 } 311 312 /* Finish creating the instance path in the registry */ 313 InitializeObjectAttributes(&ObjectAttributes, 314 &Device->InstanceID, 315 OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, 316 DeviceKeyHandle, 317 NULL); 318 Status = ZwCreateKey(&InstanceKeyHandle, KEY_QUERY_VALUE, &ObjectAttributes, 0, NULL, REG_OPTION_VOLATILE, NULL); 319 if (!NT_SUCCESS(Status)) 320 { 321 DPRINT1("Failed to create instance path (0x%x)\n", Status); 322 goto cleanup; 323 } 324 325 /* Just close the handle */ 326 ObCloseHandle(InstanceKeyHandle, KernelMode); 327 328 if (FullInstancePath) 329 { 330 FullInstancePath->MaximumLength = Device->DeviceID.Length + PathSep.Length + Device->InstanceID.Length; 331 FullInstancePath->Length = 0; 332 FullInstancePath->Buffer = ExAllocatePool(PagedPool, FullInstancePath->MaximumLength); 333 if (!FullInstancePath->Buffer) 334 { 335 Status = STATUS_NO_MEMORY; 336 goto cleanup; 337 } 338 339 RtlAppendUnicodeStringToString(FullInstancePath, &Device->DeviceID); 340 RtlAppendUnicodeStringToString(FullInstancePath, &PathSep); 341 RtlAppendUnicodeStringToString(FullInstancePath, &Device->InstanceID); 342 } 343 344 /* Initialize a device object */ 345 Status = IoCreateDevice( 346 DriverObject ? DriverObject : PnpRootDeviceObject->DriverObject, 347 sizeof(PNPROOT_PDO_DEVICE_EXTENSION), 348 NULL, 349 FILE_DEVICE_CONTROLLER, 350 FILE_AUTOGENERATED_DEVICE_NAME, 351 FALSE, 352 &Device->Pdo); 353 if (!NT_SUCCESS(Status)) 354 { 355 DPRINT("IoCreateDevice() failed with status 0x%08lx\n", Status); 356 Status = STATUS_NO_MEMORY; 357 goto cleanup; 358 } 359 360 PdoDeviceExtension = (PPNPROOT_PDO_DEVICE_EXTENSION)Device->Pdo->DeviceExtension; 361 RtlZeroMemory(PdoDeviceExtension, sizeof(PNPROOT_PDO_DEVICE_EXTENSION)); 362 PdoDeviceExtension->Common.IsFDO = FALSE; 363 PdoDeviceExtension->DeviceInfo = Device; 364 365 Device->Pdo->Flags |= DO_BUS_ENUMERATED_DEVICE; 366 Device->Pdo->Flags &= ~DO_DEVICE_INITIALIZING; 367 368 InsertTailList( 369 &DeviceExtension->DeviceListHead, 370 &Device->ListEntry); 371 DeviceExtension->DeviceListCount++; 372 373 *PhysicalDeviceObject = Device->Pdo; 374 DPRINT("Created PDO %p (%wZ\\%wZ)\n", *PhysicalDeviceObject, &Device->DeviceID, &Device->InstanceID); 375 Device = NULL; 376 Status = STATUS_SUCCESS; 377 378 cleanup: 379 KeReleaseGuardedMutex(&DeviceExtension->DeviceListLock); 380 if (Device) 381 { 382 if (Device->Pdo) 383 IoDeleteDevice(Device->Pdo); 384 RtlFreeUnicodeString(&Device->DeviceID); 385 RtlFreeUnicodeString(&Device->InstanceID); 386 ExFreePoolWithTag(Device, TAG_PNP_ROOT); 387 } 388 RtlFreeUnicodeString(&DevicePath); 389 if (DeviceKeyHandle != NULL) 390 ObCloseHandle(DeviceKeyHandle, KernelMode); 391 return Status; 392 } 393 394 static NTSTATUS NTAPI 395 QueryStringCallback( 396 IN PWSTR ValueName, 397 IN ULONG ValueType, 398 IN PVOID ValueData, 399 IN ULONG ValueLength, 400 IN PVOID Context, 401 IN PVOID EntryContext) 402 { 403 PUNICODE_STRING Destination = (PUNICODE_STRING)EntryContext; 404 UNICODE_STRING Source; 405 406 if (ValueType != REG_SZ || ValueLength == 0 || ValueLength % sizeof(WCHAR) != 0) 407 { 408 Destination->Length = 0; 409 Destination->MaximumLength = 0; 410 Destination->Buffer = NULL; 411 return STATUS_SUCCESS; 412 } 413 414 Source.MaximumLength = Source.Length = (USHORT)ValueLength; 415 Source.Buffer = ValueData; 416 417 return RtlDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE, &Source, Destination); 418 } 419 420 static NTSTATUS NTAPI 421 QueryBinaryValueCallback( 422 IN PWSTR ValueName, 423 IN ULONG ValueType, 424 IN PVOID ValueData, 425 IN ULONG ValueLength, 426 IN PVOID Context, 427 IN PVOID EntryContext) 428 { 429 PBUFFER Buffer = (PBUFFER)EntryContext; 430 PVOID BinaryValue; 431 432 if (ValueLength == 0) 433 { 434 *Buffer->Data = NULL; 435 return STATUS_SUCCESS; 436 } 437 438 BinaryValue = ExAllocatePoolWithTag(PagedPool, ValueLength, TAG_PNP_ROOT); 439 if (BinaryValue == NULL) 440 return STATUS_NO_MEMORY; 441 RtlCopyMemory(BinaryValue, ValueData, ValueLength); 442 *Buffer->Data = BinaryValue; 443 if (Buffer->Length) *Buffer->Length = ValueLength; 444 return STATUS_SUCCESS; 445 } 446 447 static 448 NTSTATUS 449 CreateDeviceFromRegistry( 450 _Inout_ PPNPROOT_FDO_DEVICE_EXTENSION DeviceExtension, 451 _Inout_ PUNICODE_STRING DevicePath, 452 _In_ PCWSTR InstanceId, 453 _In_ HANDLE SubKeyHandle) 454 { 455 NTSTATUS Status; 456 PPNPROOT_DEVICE Device; 457 HANDLE DeviceKeyHandle = NULL; 458 RTL_QUERY_REGISTRY_TABLE QueryTable[4]; 459 BUFFER Buffer1, Buffer2; 460 461 /* If the device already exists, there's nothing to do */ 462 Status = LocateChildDevice(DeviceExtension, DevicePath, InstanceId, &Device); 463 if (Status != STATUS_NO_SUCH_DEVICE) 464 { 465 return STATUS_SUCCESS; 466 } 467 468 /* Create a PPNPROOT_DEVICE object, and add it to the list of known devices */ 469 Device = ExAllocatePoolWithTag(PagedPool, sizeof(PNPROOT_DEVICE), TAG_PNP_ROOT); 470 if (!Device) 471 { 472 DPRINT("ExAllocatePoolWithTag() failed\n"); 473 Status = STATUS_NO_MEMORY; 474 goto cleanup; 475 } 476 RtlZeroMemory(Device, sizeof(PNPROOT_DEVICE)); 477 478 /* Fill device ID and instance ID */ 479 Device->DeviceID = *DevicePath; 480 RtlInitEmptyUnicodeString(DevicePath, NULL, 0); 481 if (!RtlCreateUnicodeString(&Device->InstanceID, InstanceId)) 482 { 483 DPRINT1("RtlCreateUnicodeString() failed\n"); 484 Status = STATUS_NO_MEMORY; 485 goto cleanup; 486 } 487 488 /* Open registry key to fill other informations */ 489 Status = IopOpenRegistryKeyEx(&DeviceKeyHandle, SubKeyHandle, &Device->InstanceID, KEY_READ); 490 if (!NT_SUCCESS(Status)) 491 { 492 /* If our key disappeared, let the caller go on */ 493 DPRINT1("IopOpenRegistryKeyEx() failed for '%wZ' with status 0x%lx\n", 494 &Device->InstanceID, Status); 495 Status = STATUS_SUCCESS; 496 goto cleanup; 497 } 498 499 /* Fill information from the device instance key */ 500 RtlZeroMemory(QueryTable, sizeof(QueryTable)); 501 QueryTable[0].QueryRoutine = QueryStringCallback; 502 QueryTable[0].Name = L"DeviceDesc"; 503 QueryTable[0].EntryContext = &Device->DeviceDescription; 504 505 RtlQueryRegistryValues(RTL_REGISTRY_HANDLE, 506 (PCWSTR)DeviceKeyHandle, 507 QueryTable, 508 NULL, 509 NULL); 510 511 /* Fill information from the LogConf subkey */ 512 Buffer1.Data = (PVOID *)&Device->ResourceRequirementsList; 513 Buffer1.Length = NULL; 514 Buffer2.Data = (PVOID *)&Device->ResourceList; 515 Buffer2.Length = &Device->ResourceListSize; 516 RtlZeroMemory(QueryTable, sizeof(QueryTable)); 517 QueryTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY; 518 QueryTable[0].Name = L"LogConf"; 519 QueryTable[1].QueryRoutine = QueryBinaryValueCallback; 520 QueryTable[1].Name = L"BasicConfigVector"; 521 QueryTable[1].EntryContext = &Buffer1; 522 QueryTable[2].QueryRoutine = QueryBinaryValueCallback; 523 QueryTable[2].Name = L"BootConfig"; 524 QueryTable[2].EntryContext = &Buffer2; 525 526 if (!NT_SUCCESS(RtlQueryRegistryValues(RTL_REGISTRY_HANDLE, 527 (PCWSTR)DeviceKeyHandle, 528 QueryTable, 529 NULL, 530 NULL))) 531 { 532 /* Non-fatal error */ 533 DPRINT1("Failed to read the LogConf key for %wZ\\%S\n", &Device->DeviceID, InstanceId); 534 } 535 536 /* Insert the newly created device into the list */ 537 InsertTailList(&DeviceExtension->DeviceListHead, 538 &Device->ListEntry); 539 DeviceExtension->DeviceListCount++; 540 Device = NULL; 541 542 cleanup: 543 if (DeviceKeyHandle != NULL) 544 { 545 ZwClose(DeviceKeyHandle); 546 } 547 if (Device != NULL) 548 { 549 /* We have a device that has not been added to device list. We need to clean it up */ 550 RtlFreeUnicodeString(&Device->DeviceID); 551 RtlFreeUnicodeString(&Device->InstanceID); 552 ExFreePoolWithTag(Device, TAG_PNP_ROOT); 553 } 554 return Status; 555 } 556 557 static NTSTATUS 558 EnumerateDevices( 559 IN PDEVICE_OBJECT DeviceObject) 560 { 561 PPNPROOT_FDO_DEVICE_EXTENSION DeviceExtension; 562 PKEY_BASIC_INFORMATION KeyInfo = NULL, SubKeyInfo = NULL; 563 UNICODE_STRING LegacyU = RTL_CONSTANT_STRING(L"LEGACY_"); 564 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\" REGSTR_PATH_SYSTEMENUM L"\\" REGSTR_KEY_ROOTENUM); 565 UNICODE_STRING SubKeyName; 566 UNICODE_STRING DevicePath; 567 HANDLE KeyHandle = NULL; 568 HANDLE SubKeyHandle = NULL; 569 ULONG KeyInfoSize, SubKeyInfoSize; 570 ULONG ResultSize; 571 ULONG Index1, Index2; 572 NTSTATUS Status = STATUS_UNSUCCESSFUL; 573 574 DPRINT("EnumerateDevices(FDO %p)\n", DeviceObject); 575 576 DeviceExtension = (PPNPROOT_FDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; 577 KeAcquireGuardedMutex(&DeviceExtension->DeviceListLock); 578 579 /* Should hold most key names, but we reallocate below if it's too small */ 580 KeyInfoSize = FIELD_OFFSET(KEY_BASIC_INFORMATION, Name) + 64 * sizeof(WCHAR); 581 KeyInfo = ExAllocatePoolWithTag(PagedPool, 582 KeyInfoSize + sizeof(UNICODE_NULL), 583 TAG_PNP_ROOT); 584 if (!KeyInfo) 585 { 586 DPRINT("ExAllocatePoolWithTag() failed\n"); 587 Status = STATUS_NO_MEMORY; 588 goto cleanup; 589 } 590 SubKeyInfoSize = KeyInfoSize; 591 SubKeyInfo = ExAllocatePoolWithTag(PagedPool, 592 SubKeyInfoSize + sizeof(UNICODE_NULL), 593 TAG_PNP_ROOT); 594 if (!SubKeyInfo) 595 { 596 DPRINT("ExAllocatePoolWithTag() failed\n"); 597 Status = STATUS_NO_MEMORY; 598 goto cleanup; 599 } 600 601 Status = IopOpenRegistryKeyEx(&KeyHandle, NULL, &KeyName, KEY_ENUMERATE_SUB_KEYS); 602 if (!NT_SUCCESS(Status)) 603 { 604 DPRINT("IopOpenRegistryKeyEx(%wZ) failed with status 0x%08lx\n", &KeyName, Status); 605 goto cleanup; 606 } 607 608 /* Devices are sub-sub-keys of 'KeyName'. KeyName is already opened as 609 * KeyHandle. We'll first do a first enumeration to have first level keys, 610 * and an inner one to have the real devices list. 611 */ 612 Index1 = 0; 613 while (TRUE) 614 { 615 Status = ZwEnumerateKey( 616 KeyHandle, 617 Index1, 618 KeyBasicInformation, 619 KeyInfo, 620 KeyInfoSize, 621 &ResultSize); 622 if (Status == STATUS_NO_MORE_ENTRIES) 623 { 624 Status = STATUS_SUCCESS; 625 break; 626 } 627 else if (Status == STATUS_BUFFER_OVERFLOW || 628 Status == STATUS_BUFFER_TOO_SMALL) 629 { 630 ASSERT(KeyInfoSize < ResultSize); 631 KeyInfoSize = ResultSize; 632 ExFreePoolWithTag(KeyInfo, TAG_PNP_ROOT); 633 KeyInfo = ExAllocatePoolWithTag(PagedPool, 634 KeyInfoSize + sizeof(UNICODE_NULL), 635 TAG_PNP_ROOT); 636 if (!KeyInfo) 637 { 638 DPRINT1("ExAllocatePoolWithTag(%lu) failed\n", KeyInfoSize); 639 Status = STATUS_NO_MEMORY; 640 goto cleanup; 641 } 642 continue; 643 } 644 else if (!NT_SUCCESS(Status)) 645 { 646 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status); 647 goto cleanup; 648 } 649 650 /* Terminate the string */ 651 KeyInfo->Name[KeyInfo->NameLength / sizeof(WCHAR)] = 0; 652 653 /* Check if it is a legacy driver */ 654 RtlInitUnicodeString(&SubKeyName, KeyInfo->Name); 655 if (RtlPrefixUnicodeString(&LegacyU, &SubKeyName, FALSE)) 656 { 657 DPRINT("Ignoring legacy driver '%wZ'\n", &SubKeyName); 658 Index1++; 659 continue; 660 } 661 662 /* Open the key */ 663 Status = IopOpenRegistryKeyEx(&SubKeyHandle, KeyHandle, &SubKeyName, KEY_ENUMERATE_SUB_KEYS); 664 if (!NT_SUCCESS(Status)) 665 { 666 DPRINT("IopOpenRegistryKeyEx() failed for '%wZ' with status 0x%lx\n", 667 &SubKeyName, Status); 668 break; 669 } 670 671 /* Enumerate the sub-keys */ 672 Index2 = 0; 673 while (TRUE) 674 { 675 Status = ZwEnumerateKey( 676 SubKeyHandle, 677 Index2, 678 KeyBasicInformation, 679 SubKeyInfo, 680 SubKeyInfoSize, 681 &ResultSize); 682 if (Status == STATUS_NO_MORE_ENTRIES) 683 { 684 break; 685 } 686 else if (Status == STATUS_BUFFER_OVERFLOW || 687 Status == STATUS_BUFFER_TOO_SMALL) 688 { 689 ASSERT(SubKeyInfoSize < ResultSize); 690 SubKeyInfoSize = ResultSize; 691 ExFreePoolWithTag(SubKeyInfo, TAG_PNP_ROOT); 692 SubKeyInfo = ExAllocatePoolWithTag(PagedPool, 693 SubKeyInfoSize + sizeof(UNICODE_NULL), 694 TAG_PNP_ROOT); 695 if (!SubKeyInfo) 696 { 697 DPRINT1("ExAllocatePoolWithTag(%lu) failed\n", SubKeyInfoSize); 698 Status = STATUS_NO_MEMORY; 699 goto cleanup; 700 } 701 continue; 702 } 703 else if (!NT_SUCCESS(Status)) 704 { 705 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status); 706 break; 707 } 708 709 /* Terminate the string */ 710 SubKeyInfo->Name[SubKeyInfo->NameLength / sizeof(WCHAR)] = 0; 711 712 /* Compute device ID */ 713 DevicePath.Length = 0; 714 DevicePath.MaximumLength = sizeof(REGSTR_KEY_ROOTENUM) + sizeof(L'\\') + SubKeyName.Length; 715 DevicePath.Buffer = ExAllocatePoolWithTag(PagedPool, 716 DevicePath.MaximumLength, 717 TAG_PNP_ROOT); 718 if (DevicePath.Buffer == NULL) 719 { 720 DPRINT1("ExAllocatePoolWithTag() failed\n"); 721 Status = STATUS_NO_MEMORY; 722 goto cleanup; 723 } 724 725 RtlAppendUnicodeToString(&DevicePath, REGSTR_KEY_ROOTENUM L"\\"); 726 RtlAppendUnicodeStringToString(&DevicePath, &SubKeyName); 727 DPRINT("Found device %wZ\\%S!\n", &DevicePath, SubKeyInfo->Name); 728 Status = CreateDeviceFromRegistry(DeviceExtension, 729 &DevicePath, 730 SubKeyInfo->Name, 731 SubKeyHandle); 732 733 /* If CreateDeviceFromRegistry didn't take ownership and zero this, 734 * we need to free it 735 */ 736 RtlFreeUnicodeString(&DevicePath); 737 738 if (!NT_SUCCESS(Status)) 739 { 740 goto cleanup; 741 } 742 743 Index2++; 744 } 745 746 ZwClose(SubKeyHandle); 747 SubKeyHandle = NULL; 748 Index1++; 749 } 750 751 cleanup: 752 if (SubKeyHandle != NULL) 753 ZwClose(SubKeyHandle); 754 if (KeyHandle != NULL) 755 ZwClose(KeyHandle); 756 if (KeyInfo) 757 ExFreePoolWithTag(KeyInfo, TAG_PNP_ROOT); 758 if (SubKeyInfo) 759 ExFreePoolWithTag(SubKeyInfo, TAG_PNP_ROOT); 760 KeReleaseGuardedMutex(&DeviceExtension->DeviceListLock); 761 return Status; 762 } 763 764 /* FUNCTION: Handle IRP_MN_QUERY_DEVICE_RELATIONS IRPs for the root bus device object 765 * ARGUMENTS: 766 * DeviceObject = Pointer to functional device object of the root bus driver 767 * Irp = Pointer to IRP that should be handled 768 * RETURNS: 769 * Status 770 */ 771 static NTSTATUS 772 PnpRootQueryDeviceRelations( 773 IN PDEVICE_OBJECT DeviceObject, 774 IN PIRP Irp) 775 { 776 PPNPROOT_PDO_DEVICE_EXTENSION PdoDeviceExtension; 777 PPNPROOT_FDO_DEVICE_EXTENSION DeviceExtension; 778 PDEVICE_RELATIONS Relations = NULL, OtherRelations = (PDEVICE_RELATIONS)Irp->IoStatus.Information; 779 PPNPROOT_DEVICE Device = NULL; 780 ULONG Size; 781 NTSTATUS Status; 782 PLIST_ENTRY NextEntry; 783 784 DPRINT("PnpRootQueryDeviceRelations(FDO %p, Irp %p)\n", DeviceObject, Irp); 785 786 Status = EnumerateDevices(DeviceObject); 787 if (!NT_SUCCESS(Status)) 788 { 789 DPRINT("EnumerateDevices() failed with status 0x%08lx\n", Status); 790 return Status; 791 } 792 793 DeviceExtension = (PPNPROOT_FDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; 794 795 Size = FIELD_OFFSET(DEVICE_RELATIONS, Objects) + sizeof(PDEVICE_OBJECT) * DeviceExtension->DeviceListCount; 796 if (OtherRelations) 797 { 798 /* Another bus driver has already created a DEVICE_RELATIONS 799 * structure so we must merge this structure with our own */ 800 801 Size += sizeof(PDEVICE_OBJECT) * OtherRelations->Count; 802 } 803 Relations = (PDEVICE_RELATIONS)ExAllocatePool(PagedPool, Size); 804 if (!Relations) 805 { 806 DPRINT("ExAllocatePoolWithTag() failed\n"); 807 Status = STATUS_NO_MEMORY; 808 goto cleanup; 809 } 810 RtlZeroMemory(Relations, Size); 811 if (OtherRelations) 812 { 813 Relations->Count = OtherRelations->Count; 814 RtlCopyMemory(Relations->Objects, OtherRelations->Objects, sizeof(PDEVICE_OBJECT) * OtherRelations->Count); 815 } 816 817 KeAcquireGuardedMutex(&DeviceExtension->DeviceListLock); 818 819 /* Start looping */ 820 for (NextEntry = DeviceExtension->DeviceListHead.Flink; 821 NextEntry != &DeviceExtension->DeviceListHead; 822 NextEntry = NextEntry->Flink) 823 { 824 /* Get the entry */ 825 Device = CONTAINING_RECORD(NextEntry, PNPROOT_DEVICE, ListEntry); 826 827 if (!Device->Pdo) 828 { 829 /* Create a physical device object for the 830 * device as it does not already have one */ 831 Status = IoCreateDevice( 832 DeviceObject->DriverObject, 833 sizeof(PNPROOT_PDO_DEVICE_EXTENSION), 834 NULL, 835 FILE_DEVICE_CONTROLLER, 836 FILE_AUTOGENERATED_DEVICE_NAME, 837 FALSE, 838 &Device->Pdo); 839 if (!NT_SUCCESS(Status)) 840 { 841 DPRINT("IoCreateDevice() failed with status 0x%08lx\n", Status); 842 break; 843 } 844 845 PdoDeviceExtension = (PPNPROOT_PDO_DEVICE_EXTENSION)Device->Pdo->DeviceExtension; 846 RtlZeroMemory(PdoDeviceExtension, sizeof(PNPROOT_PDO_DEVICE_EXTENSION)); 847 PdoDeviceExtension->Common.IsFDO = FALSE; 848 PdoDeviceExtension->DeviceInfo = Device; 849 850 Device->Pdo->Flags |= DO_BUS_ENUMERATED_DEVICE; 851 Device->Pdo->Flags &= ~DO_DEVICE_INITIALIZING; 852 } 853 854 /* Reference the physical device object. The PnP manager 855 will dereference it again when it is no longer needed */ 856 ObReferenceObject(Device->Pdo); 857 858 Relations->Objects[Relations->Count++] = Device->Pdo; 859 } 860 KeReleaseGuardedMutex(&DeviceExtension->DeviceListLock); 861 862 Irp->IoStatus.Information = (ULONG_PTR)Relations; 863 864 cleanup: 865 if (!NT_SUCCESS(Status)) 866 { 867 if (OtherRelations) 868 ExFreePool(OtherRelations); 869 if (Relations) 870 ExFreePool(Relations); 871 if (Device && Device->Pdo) 872 { 873 IoDeleteDevice(Device->Pdo); 874 Device->Pdo = NULL; 875 } 876 } 877 878 return Status; 879 } 880 881 /* 882 * FUNCTION: Handle Plug and Play IRPs for the root bus device object 883 * ARGUMENTS: 884 * DeviceObject = Pointer to functional device object of the root bus driver 885 * Irp = Pointer to IRP that should be handled 886 * RETURNS: 887 * Status 888 */ 889 static NTSTATUS 890 PnpRootFdoPnpControl( 891 IN PDEVICE_OBJECT DeviceObject, 892 IN PIRP Irp) 893 { 894 PPNPROOT_FDO_DEVICE_EXTENSION DeviceExtension; 895 PIO_STACK_LOCATION IrpSp; 896 NTSTATUS Status; 897 898 DeviceExtension = (PPNPROOT_FDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; 899 Status = Irp->IoStatus.Status; 900 IrpSp = IoGetCurrentIrpStackLocation(Irp); 901 902 switch (IrpSp->MinorFunction) 903 { 904 case IRP_MN_QUERY_DEVICE_RELATIONS: 905 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS\n"); 906 Status = PnpRootQueryDeviceRelations(DeviceObject, Irp); 907 break; 908 909 case IRP_MN_START_DEVICE: 910 DPRINT("IRP_MJ_PNP / IRP_MN_START_DEVICE\n"); 911 if (!IoForwardIrpSynchronously(DeviceExtension->Ldo, Irp)) 912 Status = STATUS_UNSUCCESSFUL; 913 else 914 { 915 Status = Irp->IoStatus.Status; 916 if (NT_SUCCESS(Status)) 917 DeviceExtension->State = dsStarted; 918 } 919 920 Irp->IoStatus.Status = Status; 921 IoCompleteRequest(Irp, IO_NO_INCREMENT); 922 return Status; 923 924 case IRP_MN_STOP_DEVICE: 925 DPRINT("IRP_MJ_PNP / IRP_MN_STOP_DEVICE\n"); 926 /* Root device cannot be stopped */ 927 Irp->IoStatus.Status = Status = STATUS_INVALID_DEVICE_REQUEST; 928 IoCompleteRequest(Irp, IO_NO_INCREMENT); 929 return Status; 930 931 default: 932 DPRINT("IRP_MJ_PNP / Unknown minor function 0x%lx\n", IrpSp->MinorFunction); 933 break; 934 } 935 936 if (Status != STATUS_PENDING) 937 { 938 Irp->IoStatus.Status = Status; 939 IoCompleteRequest(Irp, IO_NO_INCREMENT); 940 } 941 942 return Status; 943 } 944 945 static NTSTATUS 946 PdoQueryDeviceRelations( 947 IN PDEVICE_OBJECT DeviceObject, 948 IN PIRP Irp, 949 IN PIO_STACK_LOCATION IrpSp) 950 { 951 PDEVICE_RELATIONS Relations; 952 NTSTATUS Status = Irp->IoStatus.Status; 953 954 if (IrpSp->Parameters.QueryDeviceRelations.Type != TargetDeviceRelation) 955 return Status; 956 957 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / TargetDeviceRelation\n"); 958 Relations = (PDEVICE_RELATIONS)ExAllocatePool(PagedPool, sizeof(DEVICE_RELATIONS)); 959 if (!Relations) 960 { 961 DPRINT("ExAllocatePoolWithTag() failed\n"); 962 Status = STATUS_NO_MEMORY; 963 } 964 else 965 { 966 ObReferenceObject(DeviceObject); 967 Relations->Count = 1; 968 Relations->Objects[0] = DeviceObject; 969 Status = STATUS_SUCCESS; 970 Irp->IoStatus.Information = (ULONG_PTR)Relations; 971 } 972 973 return Status; 974 } 975 976 static NTSTATUS 977 PdoQueryCapabilities( 978 IN PDEVICE_OBJECT DeviceObject, 979 IN PIRP Irp, 980 IN PIO_STACK_LOCATION IrpSp) 981 { 982 PDEVICE_CAPABILITIES DeviceCapabilities; 983 984 DeviceCapabilities = IrpSp->Parameters.DeviceCapabilities.Capabilities; 985 986 if (DeviceCapabilities->Version != 1) 987 return STATUS_REVISION_MISMATCH; 988 989 DeviceCapabilities->UniqueID = TRUE; 990 /* FIXME: Fill other fields */ 991 992 return STATUS_SUCCESS; 993 } 994 995 static NTSTATUS 996 PdoQueryResources( 997 IN PDEVICE_OBJECT DeviceObject, 998 IN PIRP Irp, 999 IN PIO_STACK_LOCATION IrpSp) 1000 { 1001 PPNPROOT_PDO_DEVICE_EXTENSION DeviceExtension; 1002 PCM_RESOURCE_LIST ResourceList; 1003 1004 DeviceExtension = (PPNPROOT_PDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; 1005 1006 if (DeviceExtension->DeviceInfo->ResourceList) 1007 { 1008 /* Copy existing resource requirement list */ 1009 ResourceList = ExAllocatePool( 1010 PagedPool, 1011 DeviceExtension->DeviceInfo->ResourceListSize); 1012 if (!ResourceList) 1013 return STATUS_NO_MEMORY; 1014 1015 RtlCopyMemory( 1016 ResourceList, 1017 DeviceExtension->DeviceInfo->ResourceList, 1018 DeviceExtension->DeviceInfo->ResourceListSize); 1019 1020 Irp->IoStatus.Information = (ULONG_PTR)ResourceList; 1021 1022 return STATUS_SUCCESS; 1023 } 1024 else 1025 { 1026 /* No resources so just return without changing the status */ 1027 return Irp->IoStatus.Status; 1028 } 1029 } 1030 1031 static NTSTATUS 1032 PdoQueryResourceRequirements( 1033 IN PDEVICE_OBJECT DeviceObject, 1034 IN PIRP Irp, 1035 IN PIO_STACK_LOCATION IrpSp) 1036 { 1037 PPNPROOT_PDO_DEVICE_EXTENSION DeviceExtension; 1038 PIO_RESOURCE_REQUIREMENTS_LIST ResourceList; 1039 1040 DeviceExtension = (PPNPROOT_PDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; 1041 1042 if (DeviceExtension->DeviceInfo->ResourceRequirementsList) 1043 { 1044 /* Copy existing resource requirement list */ 1045 ResourceList = ExAllocatePool(PagedPool, DeviceExtension->DeviceInfo->ResourceRequirementsList->ListSize); 1046 if (!ResourceList) 1047 return STATUS_NO_MEMORY; 1048 1049 RtlCopyMemory( 1050 ResourceList, 1051 DeviceExtension->DeviceInfo->ResourceRequirementsList, 1052 DeviceExtension->DeviceInfo->ResourceRequirementsList->ListSize); 1053 1054 Irp->IoStatus.Information = (ULONG_PTR)ResourceList; 1055 1056 return STATUS_SUCCESS; 1057 } 1058 else 1059 { 1060 /* No resource requirements so just return without changing the status */ 1061 return Irp->IoStatus.Status; 1062 } 1063 } 1064 1065 static NTSTATUS 1066 PdoQueryDeviceText( 1067 IN PDEVICE_OBJECT DeviceObject, 1068 IN PIRP Irp, 1069 IN PIO_STACK_LOCATION IrpSp) 1070 { 1071 PPNPROOT_PDO_DEVICE_EXTENSION DeviceExtension; 1072 DEVICE_TEXT_TYPE DeviceTextType; 1073 NTSTATUS Status = Irp->IoStatus.Status; 1074 1075 DeviceExtension = (PPNPROOT_PDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; 1076 DeviceTextType = IrpSp->Parameters.QueryDeviceText.DeviceTextType; 1077 1078 switch (DeviceTextType) 1079 { 1080 case DeviceTextDescription: 1081 { 1082 UNICODE_STRING String; 1083 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_TEXT / DeviceTextDescription\n"); 1084 1085 if (DeviceExtension->DeviceInfo->DeviceDescription.Buffer != NULL) 1086 { 1087 Status = RtlDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE, 1088 &DeviceExtension->DeviceInfo->DeviceDescription, 1089 &String); 1090 Irp->IoStatus.Information = (ULONG_PTR)String.Buffer; 1091 } 1092 break; 1093 } 1094 1095 case DeviceTextLocationInformation: 1096 { 1097 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_TEXT / DeviceTextLocationInformation\n"); 1098 break; 1099 } 1100 1101 default: 1102 { 1103 DPRINT1("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_TEXT / unknown query id type 0x%lx\n", DeviceTextType); 1104 } 1105 } 1106 1107 return Status; 1108 } 1109 1110 static NTSTATUS 1111 PdoQueryId( 1112 IN PDEVICE_OBJECT DeviceObject, 1113 IN PIRP Irp, 1114 IN PIO_STACK_LOCATION IrpSp) 1115 { 1116 PPNPROOT_PDO_DEVICE_EXTENSION DeviceExtension; 1117 BUS_QUERY_ID_TYPE IdType; 1118 NTSTATUS Status = Irp->IoStatus.Status; 1119 1120 DeviceExtension = (PPNPROOT_PDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; 1121 IdType = IrpSp->Parameters.QueryId.IdType; 1122 1123 switch (IdType) 1124 { 1125 case BusQueryDeviceID: 1126 { 1127 UNICODE_STRING String; 1128 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_ID / BusQueryDeviceID\n"); 1129 1130 Status = RtlDuplicateUnicodeString( 1131 RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE, 1132 &DeviceExtension->DeviceInfo->DeviceID, 1133 &String); 1134 Irp->IoStatus.Information = (ULONG_PTR)String.Buffer; 1135 break; 1136 } 1137 1138 case BusQueryHardwareIDs: 1139 case BusQueryCompatibleIDs: 1140 { 1141 /* Optional, do nothing */ 1142 break; 1143 } 1144 1145 case BusQueryInstanceID: 1146 { 1147 UNICODE_STRING String; 1148 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_ID / BusQueryInstanceID\n"); 1149 1150 Status = RtlDuplicateUnicodeString( 1151 RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE, 1152 &DeviceExtension->DeviceInfo->InstanceID, 1153 &String); 1154 Irp->IoStatus.Information = (ULONG_PTR)String.Buffer; 1155 break; 1156 } 1157 1158 default: 1159 { 1160 DPRINT1("IRP_MJ_PNP / IRP_MN_QUERY_ID / unknown query id type 0x%lx\n", IdType); 1161 } 1162 } 1163 1164 return Status; 1165 } 1166 1167 static NTSTATUS 1168 PdoQueryBusInformation( 1169 IN PDEVICE_OBJECT DeviceObject, 1170 IN PIRP Irp, 1171 IN PIO_STACK_LOCATION IrpSp) 1172 { 1173 PPNP_BUS_INFORMATION BusInfo; 1174 NTSTATUS Status; 1175 1176 BusInfo = (PPNP_BUS_INFORMATION)ExAllocatePoolWithTag(PagedPool, sizeof(PNP_BUS_INFORMATION), TAG_PNP_ROOT); 1177 if (!BusInfo) 1178 Status = STATUS_NO_MEMORY; 1179 else 1180 { 1181 RtlCopyMemory( 1182 &BusInfo->BusTypeGuid, 1183 &GUID_BUS_TYPE_INTERNAL, 1184 sizeof(BusInfo->BusTypeGuid)); 1185 BusInfo->LegacyBusType = PNPBus; 1186 /* We're the only root bus enumerator on the computer */ 1187 BusInfo->BusNumber = 0; 1188 Irp->IoStatus.Information = (ULONG_PTR)BusInfo; 1189 Status = STATUS_SUCCESS; 1190 } 1191 1192 return Status; 1193 } 1194 1195 /* 1196 * FUNCTION: Handle Plug and Play IRPs for the child device 1197 * ARGUMENTS: 1198 * DeviceObject = Pointer to physical device object of the child device 1199 * Irp = Pointer to IRP that should be handled 1200 * RETURNS: 1201 * Status 1202 */ 1203 static NTSTATUS 1204 PnpRootPdoPnpControl( 1205 IN PDEVICE_OBJECT DeviceObject, 1206 IN PIRP Irp) 1207 { 1208 PPNPROOT_PDO_DEVICE_EXTENSION DeviceExtension; 1209 PPNPROOT_FDO_DEVICE_EXTENSION FdoDeviceExtension; 1210 PIO_STACK_LOCATION IrpSp; 1211 NTSTATUS Status; 1212 1213 DeviceExtension = DeviceObject->DeviceExtension; 1214 FdoDeviceExtension = PnpRootDeviceObject->DeviceExtension; 1215 Status = Irp->IoStatus.Status; 1216 IrpSp = IoGetCurrentIrpStackLocation(Irp); 1217 1218 switch (IrpSp->MinorFunction) 1219 { 1220 case IRP_MN_START_DEVICE: /* 0x00 */ 1221 DPRINT("IRP_MJ_PNP / IRP_MN_START_DEVICE\n"); 1222 Status = STATUS_SUCCESS; 1223 break; 1224 1225 case IRP_MN_QUERY_DEVICE_RELATIONS: /* 0x07 */ 1226 Status = PdoQueryDeviceRelations(DeviceObject, Irp, IrpSp); 1227 break; 1228 1229 case IRP_MN_QUERY_CAPABILITIES: /* 0x09 */ 1230 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_CAPABILITIES\n"); 1231 Status = PdoQueryCapabilities(DeviceObject, Irp, IrpSp); 1232 break; 1233 1234 case IRP_MN_QUERY_RESOURCES: /* 0x0a */ 1235 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_RESOURCES\n"); 1236 Status = PdoQueryResources(DeviceObject, Irp, IrpSp); 1237 break; 1238 1239 case IRP_MN_QUERY_RESOURCE_REQUIREMENTS: /* 0x0b */ 1240 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_RESOURCE_REQUIREMENTS\n"); 1241 Status = PdoQueryResourceRequirements(DeviceObject, Irp, IrpSp); 1242 break; 1243 1244 case IRP_MN_QUERY_DEVICE_TEXT: /* 0x0c */ 1245 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_RESOURCE_REQUIREMENTS\n"); 1246 Status = PdoQueryDeviceText(DeviceObject, Irp, IrpSp); 1247 break; 1248 1249 case IRP_MN_FILTER_RESOURCE_REQUIREMENTS: /* 0x0d */ 1250 DPRINT("IRP_MJ_PNP / IRP_MN_FILTER_RESOURCE_REQUIREMENTS\n"); 1251 break; 1252 1253 case IRP_MN_REMOVE_DEVICE: 1254 /* Remove the device from the device list and decrement the device count*/ 1255 KeAcquireGuardedMutex(&FdoDeviceExtension->DeviceListLock); 1256 RemoveEntryList(&DeviceExtension->DeviceInfo->ListEntry); 1257 FdoDeviceExtension->DeviceListCount--; 1258 KeReleaseGuardedMutex(&FdoDeviceExtension->DeviceListLock); 1259 1260 /* Free some strings we created */ 1261 RtlFreeUnicodeString(&DeviceExtension->DeviceInfo->DeviceDescription); 1262 RtlFreeUnicodeString(&DeviceExtension->DeviceInfo->DeviceID); 1263 RtlFreeUnicodeString(&DeviceExtension->DeviceInfo->InstanceID); 1264 1265 /* Free the resource requirements list */ 1266 if (DeviceExtension->DeviceInfo->ResourceRequirementsList != NULL) 1267 ExFreePool(DeviceExtension->DeviceInfo->ResourceRequirementsList); 1268 1269 /* Free the boot resources list */ 1270 if (DeviceExtension->DeviceInfo->ResourceList != NULL) 1271 ExFreePool(DeviceExtension->DeviceInfo->ResourceList); 1272 1273 /* Free the device info */ 1274 ExFreePool(DeviceExtension->DeviceInfo); 1275 1276 /* Finally, delete the device object */ 1277 IoDeleteDevice(DeviceObject); 1278 1279 /* Return success */ 1280 Status = STATUS_SUCCESS; 1281 break; 1282 1283 case IRP_MN_QUERY_ID: /* 0x13 */ 1284 Status = PdoQueryId(DeviceObject, Irp, IrpSp); 1285 break; 1286 1287 case IRP_MN_QUERY_PNP_DEVICE_STATE: /* 0x14 */ 1288 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_PNP_DEVICE_STATE\n"); 1289 break; 1290 1291 case IRP_MN_QUERY_BUS_INFORMATION: /* 0x15 */ 1292 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_BUS_INFORMATION\n"); 1293 Status = PdoQueryBusInformation(DeviceObject, Irp, IrpSp); 1294 break; 1295 1296 default: 1297 DPRINT1("IRP_MJ_PNP / Unknown minor function 0x%lx\n", IrpSp->MinorFunction); 1298 break; 1299 } 1300 1301 if (Status != STATUS_PENDING) 1302 { 1303 Irp->IoStatus.Status = Status; 1304 IoCompleteRequest(Irp, IO_NO_INCREMENT); 1305 } 1306 1307 return Status; 1308 } 1309 1310 /* 1311 * FUNCTION: Handle Plug and Play IRPs 1312 * ARGUMENTS: 1313 * DeviceObject = Pointer to PDO or FDO 1314 * Irp = Pointer to IRP that should be handled 1315 * RETURNS: 1316 * Status 1317 */ 1318 static NTSTATUS NTAPI 1319 PnpRootPnpControl( 1320 IN PDEVICE_OBJECT DeviceObject, 1321 IN PIRP Irp) 1322 { 1323 PPNPROOT_COMMON_DEVICE_EXTENSION DeviceExtension; 1324 NTSTATUS Status; 1325 1326 DeviceExtension = (PPNPROOT_COMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension; 1327 1328 if (DeviceExtension->IsFDO) 1329 Status = PnpRootFdoPnpControl(DeviceObject, Irp); 1330 else 1331 Status = PnpRootPdoPnpControl(DeviceObject, Irp); 1332 1333 return Status; 1334 } 1335 1336 /* 1337 * FUNCTION: Handle Power IRPs 1338 * ARGUMENTS: 1339 * DeviceObject = Pointer to PDO or FDO 1340 * Irp = Pointer to IRP that should be handled 1341 * RETURNS: 1342 * Status 1343 */ 1344 static NTSTATUS NTAPI 1345 PnpRootPowerControl( 1346 IN PDEVICE_OBJECT DeviceObject, 1347 IN PIRP Irp) 1348 { 1349 PPNPROOT_FDO_DEVICE_EXTENSION DeviceExtension; 1350 PIO_STACK_LOCATION IrpSp; 1351 NTSTATUS Status; 1352 1353 DeviceExtension = DeviceObject->DeviceExtension; 1354 Status = Irp->IoStatus.Status; 1355 IrpSp = IoGetCurrentIrpStackLocation(Irp); 1356 1357 if (DeviceExtension->Common.IsFDO) 1358 { 1359 ASSERT(!DeviceExtension->Common.IsFDO); 1360 PoStartNextPowerIrp(Irp); 1361 IoCopyCurrentIrpStackLocationToNext(Irp); 1362 Status = PoCallDriver(DeviceExtension->Ldo, Irp); 1363 } 1364 else 1365 { 1366 switch (IrpSp->MinorFunction) 1367 { 1368 case IRP_MN_QUERY_POWER: 1369 case IRP_MN_SET_POWER: 1370 Status = STATUS_SUCCESS; 1371 break; 1372 } 1373 Irp->IoStatus.Status = Status; 1374 PoStartNextPowerIrp(Irp); 1375 IoCompleteRequest(Irp, IO_NO_INCREMENT); 1376 } 1377 1378 return Status; 1379 } 1380 1381 NTSTATUS 1382 NTAPI 1383 PnpRootAddDevice( 1384 IN PDRIVER_OBJECT DriverObject, 1385 IN PDEVICE_OBJECT PhysicalDeviceObject) 1386 { 1387 PPNPROOT_FDO_DEVICE_EXTENSION DeviceExtension; 1388 NTSTATUS Status; 1389 1390 DPRINT("PnpRootAddDevice(DriverObject %p, Pdo %p)\n", DriverObject, PhysicalDeviceObject); 1391 1392 if (!PhysicalDeviceObject) 1393 { 1394 DPRINT("PhysicalDeviceObject 0x%p\n", PhysicalDeviceObject); 1395 Status = STATUS_INSUFFICIENT_RESOURCES; 1396 KeBugCheckEx(PHASE1_INITIALIZATION_FAILED, Status, 0, 0, 0); 1397 } 1398 1399 Status = IoCreateDevice( 1400 DriverObject, 1401 sizeof(PNPROOT_FDO_DEVICE_EXTENSION), 1402 NULL, 1403 FILE_DEVICE_BUS_EXTENDER, 1404 FILE_DEVICE_SECURE_OPEN, 1405 TRUE, 1406 &PnpRootDeviceObject); 1407 if (!NT_SUCCESS(Status)) 1408 { 1409 DPRINT("IoCreateDevice() failed with status 0x%08lx\n", Status); 1410 KeBugCheckEx(PHASE1_INITIALIZATION_FAILED, Status, 0, 0, 0); 1411 } 1412 DPRINT("Created FDO %p\n", PnpRootDeviceObject); 1413 1414 DeviceExtension = (PPNPROOT_FDO_DEVICE_EXTENSION)PnpRootDeviceObject->DeviceExtension; 1415 RtlZeroMemory(DeviceExtension, sizeof(PNPROOT_FDO_DEVICE_EXTENSION)); 1416 1417 DeviceExtension->Common.IsFDO = TRUE; 1418 DeviceExtension->State = dsStopped; 1419 InitializeListHead(&DeviceExtension->DeviceListHead); 1420 DeviceExtension->DeviceListCount = 0; 1421 KeInitializeGuardedMutex(&DeviceExtension->DeviceListLock); 1422 1423 Status = IoAttachDeviceToDeviceStackSafe( 1424 PnpRootDeviceObject, 1425 PhysicalDeviceObject, 1426 &DeviceExtension->Ldo); 1427 if (!NT_SUCCESS(Status)) 1428 { 1429 DPRINT("IoAttachDeviceToDeviceStackSafe() failed with status 0x%08lx\n", Status); 1430 KeBugCheckEx(PHASE1_INITIALIZATION_FAILED, Status, 0, 0, 0); 1431 } 1432 1433 PnpRootDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; 1434 1435 DPRINT("Done AddDevice()\n"); 1436 1437 return STATUS_SUCCESS; 1438 } 1439 1440 #if MI_TRACE_PFNS 1441 PDEVICE_OBJECT IopPfnDumpDeviceObject; 1442 1443 NTSTATUS NTAPI 1444 PnpRootCreateClose( 1445 _In_ PDEVICE_OBJECT DeviceObject, 1446 _In_ PIRP Irp) 1447 { 1448 PIO_STACK_LOCATION IoStack; 1449 1450 if (DeviceObject != IopPfnDumpDeviceObject) 1451 { 1452 Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST; 1453 IoCompleteRequest(Irp, IO_NO_INCREMENT); 1454 return STATUS_INVALID_DEVICE_REQUEST; 1455 } 1456 1457 IoStack = IoGetCurrentIrpStackLocation(Irp); 1458 if (IoStack->MajorFunction == IRP_MJ_CREATE) 1459 { 1460 MmDumpArmPfnDatabase(TRUE); 1461 } 1462 1463 Irp->IoStatus.Status = STATUS_SUCCESS; 1464 IoCompleteRequest(Irp, IO_NO_INCREMENT); 1465 return STATUS_SUCCESS; 1466 } 1467 #endif 1468 1469 NTSTATUS NTAPI 1470 PnpRootDriverEntry( 1471 IN PDRIVER_OBJECT DriverObject, 1472 IN PUNICODE_STRING RegistryPath) 1473 { 1474 #if MI_TRACE_PFNS 1475 NTSTATUS Status; 1476 UNICODE_STRING PfnDumpDeviceName = RTL_CONSTANT_STRING(L"\\Device\\PfnDump"); 1477 #endif 1478 1479 DPRINT("PnpRootDriverEntry(%p %wZ)\n", DriverObject, RegistryPath); 1480 1481 IopRootDriverObject = DriverObject; 1482 1483 DriverObject->DriverExtension->AddDevice = PnpRootAddDevice; 1484 1485 #if MI_TRACE_PFNS 1486 DriverObject->MajorFunction[IRP_MJ_CREATE] = PnpRootCreateClose; 1487 DriverObject->MajorFunction[IRP_MJ_CLOSE] = PnpRootCreateClose; 1488 #endif 1489 DriverObject->MajorFunction[IRP_MJ_PNP] = PnpRootPnpControl; 1490 DriverObject->MajorFunction[IRP_MJ_POWER] = PnpRootPowerControl; 1491 1492 #if MI_TRACE_PFNS 1493 Status = IoCreateDevice(DriverObject, 1494 0, 1495 &PfnDumpDeviceName, 1496 FILE_DEVICE_UNKNOWN, 1497 0, 1498 FALSE, 1499 &IopPfnDumpDeviceObject); 1500 if (!NT_SUCCESS(Status)) 1501 { 1502 DPRINT1("Creating PFN Dump device failed with %lx\n", Status); 1503 } 1504 else 1505 { 1506 IopPfnDumpDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; 1507 } 1508 #endif 1509 1510 return STATUS_SUCCESS; 1511 } 1512