reactos/reactos/drivers/video/videoprt/videoprt.c

1264 lines
36 KiB
C
Raw Normal View History

/*
* 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,v 1.5 2004/03/04 18:51:58 navaraf Exp $
*/
#include "videoprt.h"
BOOLEAN CsrssInitialized = FALSE;
PEPROCESS Csrss = NULL;
PVIDEO_PORT_DEVICE_EXTENSION ResetDisplayParametersDeviceExtension = NULL;
// ------------------------------------------------------- Public Interface
// DriverEntry
//
// DESCRIPTION:
// This function initializes the driver.
//
// RUN LEVEL:
// PASSIVE_LEVEL
//
// ARGUMENTS:
// IN PDRIVER_OBJECT DriverObject System allocated Driver Object
// for this driver
// IN PUNICODE_STRING RegistryPath Name of registry driver service
// key
//
// RETURNS:
// NTSTATUS
NTSTATUS STDCALL
DriverEntry(IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath)
{
DPRINT("DriverEntry()\n");
return(STATUS_SUCCESS);
}
/*
* @implemented
*/
VOID
VideoPortDebugPrint(IN VIDEO_DEBUG_LEVEL DebugPrintLevel,
IN PCHAR DebugMessage, ...)
{
char Buffer[256];
va_list ap;
/*
if (DebugPrintLevel > InternalDebugLevel)
return;
*/
va_start (ap, DebugMessage);
vsprintf (Buffer, DebugMessage, ap);
va_end (ap);
DbgPrint (Buffer);
}
/*
* @implemented
*/
VOID
STDCALL
VideoPortFreeDeviceBase(IN PVOID HwDeviceExtension,
IN PVOID MappedAddress)
{
PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
DPRINT("VideoPortFreeDeviceBase\n");
DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
VIDEO_PORT_DEVICE_EXTENSION,
MiniPortDeviceExtension);
InternalUnmapMemory(DeviceExtension, MappedAddress);
}
/*
* @implemented
*/
ULONG
STDCALL
VideoPortGetBusData(IN PVOID HwDeviceExtension,
IN BUS_DATA_TYPE BusDataType,
IN ULONG SlotNumber,
OUT PVOID Buffer,
IN ULONG Offset,
IN ULONG Length)
{
PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
DPRINT("VideoPortGetBusData\n");
DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
VIDEO_PORT_DEVICE_EXTENSION,
MiniPortDeviceExtension);
return HalGetBusDataByOffset(BusDataType,
DeviceExtension->SystemIoBusNumber,
SlotNumber,
Buffer,
Offset,
Length);
}
/*
* @implemented
*/
UCHAR
STDCALL
VideoPortGetCurrentIrql(VOID)
{
DPRINT("VideoPortGetCurrentIrql\n");
return KeGetCurrentIrql();
}
/*
* @implemented
*/
PVOID
STDCALL
VideoPortGetDeviceBase(IN PVOID HwDeviceExtension,
IN PHYSICAL_ADDRESS IoAddress,
IN ULONG NumberOfUchars,
IN UCHAR InIoSpace)
{
PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
DPRINT("VideoPortGetDeviceBase\n");
DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
VIDEO_PORT_DEVICE_EXTENSION,
MiniPortDeviceExtension);
return InternalMapMemory(DeviceExtension, IoAddress, NumberOfUchars, InIoSpace);
}
/*
* @unimplemented
*/
VP_STATUS
STDCALL
VideoPortGetDeviceData(IN PVOID HwDeviceExtension,
IN VIDEO_DEVICE_DATA_TYPE DeviceDataType,
IN PMINIPORT_QUERY_DEVICE_ROUTINE CallbackRoutine,
IN PVOID Context)
{
DPRINT("VideoPortGetDeviceData\n");
UNIMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
}
/*
* @implemented
*/
VP_STATUS
STDCALL
VideoPortGetAccessRanges(IN PVOID HwDeviceExtension,
IN ULONG NumRequestedResources,
IN PIO_RESOURCE_DESCRIPTOR RequestedResources OPTIONAL,
IN ULONG NumAccessRanges,
IN PVIDEO_ACCESS_RANGE AccessRanges,
IN PVOID VendorId,
IN PVOID DeviceId,
IN PULONG Slot)
{
PCI_SLOT_NUMBER PciSlotNumber;
BOOLEAN FoundDevice;
ULONG FunctionNumber;
PCI_COMMON_CONFIG Config;
PCM_RESOURCE_LIST AllocatedResources;
NTSTATUS Status;
UINT AssignedCount;
CM_FULL_RESOURCE_DESCRIPTOR *FullList;
CM_PARTIAL_RESOURCE_DESCRIPTOR *Descriptor;
PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
DPRINT("VideoPortGetAccessRanges\n");
DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
VIDEO_PORT_DEVICE_EXTENSION,
MiniPortDeviceExtension);
if (0 == NumRequestedResources && PCIBus == DeviceExtension->AdapterInterfaceType)
{
DPRINT("Looking for VendorId 0x%04x DeviceId 0x%04x\n", (int)*((USHORT *) VendorId),
(int)*((USHORT *) DeviceId));
FoundDevice = FALSE;
PciSlotNumber.u.AsULONG = *Slot;
for (FunctionNumber = 0; ! FoundDevice && FunctionNumber < 8; FunctionNumber++)
{
PciSlotNumber.u.bits.FunctionNumber = FunctionNumber;
if (sizeof(PCI_COMMON_CONFIG) ==
HalGetBusDataByOffset(PCIConfiguration, DeviceExtension->SystemIoBusNumber,
PciSlotNumber.u.AsULONG,&Config, 0,
sizeof(PCI_COMMON_CONFIG)))
{
DPRINT("Slot 0x%02x (Device %d Function %d) VendorId 0x%04x DeviceId 0x%04x\n",
PciSlotNumber.u.AsULONG, PciSlotNumber.u.bits.DeviceNumber,
PciSlotNumber.u.bits.FunctionNumber, Config.VendorID, Config.DeviceID);
FoundDevice = (Config.VendorID == *((USHORT *) VendorId) &&
Config.DeviceID == *((USHORT *) DeviceId));
}
}
if (! FoundDevice)
{
return STATUS_UNSUCCESSFUL;
}
Status = HalAssignSlotResources(NULL, NULL, NULL, NULL,
DeviceExtension->AdapterInterfaceType,
DeviceExtension->SystemIoBusNumber,
PciSlotNumber.u.AsULONG, &AllocatedResources);
if (! NT_SUCCESS(Status))
{
return Status;
}
AssignedCount = 0;
for (FullList = AllocatedResources->List;
FullList < AllocatedResources->List + AllocatedResources->Count;
FullList++)
{
assert(FullList->InterfaceType == PCIBus &&
FullList->BusNumber == DeviceExtension->SystemIoBusNumber &&
1 == FullList->PartialResourceList.Version &&
1 == FullList->PartialResourceList.Revision);
for (Descriptor = FullList->PartialResourceList.PartialDescriptors;
Descriptor < FullList->PartialResourceList.PartialDescriptors + FullList->PartialResourceList.Count;
Descriptor++)
{
if ((CmResourceTypeMemory == Descriptor->Type
|| CmResourceTypePort == Descriptor->Type)
&& NumAccessRanges <= AssignedCount)
{
DPRINT1("Too many access ranges found\n");
ExFreePool(AllocatedResources);
return STATUS_UNSUCCESSFUL;
}
if (CmResourceTypeMemory == Descriptor->Type)
{
if (NumAccessRanges <= AssignedCount)
{
DPRINT1("Too many access ranges found\n");
ExFreePool(AllocatedResources);
return STATUS_UNSUCCESSFUL;
}
DPRINT("Memory range starting at 0x%08x length 0x%08x\n",
Descriptor->u.Memory.Start.u.LowPart, Descriptor->u.Memory.Length);
AccessRanges[AssignedCount].RangeStart = Descriptor->u.Memory.Start;
AccessRanges[AssignedCount].RangeLength = Descriptor->u.Memory.Length;
AccessRanges[AssignedCount].RangeInIoSpace = 0;
AccessRanges[AssignedCount].RangeVisible = 0; /* FIXME: Just guessing */
AccessRanges[AssignedCount].RangeShareable =
(CmResourceShareShared == Descriptor->ShareDisposition);
AssignedCount++;
}
else if (CmResourceTypePort == Descriptor->Type)
{
DPRINT("Port range starting at 0x%04x length %d\n",
Descriptor->u.Memory.Start.u.LowPart, Descriptor->u.Memory.Length);
AccessRanges[AssignedCount].RangeStart = Descriptor->u.Port.Start;
AccessRanges[AssignedCount].RangeLength = Descriptor->u.Port.Length;
AccessRanges[AssignedCount].RangeInIoSpace = 1;
AccessRanges[AssignedCount].RangeVisible = 0; /* FIXME: Just guessing */
AccessRanges[AssignedCount].RangeShareable = 0;
AssignedCount++;
}
else if (CmResourceTypeInterrupt == Descriptor->Type)
{
DeviceExtension->InterruptLevel = Descriptor->u.Interrupt.Level;
DeviceExtension->InterruptVector = Descriptor->u.Interrupt.Vector;
}
}
}
ExFreePool(AllocatedResources);
}
else
{
UNIMPLEMENTED
}
return STATUS_SUCCESS;
}
typedef struct QueryRegistryCallbackContext
{
PVOID HwDeviceExtension;
PVOID HwContext;
PMINIPORT_GET_REGISTRY_ROUTINE HwGetRegistryRoutine;
} QUERY_REGISTRY_CALLBACK_CONTEXT, *PQUERY_REGISTRY_CALLBACK_CONTEXT;
static NTSTATUS STDCALL
QueryRegistryCallback(IN PWSTR ValueName,
IN ULONG ValueType,
IN PVOID ValueData,
IN ULONG ValueLength,
IN PVOID Context,
IN PVOID EntryContext)
{
PQUERY_REGISTRY_CALLBACK_CONTEXT CallbackContext = (PQUERY_REGISTRY_CALLBACK_CONTEXT) Context;
DPRINT("Found registry value for name %S: type %d, length %d\n",
ValueName, ValueType, ValueLength);
return (*(CallbackContext->HwGetRegistryRoutine))(CallbackContext->HwDeviceExtension,
CallbackContext->HwContext,
ValueName,
ValueData,
ValueLength);
}
/*
* @unimplemented
*/
VP_STATUS
STDCALL
VideoPortGetRegistryParameters(IN PVOID HwDeviceExtension,
IN PWSTR ParameterName,
IN UCHAR IsParameterFileName,
IN PMINIPORT_GET_REGISTRY_ROUTINE GetRegistryRoutine,
IN PVOID HwContext)
{
RTL_QUERY_REGISTRY_TABLE QueryTable[2];
QUERY_REGISTRY_CALLBACK_CONTEXT Context;
PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
DPRINT("VideoPortGetRegistryParameters ParameterName %S\n", ParameterName);
DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
VIDEO_PORT_DEVICE_EXTENSION,
MiniPortDeviceExtension);
if (IsParameterFileName)
{
UNIMPLEMENTED;
}
DPRINT("ParameterName %S\n", ParameterName);
Context.HwDeviceExtension = HwDeviceExtension;
Context.HwContext = HwContext;
Context.HwGetRegistryRoutine = GetRegistryRoutine;
QueryTable[0].QueryRoutine = QueryRegistryCallback;
QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED;
QueryTable[0].Name = ParameterName;
QueryTable[0].EntryContext = NULL;
QueryTable[0].DefaultType = REG_NONE;
QueryTable[0].DefaultData = NULL;
QueryTable[0].DefaultLength = 0;
QueryTable[1].QueryRoutine = NULL;
QueryTable[1].Name = NULL;
return NT_SUCCESS(RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
DeviceExtension->RegistryPath.Buffer,
QueryTable, &Context, NULL))
? ERROR_SUCCESS : ERROR_INVALID_PARAMETER;
}
/*
* @implemented
*/
VP_STATUS
STDCALL
VideoPortGetVgaStatus(IN PVOID HwDeviceExtension,
OUT PULONG VgaStatus)
{
PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
DPRINT("VideoPortGetVgaStatus = %S \n", VgaStatus);
DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
VIDEO_PORT_DEVICE_EXTENSION,
MiniPortDeviceExtension);
if(KeGetCurrentIrql() == PASSIVE_LEVEL)
{
if ( PCIBus == DeviceExtension->AdapterInterfaceType)
{
/*
VgaStatus 0 == VGA not enabled, 1 == VGA enabled.
*/
/* Assumed for now */
VgaStatus = (PULONG) 1;
return STATUS_SUCCESS;
}
}
return ERROR_INVALID_FUNCTION;
}
static BOOLEAN
VPInterruptRoutine(IN struct _KINTERRUPT *Interrupt,
IN PVOID ServiceContext)
{
PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
DeviceExtension = ServiceContext;
assert(NULL != DeviceExtension->HwInterrupt);
return DeviceExtension->HwInterrupt(&DeviceExtension->MiniPortDeviceExtension);
}
static VOID STDCALL
VPTimerRoutine(IN PDEVICE_OBJECT DeviceObject,
IN PVOID Context)
{
PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
DeviceExtension = Context;
assert(DeviceExtension == DeviceObject->DeviceExtension
&& NULL != DeviceExtension->HwTimer);
DeviceExtension->HwTimer(&DeviceExtension->MiniPortDeviceExtension);
}
/*
* @implemented
*/
ULONG STDCALL
VideoPortInitialize(IN PVOID Context1,
IN PVOID Context2,
IN PVIDEO_HW_INITIALIZATION_DATA HwInitializationData,
IN PVOID HwContext)
{
PUNICODE_STRING RegistryPath;
UCHAR Again;
WCHAR DeviceBuffer[20];
WCHAR SymlinkBuffer[20];
WCHAR DeviceVideoBuffer[20];
NTSTATUS Status;
PDRIVER_OBJECT MPDriverObject = (PDRIVER_OBJECT) Context1;
PDEVICE_OBJECT MPDeviceObject;
VIDEO_PORT_CONFIG_INFO ConfigInfo;
PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
ULONG DeviceNumber = 0;
UNICODE_STRING DeviceName;
UNICODE_STRING SymlinkName;
ULONG MaxBus;
ULONG MaxLen;
KIRQL IRQL;
KAFFINITY Affinity;
ULONG InterruptVector;
DPRINT("VideoPortInitialize\n");
RegistryPath = (PUNICODE_STRING) Context2;
/* Build Dispatch table from passed data */
MPDriverObject->DriverStartIo = (PDRIVER_STARTIO) HwInitializationData->HwStartIO;
/* Create a unicode device name */
Again = FALSE;
do
{
swprintf(DeviceBuffer, L"\\Device\\Video%lu", DeviceNumber);
RtlInitUnicodeString(&DeviceName, DeviceBuffer);
/* Create the device */
Status = IoCreateDevice(MPDriverObject,
HwInitializationData->HwDeviceExtensionSize +
sizeof(VIDEO_PORT_DEVICE_EXTENSION),
&DeviceName,
FILE_DEVICE_VIDEO,
0,
TRUE,
&MPDeviceObject);
if (!NT_SUCCESS(Status))
{
DPRINT("IoCreateDevice call failed with status 0x%08x\n", Status);
return Status;
}
MPDriverObject->DeviceObject = MPDeviceObject;
/* Initialize the miniport drivers dispatch table */
MPDriverObject->MajorFunction[IRP_MJ_CREATE] = VidDispatchOpen;
MPDriverObject->MajorFunction[IRP_MJ_CLOSE] = VidDispatchClose;
MPDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = VidDispatchDeviceControl;
/* Initialize our device extension */
DeviceExtension =
(PVIDEO_PORT_DEVICE_EXTENSION) MPDeviceObject->DeviceExtension;
DeviceExtension->DeviceObject = MPDeviceObject;
DeviceExtension->HwInitialize = HwInitializationData->HwInitialize;
DeviceExtension->HwResetHw = HwInitializationData->HwResetHw;
DeviceExtension->AdapterInterfaceType = HwInitializationData->AdapterInterfaceType;
DeviceExtension->SystemIoBusNumber = 0;
MaxLen = (wcslen(RegistryPath->Buffer) + 10) * sizeof(WCHAR);
DeviceExtension->RegistryPath.MaximumLength = MaxLen;
DeviceExtension->RegistryPath.Buffer = ExAllocatePoolWithTag(PagedPool,
MaxLen,
TAG_VIDEO_PORT);
swprintf(DeviceExtension->RegistryPath.Buffer, L"%s\\Device%d",
RegistryPath->Buffer, DeviceNumber);
DeviceExtension->RegistryPath.Length = wcslen(DeviceExtension->RegistryPath.Buffer) *
sizeof(WCHAR);
MaxBus = (DeviceExtension->AdapterInterfaceType == PCIBus) ? 8 : 1;
DPRINT("MaxBus: %lu\n", MaxBus);
InitializeListHead(&DeviceExtension->AddressMappingListHead);
/* Set the buffering strategy here... */
/* If you change this, remember to change VidDispatchDeviceControl too */
MPDeviceObject->Flags |= DO_BUFFERED_IO;
do
{
RtlZeroMemory(&DeviceExtension->MiniPortDeviceExtension,
HwInitializationData->HwDeviceExtensionSize);
DPRINT("Searching on bus %d\n", DeviceExtension->SystemIoBusNumber);
/* Setup configuration info */
RtlZeroMemory(&ConfigInfo, sizeof(VIDEO_PORT_CONFIG_INFO));
ConfigInfo.Length = sizeof(VIDEO_PORT_CONFIG_INFO);
ConfigInfo.AdapterInterfaceType = DeviceExtension->AdapterInterfaceType;
ConfigInfo.SystemIoBusNumber = DeviceExtension->SystemIoBusNumber;
ConfigInfo.InterruptMode = (PCIBus == DeviceExtension->AdapterInterfaceType) ?
LevelSensitive : Latched;
/* Call HwFindAdapter entry point */
/* FIXME: Need to figure out what string to pass as param 3 */
Status = HwInitializationData->HwFindAdapter(&DeviceExtension->MiniPortDeviceExtension,
Context2,
NULL,
&ConfigInfo,
&Again);
if (NO_ERROR != Status)
{
DPRINT("HwFindAdapter call failed with error %d\n", Status);
DeviceExtension->SystemIoBusNumber++;
}
}
while (NO_ERROR != Status && DeviceExtension->SystemIoBusNumber < MaxBus);
if (NO_ERROR != Status)
{
RtlFreeUnicodeString(&DeviceExtension->RegistryPath);
IoDeleteDevice(MPDeviceObject);
return Status;
}
DPRINT("Found adapter\n");
/* 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.Length + sizeof(WCHAR));
/* FIXME: Allocate hardware resources for device */
/* Allocate interrupt for device */
DeviceExtension->HwInterrupt = HwInitializationData->HwInterrupt;
if (0 == ConfigInfo.BusInterruptVector)
{
ConfigInfo.BusInterruptVector = DeviceExtension->InterruptVector;
}
if (0 == ConfigInfo.BusInterruptLevel)
{
ConfigInfo.BusInterruptLevel = DeviceExtension->InterruptLevel;
}
if (NULL != HwInitializationData->HwInterrupt)
{
InterruptVector =
HalGetInterruptVector(ConfigInfo.AdapterInterfaceType,
ConfigInfo.SystemIoBusNumber,
ConfigInfo.BusInterruptLevel,
ConfigInfo.BusInterruptVector,
&IRQL,
&Affinity);
if (0 == InterruptVector)
{
DPRINT1("HalGetInterruptVector failed\n");
IoDeleteDevice(MPDeviceObject);
return STATUS_INSUFFICIENT_RESOURCES;
}
KeInitializeSpinLock(&DeviceExtension->InterruptSpinLock);
Status = IoConnectInterrupt(&DeviceExtension->InterruptObject,
VPInterruptRoutine,
DeviceExtension,
&DeviceExtension->InterruptSpinLock,
InterruptVector,
IRQL,
IRQL,
ConfigInfo.InterruptMode,
FALSE,
Affinity,
FALSE);
if (!NT_SUCCESS(Status))
{
DPRINT1("IoConnectInterrupt failed with status 0x%08x\n", Status);
IoDeleteDevice(MPDeviceObject);
return Status;
}
}
DeviceNumber++;
}
while (Again);
DeviceExtension->HwTimer = HwInitializationData->HwTimer;
if (HwInitializationData->HwTimer != NULL)
{
DPRINT("Initializing timer\n");
Status = IoInitializeTimer(MPDeviceObject,
VPTimerRoutine,
DeviceExtension);
if (!NT_SUCCESS(Status))
{
DPRINT("IoInitializeTimer failed with status 0x%08x\n", Status);
if (HwInitializationData->HwInterrupt != NULL)
{
IoDisconnectInterrupt(DeviceExtension->InterruptObject);
}
IoDeleteDevice(MPDeviceObject);
return Status;
}
}
return STATUS_SUCCESS;
}
/*
* @unimplemented
*/
VOID
STDCALL
VideoPortLogError(IN PVOID HwDeviceExtension,
IN PVIDEO_REQUEST_PACKET Vrp OPTIONAL,
IN VP_STATUS ErrorCode,
IN ULONG UniqueId)
{
DPRINT1("VideoPortLogError ErrorCode %d (0x%x) UniqueId %lu (0x%lx)\n",
ErrorCode, ErrorCode, UniqueId, UniqueId);
if (NULL != Vrp)
{
DPRINT1("Vrp->IoControlCode %lu (0x%lx)\n", Vrp->IoControlCode, Vrp->IoControlCode);
}
}
/*
* @unimplemented
*/
VP_STATUS
STDCALL
VideoPortMapBankedMemory(IN PVOID HwDeviceExtension,
IN PHYSICAL_ADDRESS PhysicalAddress,
IN PULONG Length,
IN PULONG InIoSpace,
OUT PVOID *VirtualAddress,
IN ULONG BankLength,
IN UCHAR ReadWriteBank,
IN PBANKED_SECTION_ROUTINE BankRoutine,
IN PVOID Context)
{
DPRINT("VideoPortMapBankedMemory\n");
UNIMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
}
/*
* @implemented
*/
VP_STATUS
STDCALL
VideoPortMapMemory(IN PVOID HwDeviceExtension,
IN PHYSICAL_ADDRESS PhysicalAddress,
IN PULONG Length,
IN PULONG InIoSpace,
OUT PVOID *VirtualAddress)
{
PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
DPRINT("VideoPortMapMemory\n");
DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
VIDEO_PORT_DEVICE_EXTENSION,
MiniPortDeviceExtension);
*VirtualAddress = InternalMapMemory(DeviceExtension, PhysicalAddress,
*Length, *InIoSpace);
return NULL == *VirtualAddress ? STATUS_NO_MEMORY : STATUS_SUCCESS;
}
/*
* @implemented
*/
BOOLEAN
STDCALL
VideoPortScanRom(IN PVOID HwDeviceExtension,
IN PUCHAR RomBase,
IN ULONG RomLength,
IN PUCHAR String)
{
ULONG StringLength;
BOOLEAN Found;
PUCHAR SearchLocation;
DPRINT("VideoPortScanRom RomBase %p RomLength 0x%x String %s\n", RomBase, RomLength, String);
StringLength = strlen(String);
Found = FALSE;
SearchLocation = RomBase;
for (SearchLocation = RomBase;
! Found && SearchLocation < RomBase + RomLength - StringLength;
SearchLocation++)
{
Found = (RtlCompareMemory(SearchLocation, String, StringLength) == StringLength);
if (Found)
{
DPRINT("Match found at %p\n", SearchLocation);
}
}
return Found;
}
/*
* @implemented
*/
ULONG
STDCALL
VideoPortSetBusData(IN PVOID HwDeviceExtension,
IN BUS_DATA_TYPE BusDataType,
IN ULONG SlotNumber,
IN PVOID Buffer,
IN ULONG Offset,
IN ULONG Length)
{
DPRINT("VideoPortSetBusData\n");
return HalSetBusDataByOffset(BusDataType,
0,
SlotNumber,
Buffer,
Offset,
Length);
}
/*
* @implemented
*/
VP_STATUS
STDCALL
VideoPortSetRegistryParameters(IN PVOID HwDeviceExtension,
IN PWSTR ValueName,
IN PVOID ValueData,
IN ULONG ValueLength)
{
PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
DPRINT("VideoSetRegistryParameters\n");
assert_irql(PASSIVE_LEVEL);
DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
VIDEO_PORT_DEVICE_EXTENSION,
MiniPortDeviceExtension);
return RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE,
DeviceExtension->RegistryPath.Buffer,
ValueName,
REG_BINARY,
ValueData,
ValueLength);
}
/*
* @unimplemented
*/
VP_STATUS
STDCALL
VideoPortSetTrappedEmulatorPorts(IN PVOID HwDeviceExtension,
IN ULONG NumAccessRanges,
IN PVIDEO_ACCESS_RANGE AccessRange)
{
DPRINT("VideoPortSetTrappedEmulatorPorts\n");
UNIMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
}
/*
* @implemented
*/
VOID
STDCALL
VideoPortStartTimer(IN PVOID HwDeviceExtension)
{
PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
DPRINT("VideoPortStartTimer\n");
DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
VIDEO_PORT_DEVICE_EXTENSION,
MiniPortDeviceExtension);
IoStartTimer(DeviceExtension->DeviceObject);
}
/*
* @implemented
*/
VOID
STDCALL
VideoPortStopTimer(IN PVOID HwDeviceExtension)
{
PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
DPRINT("VideoPortStopTimer\n");
DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
VIDEO_PORT_DEVICE_EXTENSION,
MiniPortDeviceExtension);
IoStopTimer(DeviceExtension->DeviceObject);
}
/*
* @implemented
*/
BOOLEAN
STDCALL
VideoPortSynchronizeExecution(IN PVOID HwDeviceExtension,
IN VIDEO_SYNCHRONIZE_PRIORITY Priority,
IN PMINIPORT_SYNCHRONIZE_ROUTINE SynchronizeRoutine,
OUT PVOID Context)
{
BOOLEAN Ret;
PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
KIRQL OldIrql;
DPRINT("VideoPortSynchronizeExecution\n");
switch(Priority)
{
case VpLowPriority:
Ret = (*SynchronizeRoutine)(Context);
break;
case VpMediumPriority:
DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
VIDEO_PORT_DEVICE_EXTENSION,
MiniPortDeviceExtension);
if (NULL == DeviceExtension->InterruptObject)
{
Ret = (*SynchronizeRoutine)(Context);
}
else
{
Ret = KeSynchronizeExecution(DeviceExtension->InterruptObject,
SynchronizeRoutine,
Context);
}
break;
case VpHighPriority:
OldIrql = KeGetCurrentIrql();
if (OldIrql < SYNCH_LEVEL)
{
OldIrql = KfRaiseIrql(SYNCH_LEVEL);
}
Ret = (*SynchronizeRoutine)(Context);
if (OldIrql < SYNCH_LEVEL)
{
KfLowerIrql(OldIrql);
}
break;
default:
Ret = FALSE;
}
return Ret;
}
/*
* @implemented
*/
VP_STATUS
STDCALL
VideoPortUnmapMemory(IN PVOID HwDeviceExtension,
IN PVOID VirtualAddress,
IN HANDLE ProcessHandle)
{
PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
DPRINT("VideoPortFreeDeviceBase\n");
DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
VIDEO_PORT_DEVICE_EXTENSION,
MiniPortDeviceExtension);
InternalUnmapMemory(DeviceExtension, VirtualAddress);
return STATUS_SUCCESS;
}
/*
* @unimplemented
*/
VP_STATUS
STDCALL
VideoPortVerifyAccessRanges(IN PVOID HwDeviceExtension,
IN ULONG NumAccessRanges,
IN PVIDEO_ACCESS_RANGE AccessRanges)
{
DPRINT1("VideoPortVerifyAccessRanges not implemented\n");
return NO_ERROR;
}
/*
* Reset display to blue screen
*/
static BOOLEAN STDCALL
VideoPortResetDisplayParameters(Columns, Rows)
{
if (NULL == ResetDisplayParametersDeviceExtension)
{
return(FALSE);
}
if (NULL == ResetDisplayParametersDeviceExtension->HwResetHw)
{
return(FALSE);
}
if (!ResetDisplayParametersDeviceExtension->HwResetHw(&ResetDisplayParametersDeviceExtension->MiniPortDeviceExtension,
Columns, Rows))
{
return(FALSE);
}
ResetDisplayParametersDeviceExtension = NULL;
return TRUE;
}
/*
* @implemented
*/
PVOID
STDCALL
VideoPortAllocatePool(
IN PVOID HwDeviceExtension,
IN VP_POOL_TYPE PoolType,
IN SIZE_T NumberOfBytes,
IN ULONG Tag)
{
return ExAllocatePoolWithTag(PoolType, NumberOfBytes, Tag);
}
/*
* @implemented
*/
VOID
STDCALL
VideoPortFreePool(
IN PVOID HwDeviceExtension,
IN PVOID Ptr)
{
ExFreePool(Ptr);
}
// VidDispatchOpen
//
// DESCRIPTION:
// Answer requests for Open calls
//
// RUN LEVEL:
// PASSIVE_LEVEL
//
// ARGUMENTS:
// Standard dispatch arguments
//
// RETURNS:
// NTSTATUS
//
NTSTATUS STDCALL
VidDispatchOpen(IN PDEVICE_OBJECT pDO,
IN PIRP Irp)
{
PIO_STACK_LOCATION IrpStack;
PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
DPRINT("VidDispatchOpen() called\n");
IrpStack = IoGetCurrentIrpStackLocation(Irp);
if (! CsrssInitialized)
{
DPRINT("Referencing CSRSS\n");
Csrss = PsGetCurrentProcess();
DPRINT("Csrss %p\n", Csrss);
}
else
{
DeviceExtension = (PVIDEO_PORT_DEVICE_EXTENSION) pDO->DeviceExtension;
if (DeviceExtension->HwInitialize(&DeviceExtension->MiniPortDeviceExtension))
{
Irp->IoStatus.Status = STATUS_SUCCESS;
/* Storing the device extension pointer in a static variable is an ugly
* hack. Unfortunately, we need it in VideoPortResetDisplayParameters
* and HalAcquireDisplayOwnership doesn't allow us to pass a userdata
* parameter. On the bright side, the DISPLAY device is opened
* exclusively, so there can be only one device extension active at
* any point in time. */
ResetDisplayParametersDeviceExtension = DeviceExtension;
HalAcquireDisplayOwnership(VideoPortResetDisplayParameters);
}
else
{
Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
}
}
Irp->IoStatus.Information = FILE_OPENED;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
// VidDispatchClose
//
// DESCRIPTION:
// Answer requests for Close calls
//
// RUN LEVEL:
// PASSIVE_LEVEL
//
// ARGUMENTS:
// Standard dispatch arguments
//
// RETURNS:
// NTSTATUS
//
NTSTATUS STDCALL
VidDispatchClose(IN PDEVICE_OBJECT pDO,
IN PIRP Irp)
{
PIO_STACK_LOCATION IrpStack;
DPRINT("VidDispatchClose() called\n");
IrpStack = IoGetCurrentIrpStackLocation(Irp);
if (! CsrssInitialized)
{
CsrssInitialized = TRUE;
}
else
{
HalReleaseDisplayOwnership();
}
Irp->IoStatus.Status = STATUS_SUCCESS;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
// VidDispatchDeviceControl
//
// DESCRIPTION:
// Answer requests for device control calls
//
// RUN LEVEL:
// PASSIVE_LEVEL
//
// ARGUMENTS:
// Standard dispatch arguments
//
// RETURNS:
// NTSTATUS
//
NTSTATUS STDCALL
VidDispatchDeviceControl(IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
PIO_STACK_LOCATION IrpStack;
PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
PVIDEO_REQUEST_PACKET vrp;
DPRINT("VidDispatchDeviceControl\n");
IrpStack = IoGetCurrentIrpStackLocation(Irp);
DeviceExtension = DeviceObject->DeviceExtension;
/* Translate the IRP to a VRP */
vrp = ExAllocatePool(PagedPool, sizeof(VIDEO_REQUEST_PACKET));
if (NULL == vrp)
{
return STATUS_NO_MEMORY;
}
vrp->StatusBlock = (PSTATUS_BLOCK) &(Irp->IoStatus);
vrp->IoControlCode = IrpStack->Parameters.DeviceIoControl.IoControlCode;
/* We're assuming METHOD_BUFFERED */
vrp->InputBuffer = Irp->AssociatedIrp.SystemBuffer;
vrp->InputBufferLength = IrpStack->Parameters.DeviceIoControl.InputBufferLength;
vrp->OutputBuffer = Irp->AssociatedIrp.SystemBuffer;
vrp->OutputBufferLength = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;
/* Call the Miniport Driver with the VRP */
((PDRIVER_STARTIO)DeviceObject->DriverObject->DriverStartIo)((PVOID) &DeviceExtension->MiniPortDeviceExtension, (PIRP)vrp);
/* Free the VRP */
ExFreePool(vrp);
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
PVOID STDCALL
InternalMapMemory(IN PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension,
IN PHYSICAL_ADDRESS IoAddress,
IN ULONG NumberOfUchars,
IN UCHAR InIoSpace)
{
PHYSICAL_ADDRESS TranslatedAddress;
PVIDEO_PORT_ADDRESS_MAPPING AddressMapping;
ULONG AddressSpace;
PVOID MappedAddress;
PLIST_ENTRY Entry;
if (0 != (InIoSpace & VIDEO_MEMORY_SPACE_P6CACHE))
{
DPRINT("VIDEO_MEMORY_SPACE_P6CACHE not supported, turning off\n");
InIoSpace &= ~VIDEO_MEMORY_SPACE_P6CACHE;
}
if (! IsListEmpty(&DeviceExtension->AddressMappingListHead))
{
Entry = DeviceExtension->AddressMappingListHead.Flink;
while (Entry != &DeviceExtension->AddressMappingListHead)
{
AddressMapping = CONTAINING_RECORD(Entry,
VIDEO_PORT_ADDRESS_MAPPING,
List);
if (IoAddress.QuadPart == AddressMapping->IoAddress.QuadPart &&
NumberOfUchars <= AddressMapping->NumberOfUchars)
{
AddressMapping->MappingCount++;
return AddressMapping->MappedAddress;
}
Entry = Entry->Flink;
}
}
AddressSpace = (ULONG)InIoSpace;
if (HalTranslateBusAddress(DeviceExtension->AdapterInterfaceType,
DeviceExtension->SystemIoBusNumber,
IoAddress,
&AddressSpace,
&TranslatedAddress) == FALSE)
return NULL;
/* i/o space */
if (AddressSpace != 0)
{
assert(0 == TranslatedAddress.u.HighPart);
return (PVOID) TranslatedAddress.u.LowPart;
}
MappedAddress = MmMapIoSpace(TranslatedAddress,
NumberOfUchars,
FALSE);
AddressMapping = ExAllocatePoolWithTag(PagedPool,
sizeof(VIDEO_PORT_ADDRESS_MAPPING),
TAG_VIDEO_PORT);
if (AddressMapping == NULL)
return MappedAddress;
AddressMapping->MappedAddress = MappedAddress;
AddressMapping->NumberOfUchars = NumberOfUchars;
AddressMapping->IoAddress = IoAddress;
AddressMapping->SystemIoBusNumber = DeviceExtension->SystemIoBusNumber;
AddressMapping->MappingCount = 1;
InsertHeadList(&DeviceExtension->AddressMappingListHead,
&AddressMapping->List);
return MappedAddress;
}
VOID STDCALL
InternalUnmapMemory(IN PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension,
IN PVOID MappedAddress)
{
PVIDEO_PORT_ADDRESS_MAPPING AddressMapping;
PLIST_ENTRY Entry;
Entry = DeviceExtension->AddressMappingListHead.Flink;
while (Entry != &DeviceExtension->AddressMappingListHead)
{
AddressMapping = CONTAINING_RECORD(Entry,
VIDEO_PORT_ADDRESS_MAPPING,
List);
if (AddressMapping->MappedAddress == MappedAddress)
{
assert(0 <= AddressMapping->MappingCount);
AddressMapping->MappingCount--;
if (0 == AddressMapping->MappingCount)
{
MmUnmapIoSpace(AddressMapping->MappedAddress,
AddressMapping->NumberOfUchars);
RemoveEntryList(Entry);
ExFreePool(AddressMapping);
return;
}
}
Entry = Entry->Flink;
}
}