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