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
AreDriversLoaded(IN PCWSTR DeviceId)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
InstallDriver(IN HINF hInf,IN HANDLE hServices,IN HANDLE hDeviceKey,IN LPCWSTR DeviceId,IN LPCWSTR HardwareId)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
InstallDevice(IN HINF hInf,IN HANDLE hEnum,IN HANDLE hServices,IN LPCWSTR DeviceId)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
DeviceInstallThread(IN PVOID Parameter)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
PnpEventThread(IN PVOID Parameter)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
WaitNoPendingInstallEvents(IN PLARGE_INTEGER Timeout OPTIONAL)514 WaitNoPendingInstallEvents(
515 IN PLARGE_INTEGER Timeout OPTIONAL)
516 {
517 return NtWaitForSingleObject(hNoPendingInstalls, FALSE, Timeout);
518 }
519
520 BOOLEAN
EnableUserModePnpManager(VOID)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
DisableUserModePnpManager(VOID)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
InitializeUserModePnpManager(IN HINF * phSetupInf)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
TerminateUserModePnpManager(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