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