videoprt.c

来自「一个类似windows」· C语言 代码 · 共 1,277 行 · 第 1/3 页

C
1,277
字号
/*
 * VideoPort driver
 *
 * Copyright (C) 2002, 2003, 2004 ReactOS Team
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 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
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; see the file COPYING.LIB.
 * If not, write to the Free Software Foundation,
 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 *
 * $Id: videoprt.c 21844 2006-05-07 19:34:23Z ion $
 */

#include "videoprt.h"
#include <wdmguid.h>

/* GLOBAL VARIABLES ***********************************************************/

ULONG CsrssInitialized = FALSE;
PKPROCESS Csrss = NULL;
ULONG VideoPortDeviceNumber = 0;

/* PRIVATE FUNCTIONS **********************************************************/

NTSTATUS NTAPI
DriverEntry(
   IN PDRIVER_OBJECT DriverObject,
   IN PUNICODE_STRING RegistryPath)
{
   return STATUS_SUCCESS;
}

PVOID NTAPI
IntVideoPortImageDirectoryEntryToData(
   PVOID BaseAddress,
   ULONG Directory)
{
   PIMAGE_NT_HEADERS NtHeader;
   ULONG Va;

   NtHeader = RtlImageNtHeader(BaseAddress);
   if (NtHeader == NULL)
      return NULL;

   if (Directory >= NtHeader->OptionalHeader.NumberOfRvaAndSizes)
      return NULL;

   Va = NtHeader->OptionalHeader.DataDirectory[Directory].VirtualAddress;
   if (Va == 0)
      return NULL;

   return (PVOID)((ULONG_PTR)BaseAddress + Va);
}

PVOID NTAPI
IntVideoPortGetProcAddress(
   IN PVOID HwDeviceExtension,
   IN PUCHAR FunctionName)
{
   SYSTEM_GDI_DRIVER_INFORMATION GdiDriverInfo;
   PVOID BaseAddress;
   PIMAGE_EXPORT_DIRECTORY ExportDir;
   PUSHORT OrdinalPtr;
   PULONG NamePtr;
   PULONG AddressPtr;
   ULONG i = 0;
   NTSTATUS Status;

   DPRINT("VideoPortGetProcAddress(%s)\n", FunctionName);

   RtlInitUnicodeString(&GdiDriverInfo.DriverName, L"videoprt");
   Status = ZwSetSystemInformation(
      SystemLoadGdiDriverInformation,
      &GdiDriverInfo,
      sizeof(SYSTEM_GDI_DRIVER_INFORMATION));
   if (!NT_SUCCESS(Status))
   {
      DPRINT("Couldn't get our own module handle?\n");
      return NULL;
   }

   BaseAddress = GdiDriverInfo.ImageAddress;

   /* Get the pointer to the export directory */
   ExportDir = (PIMAGE_EXPORT_DIRECTORY)IntVideoPortImageDirectoryEntryToData(
      BaseAddress,
      IMAGE_DIRECTORY_ENTRY_EXPORT);

   /* Search by name */
   AddressPtr = (PULONG)
      ((ULONG_PTR)BaseAddress + (ULONG_PTR)ExportDir->AddressOfFunctions);
   OrdinalPtr = (PUSHORT)
      ((ULONG_PTR)BaseAddress + (ULONG_PTR)ExportDir->AddressOfNameOrdinals);
   NamePtr = (PULONG)
      ((ULONG_PTR)BaseAddress + (ULONG_PTR)ExportDir->AddressOfNames);
   for (i = 0; i < ExportDir->NumberOfNames; i++, NamePtr++, OrdinalPtr++)
   {
      if (!_strnicmp((PCHAR)FunctionName, (PCHAR)((ULONG_PTR)BaseAddress + *NamePtr),
                     strlen((PCHAR)FunctionName)))
      {
         return (PVOID)((ULONG_PTR)BaseAddress +
                        (ULONG_PTR)AddressPtr[*OrdinalPtr]);
      }
   }

   DPRINT("VideoPortGetProcAddress: Can't resolve symbol %s\n", FunctionName);

   return NULL;
}

VOID NTAPI
IntVideoPortDeferredRoutine(
   IN PKDPC Dpc,
   IN PVOID DeferredContext,
   IN PVOID SystemArgument1,
   IN PVOID SystemArgument2)
{
   PVOID HwDeviceExtension =
      &((PVIDEO_PORT_DEVICE_EXTENSION)DeferredContext)->MiniPortDeviceExtension;
   ((PMINIPORT_DPC_ROUTINE)SystemArgument1)(HwDeviceExtension, SystemArgument2);
}

NTSTATUS NTAPI
IntVideoPortCreateAdapterDeviceObject(
   IN PDRIVER_OBJECT DriverObject,
   IN PVIDEO_PORT_DRIVER_EXTENSION DriverExtension,
   IN PDEVICE_OBJECT PhysicalDeviceObject,
   OUT PDEVICE_OBJECT *DeviceObject  OPTIONAL)
{
   PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
   ULONG DeviceNumber;
   ULONG Size;
   NTSTATUS Status;
   WCHAR DeviceBuffer[20];
   UNICODE_STRING DeviceName;
   PDEVICE_OBJECT DeviceObject_;

   if (DeviceObject == NULL)
      DeviceObject = &DeviceObject_;

   /*
    * Find the first free device number that can be used for video device
    * object names and symlinks.
    */

   DeviceNumber = VideoPortDeviceNumber++;
   if (DeviceNumber == 0xFFFFFFFF)
   {
      DPRINT("Can't find free device number\n");
      return STATUS_UNSUCCESSFUL;
   }

   /*
    * Create the device object.
    */

   /* Create a unicode device name. */
   swprintf(DeviceBuffer, L"\\Device\\Video%lu", DeviceNumber);
   RtlInitUnicodeString(&DeviceName, DeviceBuffer);

   /* Create the device object. */
   Status = IoCreateDevice(
      DriverObject,
      sizeof(VIDEO_PORT_DEVICE_EXTENSION) +
      DriverExtension->InitializationData.HwDeviceExtensionSize,
      &DeviceName,
      FILE_DEVICE_VIDEO,
      0,
      TRUE,
      DeviceObject);

   if (!NT_SUCCESS(Status))
   {
      DPRINT("IoCreateDevice call failed with status 0x%08x\n", Status);
      return Status;
   }

   /*
    * Set the buffering strategy here. If you change this, remember
    * to change VidDispatchDeviceControl too.
    */

   (*DeviceObject)->Flags |= DO_BUFFERED_IO;

   /*
    * Initialize device extension.
    */

   DeviceExtension = (PVIDEO_PORT_DEVICE_EXTENSION)((*DeviceObject)->DeviceExtension);
   DeviceExtension->DeviceNumber = DeviceNumber;
   DeviceExtension->DriverObject = DriverObject;
   DeviceExtension->PhysicalDeviceObject = PhysicalDeviceObject;
   DeviceExtension->FunctionalDeviceObject = *DeviceObject;
   DeviceExtension->DriverExtension = DriverExtension;

   DeviceExtension->RegistryPath.Length =
   DeviceExtension->RegistryPath.MaximumLength =
      DriverExtension->RegistryPath.Length + (9 * sizeof(WCHAR));
   DeviceExtension->RegistryPath.Length -= sizeof(WCHAR);
   DeviceExtension->RegistryPath.Buffer = ExAllocatePoolWithTag(
      NonPagedPool,
      DeviceExtension->RegistryPath.MaximumLength,
      TAG_VIDEO_PORT);
   swprintf(DeviceExtension->RegistryPath.Buffer, L"%s\\Device0",
      DriverExtension->RegistryPath.Buffer);

   if (PhysicalDeviceObject != NULL)
   {
      /* Get bus number from the upper level bus driver. */
      Size = sizeof(ULONG);
      Status = IoGetDeviceProperty(
         PhysicalDeviceObject,
         DevicePropertyBusNumber,
         Size,
         &DeviceExtension->SystemIoBusNumber,
         &Size);
      if (!NT_SUCCESS(Status))
      {
         DPRINT("Couldn't get an information from bus driver. We will try to\n"
                "use legacy detection method, but even that doesn't mean that\n"
                "it will work.\n");
         DeviceExtension->PhysicalDeviceObject = NULL;
      }
   }

   DeviceExtension->AdapterInterfaceType =
      DriverExtension->InitializationData.AdapterInterfaceType;

   if (PhysicalDeviceObject != NULL)
   {
      /* Get bus type from the upper level bus driver. */
      Size = sizeof(ULONG);
      IoGetDeviceProperty(
         PhysicalDeviceObject,
         DevicePropertyLegacyBusType,
         Size,
         &DeviceExtension->AdapterInterfaceType,
         &Size);

      /* Get bus device address from the upper level bus driver. */
      Size = sizeof(ULONG);
      IoGetDeviceProperty(
         PhysicalDeviceObject,
         DevicePropertyAddress,
         Size,
         &DeviceExtension->SystemIoSlotNumber,
         &Size);
   }

   InitializeListHead(&DeviceExtension->AddressMappingListHead);
   KeInitializeDpc(
      &DeviceExtension->DpcObject,
      IntVideoPortDeferredRoutine,
      DeviceExtension);

   KeInitializeMutex(&DeviceExtension->DeviceLock, 0);

   /* Attach the device. */
   if (PhysicalDeviceObject != NULL)
      DeviceExtension->NextDeviceObject = IoAttachDeviceToDeviceStack(
         *DeviceObject, PhysicalDeviceObject);

   return STATUS_SUCCESS;
}


/* FIXME: we have to detach the device object in IntVideoPortFindAdapter if it fails */
NTSTATUS NTAPI
IntVideoPortFindAdapter(
   IN PDRIVER_OBJECT DriverObject,
   IN PVIDEO_PORT_DRIVER_EXTENSION DriverExtension,
   IN PDEVICE_OBJECT DeviceObject)
{
   WCHAR DeviceVideoBuffer[20];
   PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
   ULONG Size;
   NTSTATUS Status;
   VIDEO_PORT_CONFIG_INFO ConfigInfo;
   SYSTEM_BASIC_INFORMATION SystemBasicInfo;
   UCHAR Again = FALSE;
   WCHAR DeviceBuffer[20];
   UNICODE_STRING DeviceName;
   WCHAR SymlinkBuffer[20];
   UNICODE_STRING SymlinkName;
   BOOL LegacyDetection = FALSE;
   ULONG DeviceNumber;

   DeviceExtension = (PVIDEO_PORT_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
   DeviceNumber = DeviceExtension->DeviceNumber;

   /*
    * Setup a ConfigInfo structure that we will pass to HwFindAdapter.
    */

   RtlZeroMemory(&ConfigInfo, sizeof(VIDEO_PORT_CONFIG_INFO));
   ConfigInfo.Length = sizeof(VIDEO_PORT_CONFIG_INFO);
   ConfigInfo.AdapterInterfaceType = DeviceExtension->AdapterInterfaceType;
   if (ConfigInfo.AdapterInterfaceType == PCIBus)
      ConfigInfo.InterruptMode = LevelSensitive;
   else
      ConfigInfo.InterruptMode = Latched;
   ConfigInfo.DriverRegistryPath = DriverExtension->RegistryPath.Buffer;
   ConfigInfo.VideoPortGetProcAddress = IntVideoPortGetProcAddress;
   ConfigInfo.SystemIoBusNumber = DeviceExtension->SystemIoBusNumber;
   ConfigInfo.BusInterruptLevel = DeviceExtension->InterruptLevel;
   ConfigInfo.BusInterruptVector = DeviceExtension->InterruptVector;

   Size = sizeof(SystemBasicInfo);
   Status = ZwQuerySystemInformation(
      SystemBasicInformation,
      &SystemBasicInfo,
      Size,
      &Size);

   if (NT_SUCCESS(Status))
   {
      ConfigInfo.SystemMemorySize =
         SystemBasicInfo.NumberOfPhysicalPages *
         SystemBasicInfo.PageSize;
   }

   /*
    * Call miniport HwVidFindAdapter entry point to detect if
    * particular device is present. There are two possible code
    * paths. The first one is for Legacy drivers (NT4) and cases
    * when we don't have information about what bus we're on. The
    * second case is the standard one for Plug & Play drivers.
    */
   if (DeviceExtension->PhysicalDeviceObject == NULL)
   {
      LegacyDetection = TRUE;
   }

   if (LegacyDetection)
   {
      ULONG BusNumber, MaxBuses;

      MaxBuses = DeviceExtension->AdapterInterfaceType == PCIBus ? 8 : 1;

      for (BusNumber = 0; BusNumber < MaxBuses; BusNumber++)
      {
         DeviceExtension->SystemIoBusNumber =
         ConfigInfo.SystemIoBusNumber = BusNumber;

         RtlZeroMemory(&DeviceExtension->MiniPortDeviceExtension,
                       DriverExtension->InitializationData.HwDeviceExtensionSize);

         /* FIXME: Need to figure out what string to pass as param 3. */
         Status = DriverExtension->InitializationData.HwFindAdapter(
            &DeviceExtension->MiniPortDeviceExtension,
            DriverExtension->HwContext,
            NULL,
            &ConfigInfo,
            &Again);

         if (Status == ERROR_DEV_NOT_EXIST)
         {
            continue;
         }
         else if (Status == NO_ERROR)
         {
            break;
         }
         else
         {
            DPRINT("HwFindAdapter call failed with error 0x%X\n", Status);
            RtlFreeUnicodeString(&DeviceExtension->RegistryPath);
            IoDeleteDevice(DeviceObject);

            return Status;
         }
      }
   }
   else
   {
      /* FIXME: Need to figure out what string to pass as param 3. */
      Status = DriverExtension->InitializationData.HwFindAdapter(
         &DeviceExtension->MiniPortDeviceExtension,
         DriverExtension->HwContext,
         NULL,
         &ConfigInfo,
         &Again);
   }

   if (Status != NO_ERROR)
   {
      DPRINT("HwFindAdapter call failed with error 0x%X\n", Status);
      RtlFreeUnicodeString(&DeviceExtension->RegistryPath);
      IoDeleteDevice(DeviceObject);
      return Status;
   }

   /*
    * Now we know the device is present, so let's do all additional tasks
    * such as creating symlinks or setting up interrupts and timer.
    */

   /* Create a unicode device name. */
   swprintf(DeviceBuffer, L"\\Device\\Video%lu", DeviceNumber);
   RtlInitUnicodeString(&DeviceName, DeviceBuffer);

   /* Create symbolic link "\??\DISPLAYx" */
   swprintf(SymlinkBuffer, L"\\??\\DISPLAY%lu", DeviceNumber + 1);
   RtlInitUnicodeString(&SymlinkName, SymlinkBuffer);
   IoCreateSymbolicLink(&SymlinkName, &DeviceName);

   /* Add entry to DEVICEMAP\VIDEO key in registry. */
   swprintf(DeviceVideoBuffer, L"\\Device\\Video%d", DeviceNumber);
   RtlWriteRegistryValue(
      RTL_REGISTRY_DEVICEMAP,
      L"VIDEO",
      DeviceVideoBuffer,
      REG_SZ,
      DeviceExtension->RegistryPath.Buffer,
      DeviceExtension->RegistryPath.MaximumLength);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?