/* PRIVATE FUNCTIONS **********************************************************/
-NTSTATUS NTAPI
+ULONG NTAPI
DriverEntry(
- IN PDRIVER_OBJECT DriverObject,
- IN PUNICODE_STRING RegistryPath)
+ IN PVOID Context1,
+ IN PVOID Context2)
{
return STATUS_SUCCESS;
}
static WCHAR ControlSet[] = L"CONTROLSET";
static WCHAR Insert1[] = L"Hardware Profiles\\Current\\System\\CurrentControlSet\\";
static WCHAR Insert2[] = L"\\Device0";
- LPWSTR ProfilePath = NULL;
BOOLEAN Valid;
- PWCHAR AfterControlSet;
+ UNICODE_STRING AfterControlSet;
- Valid = (0 == _wcsnicmp(DriverRegistryPath->Buffer, RegistryMachineSystem,
- wcslen(RegistryMachineSystem)));
+ 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 = DriverRegistryPath->Buffer + wcslen(RegistryMachineSystem);
- if (0 == _wcsnicmp(AfterControlSet, CurrentControlSet, wcslen(CurrentControlSet)))
+ 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 += wcslen(CurrentControlSet);
+ AfterControlSet.Buffer += wcslen(CurrentControlSet);
+ AfterControlSet.Length -= sizeof(CurrentControlSet) - sizeof(UNICODE_NULL);
}
- else if (0 == _wcsnicmp(AfterControlSet, ControlSet, wcslen(ControlSet)))
+ /* Check if path contains CONTROLSETnum */
+ else if (AfterControlSet.Length > sizeof(ControlSet) &&
+ 0 == _wcsnicmp(AfterControlSet.Buffer, ControlSet, wcslen(ControlSet)))
{
- AfterControlSet += wcslen(ControlSet);
- while (L'0' <= *AfterControlSet && L'9' <= *AfterControlSet)
+ AfterControlSet.Buffer += wcslen(ControlSet);
+ AfterControlSet.Length -= sizeof(ControlSet) - sizeof(UNICODE_NULL);
+ while (AfterControlSet.Length > 0 &&
+ L'0' <= *AfterControlSet.Buffer &&
+ L'9' <= *AfterControlSet.Buffer)
{
- AfterControlSet++;
+ AfterControlSet.Buffer++;
+ AfterControlSet.Length -= sizeof(WCHAR);
}
- Valid = (L'\\' == *AfterControlSet);
- AfterControlSet++;
+ Valid = (AfterControlSet.Length > 0 && L'\\' == *AfterControlSet.Buffer);
+ AfterControlSet.Buffer++;
+ AfterControlSet.Length -= sizeof(WCHAR);
+ AfterControlSet.MaximumLength = AfterControlSet.Length;
}
else
{
if (Valid)
{
- ProfilePath = ExAllocatePoolWithTag(PagedPool,
- (wcslen(DriverRegistryPath->Buffer) +
- wcslen(Insert1) + wcslen(Insert2) + 1) * sizeof(WCHAR),
- TAG_VIDEO_PORT);
- if (NULL != ProfilePath)
+ DeviceRegistryPath->MaximumLength = DriverRegistryPath->Length + sizeof(Insert1) + sizeof(Insert2);
+ DeviceRegistryPath->Buffer = ExAllocatePoolWithTag(PagedPool,
+ DeviceRegistryPath->MaximumLength,
+ TAG_VIDEO_PORT);
+ if (NULL != DeviceRegistryPath->Buffer)
{
- wcsncpy(ProfilePath, DriverRegistryPath->Buffer, AfterControlSet - DriverRegistryPath->Buffer);
- wcscpy(ProfilePath + (AfterControlSet - DriverRegistryPath->Buffer), Insert1);
- wcscat(ProfilePath, AfterControlSet);
- wcscat(ProfilePath, Insert2);
-
- Valid = NT_SUCCESS(RtlCheckRegistryKey(RTL_REGISTRY_ABSOLUTE, ProfilePath));
+ /* 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, DriverRegistryPath->Buffer));
+
+ if(!Valid)
+ ExFreePoolWithTag(DeviceRegistryPath->Buffer, TAG_VIDEO_PORT);
}
else
{
WARN_(VIDEOPRT, "Unparsable registry path %wZ", DriverRegistryPath);
}
- if (Valid)
- {
- RtlInitUnicodeString(DeviceRegistryPath, ProfilePath);
- }
- else
+ /* If path doesn't point to *ControlSet*, use DriverRegistryPath directly */
+ if (!Valid)
{
- if (ProfilePath)
- ExFreePoolWithTag(ProfilePath, TAG_VIDEO_PORT);
-
- DeviceRegistryPath->Length =
- DeviceRegistryPath->MaximumLength =
- DriverRegistryPath->Length + (9 * sizeof(WCHAR));
- DeviceRegistryPath->Length -= sizeof(WCHAR);
+ DeviceRegistryPath->MaximumLength = DriverRegistryPath->Length + sizeof(Insert2);
DeviceRegistryPath->Buffer = ExAllocatePoolWithTag(
NonPagedPool,
DeviceRegistryPath->MaximumLength,
TAG_VIDEO_PORT);
+
if (!DeviceRegistryPath->Buffer)
return STATUS_NO_MEMORY;
- swprintf(DeviceRegistryPath->Buffer, L"%s\\Device0",
- DriverRegistryPath->Buffer);
+
+ RtlCopyUnicodeString(DeviceRegistryPath, DriverRegistryPath);
+ RtlAppendUnicodeToString(DeviceRegistryPath, Insert2);
}
+
return STATUS_SUCCESS;
}
}
InitializeListHead(&DeviceExtension->AddressMappingListHead);
+ InitializeListHead(&DeviceExtension->DmaAdapterList);
+
KeInitializeDpc(
&DeviceExtension->DpcObject,
IntVideoPortDeferredRoutine,
}
-/* FIXME: we have to detach the device object in IntVideoPortFindAdapter if it fails */
NTSTATUS NTAPI
IntVideoPortFindAdapter(
IN PDRIVER_OBJECT DriverObject,
WCHAR SymlinkBuffer[20];
UNICODE_STRING SymlinkName;
BOOL LegacyDetection = FALSE;
- ULONG DeviceNumber;
+ ULONG DeviceNumber, DisplayNumber;
DeviceExtension = (PVIDEO_PORT_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
DeviceNumber = DeviceExtension->DeviceNumber;
{
WARN_(VIDEOPRT, "HwFindAdapter call failed with error 0x%X\n", Status);
RtlFreeUnicodeString(&DeviceExtension->RegistryPath);
+ if (DeviceExtension->NextDeviceObject)
+ IoDetachDevice(DeviceExtension->NextDeviceObject);
IoDeleteDevice(DeviceObject);
return Status;
{
WARN_(VIDEOPRT, "HwFindAdapter call failed with error 0x%X\n", Status);
RtlFreeUnicodeString(&DeviceExtension->RegistryPath);
+ if (DeviceExtension->NextDeviceObject)
+ IoDetachDevice(DeviceExtension->NextDeviceObject);
IoDeleteDevice(DeviceObject);
return Status;
}
RtlInitUnicodeString(&DeviceName, DeviceBuffer);
/* Create symbolic link "\??\DISPLAYx" */
- swprintf(SymlinkBuffer, L"\\??\\DISPLAY%lu", DeviceNumber + 1);
- RtlInitUnicodeString(&SymlinkName, SymlinkBuffer);
- IoCreateSymbolicLink(&SymlinkName, &DeviceName);
+
+ /* HACK: We need this to find the first available display to
+ * use. We can't use the device number because then we could
+ * end up with \Device\Video0 being non-functional because
+ * HwFindAdapter returned an error. \Device\Video1 would be
+ * the correct primary display but it would be set to DISPLAY2
+ * so it would never be used and ROS would bugcheck on boot.
+ * By doing it this way, we ensure that DISPLAY1 is always
+ * functional. Another idea would be letting the IO manager
+ * give our video devices names then getting those names
+ * somehow and creating symbolic links to \Device\VideoX
+ * and \??\DISPLAYX once we know that HwFindAdapter has succeeded.
+ */
+ DisplayNumber = 0;
+ do
+ {
+ DisplayNumber++;
+ swprintf(SymlinkBuffer, L"\\??\\DISPLAY%lu", DisplayNumber);
+ RtlInitUnicodeString(&SymlinkName, SymlinkBuffer);
+ }
+ while (IoCreateSymbolicLink(&SymlinkName, &DeviceName) != STATUS_SUCCESS);
/* Add entry to DEVICEMAP\VIDEO key in registry. */
- swprintf(DeviceVideoBuffer, L"\\Device\\Video%d", DeviceNumber);
+ swprintf(DeviceVideoBuffer, L"\\Device\\Video%d", DisplayNumber - 1);
RtlWriteRegistryValue(
RTL_REGISTRY_DEVICEMAP,
L"VIDEO",
if (!IntVideoPortSetupInterrupt(DeviceObject, DriverExtension, &ConfigInfo))
{
RtlFreeUnicodeString(&DeviceExtension->RegistryPath);
+ if (DeviceExtension->NextDeviceObject)
+ IoDetachDevice(DeviceExtension->NextDeviceObject);
IoDeleteDevice(DeviceObject);
return STATUS_INSUFFICIENT_RESOURCES;
}
{
if (DeviceExtension->InterruptObject != NULL)
IoDisconnectInterrupt(DeviceExtension->InterruptObject);
+ if (DeviceExtension->NextDeviceObject)
+ IoDetachDevice(DeviceExtension->NextDeviceObject);
RtlFreeUnicodeString(&DeviceExtension->RegistryPath);
IoDeleteDevice(DeviceObject);
WARN_(VIDEOPRT, "STATUS_INSUFFICIENT_RESOURCES\n");
VideoPortRegisterBugcheckCallback(
IN PVOID HwDeviceExtension,
IN ULONG BugcheckCode,
- IN PVOID Callback,
+ IN PVIDEO_BUGCHECK_CALLBACK Callback,
IN ULONG BugcheckDataSize)
{
UNIMPLEMENTED;
return MmAllocateContiguousMemory(NumberOfBytes, HighestAcceptableAddress);
}
+
+/*
+ * @implemented
+ */
+BOOLEAN NTAPI
+VideoPortIsNoVesa(VOID)
+{
+ NTSTATUS Status;
+ HANDLE KeyHandle;
+ UNICODE_STRING Path = RTL_CONSTANT_STRING(L"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Control");
+ UNICODE_STRING ValueName = RTL_CONSTANT_STRING(L"SystemStartOptions");
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ PKEY_VALUE_PARTIAL_INFORMATION KeyInfo;
+ ULONG Length, NewLength;
+
+ /* Initialize object attributes with the path we want */
+ InitializeObjectAttributes(&ObjectAttributes,
+ &Path,
+ OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
+ NULL,
+ NULL);
+
+ /* Open the key */
+ Status = ZwOpenKey(&KeyHandle,
+ KEY_QUERY_VALUE,
+ &ObjectAttributes);
+
+ if (!NT_SUCCESS(Status))
+ {
+ VideoPortDebugPrint(Error, "ZwOpenKey failed (0x%x)\n", Status);
+ return FALSE;
+ }
+
+ /* Find out how large our buffer should be */
+ Status = ZwQueryValueKey(KeyHandle,
+ &ValueName,
+ KeyValuePartialInformation,
+ NULL,
+ 0,
+ &Length);
+ if (Status != STATUS_BUFFER_OVERFLOW && Status != STATUS_BUFFER_TOO_SMALL)
+ {
+ VideoPortDebugPrint(Error, "ZwQueryValueKey failed (0x%x)\n", Status);
+ ZwClose(KeyHandle);
+ return FALSE;
+ }
+
+ /* Allocate it */
+ KeyInfo = ExAllocatePool(PagedPool, Length);
+ if (!KeyInfo)
+ {
+ VideoPortDebugPrint(Error, "Out of memory\n");
+ ZwClose(KeyHandle);
+ return FALSE;
+ }
+
+ /* Now for real this time */
+ Status = ZwQueryValueKey(KeyHandle,
+ &ValueName,
+ KeyValuePartialInformation,
+ KeyInfo,
+ Length,
+ &NewLength);
+
+ ZwClose(KeyHandle);
+
+ if (!NT_SUCCESS(Status))
+ {
+ VideoPortDebugPrint(Error, "ZwQueryValueKey failed (0x%x)\n", Status);
+ ExFreePool(KeyInfo);
+ return FALSE;
+ }
+
+ /* Sanity check */
+ if (KeyInfo->Type != REG_SZ)
+ {
+ VideoPortDebugPrint(Error, "Invalid type for SystemStartOptions\n");
+ ExFreePool(KeyInfo);
+ return FALSE;
+ }
+
+ /* Check if NOVESA or BASEVIDEO is present in the start options */
+ if (wcsstr((PWCHAR)KeyInfo->Data, L"NOVESA") ||
+ wcsstr((PWCHAR)KeyInfo->Data, L"BASEVIDEO"))
+ {
+ VideoPortDebugPrint(Info, "VESA mode disabled\n");
+ ExFreePool(KeyInfo);
+ return TRUE;
+ }
+
+ ExFreePool(KeyInfo);
+
+ VideoPortDebugPrint(Info, "VESA mode enabled\n");
+
+ return FALSE;
+}
+