diff --git a/reactos/base/setup/usetup/interface/devinst.c b/reactos/base/setup/usetup/interface/devinst.c new file mode 100644 index 00000000000..aae2b9d715b --- /dev/null +++ b/reactos/base/setup/usetup/interface/devinst.c @@ -0,0 +1,396 @@ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS text-mode setup + * FILE: subsys/system/usetup/interface/devinst.c + * PURPOSE: Device installation + * PROGRAMMER: Hervé Poussineau (hpoussin@reactos.org) + */ + +#include "usetup.h" + +#define NDEBUG +#include + +#define INITGUID +#include +#include + +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; + LPWSTR Driver, ImagePath, FullImagePath; + ULONG dwValue; + ULONG Disposition; + NTSTATUS Status; + BOOLEAN deviceInstalled = FALSE; + + /* Check if we know the hardware */ + if (!SetupFindFirstLineW(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"Keyboard.Load", Driver, &Context)) + return FALSE; + if (!INF_GetDataField(&Context, 1, &ImagePath)) + return FALSE; + + /* Prepare full driver path */ + dwValue = PathPrefix.MaximumLength + wcslen(ImagePath) * sizeof(WCHAR); + FullImagePath = (LPWSTR)RtlAllocateHeap(ProcessHeap, 0, dwValue); + if (!FullImagePath) + { + DPRINT1("RtlAllocateHeap() failed\n"); + return FALSE; + } + RtlCopyMemory(FullImagePath, PathPrefix.Buffer, PathPrefix.MaximumLength); + wcscat(FullImagePath, 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, 0, &Disposition); + if (!NT_SUCCESS(Status)) + { + DPRINT1("NtCreateKey('%wZ') failed with status 0x%08x\n", &StringU, Status); + RtlFreeHeap(ProcessHeap, 0, FullImagePath); + 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)); + + /* 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 registred */ + deviceInstalled = ResetDevice(DeviceId); + } + + /* 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 + { + 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 + { + 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, 0, &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, 0, &ObjectAttributes, 0, NULL, 0, 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; + PnpEvent = (PPLUGPLAY_EVENT_BLOCK)RtlReAllocateHeap(ProcessHeap, 0, PnpEvent, 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, (UUID*)&GUID_DEVICE_ARRIVAL)) + { + DPRINT1("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; +} diff --git a/reactos/base/setup/usetup/interface/usetup.c b/reactos/base/setup/usetup/interface/usetup.c index f4a8b629356..82d9331815e 100644 --- a/reactos/base/setup/usetup/interface/usetup.c +++ b/reactos/base/setup/usetup/interface/usetup.c @@ -84,6 +84,7 @@ LONG UnattendFormatPartition = 0; LONG AutoPartition = 0; WCHAR UnattendInstallationDirectory[MAX_PATH]; BOOLEAN RepairUpdateFlag = FALSE; +HANDLE hPnpThread = INVALID_HANDLE_VALUE; /* LOCALS *******************************************************************/ @@ -699,6 +700,13 @@ SetupStartPage(PINPUT_RECORD Ir) return QUIT_PAGE; } + /* Start PnP thread */ + if (hPnpThread != INVALID_HANDLE_VALUE) + { + NtResumeThread(hPnpThread, NULL); + hPnpThread = INVALID_HANDLE_VALUE; + } + CheckUnattendedSetup(); return INTRO_PAGE; @@ -3630,15 +3638,22 @@ FlushPage(PINPUT_RECORD Ir) } +DWORD WINAPI +PnpEventThread(IN LPVOID lpParameter); + VOID RunUSetup(VOID) { INPUT_RECORD Ir; PAGE_NUMBER Page; LARGE_INTEGER Time; + NTSTATUS Status; NtQuerySystemTime(&Time); + Status = RtlCreateUserThread(NtCurrentProcess(), NULL, TRUE, 0, 0, 0, PnpEventThread, &SetupInf, &hPnpThread, NULL); + if (!NT_SUCCESS(Status)) + hPnpThread = INVALID_HANDLE_VALUE; if (!CONSOLE_Init()) { PrintString("Unable to open the console\n\n"); diff --git a/reactos/base/setup/usetup/usetup.rbuild b/reactos/base/setup/usetup/usetup.rbuild index 03b7c0217ac..24e3dfabafa 100644 --- a/reactos/base/setup/usetup/usetup.rbuild +++ b/reactos/base/setup/usetup/usetup.rbuild @@ -16,6 +16,7 @@ ntdll consup.c + devinst.c usetup.c diff --git a/reactos/boot/bootdata/txtsetup.sif b/reactos/boot/bootdata/txtsetup.sif index 1d4cfe6b006..2a3b3bc57ef 100644 --- a/reactos/boot/bootdata/txtsetup.sif +++ b/reactos/boot/bootdata/txtsetup.sif @@ -29,12 +29,20 @@ i8042prt.sys=,,,,,,x,,,,,,4 kbdclass.sys=,,,,,,x,,,,,,4 l_intl.nls=,,,,,,,,,,,,2 ntfs.sys=,,,,,,,,,,,,4 -ntoskrnl.exe=,,,,,,,,,,,,2 pci.sys=,,,,,,,,,,,,4 scsiport.sys=,,,,,,x,,,,,,4 uniata.sys=,,,,,,,,,,,,4 vfatfs.sys=,,,,,,,,,,,,4 +[HardwareIdsDatabase] +*PNP0C08 = acpi +*PNP0A03 = pci +PCI\CC_0604 = pci + +[BootBusExtenders.Load] +acpi = acpi.sys +pci = pci.sys + [Cabinets] Cabinet=reactos.cab