/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS text-mode setup
- * FILE: base/setup/usetup/devinst.c
* PURPOSE: Device installation
* PROGRAMMER: Hervé Poussineau (hpoussin@reactos.org)
+ * Hermes Belusca-Maito
*/
#include <usetup.h>
#include <guiddef.h>
#include <libs/umpnpmgr/sysguid.h>
-BOOLEAN
-ResetDevice(
- IN LPCWSTR DeviceId)
+/* LOCALS *******************************************************************/
+
+static HANDLE hEnumKey = NULL;
+static HANDLE hServicesKey = NULL;
+
+static HANDLE hNoPendingInstalls = NULL;
+
+static HANDLE hPnpThread = NULL;
+static HANDLE hDeviceInstallThread = NULL;
+
+/* Device-install event list */
+static HANDLE hDeviceInstallListMutex = NULL;
+static LIST_ENTRY DeviceInstallListHead;
+static HANDLE hDeviceInstallListNotEmpty = NULL;
+
+typedef struct
+{
+ LIST_ENTRY ListEntry;
+ WCHAR DeviceIds[ANYSIZE_ARRAY];
+} DeviceInstallParams;
+
+/* FUNCTIONS ****************************************************************/
+
+static BOOLEAN
+AreDriversLoaded(
+ IN PCWSTR DeviceId)
{
- PLUGPLAY_CONTROL_RESET_DEVICE_DATA ResetDeviceData;
+ PLUGPLAY_CONTROL_STATUS_DATA PlugPlayData;
NTSTATUS Status;
- RtlInitUnicodeString(&ResetDeviceData.DeviceInstance, DeviceId);
- Status = NtPlugPlayControl(PlugPlayControlResetDevice, &ResetDeviceData, sizeof(PLUGPLAY_CONTROL_RESET_DEVICE_DATA));
- if (!NT_SUCCESS(Status))
+ RtlInitUnicodeString(&PlugPlayData.DeviceInstance, DeviceId);
+ PlugPlayData.Operation = PNP_GET_DEVICE_STATUS;
+
+ Status = NtPlugPlayControl(PlugPlayControlDeviceStatus, &PlugPlayData, sizeof(PlugPlayData));
+ if (NT_SUCCESS(Status))
+ {
+ return (_Bool)((PlugPlayData.DeviceStatus & DN_DRIVER_LOADED) &&
+ !(PlugPlayData.DeviceStatus & DN_HAS_PROBLEM));
+ }
+ else
{
- DPRINT1("NtPlugPlayControl() failed with status 0x%08x\n", Status);
return FALSE;
}
- return TRUE;
}
-BOOLEAN
+static BOOLEAN
InstallDriver(
IN HINF hInf,
IN HANDLE hServices,
IN LPCWSTR DeviceId,
IN LPCWSTR HardwareId)
{
- UNICODE_STRING PathPrefix = RTL_CONSTANT_STRING(L"System32\\DRIVERS\\");
UNICODE_STRING ServiceU = RTL_CONSTANT_STRING(L"Service");
UNICODE_STRING ErrorControlU = RTL_CONSTANT_STRING(L"ErrorControl");
- UNICODE_STRING ImagePathU = RTL_CONSTANT_STRING(L"ImagePath");
UNICODE_STRING StartU = RTL_CONSTANT_STRING(L"Start");
UNICODE_STRING TypeU = RTL_CONSTANT_STRING(L"Type");
+ UNICODE_STRING UpperFiltersU = RTL_CONSTANT_STRING(L"UpperFilters");
+ PWSTR keyboardClass = L"kbdclass\0";
+ PWSTR partMgr = L"partmgr\0";
+
UNICODE_STRING StringU;
OBJECT_ATTRIBUTES ObjectAttributes;
HANDLE hService;
INFCONTEXT Context;
- PWSTR Driver, ClassGuid, ImagePath, FullImagePath;
+ PCWSTR Driver, ClassGuid, ImagePath;
ULONG dwValue;
ULONG Disposition;
NTSTATUS Status;
BOOLEAN deviceInstalled = FALSE;
- UNICODE_STRING UpperFiltersU = RTL_CONSTANT_STRING(L"UpperFilters");
- PWSTR keyboardClass = L"kbdclass\0";
+
+ /* First check if the driver needs any action at all */
+ if (AreDriversLoaded(DeviceId))
+ return TRUE;
/* Check if we know the hardware */
- if (!SetupFindFirstLineW(hInf, L"HardwareIdsDatabase", HardwareId, &Context))
+ if (!SpInfFindFirstLine(hInf, L"HardwareIdsDatabase", HardwareId, &Context))
return FALSE;
if (!INF_GetDataField(&Context, 1, &Driver))
return FALSE;
/* Find associated driver name */
/* FIXME: check in other sections too! */
- if (!SetupFindFirstLineW(hInf, L"BootBusExtenders.Load", Driver, &Context)
- && !SetupFindFirstLineW(hInf, L"BusExtenders.Load", Driver, &Context)
- && !SetupFindFirstLineW(hInf, L"SCSI.Load", Driver, &Context)
- && !SetupFindFirstLineW(hInf, L"InputDevicesSupport.Load", Driver, &Context)
- && !SetupFindFirstLineW(hInf, L"Keyboard.Load", Driver, &Context))
+ if (!SpInfFindFirstLine(hInf, L"BootBusExtenders.Load", Driver, &Context)
+ && !SpInfFindFirstLine(hInf, L"BusExtenders.Load", Driver, &Context)
+ && !SpInfFindFirstLine(hInf, L"SCSI.Load", Driver, &Context)
+ && !SpInfFindFirstLine(hInf, L"InputDevicesSupport.Load", Driver, &Context)
+ && !SpInfFindFirstLine(hInf, L"Keyboard.Load", Driver, &Context))
{
+ INF_FreeData(ClassGuid);
+ INF_FreeData(Driver);
return FALSE;
}
if (!INF_GetDataField(&Context, 1, &ImagePath))
- return FALSE;
-
- /* Prepare full driver path */
- dwValue = PathPrefix.MaximumLength + wcslen(ImagePath) * sizeof(WCHAR);
- FullImagePath = (PWSTR)RtlAllocateHeap(ProcessHeap, 0, dwValue);
- if (!FullImagePath)
{
- DPRINT1("RtlAllocateHeap() failed\n");
+ INF_FreeData(ClassGuid);
+ INF_FreeData(Driver);
return FALSE;
}
- RtlCopyMemory(FullImagePath, PathPrefix.Buffer, PathPrefix.MaximumLength);
- ConcatPaths(FullImagePath, dwValue / sizeof(WCHAR), 1, ImagePath);
DPRINT1("Using driver '%S' for device '%S'\n", ImagePath, DeviceId);
/* Create service key */
RtlInitUnicodeString(&StringU, Driver);
- InitializeObjectAttributes(&ObjectAttributes, &StringU, 0, hServices, NULL);
+ InitializeObjectAttributes(&ObjectAttributes, &StringU, OBJ_CASE_INSENSITIVE, hServices, NULL);
Status = NtCreateKey(&hService, KEY_SET_VALUE, &ObjectAttributes, 0, NULL, REG_OPTION_NON_VOLATILE, &Disposition);
if (!NT_SUCCESS(Status))
{
DPRINT1("NtCreateKey('%wZ') failed with status 0x%08x\n", &StringU, Status);
- RtlFreeHeap(ProcessHeap, 0, FullImagePath);
+ INF_FreeData(ImagePath);
+ INF_FreeData(ClassGuid);
+ INF_FreeData(Driver);
return FALSE;
}
if (Disposition == REG_CREATED_NEW_KEY)
{
dwValue = 0;
- NtSetValueKey(
- hService,
- &ErrorControlU,
- 0,
- REG_DWORD,
- &dwValue,
- sizeof(dwValue));
+ NtSetValueKey(hService,
+ &ErrorControlU,
+ 0,
+ REG_DWORD,
+ &dwValue,
+ sizeof(dwValue));
+
dwValue = 0;
- NtSetValueKey(
- hService,
- &StartU,
- 0,
- REG_DWORD,
- &dwValue,
- sizeof(dwValue));
+ NtSetValueKey(hService,
+ &StartU,
+ 0,
+ REG_DWORD,
+ &dwValue,
+ sizeof(dwValue));
+
dwValue = SERVICE_KERNEL_DRIVER;
- NtSetValueKey(
- hService,
- &TypeU,
- 0,
- REG_DWORD,
- &dwValue,
- sizeof(dwValue));
+ NtSetValueKey(hService,
+ &TypeU,
+ 0,
+ REG_DWORD,
+ &dwValue,
+ sizeof(dwValue));
}
- /* HACK: don't put any path in registry */
- NtSetValueKey(
- hService,
- &ImagePathU,
- 0,
- REG_SZ,
- ImagePath,
- (wcslen(ImagePath) + 1) * sizeof(WCHAR));
+ INF_FreeData(ImagePath);
+ NtClose(hService);
+
+ /* Add kbdclass and partmgr upper filters */
if (ClassGuid &&_wcsicmp(ClassGuid, L"{4D36E96B-E325-11CE-BFC1-08002BE10318}") == 0)
{
DPRINT1("Installing keyboard class driver for '%S'\n", DeviceId);
keyboardClass,
(wcslen(keyboardClass) + 2) * sizeof(WCHAR));
}
+ else if (ClassGuid && _wcsicmp(ClassGuid, L"{4D36E967-E325-11CE-BFC1-08002BE10318}") == 0)
+ {
+ DPRINT1("Installing partition manager driver for '%S'\n", DeviceId);
+ NtSetValueKey(hDeviceKey,
+ &UpperFiltersU,
+ 0,
+ REG_MULTI_SZ,
+ partMgr,
+ (wcslen(partMgr) + 2) * sizeof(WCHAR));
+ }
+
+ INF_FreeData(ClassGuid);
/* Associate device with the service we just filled */
- Status = NtSetValueKey(
- hDeviceKey,
- &ServiceU,
- 0,
- REG_SZ,
- Driver,
- (wcslen(Driver) + 1) * sizeof(WCHAR));
+ Status = NtSetValueKey(hDeviceKey,
+ &ServiceU,
+ 0,
+ REG_SZ,
+ (PVOID)Driver,
+ (wcslen(Driver) + 1) * sizeof(WCHAR));
if (NT_SUCCESS(Status))
{
- /* Restart the device, so it will use the driver we registered */
- deviceInstalled = ResetDevice(DeviceId);
+ /* We've registered the driver, time to start a device */
+ PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA ControlData;
+ RtlInitUnicodeString(&ControlData.DeviceInstance, DeviceId);
+
+ Status = NtPlugPlayControl(PlugPlayControlStartDevice, &ControlData, sizeof(ControlData));
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("NtPlugPlayControl() failed with status 0x%08x\n", Status);
+ }
+
+ deviceInstalled = NT_SUCCESS(Status);
}
- /* HACK: Update driver path */
- NtSetValueKey(
- hService,
- &ImagePathU,
- 0,
- REG_SZ,
- FullImagePath,
- (wcslen(FullImagePath) + 1) * sizeof(WCHAR));
- RtlFreeHeap(ProcessHeap, 0, FullImagePath);
- NtClose(hService);
+ INF_FreeData(Driver);
return deviceInstalled;
}
-VOID
+static VOID
InstallDevice(
IN HINF hInf,
IN HANDLE hEnum,
{
UNICODE_STRING HardwareIDU = RTL_CONSTANT_STRING(L"HardwareID");
UNICODE_STRING CompatibleIDsU = RTL_CONSTANT_STRING(L"CompatibleIDs");
+
UNICODE_STRING DeviceIdU;
OBJECT_ATTRIBUTES ObjectAttributes;
LPCWSTR HardwareID;
NTSTATUS Status;
RtlInitUnicodeString(&DeviceIdU, DeviceId);
- InitializeObjectAttributes(&ObjectAttributes, &DeviceIdU, 0, hEnum, NULL);
+ InitializeObjectAttributes(&ObjectAttributes, &DeviceIdU, OBJ_CASE_INSENSITIVE, hEnum, NULL);
Status = NtOpenKey(&hDeviceKey, KEY_QUERY_VALUE | KEY_SET_VALUE, &ObjectAttributes);
if (!NT_SUCCESS(Status))
{
NtClose(hDeviceKey);
}
-NTSTATUS
-EventThread(IN LPVOID lpParameter)
+/* Loop to install all queued devices installations */
+static ULONG NTAPI
+DeviceInstallThread(IN PVOID Parameter)
{
- UNICODE_STRING EnumU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Enum");
- UNICODE_STRING ServicesU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Services");
- PPLUGPLAY_EVENT_BLOCK PnpEvent;
- OBJECT_ATTRIBUTES ObjectAttributes;
- ULONG PnpEventSize;
- HINF hInf;
- HANDLE hEnum, hServices;
- NTSTATUS Status;
+ HINF hSetupInf = *(HINF*)Parameter;
+ PLIST_ENTRY ListEntry;
+ DeviceInstallParams* Params;
+ LARGE_INTEGER Timeout;
- hInf = *(HINF *)lpParameter;
-
- InitializeObjectAttributes(&ObjectAttributes, &EnumU, OBJ_CASE_INSENSITIVE, NULL, NULL);
- Status = NtOpenKey(&hEnum, KEY_QUERY_VALUE, &ObjectAttributes);
- if (!NT_SUCCESS(Status))
+ for (;;)
{
- DPRINT1("NtOpenKey('%wZ') failed with status 0x%08lx\n", &EnumU, Status);
- return Status;
- }
+ /* Dequeue the next oldest device-install event */
+ NtWaitForSingleObject(hDeviceInstallListMutex, FALSE, NULL);
+ ListEntry = (IsListEmpty(&DeviceInstallListHead)
+ ? NULL : RemoveHeadList(&DeviceInstallListHead));
+ NtReleaseMutant(hDeviceInstallListMutex, NULL);
- InitializeObjectAttributes(&ObjectAttributes, &ServicesU, OBJ_CASE_INSENSITIVE, NULL, NULL);
- Status = NtCreateKey(&hServices, KEY_ALL_ACCESS, &ObjectAttributes, 0, NULL, REG_OPTION_NON_VOLATILE, NULL);
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("NtCreateKey('%wZ') failed with status 0x%08lx\n", &ServicesU, Status);
- NtClose(hEnum);
- return Status;
+ if (ListEntry == NULL)
+ {
+ /*
+ * The list is now empty, but there may be a new enumerated device
+ * that is going to be added to the list soon. In order to avoid
+ * setting the hNoPendingInstalls event to release it soon after,
+ * we wait for maximum 1 second for no PnP enumeration event being
+ * received before declaring that no pending installations are
+ * taking place and setting the corresponding event.
+ */
+ Timeout.QuadPart = -10000000LL; /* Wait for 1 second */
+ if (NtWaitForSingleObject(hDeviceInstallListNotEmpty, FALSE, &Timeout) == STATUS_TIMEOUT)
+ {
+ /* We timed out: set the event and do the actual wait */
+ NtSetEvent(hNoPendingInstalls, NULL);
+ NtWaitForSingleObject(hDeviceInstallListNotEmpty, FALSE, NULL);
+ }
+ }
+ else
+ {
+ NtResetEvent(hNoPendingInstalls, NULL);
+ Params = CONTAINING_RECORD(ListEntry, DeviceInstallParams, ListEntry);
+ InstallDevice(hSetupInf, hEnumKey, hServicesKey, Params->DeviceIds);
+ RtlFreeHeap(ProcessHeap, 0, Params);
+ }
}
+ return 0;
+}
+
+static ULONG NTAPI
+PnpEventThread(IN PVOID Parameter)
+{
+ NTSTATUS Status;
+ PLUGPLAY_CONTROL_USER_RESPONSE_DATA ResponseData = {0, 0, 0, 0};
+ PPLUGPLAY_EVENT_BLOCK PnpEvent, NewPnpEvent;
+ ULONG PnpEventSize;
+
+ UNREFERENCED_PARAMETER(Parameter);
+
PnpEventSize = 0x1000;
- PnpEvent = (PPLUGPLAY_EVENT_BLOCK)RtlAllocateHeap(ProcessHeap, 0, PnpEventSize);
+ PnpEvent = RtlAllocateHeap(ProcessHeap, 0, PnpEventSize);
if (PnpEvent == NULL)
{
- NtClose(hEnum);
- NtClose(hServices);
- return STATUS_NO_MEMORY;
+ Status = STATUS_NO_MEMORY;
+ goto Quit;
}
for (;;)
{
DPRINT("Calling NtGetPlugPlayEvent()\n");
- /* Wait for the next pnp event */
+ /* Wait for the next PnP event */
Status = NtGetPlugPlayEvent(0, 0, PnpEvent, PnpEventSize);
- /* Resize the buffer for the PnP event if it's too small. */
+ /* Resize the buffer for the PnP event if it's too small */
if (Status == STATUS_BUFFER_TOO_SMALL)
{
PnpEventSize += 0x400;
- RtlFreeHeap(ProcessHeap, 0, PnpEvent);
- PnpEvent = (PPLUGPLAY_EVENT_BLOCK)RtlAllocateHeap(ProcessHeap, 0, PnpEventSize);
- if (PnpEvent == NULL)
+ NewPnpEvent = RtlReAllocateHeap(ProcessHeap, 0, PnpEvent, PnpEventSize);
+ if (NewPnpEvent == NULL)
{
- NtClose(hEnum);
- NtClose(hServices);
- return STATUS_NO_MEMORY;
+ Status = STATUS_NO_MEMORY;
+ goto Quit;
}
+ PnpEvent = NewPnpEvent;
continue;
}
if (!NT_SUCCESS(Status))
{
- DPRINT("NtPlugPlayEvent() failed (Status %lx)\n", Status);
- break;
+ DPRINT1("NtGetPlugPlayEvent() failed (Status 0x%08lx)\n", Status);
+ goto Quit;
}
- /* Process the pnp event */
+ /* Process the PnP event */
DPRINT("Received PnP Event\n");
- if (IsEqualIID(&PnpEvent->EventGuid, (REFGUID)&GUID_DEVICE_ENUMERATED))
+ if (IsEqualGUID(&PnpEvent->EventGuid, &GUID_DEVICE_ENUMERATED))
{
- DPRINT("Device arrival event: %S\n", PnpEvent->TargetDevice.DeviceIds);
- InstallDevice(hInf, hEnum, hServices, PnpEvent->TargetDevice.DeviceIds);
+ DeviceInstallParams* Params;
+ ULONG len;
+ ULONG DeviceIdLength;
+
+ DPRINT("Device enumerated: %S\n", PnpEvent->TargetDevice.DeviceIds);
+
+ DeviceIdLength = wcslen(PnpEvent->TargetDevice.DeviceIds);
+ if (DeviceIdLength)
+ {
+ /* Allocate a new device-install event */
+ len = FIELD_OFFSET(DeviceInstallParams, DeviceIds) + (DeviceIdLength + 1) * sizeof(WCHAR);
+ Params = RtlAllocateHeap(ProcessHeap, 0, len);
+ if (Params)
+ {
+ wcscpy(Params->DeviceIds, PnpEvent->TargetDevice.DeviceIds);
+
+ /* Queue the event (will be dequeued by DeviceInstallThread) */
+ NtWaitForSingleObject(hDeviceInstallListMutex, FALSE, NULL);
+ InsertTailList(&DeviceInstallListHead, &Params->ListEntry);
+ NtReleaseMutant(hDeviceInstallListMutex, NULL);
+
+ NtSetEvent(hDeviceInstallListNotEmpty, NULL);
+ }
+ else
+ {
+ DPRINT1("Not enough memory (size %lu)\n", len);
+ }
+ }
}
else
{
- DPRINT("Unknown event\n");
+ DPRINT("Unknown event, GUID {%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}\n",
+ PnpEvent->EventGuid.Data1, PnpEvent->EventGuid.Data2, PnpEvent->EventGuid.Data3,
+ PnpEvent->EventGuid.Data4[0], PnpEvent->EventGuid.Data4[1], PnpEvent->EventGuid.Data4[2],
+ PnpEvent->EventGuid.Data4[3], PnpEvent->EventGuid.Data4[4], PnpEvent->EventGuid.Data4[5],
+ PnpEvent->EventGuid.Data4[6], PnpEvent->EventGuid.Data4[7]);
}
- /* Dequeue the current pnp event and signal the next one */
- NtPlugPlayControl(PlugPlayControlUserResponse, NULL, 0);
+ /* Dequeue the current PnP event and signal the next one */
+ Status = NtPlugPlayControl(PlugPlayControlUserResponse,
+ &ResponseData,
+ sizeof(ResponseData));
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("NtPlugPlayControl(PlugPlayControlUserResponse) failed (Status 0x%08lx)\n", Status);
+ goto Quit;
+ }
}
- RtlFreeHeap(ProcessHeap, 0, PnpEvent);
- NtClose(hEnum);
- NtClose(hServices);
+ Status = STATUS_SUCCESS;
- return STATUS_SUCCESS;
+Quit:
+ if (PnpEvent)
+ RtlFreeHeap(ProcessHeap, 0, PnpEvent);
+
+ NtTerminateThread(NtCurrentThread(), Status);
+ return Status;
+}
+
+NTSTATUS
+WaitNoPendingInstallEvents(
+ IN PLARGE_INTEGER Timeout OPTIONAL)
+{
+ return NtWaitForSingleObject(hNoPendingInstalls, FALSE, Timeout);
}
-DWORD WINAPI
-PnpEventThread(IN LPVOID lpParameter)
+BOOLEAN
+EnableUserModePnpManager(VOID)
+{
+ LARGE_INTEGER Timeout;
+
+ /* Start the PnP thread */
+ if (hPnpThread != NULL)
+ NtResumeThread(hPnpThread, NULL);
+
+ /*
+ * Wait a little bit so that we get a chance to have some events being
+ * queued by the time the device-installation thread becomes resumed.
+ */
+ Timeout.QuadPart = -10000000LL; /* Wait for 1 second */
+ NtWaitForSingleObject(hDeviceInstallListNotEmpty, FALSE, &Timeout);
+
+ /* Start the device installation thread */
+ if (hDeviceInstallThread != NULL)
+ NtResumeThread(hDeviceInstallThread, NULL);
+
+ return TRUE;
+}
+
+BOOLEAN
+DisableUserModePnpManager(VOID)
+{
+ /* Wait until all pending installations are done, then freeze the threads */
+ if (WaitNoPendingInstallEvents(NULL) != STATUS_WAIT_0)
+ DPRINT1("WaitNoPendingInstallEvents() failed to wait!\n");
+
+ // TODO: use signalling events
+
+ NtSuspendThread(hPnpThread, NULL);
+ NtSuspendThread(hDeviceInstallThread, NULL);
+
+ return TRUE;
+}
+
+NTSTATUS
+InitializeUserModePnpManager(
+ IN HINF* phSetupInf)
{
NTSTATUS Status;
- Status = EventThread(lpParameter);
- NtTerminateThread(NtCurrentThread(), Status);
- return 0;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+
+ UNICODE_STRING EnumU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Enum");
+ UNICODE_STRING ServicesU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Services");
+
+ Status = NtCreateEvent(&hNoPendingInstalls,
+ EVENT_ALL_ACCESS,
+ NULL,
+ NotificationEvent,
+ FALSE);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Could not create the Pending-Install Event! (Status 0x%08lx)\n", Status);
+ goto Failure;
+ }
+
+ /*
+ * Initialize the device-install event list
+ */
+
+ Status = NtCreateEvent(&hDeviceInstallListNotEmpty,
+ EVENT_ALL_ACCESS,
+ NULL,
+ SynchronizationEvent,
+ FALSE);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Could not create the List Event! (Status 0x%08lx)\n", Status);
+ goto Failure;
+ }
+
+ Status = NtCreateMutant(&hDeviceInstallListMutex,
+ MUTANT_ALL_ACCESS,
+ NULL, FALSE);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Could not create the List Mutex! (Status 0x%08lx)\n", Status);
+ goto Failure;
+ }
+ InitializeListHead(&DeviceInstallListHead);
+
+ InitializeObjectAttributes(&ObjectAttributes, &EnumU, OBJ_CASE_INSENSITIVE, NULL, NULL);
+ Status = NtOpenKey(&hEnumKey, KEY_QUERY_VALUE, &ObjectAttributes);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("NtOpenKey('%wZ') failed (Status 0x%08lx)\n", &EnumU, Status);
+ goto Failure;
+ }
+
+ InitializeObjectAttributes(&ObjectAttributes, &ServicesU, OBJ_CASE_INSENSITIVE, NULL, NULL);
+ Status = NtCreateKey(&hServicesKey, KEY_ALL_ACCESS, &ObjectAttributes, 0, NULL, REG_OPTION_NON_VOLATILE, NULL);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("NtCreateKey('%wZ') failed (Status 0x%08lx)\n", &ServicesU, Status);
+ goto Failure;
+ }
+
+ /* Create the PnP event thread in suspended state */
+ Status = RtlCreateUserThread(NtCurrentProcess(),
+ NULL,
+ TRUE,
+ 0,
+ 0,
+ 0,
+ PnpEventThread,
+ NULL,
+ &hPnpThread,
+ NULL);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to create the PnP event thread (Status 0x%08lx)\n", Status);
+ hPnpThread = NULL;
+ goto Failure;
+ }
+
+ /* Create the device installation thread in suspended state */
+ Status = RtlCreateUserThread(NtCurrentProcess(),
+ NULL,
+ TRUE,
+ 0,
+ 0,
+ 0,
+ DeviceInstallThread,
+ phSetupInf,
+ &hDeviceInstallThread,
+ NULL);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to create the device installation thread (Status 0x%08lx)\n", Status);
+ hDeviceInstallThread = NULL;
+ goto Failure;
+ }
+
+ return STATUS_SUCCESS;
+
+Failure:
+ if (hPnpThread)
+ {
+ NtTerminateThread(hPnpThread, STATUS_SUCCESS);
+ NtClose(hPnpThread);
+ }
+ hPnpThread = NULL;
+
+ if (hServicesKey)
+ NtClose(hServicesKey);
+ hServicesKey = NULL;
+
+ if (hEnumKey)
+ NtClose(hEnumKey);
+ hEnumKey = NULL;
+
+ if (hDeviceInstallListMutex)
+ NtClose(hDeviceInstallListMutex);
+ hDeviceInstallListMutex = NULL;
+
+ if (hDeviceInstallListNotEmpty)
+ NtClose(hDeviceInstallListNotEmpty);
+ hDeviceInstallListNotEmpty = NULL;
+
+ if (hNoPendingInstalls)
+ NtClose(hNoPendingInstalls);
+ hNoPendingInstalls = NULL;
+
+ return Status;
+}
+
+VOID
+TerminateUserModePnpManager(VOID)
+{
+ DisableUserModePnpManager();
+
+ // TODO: use signalling events
+
+ /* Kill the PnP thread as it blocks inside the NtGetPlugPlayEvent() call */
+ if (hPnpThread)
+ {
+ NtTerminateThread(hPnpThread, STATUS_SUCCESS);
+ NtClose(hPnpThread);
+ }
+ hPnpThread = NULL;
+
+ /* Kill the device installation thread */
+ if (hDeviceInstallThread)
+ {
+ NtTerminateThread(hDeviceInstallThread, STATUS_SUCCESS);
+ NtClose(hDeviceInstallThread);
+ }
+ hDeviceInstallThread = NULL;
+
+ /* Close the opened handles */
+
+ if (hServicesKey)
+ NtClose(hServicesKey);
+ hServicesKey = NULL;
+
+ if (hEnumKey)
+ NtClose(hEnumKey);
+ hEnumKey = NULL;
+
+ if (hNoPendingInstalls)
+ NtClose(hNoPendingInstalls);
+ hNoPendingInstalls = NULL;
+
+ if (hDeviceInstallListNotEmpty)
+ NtClose(hDeviceInstallListNotEmpty);
+ hDeviceInstallListNotEmpty = NULL;
}