- Update to r53061
[reactos.git] / drivers / video / videoprt / videoprt.c
index 6d106f6..f90801d 100644 (file)
@@ -21,7 +21,6 @@
 
 
 #include "videoprt.h"
-#include <wdmguid.h>
 
 /* GLOBAL VARIABLES ***********************************************************/
 
@@ -31,10 +30,10 @@ ULONG VideoPortDeviceNumber = 0;
 
 /* PRIVATE FUNCTIONS **********************************************************/
 
-NTSTATUS NTAPI
+ULONG NTAPI
 DriverEntry(
-   IN PDRIVER_OBJECT DriverObject,
-   IN PUNICODE_STRING RegistryPath)
+   IN PVOID Context1,
+   IN PVOID Context2)
 {
    return STATUS_SUCCESS;
 }
@@ -83,27 +82,43 @@ IntCreateRegistryPath(
    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 &&
+                *AfterControlSet.Buffer >= L'0' &&
+                *AfterControlSet.Buffer <= L'9')
          {
-            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
       {
@@ -113,18 +128,26 @@ IntCreateRegistryPath(
 
    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 (DeviceRegistryPath->Buffer != NULL)
       {
-         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, DeviceRegistryPath->Buffer));
+
+         if (!Valid)
+            ExFreePoolWithTag(DeviceRegistryPath->Buffer, TAG_VIDEO_PORT);
       }
       else
       {
@@ -136,28 +159,22 @@ IntCreateRegistryPath(
       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;
 }
 
@@ -304,6 +321,8 @@ IntVideoPortCreateAdapterDeviceObject(
    }
 
    InitializeListHead(&DeviceExtension->AddressMappingListHead);
+   InitializeListHead(&DeviceExtension->DmaAdapterList);
+
    KeInitializeDpc(
       &DeviceExtension->DpcObject,
       IntVideoPortDeferredRoutine,
@@ -322,7 +341,6 @@ IntVideoPortCreateAdapterDeviceObject(
 }
 
 
-/* FIXME: we have to detach the device object in IntVideoPortFindAdapter if it fails */
 NTSTATUS NTAPI
 IntVideoPortFindAdapter(
    IN PDRIVER_OBJECT DriverObject,
@@ -331,7 +349,7 @@ IntVideoPortFindAdapter(
 {
    WCHAR DeviceVideoBuffer[20];
    PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
-   ULONG Size;
+   SIZE_T Size;
    NTSTATUS Status;
    VIDEO_PORT_CONFIG_INFO ConfigInfo;
    SYSTEM_BASIC_INFORMATION SystemBasicInfo;
@@ -341,7 +359,7 @@ IntVideoPortFindAdapter(
    WCHAR SymlinkBuffer[20];
    UNICODE_STRING SymlinkName;
    BOOL LegacyDetection = FALSE;
-   ULONG DeviceNumber;
+   ULONG DeviceNumber, DisplayNumber;
 
    DeviceExtension = (PVIDEO_PORT_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
    DeviceNumber = DeviceExtension->DeviceNumber;
@@ -423,6 +441,8 @@ IntVideoPortFindAdapter(
          {
             WARN_(VIDEOPRT, "HwFindAdapter call failed with error 0x%X\n", Status);
             RtlFreeUnicodeString(&DeviceExtension->RegistryPath);
+            if (DeviceExtension->NextDeviceObject)
+                IoDetachDevice(DeviceExtension->NextDeviceObject);
             IoDeleteDevice(DeviceObject);
 
             return Status;
@@ -444,6 +464,8 @@ IntVideoPortFindAdapter(
    {
       WARN_(VIDEOPRT, "HwFindAdapter call failed with error 0x%X\n", Status);
       RtlFreeUnicodeString(&DeviceExtension->RegistryPath);
+      if (DeviceExtension->NextDeviceObject)
+          IoDetachDevice(DeviceExtension->NextDeviceObject);
       IoDeleteDevice(DeviceObject);
       return Status;
    }
@@ -458,12 +480,30 @@ IntVideoPortFindAdapter(
    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",
@@ -489,6 +529,8 @@ IntVideoPortFindAdapter(
    if (!IntVideoPortSetupInterrupt(DeviceObject, DriverExtension, &ConfigInfo))
    {
       RtlFreeUnicodeString(&DeviceExtension->RegistryPath);
+      if (DeviceExtension->NextDeviceObject)
+          IoDetachDevice(DeviceExtension->NextDeviceObject);
       IoDeleteDevice(DeviceObject);
       return STATUS_INSUFFICIENT_RESOURCES;
    }
@@ -501,6 +543,8 @@ IntVideoPortFindAdapter(
    {
       if (DeviceExtension->InterruptObject != NULL)
          IoDisconnectInterrupt(DeviceExtension->InterruptObject);
+      if (DeviceExtension->NextDeviceObject)
+          IoDetachDevice(DeviceExtension->NextDeviceObject);
       RtlFreeUnicodeString(&DeviceExtension->RegistryPath);
       IoDeleteDevice(DeviceObject);
       WARN_(VIDEOPRT, "STATUS_INSUFFICIENT_RESOURCES\n");
@@ -1332,7 +1376,7 @@ VP_STATUS NTAPI
 VideoPortRegisterBugcheckCallback(
    IN PVOID HwDeviceExtension,
    IN ULONG BugcheckCode,
-   IN PVOID Callback,
+   IN PVIDEO_BUGCHECK_CALLBACK Callback,
    IN ULONG BugcheckDataSize)
 {
     UNIMPLEMENTED;
@@ -1417,3 +1461,100 @@ VideoPortAllocateContiguousMemory(
 
     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;
+}
+