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