80d93ce1d519dc3285e04395a88ec3ab794572cd
[reactos.git] / base / setup / usetup / devinst.c
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_DEVICE_CONTROL_DATA ResetDeviceData;
46 NTSTATUS Status;
47
48 RtlInitUnicodeString(&ResetDeviceData.DeviceInstance, DeviceId);
49 Status = NtPlugPlayControl(PlugPlayControlResetDevice, &ResetDeviceData, sizeof(PLUGPLAY_CONTROL_DEVICE_CONTROL_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 }