1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS text-mode setup 4 * PURPOSE: Device installation 5 * PROGRAMMER: Herv� Poussineau (hpoussin@reactos.org) 6 * Hermes Belusca-Maito 7 */ 8 9 #include <usetup.h> 10 11 #define NDEBUG 12 #include <debug.h> 13 14 #define INITGUID 15 #include <guiddef.h> 16 #include <libs/umpnpmgr/sysguid.h> 17 18 /* LOCALS *******************************************************************/ 19 20 static HANDLE hEnumKey = NULL; 21 static HANDLE hServicesKey = NULL; 22 23 static HANDLE hNoPendingInstalls = NULL; 24 25 static HANDLE hPnpThread = NULL; 26 static HANDLE hDeviceInstallThread = NULL; 27 28 /* Device-install event list */ 29 static HANDLE hDeviceInstallListMutex = NULL; 30 static LIST_ENTRY DeviceInstallListHead; 31 static HANDLE hDeviceInstallListNotEmpty = NULL; 32 33 typedef struct 34 { 35 LIST_ENTRY ListEntry; 36 WCHAR DeviceIds[ANYSIZE_ARRAY]; 37 } DeviceInstallParams; 38 39 /* FUNCTIONS ****************************************************************/ 40 41 static BOOLEAN 42 AreDriversLoaded( 43 IN PCWSTR DeviceId) 44 { 45 PLUGPLAY_CONTROL_STATUS_DATA PlugPlayData; 46 NTSTATUS Status; 47 48 RtlInitUnicodeString(&PlugPlayData.DeviceInstance, DeviceId); 49 PlugPlayData.Operation = PNP_GET_DEVICE_STATUS; 50 51 Status = NtPlugPlayControl(PlugPlayControlDeviceStatus, &PlugPlayData, sizeof(PlugPlayData)); 52 if (NT_SUCCESS(Status)) 53 { 54 return (_Bool)((PlugPlayData.DeviceStatus & DN_DRIVER_LOADED) && 55 !(PlugPlayData.DeviceStatus & DN_HAS_PROBLEM)); 56 } 57 else 58 { 59 return FALSE; 60 } 61 } 62 63 static BOOLEAN 64 InstallDriver( 65 IN HINF hInf, 66 IN HANDLE hServices, 67 IN HANDLE hDeviceKey, 68 IN LPCWSTR DeviceId, 69 IN LPCWSTR HardwareId) 70 { 71 UNICODE_STRING ServiceU = RTL_CONSTANT_STRING(L"Service"); 72 UNICODE_STRING ErrorControlU = RTL_CONSTANT_STRING(L"ErrorControl"); 73 UNICODE_STRING StartU = RTL_CONSTANT_STRING(L"Start"); 74 UNICODE_STRING TypeU = RTL_CONSTANT_STRING(L"Type"); 75 UNICODE_STRING UpperFiltersU = RTL_CONSTANT_STRING(L"UpperFilters"); 76 PWSTR keyboardClass = L"kbdclass\0"; 77 PWSTR partMgr = L"partmgr\0"; 78 79 UNICODE_STRING StringU; 80 OBJECT_ATTRIBUTES ObjectAttributes; 81 HANDLE hService; 82 INFCONTEXT Context; 83 PCWSTR Driver, ClassGuid, ImagePath; 84 ULONG dwValue; 85 ULONG Disposition; 86 NTSTATUS Status; 87 BOOLEAN deviceInstalled = FALSE; 88 89 /* First check if the driver needs any action at all */ 90 if (AreDriversLoaded(DeviceId)) 91 return TRUE; 92 93 /* Check if we know the hardware */ 94 if (!SpInfFindFirstLine(hInf, L"HardwareIdsDatabase", HardwareId, &Context)) 95 return FALSE; 96 if (!INF_GetDataField(&Context, 1, &Driver)) 97 return FALSE; 98 99 /* Get associated class GUID (if any) */ 100 if (!INF_GetDataField(&Context, 2, &ClassGuid)) 101 ClassGuid = NULL; 102 103 /* Find associated driver name */ 104 /* FIXME: check in other sections too! */ 105 if (!SpInfFindFirstLine(hInf, L"BootBusExtenders.Load", Driver, &Context) 106 && !SpInfFindFirstLine(hInf, L"BusExtenders.Load", Driver, &Context) 107 && !SpInfFindFirstLine(hInf, L"SCSI.Load", Driver, &Context) 108 && !SpInfFindFirstLine(hInf, L"InputDevicesSupport.Load", Driver, &Context) 109 && !SpInfFindFirstLine(hInf, L"Keyboard.Load", Driver, &Context)) 110 { 111 INF_FreeData(ClassGuid); 112 INF_FreeData(Driver); 113 return FALSE; 114 } 115 116 if (!INF_GetDataField(&Context, 1, &ImagePath)) 117 { 118 INF_FreeData(ClassGuid); 119 INF_FreeData(Driver); 120 return FALSE; 121 } 122 123 DPRINT1("Using driver '%S' for device '%S'\n", ImagePath, DeviceId); 124 125 /* Create service key */ 126 RtlInitUnicodeString(&StringU, Driver); 127 InitializeObjectAttributes(&ObjectAttributes, &StringU, OBJ_CASE_INSENSITIVE, hServices, NULL); 128 Status = NtCreateKey(&hService, KEY_SET_VALUE, &ObjectAttributes, 0, NULL, REG_OPTION_NON_VOLATILE, &Disposition); 129 if (!NT_SUCCESS(Status)) 130 { 131 DPRINT1("NtCreateKey('%wZ') failed with status 0x%08x\n", &StringU, Status); 132 INF_FreeData(ImagePath); 133 INF_FreeData(ClassGuid); 134 INF_FreeData(Driver); 135 return FALSE; 136 } 137 138 /* Fill service key */ 139 if (Disposition == REG_CREATED_NEW_KEY) 140 { 141 dwValue = 0; 142 NtSetValueKey(hService, 143 &ErrorControlU, 144 0, 145 REG_DWORD, 146 &dwValue, 147 sizeof(dwValue)); 148 149 dwValue = 0; 150 NtSetValueKey(hService, 151 &StartU, 152 0, 153 REG_DWORD, 154 &dwValue, 155 sizeof(dwValue)); 156 157 dwValue = SERVICE_KERNEL_DRIVER; 158 NtSetValueKey(hService, 159 &TypeU, 160 0, 161 REG_DWORD, 162 &dwValue, 163 sizeof(dwValue)); 164 } 165 166 INF_FreeData(ImagePath); 167 NtClose(hService); 168 169 /* Add kbdclass and partmgr upper filters */ 170 if (ClassGuid &&_wcsicmp(ClassGuid, L"{4D36E96B-E325-11CE-BFC1-08002BE10318}") == 0) 171 { 172 DPRINT1("Installing keyboard class driver for '%S'\n", DeviceId); 173 NtSetValueKey(hDeviceKey, 174 &UpperFiltersU, 175 0, 176 REG_MULTI_SZ, 177 keyboardClass, 178 (wcslen(keyboardClass) + 2) * sizeof(WCHAR)); 179 } 180 else if (ClassGuid && _wcsicmp(ClassGuid, L"{4D36E967-E325-11CE-BFC1-08002BE10318}") == 0) 181 { 182 DPRINT1("Installing partition manager driver for '%S'\n", DeviceId); 183 NtSetValueKey(hDeviceKey, 184 &UpperFiltersU, 185 0, 186 REG_MULTI_SZ, 187 partMgr, 188 (wcslen(partMgr) + 2) * sizeof(WCHAR)); 189 } 190 191 INF_FreeData(ClassGuid); 192 193 /* Associate device with the service we just filled */ 194 Status = NtSetValueKey(hDeviceKey, 195 &ServiceU, 196 0, 197 REG_SZ, 198 (PVOID)Driver, 199 (wcslen(Driver) + 1) * sizeof(WCHAR)); 200 if (NT_SUCCESS(Status)) 201 { 202 /* We've registered the driver, time to start a device */ 203 PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA ControlData; 204 RtlInitUnicodeString(&ControlData.DeviceInstance, DeviceId); 205 206 Status = NtPlugPlayControl(PlugPlayControlStartDevice, &ControlData, sizeof(ControlData)); 207 if (!NT_SUCCESS(Status)) 208 { 209 DPRINT1("NtPlugPlayControl() failed with status 0x%08x\n", Status); 210 } 211 212 deviceInstalled = NT_SUCCESS(Status); 213 } 214 215 INF_FreeData(Driver); 216 217 return deviceInstalled; 218 } 219 220 static VOID 221 InstallDevice( 222 IN HINF hInf, 223 IN HANDLE hEnum, 224 IN HANDLE hServices, 225 IN LPCWSTR DeviceId) 226 { 227 UNICODE_STRING HardwareIDU = RTL_CONSTANT_STRING(L"HardwareID"); 228 UNICODE_STRING CompatibleIDsU = RTL_CONSTANT_STRING(L"CompatibleIDs"); 229 230 UNICODE_STRING DeviceIdU; 231 OBJECT_ATTRIBUTES ObjectAttributes; 232 LPCWSTR HardwareID; 233 PKEY_VALUE_PARTIAL_INFORMATION pPartialInformation = NULL; 234 HANDLE hDeviceKey; 235 ULONG ulRequired; 236 BOOLEAN bDriverInstalled = FALSE; 237 NTSTATUS Status; 238 239 RtlInitUnicodeString(&DeviceIdU, DeviceId); 240 InitializeObjectAttributes(&ObjectAttributes, &DeviceIdU, OBJ_CASE_INSENSITIVE, hEnum, NULL); 241 Status = NtOpenKey(&hDeviceKey, KEY_QUERY_VALUE | KEY_SET_VALUE, &ObjectAttributes); 242 if (!NT_SUCCESS(Status)) 243 { 244 DPRINT("Unable to open subkey '%S'\n", DeviceId); 245 return; 246 } 247 248 Status = NtQueryValueKey( 249 hDeviceKey, 250 &HardwareIDU, 251 KeyValuePartialInformation, 252 NULL, 253 0, 254 &ulRequired); 255 if (Status == STATUS_BUFFER_TOO_SMALL) 256 { 257 pPartialInformation = (PKEY_VALUE_PARTIAL_INFORMATION)RtlAllocateHeap(ProcessHeap, 0, ulRequired); 258 if (!pPartialInformation) 259 { 260 DPRINT1("RtlAllocateHeap() failed\n"); 261 NtClose(hDeviceKey); 262 return; 263 } 264 Status = NtQueryValueKey( 265 hDeviceKey, 266 &HardwareIDU, 267 KeyValuePartialInformation, 268 pPartialInformation, 269 ulRequired, 270 &ulRequired); 271 } 272 if (Status == STATUS_OBJECT_NAME_NOT_FOUND) 273 { 274 /* Nothing to do */ 275 } 276 else if (!NT_SUCCESS(Status)) 277 { 278 DPRINT1("NtQueryValueKey() failed with status 0x%08x\n", Status); 279 if (pPartialInformation) 280 RtlFreeHeap(ProcessHeap, 0, pPartialInformation); 281 NtClose(hDeviceKey); 282 return; 283 } 284 else if (pPartialInformation) 285 { 286 for (HardwareID = (LPCWSTR)pPartialInformation->Data; 287 (PUCHAR)HardwareID < pPartialInformation->Data + pPartialInformation->DataLength 288 && *HardwareID 289 && !bDriverInstalled; 290 HardwareID += wcslen(HardwareID) + 1) 291 { 292 bDriverInstalled = InstallDriver(hInf, hServices,hDeviceKey, DeviceId, HardwareID); 293 } 294 } 295 296 if (!bDriverInstalled) 297 { 298 if (pPartialInformation) 299 { 300 RtlFreeHeap(ProcessHeap, 0, pPartialInformation); 301 pPartialInformation = NULL; 302 } 303 Status = NtQueryValueKey( 304 hDeviceKey, 305 &CompatibleIDsU, 306 KeyValuePartialInformation, 307 NULL, 308 0, 309 &ulRequired); 310 if (Status == STATUS_BUFFER_TOO_SMALL) 311 { 312 pPartialInformation = (PKEY_VALUE_PARTIAL_INFORMATION)RtlAllocateHeap(ProcessHeap, 0, ulRequired); 313 if (!pPartialInformation) 314 { 315 DPRINT("RtlAllocateHeap() failed\n"); 316 NtClose(hDeviceKey); 317 return; 318 } 319 Status = NtQueryValueKey( 320 hDeviceKey, 321 &CompatibleIDsU, 322 KeyValuePartialInformation, 323 pPartialInformation, 324 ulRequired, 325 &ulRequired); 326 } 327 if (Status == STATUS_OBJECT_NAME_NOT_FOUND) 328 { 329 /* Nothing to do */ 330 } 331 else if (!NT_SUCCESS(Status)) 332 { 333 if (pPartialInformation) 334 RtlFreeHeap(ProcessHeap, 0, pPartialInformation); 335 NtClose(hDeviceKey); 336 DPRINT1("NtQueryValueKey() failed with status 0x%08x\n", Status); 337 return; 338 } 339 else if (pPartialInformation) 340 { 341 for (HardwareID = (LPCWSTR)pPartialInformation->Data; 342 (PUCHAR)HardwareID < pPartialInformation->Data + pPartialInformation->DataLength 343 && *HardwareID 344 && !bDriverInstalled; 345 HardwareID += wcslen(HardwareID) + 1) 346 { 347 bDriverInstalled = InstallDriver(hInf, hServices,hDeviceKey, DeviceId, HardwareID); 348 } 349 } 350 } 351 if (!bDriverInstalled) 352 DPRINT("No driver available for %S\n", DeviceId); 353 354 RtlFreeHeap(ProcessHeap, 0, pPartialInformation); 355 NtClose(hDeviceKey); 356 } 357 358 /* Loop to install all queued devices installations */ 359 static ULONG NTAPI 360 DeviceInstallThread(IN PVOID Parameter) 361 { 362 HINF hSetupInf = *(HINF*)Parameter; 363 PLIST_ENTRY ListEntry; 364 DeviceInstallParams* Params; 365 LARGE_INTEGER Timeout; 366 367 for (;;) 368 { 369 /* Dequeue the next oldest device-install event */ 370 NtWaitForSingleObject(hDeviceInstallListMutex, FALSE, NULL); 371 ListEntry = (IsListEmpty(&DeviceInstallListHead) 372 ? NULL : RemoveHeadList(&DeviceInstallListHead)); 373 NtReleaseMutant(hDeviceInstallListMutex, NULL); 374 375 if (ListEntry == NULL) 376 { 377 /* 378 * The list is now empty, but there may be a new enumerated device 379 * that is going to be added to the list soon. In order to avoid 380 * setting the hNoPendingInstalls event to release it soon after, 381 * we wait for maximum 1 second for no PnP enumeration event being 382 * received before declaring that no pending installations are 383 * taking place and setting the corresponding event. 384 */ 385 Timeout.QuadPart = -10000000LL; /* Wait for 1 second */ 386 if (NtWaitForSingleObject(hDeviceInstallListNotEmpty, FALSE, &Timeout) == STATUS_TIMEOUT) 387 { 388 /* We timed out: set the event and do the actual wait */ 389 NtSetEvent(hNoPendingInstalls, NULL); 390 NtWaitForSingleObject(hDeviceInstallListNotEmpty, FALSE, NULL); 391 } 392 } 393 else 394 { 395 NtResetEvent(hNoPendingInstalls, NULL); 396 Params = CONTAINING_RECORD(ListEntry, DeviceInstallParams, ListEntry); 397 InstallDevice(hSetupInf, hEnumKey, hServicesKey, Params->DeviceIds); 398 RtlFreeHeap(ProcessHeap, 0, Params); 399 } 400 } 401 402 return 0; 403 } 404 405 static ULONG NTAPI 406 PnpEventThread(IN PVOID Parameter) 407 { 408 NTSTATUS Status; 409 PLUGPLAY_CONTROL_USER_RESPONSE_DATA ResponseData = {0, 0, 0, 0}; 410 PPLUGPLAY_EVENT_BLOCK PnpEvent, NewPnpEvent; 411 ULONG PnpEventSize; 412 413 UNREFERENCED_PARAMETER(Parameter); 414 415 PnpEventSize = 0x1000; 416 PnpEvent = RtlAllocateHeap(ProcessHeap, 0, PnpEventSize); 417 if (PnpEvent == NULL) 418 { 419 Status = STATUS_NO_MEMORY; 420 goto Quit; 421 } 422 423 for (;;) 424 { 425 DPRINT("Calling NtGetPlugPlayEvent()\n"); 426 427 /* Wait for the next PnP event */ 428 Status = NtGetPlugPlayEvent(0, 0, PnpEvent, PnpEventSize); 429 430 /* Resize the buffer for the PnP event if it's too small */ 431 if (Status == STATUS_BUFFER_TOO_SMALL) 432 { 433 PnpEventSize += 0x400; 434 NewPnpEvent = RtlReAllocateHeap(ProcessHeap, 0, PnpEvent, PnpEventSize); 435 if (NewPnpEvent == NULL) 436 { 437 Status = STATUS_NO_MEMORY; 438 goto Quit; 439 } 440 PnpEvent = NewPnpEvent; 441 continue; 442 } 443 444 if (!NT_SUCCESS(Status)) 445 { 446 DPRINT1("NtGetPlugPlayEvent() failed (Status 0x%08lx)\n", Status); 447 goto Quit; 448 } 449 450 /* Process the PnP event */ 451 DPRINT("Received PnP Event\n"); 452 if (IsEqualGUID(&PnpEvent->EventGuid, &GUID_DEVICE_ENUMERATED)) 453 { 454 DeviceInstallParams* Params; 455 ULONG len; 456 ULONG DeviceIdLength; 457 458 DPRINT("Device enumerated: %S\n", PnpEvent->TargetDevice.DeviceIds); 459 460 DeviceIdLength = wcslen(PnpEvent->TargetDevice.DeviceIds); 461 if (DeviceIdLength) 462 { 463 /* Allocate a new device-install event */ 464 len = FIELD_OFFSET(DeviceInstallParams, DeviceIds) + (DeviceIdLength + 1) * sizeof(WCHAR); 465 Params = RtlAllocateHeap(ProcessHeap, 0, len); 466 if (Params) 467 { 468 wcscpy(Params->DeviceIds, PnpEvent->TargetDevice.DeviceIds); 469 470 /* Queue the event (will be dequeued by DeviceInstallThread) */ 471 NtWaitForSingleObject(hDeviceInstallListMutex, FALSE, NULL); 472 InsertTailList(&DeviceInstallListHead, &Params->ListEntry); 473 NtReleaseMutant(hDeviceInstallListMutex, NULL); 474 475 NtSetEvent(hDeviceInstallListNotEmpty, NULL); 476 } 477 else 478 { 479 DPRINT1("Not enough memory (size %lu)\n", len); 480 } 481 } 482 } 483 else 484 { 485 DPRINT("Unknown event, GUID {%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}\n", 486 PnpEvent->EventGuid.Data1, PnpEvent->EventGuid.Data2, PnpEvent->EventGuid.Data3, 487 PnpEvent->EventGuid.Data4[0], PnpEvent->EventGuid.Data4[1], PnpEvent->EventGuid.Data4[2], 488 PnpEvent->EventGuid.Data4[3], PnpEvent->EventGuid.Data4[4], PnpEvent->EventGuid.Data4[5], 489 PnpEvent->EventGuid.Data4[6], PnpEvent->EventGuid.Data4[7]); 490 } 491 492 /* Dequeue the current PnP event and signal the next one */ 493 Status = NtPlugPlayControl(PlugPlayControlUserResponse, 494 &ResponseData, 495 sizeof(ResponseData)); 496 if (!NT_SUCCESS(Status)) 497 { 498 DPRINT1("NtPlugPlayControl(PlugPlayControlUserResponse) failed (Status 0x%08lx)\n", Status); 499 goto Quit; 500 } 501 } 502 503 Status = STATUS_SUCCESS; 504 505 Quit: 506 if (PnpEvent) 507 RtlFreeHeap(ProcessHeap, 0, PnpEvent); 508 509 NtTerminateThread(NtCurrentThread(), Status); 510 return Status; 511 } 512 513 NTSTATUS 514 WaitNoPendingInstallEvents( 515 IN PLARGE_INTEGER Timeout OPTIONAL) 516 { 517 return NtWaitForSingleObject(hNoPendingInstalls, FALSE, Timeout); 518 } 519 520 BOOLEAN 521 EnableUserModePnpManager(VOID) 522 { 523 LARGE_INTEGER Timeout; 524 525 /* Start the PnP thread */ 526 if (hPnpThread != NULL) 527 NtResumeThread(hPnpThread, NULL); 528 529 /* 530 * Wait a little bit so that we get a chance to have some events being 531 * queued by the time the device-installation thread becomes resumed. 532 */ 533 Timeout.QuadPart = -10000000LL; /* Wait for 1 second */ 534 NtWaitForSingleObject(hDeviceInstallListNotEmpty, FALSE, &Timeout); 535 536 /* Start the device installation thread */ 537 if (hDeviceInstallThread != NULL) 538 NtResumeThread(hDeviceInstallThread, NULL); 539 540 return TRUE; 541 } 542 543 BOOLEAN 544 DisableUserModePnpManager(VOID) 545 { 546 /* Wait until all pending installations are done, then freeze the threads */ 547 if (WaitNoPendingInstallEvents(NULL) != STATUS_WAIT_0) 548 DPRINT1("WaitNoPendingInstallEvents() failed to wait!\n"); 549 550 // TODO: use signalling events 551 552 NtSuspendThread(hPnpThread, NULL); 553 NtSuspendThread(hDeviceInstallThread, NULL); 554 555 return TRUE; 556 } 557 558 NTSTATUS 559 InitializeUserModePnpManager( 560 IN HINF* phSetupInf) 561 { 562 NTSTATUS Status; 563 OBJECT_ATTRIBUTES ObjectAttributes; 564 565 UNICODE_STRING EnumU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Enum"); 566 UNICODE_STRING ServicesU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Services"); 567 568 Status = NtCreateEvent(&hNoPendingInstalls, 569 EVENT_ALL_ACCESS, 570 NULL, 571 NotificationEvent, 572 FALSE); 573 if (!NT_SUCCESS(Status)) 574 { 575 DPRINT1("Could not create the Pending-Install Event! (Status 0x%08lx)\n", Status); 576 goto Failure; 577 } 578 579 /* 580 * Initialize the device-install event list 581 */ 582 583 Status = NtCreateEvent(&hDeviceInstallListNotEmpty, 584 EVENT_ALL_ACCESS, 585 NULL, 586 SynchronizationEvent, 587 FALSE); 588 if (!NT_SUCCESS(Status)) 589 { 590 DPRINT1("Could not create the List Event! (Status 0x%08lx)\n", Status); 591 goto Failure; 592 } 593 594 Status = NtCreateMutant(&hDeviceInstallListMutex, 595 MUTANT_ALL_ACCESS, 596 NULL, FALSE); 597 if (!NT_SUCCESS(Status)) 598 { 599 DPRINT1("Could not create the List Mutex! (Status 0x%08lx)\n", Status); 600 goto Failure; 601 } 602 InitializeListHead(&DeviceInstallListHead); 603 604 InitializeObjectAttributes(&ObjectAttributes, &EnumU, OBJ_CASE_INSENSITIVE, NULL, NULL); 605 Status = NtOpenKey(&hEnumKey, KEY_QUERY_VALUE, &ObjectAttributes); 606 if (!NT_SUCCESS(Status)) 607 { 608 DPRINT1("NtOpenKey('%wZ') failed (Status 0x%08lx)\n", &EnumU, Status); 609 goto Failure; 610 } 611 612 InitializeObjectAttributes(&ObjectAttributes, &ServicesU, OBJ_CASE_INSENSITIVE, NULL, NULL); 613 Status = NtCreateKey(&hServicesKey, KEY_ALL_ACCESS, &ObjectAttributes, 0, NULL, REG_OPTION_NON_VOLATILE, NULL); 614 if (!NT_SUCCESS(Status)) 615 { 616 DPRINT1("NtCreateKey('%wZ') failed (Status 0x%08lx)\n", &ServicesU, Status); 617 goto Failure; 618 } 619 620 /* Create the PnP event thread in suspended state */ 621 Status = RtlCreateUserThread(NtCurrentProcess(), 622 NULL, 623 TRUE, 624 0, 625 0, 626 0, 627 PnpEventThread, 628 NULL, 629 &hPnpThread, 630 NULL); 631 if (!NT_SUCCESS(Status)) 632 { 633 DPRINT1("Failed to create the PnP event thread (Status 0x%08lx)\n", Status); 634 hPnpThread = NULL; 635 goto Failure; 636 } 637 638 /* Create the device installation thread in suspended state */ 639 Status = RtlCreateUserThread(NtCurrentProcess(), 640 NULL, 641 TRUE, 642 0, 643 0, 644 0, 645 DeviceInstallThread, 646 phSetupInf, 647 &hDeviceInstallThread, 648 NULL); 649 if (!NT_SUCCESS(Status)) 650 { 651 DPRINT1("Failed to create the device installation thread (Status 0x%08lx)\n", Status); 652 hDeviceInstallThread = NULL; 653 goto Failure; 654 } 655 656 return STATUS_SUCCESS; 657 658 Failure: 659 if (hPnpThread) 660 { 661 NtTerminateThread(hPnpThread, STATUS_SUCCESS); 662 NtClose(hPnpThread); 663 } 664 hPnpThread = NULL; 665 666 if (hServicesKey) 667 NtClose(hServicesKey); 668 hServicesKey = NULL; 669 670 if (hEnumKey) 671 NtClose(hEnumKey); 672 hEnumKey = NULL; 673 674 if (hDeviceInstallListMutex) 675 NtClose(hDeviceInstallListMutex); 676 hDeviceInstallListMutex = NULL; 677 678 if (hDeviceInstallListNotEmpty) 679 NtClose(hDeviceInstallListNotEmpty); 680 hDeviceInstallListNotEmpty = NULL; 681 682 if (hNoPendingInstalls) 683 NtClose(hNoPendingInstalls); 684 hNoPendingInstalls = NULL; 685 686 return Status; 687 } 688 689 VOID 690 TerminateUserModePnpManager(VOID) 691 { 692 DisableUserModePnpManager(); 693 694 // TODO: use signalling events 695 696 /* Kill the PnP thread as it blocks inside the NtGetPlugPlayEvent() call */ 697 if (hPnpThread) 698 { 699 NtTerminateThread(hPnpThread, STATUS_SUCCESS); 700 NtClose(hPnpThread); 701 } 702 hPnpThread = NULL; 703 704 /* Kill the device installation thread */ 705 if (hDeviceInstallThread) 706 { 707 NtTerminateThread(hDeviceInstallThread, STATUS_SUCCESS); 708 NtClose(hDeviceInstallThread); 709 } 710 hDeviceInstallThread = NULL; 711 712 /* Close the opened handles */ 713 714 if (hServicesKey) 715 NtClose(hServicesKey); 716 hServicesKey = NULL; 717 718 if (hEnumKey) 719 NtClose(hEnumKey); 720 hEnumKey = NULL; 721 722 if (hNoPendingInstalls) 723 NtClose(hNoPendingInstalls); 724 hNoPendingInstalls = NULL; 725 726 if (hDeviceInstallListNotEmpty) 727 NtClose(hDeviceInstallListNotEmpty); 728 hDeviceInstallListNotEmpty = NULL; 729 } 730