reactos/base/setup/usetup/devinst.c
Hermès Bélusca-Maïto cf2571de6e
[USETUP] Sprinkle some INF_FreeData() calls to balance the INF_GetData() / INF_GetDataField() calls.
They currently do nothing, since the getter functions don't actually
capture (copy) the strings but merely return pointers to read-only strings.

But the calls are placed here for consistency, because if one day the
getters' implementation is changed so that strings are captured, it would
then be needed to free the allocated buffers.

In addition, fix a buggy call to INF_GetData() -- should be instead
INF_GetDataField() -- in AddSectionToCopyQueue().

svn path=/branches/setup_improvements/; revision=75516
2018-10-27 03:18:00 +02:00

436 lines
13 KiB
C

/*
* 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)
*/
#include <usetup.h>
#define NDEBUG
#include <debug.h>
#define INITGUID
#include <guiddef.h>
#include <libs/umpnpmgr/sysguid.h>
BOOLEAN
ResetDevice(
IN LPCWSTR DeviceId)
{
PLUGPLAY_CONTROL_RESET_DEVICE_DATA ResetDeviceData;
NTSTATUS Status;
RtlInitUnicodeString(&ResetDeviceData.DeviceInstance, DeviceId);
Status = NtPlugPlayControl(PlugPlayControlResetDevice, &ResetDeviceData, sizeof(PLUGPLAY_CONTROL_RESET_DEVICE_DATA));
if (!NT_SUCCESS(Status))
{
DPRINT1("NtPlugPlayControl() failed with status 0x%08x\n", Status);
return FALSE;
}
return TRUE;
}
BOOLEAN
InstallDriver(
IN HINF hInf,
IN HANDLE hServices,
IN HANDLE hDeviceKey,
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 StringU;
OBJECT_ATTRIBUTES ObjectAttributes;
HANDLE hService;
INFCONTEXT Context;
PWSTR Driver, ClassGuid, ImagePath, FullImagePath;
ULONG dwValue;
ULONG Disposition;
NTSTATUS Status;
BOOLEAN deviceInstalled = FALSE;
UNICODE_STRING UpperFiltersU = RTL_CONSTANT_STRING(L"UpperFilters");
PWSTR keyboardClass = L"kbdclass\0";
/* Check if we know the hardware */
if (!SetupFindFirstLineW(hInf, L"HardwareIdsDatabase", HardwareId, &Context))
return FALSE;
if (!INF_GetDataField(&Context, 1, &Driver))
return FALSE;
/* Get associated class GUID (if any) */
if (!INF_GetDataField(&Context, 2, &ClassGuid))
ClassGuid = NULL;
/* 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))
{
INF_FreeData(ClassGuid);
INF_FreeData(Driver);
return FALSE;
}
if (!INF_GetDataField(&Context, 1, &ImagePath))
{
INF_FreeData(ClassGuid);
INF_FreeData(Driver);
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(ImagePath);
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);
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;
}
/* Fill service key */
if (Disposition == REG_CREATED_NEW_KEY)
{
dwValue = 0;
NtSetValueKey(hService,
&ErrorControlU,
0,
REG_DWORD,
&dwValue,
sizeof(dwValue));
dwValue = 0;
NtSetValueKey(hService,
&StartU,
0,
REG_DWORD,
&dwValue,
sizeof(dwValue));
dwValue = SERVICE_KERNEL_DRIVER;
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);
if (ClassGuid &&_wcsicmp(ClassGuid, L"{4D36E96B-E325-11CE-BFC1-08002BE10318}") == 0)
{
DPRINT1("Installing keyboard class driver for '%S'\n", DeviceId);
NtSetValueKey(hDeviceKey,
&UpperFiltersU,
0,
REG_MULTI_SZ,
keyboardClass,
(wcslen(keyboardClass) + 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));
if (NT_SUCCESS(Status))
{
/* Restart the device, so it will use the driver we registered */
deviceInstalled = ResetDevice(DeviceId);
}
INF_FreeData(Driver);
/* HACK: Update driver path */
NtSetValueKey(hService,
&ImagePathU,
0,
REG_SZ,
FullImagePath,
(wcslen(FullImagePath) + 1) * sizeof(WCHAR));
RtlFreeHeap(ProcessHeap, 0, FullImagePath);
NtClose(hService);
return deviceInstalled;
}
VOID
InstallDevice(
IN HINF hInf,
IN HANDLE hEnum,
IN HANDLE hServices,
IN LPCWSTR DeviceId)
{
UNICODE_STRING HardwareIDU = RTL_CONSTANT_STRING(L"HardwareID");
UNICODE_STRING CompatibleIDsU = RTL_CONSTANT_STRING(L"CompatibleIDs");
UNICODE_STRING DeviceIdU;
OBJECT_ATTRIBUTES ObjectAttributes;
LPCWSTR HardwareID;
PKEY_VALUE_PARTIAL_INFORMATION pPartialInformation = NULL;
HANDLE hDeviceKey;
ULONG ulRequired;
BOOLEAN bDriverInstalled = FALSE;
NTSTATUS Status;
RtlInitUnicodeString(&DeviceIdU, DeviceId);
InitializeObjectAttributes(&ObjectAttributes, &DeviceIdU, 0, hEnum, NULL);
Status = NtOpenKey(&hDeviceKey, KEY_QUERY_VALUE | KEY_SET_VALUE, &ObjectAttributes);
if (!NT_SUCCESS(Status))
{
DPRINT("Unable to open subkey '%S'\n", DeviceId);
return;
}
Status = NtQueryValueKey(
hDeviceKey,
&HardwareIDU,
KeyValuePartialInformation,
NULL,
0,
&ulRequired);
if (Status == STATUS_BUFFER_TOO_SMALL)
{
pPartialInformation = (PKEY_VALUE_PARTIAL_INFORMATION)RtlAllocateHeap(ProcessHeap, 0, ulRequired);
if (!pPartialInformation)
{
DPRINT1("RtlAllocateHeap() failed\n");
NtClose(hDeviceKey);
return;
}
Status = NtQueryValueKey(
hDeviceKey,
&HardwareIDU,
KeyValuePartialInformation,
pPartialInformation,
ulRequired,
&ulRequired);
}
if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
{
/* Nothing to do */
}
else if (!NT_SUCCESS(Status))
{
DPRINT1("NtQueryValueKey() failed with status 0x%08x\n", Status);
if (pPartialInformation)
RtlFreeHeap(ProcessHeap, 0, pPartialInformation);
NtClose(hDeviceKey);
return;
}
else if (pPartialInformation)
{
for (HardwareID = (LPCWSTR)pPartialInformation->Data;
(PUCHAR)HardwareID < pPartialInformation->Data + pPartialInformation->DataLength
&& *HardwareID
&& !bDriverInstalled;
HardwareID += wcslen(HardwareID) + 1)
{
bDriverInstalled = InstallDriver(hInf, hServices,hDeviceKey, DeviceId, HardwareID);
}
}
if (!bDriverInstalled)
{
if (pPartialInformation)
{
RtlFreeHeap(ProcessHeap, 0, pPartialInformation);
pPartialInformation = NULL;
}
Status = NtQueryValueKey(
hDeviceKey,
&CompatibleIDsU,
KeyValuePartialInformation,
NULL,
0,
&ulRequired);
if (Status == STATUS_BUFFER_TOO_SMALL)
{
pPartialInformation = (PKEY_VALUE_PARTIAL_INFORMATION)RtlAllocateHeap(ProcessHeap, 0, ulRequired);
if (!pPartialInformation)
{
DPRINT("RtlAllocateHeap() failed\n");
NtClose(hDeviceKey);
return;
}
Status = NtQueryValueKey(
hDeviceKey,
&CompatibleIDsU,
KeyValuePartialInformation,
pPartialInformation,
ulRequired,
&ulRequired);
}
if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
{
/* Nothing to do */
}
else if (!NT_SUCCESS(Status))
{
if (pPartialInformation)
RtlFreeHeap(ProcessHeap, 0, pPartialInformation);
NtClose(hDeviceKey);
DPRINT1("NtQueryValueKey() failed with status 0x%08x\n", Status);
return;
}
else if (pPartialInformation)
{
for (HardwareID = (LPCWSTR)pPartialInformation->Data;
(PUCHAR)HardwareID < pPartialInformation->Data + pPartialInformation->DataLength
&& *HardwareID
&& !bDriverInstalled;
HardwareID += wcslen(HardwareID) + 1)
{
bDriverInstalled = InstallDriver(hInf, hServices,hDeviceKey, DeviceId, HardwareID);
}
}
}
if (!bDriverInstalled)
DPRINT("No driver available for %S\n", DeviceId);
RtlFreeHeap(ProcessHeap, 0, pPartialInformation);
NtClose(hDeviceKey);
}
NTSTATUS
EventThread(IN LPVOID lpParameter)
{
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 = *(HINF *)lpParameter;
InitializeObjectAttributes(&ObjectAttributes, &EnumU, OBJ_CASE_INSENSITIVE, NULL, NULL);
Status = NtOpenKey(&hEnum, KEY_QUERY_VALUE, &ObjectAttributes);
if (!NT_SUCCESS(Status))
{
DPRINT1("NtOpenKey('%wZ') failed with status 0x%08lx\n", &EnumU, Status);
return Status;
}
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;
}
PnpEventSize = 0x1000;
PnpEvent = (PPLUGPLAY_EVENT_BLOCK)RtlAllocateHeap(ProcessHeap, 0, PnpEventSize);
if (PnpEvent == NULL)
{
NtClose(hEnum);
NtClose(hServices);
return STATUS_NO_MEMORY;
}
for (;;)
{
DPRINT("Calling NtGetPlugPlayEvent()\n");
/* Wait for the next pnp event */
Status = NtGetPlugPlayEvent(0, 0, PnpEvent, PnpEventSize);
/* 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)
{
NtClose(hEnum);
NtClose(hServices);
return STATUS_NO_MEMORY;
}
continue;
}
if (!NT_SUCCESS(Status))
{
DPRINT("NtPlugPlayEvent() failed (Status %lx)\n", Status);
break;
}
/* Process the pnp event */
DPRINT("Received PnP Event\n");
if (IsEqualIID(&PnpEvent->EventGuid, (REFGUID)&GUID_DEVICE_ENUMERATED))
{
DPRINT("Device arrival event: %S\n", PnpEvent->TargetDevice.DeviceIds);
InstallDevice(hInf, hEnum, hServices, PnpEvent->TargetDevice.DeviceIds);
}
else
{
DPRINT("Unknown event\n");
}
/* Dequeue the current pnp event and signal the next one */
NtPlugPlayControl(PlugPlayControlUserResponse, NULL, 0);
}
RtlFreeHeap(ProcessHeap, 0, PnpEvent);
NtClose(hEnum);
NtClose(hServices);
return STATUS_SUCCESS;
}
DWORD WINAPI
PnpEventThread(IN LPVOID lpParameter)
{
NTSTATUS Status;
Status = EventThread(lpParameter);
NtTerminateThread(NtCurrentThread(), Status);
return 0;
}