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