reactos/win32ss/drivers/videoprt/registry.c

640 lines
23 KiB
C

/*
* VideoPort driver
*
* Copyright (C) 2002-2004, 2007 ReactOS Team
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#include "videoprt.h"
#include <ndk/obfuncs.h>
#define NDEBUG
#include <debug.h>
NTSTATUS
NTAPI
IntCopyRegistryKey(
_In_ HANDLE SourceKeyHandle,
_In_ HANDLE DestKeyHandle)
{
PVOID InfoBuffer;
PKEY_BASIC_INFORMATION KeyInformation;
PKEY_VALUE_FULL_INFORMATION KeyValueInformation;
OBJECT_ATTRIBUTES ObjectAttributes;
ULONG Index, InformationLength, RequiredLength;
UNICODE_STRING NameString;
NTSTATUS Status;
HANDLE SourceSubKeyHandle, DestSubKeyHandle;
/* Start with no buffer, set initial size */
InfoBuffer = NULL;
InformationLength = 256;
/* Start looping with key index 0 */
Index = 0;
while (TRUE)
{
/* Check if we have no buffer */
if (InfoBuffer == NULL)
{
/* Allocate a new buffer */
InfoBuffer = ExAllocatePoolWithTag(PagedPool,
InformationLength,
TAG_VIDEO_PORT_BUFFER);
if (InfoBuffer == NULL)
{
ERR_(VIDEOPRT, "Could not allocate buffer for key info\n");
return STATUS_INSUFFICIENT_RESOURCES;
}
}
/* Enumerate the next sub-key */
KeyInformation = InfoBuffer;
Status = ZwEnumerateKey(SourceKeyHandle,
Index,
KeyBasicInformation,
KeyInformation,
InformationLength,
&RequiredLength);
if ((Status == STATUS_BUFFER_OVERFLOW) ||
(Status == STATUS_BUFFER_TOO_SMALL))
{
/* Free the buffer and remember the required size */
ExFreePoolWithTag(InfoBuffer, TAG_VIDEO_PORT_BUFFER);
InfoBuffer = NULL;
InformationLength = RequiredLength;
/* Try again */
continue;
}
else if (Status == STATUS_NO_MORE_ENTRIES)
{
/* We are done with the sub-keys */
break;
}
else if (!NT_SUCCESS(Status))
{
ERR_(VIDEOPRT, "ZwEnumerateKey failed, status 0x%lx\n", Status);
goto Cleanup;
}
/* Initialize a unicode string from the key name */
NameString.Buffer = KeyInformation->Name;
NameString.Length = (USHORT)KeyInformation->NameLength;
NameString.MaximumLength = NameString.Length;
/* Initialize object attributes and open the source sub-key */
InitializeObjectAttributes(&ObjectAttributes,
&NameString,
OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
SourceKeyHandle,
NULL);
Status = ZwOpenKey(&SourceSubKeyHandle, KEY_READ, &ObjectAttributes);
if (!NT_SUCCESS(Status))
{
ERR_(VIDEOPRT, "failed to open the source key.\n");
goto Cleanup;
}
/* Initialize object attributes and create the dest sub-key */
InitializeObjectAttributes(&ObjectAttributes,
&NameString,
OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
DestKeyHandle,
NULL);
Status = ZwCreateKey(&DestSubKeyHandle,
KEY_WRITE,
&ObjectAttributes,
0,
NULL,
0,
NULL);
if (!NT_SUCCESS(Status))
{
ERR_(VIDEOPRT, "failed to create the destination key.\n");
ObCloseHandle(SourceSubKeyHandle, KernelMode);
goto Cleanup;
}
/* Recursively copy the sub-key */
Status = IntCopyRegistryKey(SourceSubKeyHandle, DestSubKeyHandle);
if (!NT_SUCCESS(Status))
{
/* Just warn, but continue with the remaining sub-keys */
WARN_(VIDEOPRT, "failed to copy subkey '%wZ'.\n", &NameString);
}
/* Close the sub-key handles */
ObCloseHandle(SourceSubKeyHandle, KernelMode);
ObCloseHandle(DestSubKeyHandle, KernelMode);
/* Next sub-key */
Index++;
}
/* Start looping with value index 0 */
Index = 0;
while (TRUE)
{
/* Check if we have no buffer */
if (InfoBuffer == NULL)
{
/* Allocate a new buffer */
InfoBuffer = ExAllocatePoolWithTag(PagedPool,
InformationLength,
TAG_VIDEO_PORT_BUFFER);
if (InfoBuffer == NULL)
{
ERR_(VIDEOPRT, "Could not allocate buffer for key values\n");
return Status;
}
}
/* Enumerate the next value */
KeyValueInformation = InfoBuffer;
Status = ZwEnumerateValueKey(SourceKeyHandle,
Index,
KeyValueFullInformation,
KeyValueInformation,
InformationLength,
&RequiredLength);
if ((Status == STATUS_BUFFER_OVERFLOW) ||
(Status == STATUS_BUFFER_TOO_SMALL))
{
/* Free the buffer and remember the required size */
ExFreePoolWithTag(InfoBuffer, TAG_VIDEO_PORT_BUFFER);
InfoBuffer = NULL;
InformationLength = RequiredLength;
/* Try again */
continue;
}
else if (Status == STATUS_NO_MORE_ENTRIES)
{
/* We are done with the values */
Status = STATUS_SUCCESS;
break;
}
else if (!NT_SUCCESS(Status))
{
ERR_(VIDEOPRT, "ZwEnumerateValueKey failed, status 0x%lx\n", Status);
goto Cleanup;
}
/* Initialize a unicode string from the value name */
NameString.Buffer = KeyValueInformation->Name;
NameString.Length = (USHORT)KeyValueInformation->NameLength;
NameString.MaximumLength = NameString.Length;
/* Create the key value in the destination key */
Status = ZwSetValueKey(DestKeyHandle,
&NameString,
KeyValueInformation->TitleIndex,
KeyValueInformation->Type,
(PUCHAR)KeyValueInformation + KeyValueInformation->DataOffset,
KeyValueInformation->DataLength);
if (!NT_SUCCESS(Status))
{
/* Just warn, but continue with the remaining sub-keys */
WARN_(VIDEOPRT, "failed to set value '%wZ'.\n", &NameString);
}
/* Next subkey */
Index++;
}
Cleanup:
/* Free the buffer and return the failure code */
if (InfoBuffer != NULL)
ExFreePoolWithTag(InfoBuffer, TAG_VIDEO_PORT_BUFFER);
return Status;
}
NTSTATUS
NTAPI
IntCopyRegistryValue(
HANDLE SourceKeyHandle,
HANDLE DestKeyHandle,
PWSTR ValueName)
{
PKEY_VALUE_PARTIAL_INFORMATION ValueInformation;
UNICODE_STRING ValueNameString;
ULONG Length;
NTSTATUS Status;
RtlInitUnicodeString(&ValueNameString, ValueName);
/* Query the value length */
Status = ZwQueryValueKey(SourceKeyHandle,
&ValueNameString,
KeyValuePartialInformation,
NULL,
0,
&Length);
if ((Status != STATUS_BUFFER_OVERFLOW) &&
(Status != STATUS_BUFFER_TOO_SMALL))
{
/* The key seems not present */
NT_ASSERT(!NT_SUCCESS(Status));
return Status;
}
/* Allocate a buffer */
ValueInformation = ExAllocatePoolWithTag(PagedPool, Length, TAG_VIDEO_PORT_BUFFER);
if (ValueInformation == NULL)
{
return Status;
}
/* Query the value */
Status = ZwQueryValueKey(SourceKeyHandle,
&ValueNameString,
KeyValuePartialInformation,
ValueInformation,
Length,
&Length);
if (!NT_SUCCESS(Status))
{
ExFreePoolWithTag(ValueInformation, TAG_VIDEO_PORT_BUFFER);
return Status;
}
/* Write the registry value */
Status = ZwSetValueKey(DestKeyHandle,
&ValueNameString,
ValueInformation->TitleIndex,
ValueInformation->Type,
ValueInformation->Data,
ValueInformation->DataLength);
ExFreePoolWithTag(ValueInformation, TAG_VIDEO_PORT_BUFFER);
if (!NT_SUCCESS(Status))
{
ERR_(VIDEOPRT, "ZwSetValueKey failed: status 0x%lx\n", Status);
}
return Status;
}
NTSTATUS
NTAPI
IntSetupDeviceSettingsKey(
PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension)
{
static UNICODE_STRING SettingsKeyName = RTL_CONSTANT_STRING(L"Settings");
HANDLE DevInstRegKey, SourceKeyHandle, DestKeyHandle;
OBJECT_ATTRIBUTES ObjectAttributes;
NTSTATUS Status;
/* Open the software key: HKLM\System\CurrentControlSet\Control\Class\<ClassGUID>\<n> */
Status = IoOpenDeviceRegistryKey(DeviceExtension->PhysicalDeviceObject,
PLUGPLAY_REGKEY_DRIVER,
KEY_ALL_ACCESS,
&DevInstRegKey);
if (Status != STATUS_SUCCESS)
{
ERR_(VIDEOPRT, "Failed to open device software key. Status 0x%lx\n", Status);
return Status;
}
/* Open the 'Settings' sub-key */
InitializeObjectAttributes(&ObjectAttributes,
&SettingsKeyName,
OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
DevInstRegKey,
NULL);
Status = ZwOpenKey(&DestKeyHandle, KEY_WRITE, &ObjectAttributes);
/* Close the device software key */
ObCloseHandle(DevInstRegKey, KernelMode);
if (Status != STATUS_SUCCESS)
{
ERR_(VIDEOPRT, "Failed to open settings key. Status 0x%lx\n", Status);
return Status;
}
/* Open the device profile key */
InitializeObjectAttributes(&ObjectAttributes,
&DeviceExtension->RegistryPath,
OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
NULL,
NULL);
Status = ZwOpenKey(&SourceKeyHandle, KEY_WRITE, &ObjectAttributes);
if (Status != STATUS_SUCCESS)
{
ERR_(VIDEOPRT, "ZwOpenKey failed for settings key: status 0x%lx\n", Status);
ObCloseHandle(DestKeyHandle, KernelMode);
return Status;
}
IntCopyRegistryValue(SourceKeyHandle, DestKeyHandle, L"InstalledDisplayDrivers");
IntCopyRegistryValue(SourceKeyHandle, DestKeyHandle, L"Attach.ToDesktop");
ObCloseHandle(SourceKeyHandle, KernelMode);
ObCloseHandle(DestKeyHandle, KernelMode);
return STATUS_SUCCESS;
}
NTSTATUS
NTAPI
IntCreateNewRegistryPath(
PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension)
{
static UNICODE_STRING VideoIdValueName = RTL_CONSTANT_STRING(L"VideoId");
static UNICODE_STRING ControlVideoPathName =
RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Video\\");
HANDLE DevInstRegKey, SettingsKey, NewKey;
UCHAR VideoIdBuffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + GUID_STRING_LENGTH];
UNICODE_STRING VideoIdString;
UUID VideoId;
PKEY_VALUE_PARTIAL_INFORMATION ValueInformation ;
NTSTATUS Status;
ULONG ResultLength;
USHORT KeyMaxLength;
OBJECT_ATTRIBUTES ObjectAttributes;
/* Open the hardware key: HKLM\System\CurrentControlSet\Enum\... */
Status = IoOpenDeviceRegistryKey(DeviceExtension->PhysicalDeviceObject,
PLUGPLAY_REGKEY_DEVICE,
KEY_ALL_ACCESS,
&DevInstRegKey);
if (Status != STATUS_SUCCESS)
{
ERR_(VIDEOPRT, "IoOpenDeviceRegistryKey failed: status 0x%lx\n", Status);
return Status;
}
/* Query the VideoId value */
ValueInformation = (PKEY_VALUE_PARTIAL_INFORMATION)VideoIdBuffer;
Status = ZwQueryValueKey(DevInstRegKey,
&VideoIdValueName,
KeyValuePartialInformation,
ValueInformation,
sizeof(VideoIdBuffer),
&ResultLength);
if (!NT_SUCCESS(Status))
{
/* Create a new video Id */
Status = ExUuidCreate(&VideoId);
if (!NT_SUCCESS(Status))
{
ERR_(VIDEOPRT, "ExUuidCreate failed: status 0x%lx\n", Status);
ObCloseHandle(DevInstRegKey, KernelMode);
return Status;
}
/* Convert the GUID into a string */
Status = RtlStringFromGUID(&VideoId, &VideoIdString);
if (!NT_SUCCESS(Status))
{
ERR_(VIDEOPRT, "RtlStringFromGUID failed: status 0x%lx\n", Status);
ObCloseHandle(DevInstRegKey, KernelMode);
return Status;
}
/* Copy the GUID String to our buffer */
ValueInformation->DataLength = min(VideoIdString.Length, GUID_STRING_LENGTH);
RtlCopyMemory(ValueInformation->Data,
VideoIdString.Buffer,
ValueInformation->DataLength);
/* Free the GUID string */
RtlFreeUnicodeString(&VideoIdString);
/* Write the VideoId registry value */
Status = ZwSetValueKey(DevInstRegKey,
&VideoIdValueName,
0,
REG_SZ,
ValueInformation->Data,
ValueInformation->DataLength);
if (!NT_SUCCESS(Status))
{
ERR_(VIDEOPRT, "ZwSetValueKey failed: status 0x%lx\n", Status);
ObCloseHandle(DevInstRegKey, KernelMode);
return Status;
}
}
/* Initialize the VideoId string from the registry data */
VideoIdString.Buffer = (PWCHAR)ValueInformation->Data;
VideoIdString.Length = (USHORT)ValueInformation->DataLength;
VideoIdString.MaximumLength = VideoIdString.Length;
/* Close the hardware key */
ObCloseHandle(DevInstRegKey, KernelMode);
/* Calculate the size needed for the new registry path name */
KeyMaxLength = ControlVideoPathName.Length +
VideoIdString.Length +
sizeof(L"\\0000");
/* Allocate the path name buffer */
DeviceExtension->NewRegistryPath.Length = 0;
DeviceExtension->NewRegistryPath.MaximumLength = KeyMaxLength;
DeviceExtension->NewRegistryPath.Buffer = ExAllocatePoolWithTag(PagedPool,
KeyMaxLength,
TAG_VIDEO_PORT);
if (DeviceExtension->NewRegistryPath.Buffer == NULL)
{
ERR_(VIDEOPRT, "Failed to allocate key name buffer.\n");
return STATUS_INSUFFICIENT_RESOURCES;
}
/* Copy the root key name and append the VideoId string */
RtlCopyUnicodeString(&DeviceExtension->NewRegistryPath,
&ControlVideoPathName);
RtlAppendUnicodeStringToString(&DeviceExtension->NewRegistryPath,
&VideoIdString);
/* Check if we have the key already */
Status = RtlCheckRegistryKey(RTL_REGISTRY_ABSOLUTE,
DeviceExtension->NewRegistryPath.Buffer);
if (Status != STATUS_SUCCESS)
{
/* Try to create the new key */
Status = RtlCreateRegistryKey(RTL_REGISTRY_ABSOLUTE,
DeviceExtension->NewRegistryPath.Buffer);
}
/* Append a the instance path */ /// \todo HACK
RtlAppendUnicodeToString(&DeviceExtension->NewRegistryPath, L"\\");
RtlAppendUnicodeToString(&DeviceExtension->NewRegistryPath, L"0000");
/* Check this key again */
Status = RtlCheckRegistryKey(RTL_REGISTRY_ABSOLUTE,
DeviceExtension->NewRegistryPath.Buffer);
if (Status != STATUS_SUCCESS)
{
/* Try to create the new key */
Status = RtlCreateRegistryKey(RTL_REGISTRY_ABSOLUTE,
DeviceExtension->NewRegistryPath.Buffer);
if (!NT_SUCCESS(Status))
{
ERR_(VIDEOPRT, "Failed create key '%wZ'\n", &DeviceExtension->NewRegistryPath);
return Status;
}
/* Open the new key */
InitializeObjectAttributes(&ObjectAttributes,
&DeviceExtension->NewRegistryPath,
OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
NULL,
NULL);
Status = ZwOpenKey(&NewKey, KEY_READ, &ObjectAttributes);
if (!NT_SUCCESS(Status))
{
ERR_(VIDEOPRT, "Failed to open settings key. Status 0x%lx\n", Status);
return Status;
}
/* Open the device profile key */
InitializeObjectAttributes(&ObjectAttributes,
&DeviceExtension->RegistryPath,
OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
NULL,
NULL);
Status = ZwOpenKey(&SettingsKey, KEY_READ, &ObjectAttributes);
if (!NT_SUCCESS(Status))
{
ERR_(VIDEOPRT, "Failed to open settings key. Status 0x%lx\n", Status);
ObCloseHandle(NewKey, KernelMode);
return Status;
}
/* Copy the registry data from the legacy key */
Status = IntCopyRegistryKey(SettingsKey, NewKey);
}
return Status;
}
NTSTATUS
NTAPI
IntCreateRegistryPath(
IN PCUNICODE_STRING DriverRegistryPath,
OUT PUNICODE_STRING DeviceRegistryPath)
{
static WCHAR RegistryMachineSystem[] = L"\\REGISTRY\\MACHINE\\SYSTEM\\";
static WCHAR CurrentControlSet[] = L"CURRENTCONTROLSET\\";
static WCHAR ControlSet[] = L"CONTROLSET";
static WCHAR Insert1[] = L"Hardware Profiles\\Current\\System\\CurrentControlSet\\";
static WCHAR Insert2[] = L"\\Device0";
BOOLEAN Valid;
UNICODE_STRING AfterControlSet;
AfterControlSet = *DriverRegistryPath;
/* Check if path begins with \\REGISTRY\\MACHINE\\SYSTEM\\ */
Valid = (DriverRegistryPath->Length > sizeof(RegistryMachineSystem) &&
0 == _wcsnicmp(DriverRegistryPath->Buffer, RegistryMachineSystem,
wcslen(RegistryMachineSystem)));
if (Valid)
{
AfterControlSet.Buffer += wcslen(RegistryMachineSystem);
AfterControlSet.Length -= sizeof(RegistryMachineSystem) - sizeof(UNICODE_NULL);
/* Check if path contains CURRENTCONTROLSET */
if (AfterControlSet.Length > sizeof(CurrentControlSet) &&
0 == _wcsnicmp(AfterControlSet.Buffer, CurrentControlSet, wcslen(CurrentControlSet)))
{
AfterControlSet.Buffer += wcslen(CurrentControlSet);
AfterControlSet.Length -= sizeof(CurrentControlSet) - sizeof(UNICODE_NULL);
}
/* Check if path contains CONTROLSETnum */
else if (AfterControlSet.Length > sizeof(ControlSet) &&
0 == _wcsnicmp(AfterControlSet.Buffer, ControlSet, wcslen(ControlSet)))
{
AfterControlSet.Buffer += wcslen(ControlSet);
AfterControlSet.Length -= sizeof(ControlSet) - sizeof(UNICODE_NULL);
while (AfterControlSet.Length > 0 &&
*AfterControlSet.Buffer >= L'0' &&
*AfterControlSet.Buffer <= L'9')
{
AfterControlSet.Buffer++;
AfterControlSet.Length -= sizeof(WCHAR);
}
Valid = (AfterControlSet.Length > 0 && L'\\' == *AfterControlSet.Buffer);
AfterControlSet.Buffer++;
AfterControlSet.Length -= sizeof(WCHAR);
AfterControlSet.MaximumLength = AfterControlSet.Length;
}
else
{
Valid = FALSE;
}
}
if (Valid)
{
DeviceRegistryPath->MaximumLength = DriverRegistryPath->Length + sizeof(Insert1) + sizeof(Insert2);
DeviceRegistryPath->Buffer = ExAllocatePoolWithTag(PagedPool,
DeviceRegistryPath->MaximumLength,
TAG_VIDEO_PORT);
if (DeviceRegistryPath->Buffer != NULL)
{
/* Build device path */
wcsncpy(DeviceRegistryPath->Buffer,
DriverRegistryPath->Buffer,
AfterControlSet.Buffer - DriverRegistryPath->Buffer);
DeviceRegistryPath->Length = (AfterControlSet.Buffer - DriverRegistryPath->Buffer) * sizeof(WCHAR);
RtlAppendUnicodeToString(DeviceRegistryPath, Insert1);
RtlAppendUnicodeStringToString(DeviceRegistryPath, &AfterControlSet);
RtlAppendUnicodeToString(DeviceRegistryPath, Insert2);
/* Check if registry key exists */
Valid = NT_SUCCESS(RtlCheckRegistryKey(RTL_REGISTRY_ABSOLUTE, DeviceRegistryPath->Buffer));
if (!Valid)
ExFreePoolWithTag(DeviceRegistryPath->Buffer, TAG_VIDEO_PORT);
}
else
{
Valid = FALSE;
}
}
else
{
WARN_(VIDEOPRT, "Unparsable registry path %wZ\n", DriverRegistryPath);
}
/* If path doesn't point to *ControlSet*, use DriverRegistryPath directly */
if (!Valid)
{
DeviceRegistryPath->MaximumLength = DriverRegistryPath->Length + sizeof(Insert2);
DeviceRegistryPath->Buffer = ExAllocatePoolWithTag(NonPagedPool,
DeviceRegistryPath->MaximumLength,
TAG_VIDEO_PORT);
if (!DeviceRegistryPath->Buffer)
return STATUS_NO_MEMORY;
RtlCopyUnicodeString(DeviceRegistryPath, DriverRegistryPath);
RtlAppendUnicodeToString(DeviceRegistryPath, Insert2);
}
DPRINT("Formatted registry key '%wZ' -> '%wZ'\n",
DriverRegistryPath, DeviceRegistryPath);
return STATUS_SUCCESS;
}